声をかけると目が光りシッポをブルブルさせるフェルトのネコです。
主な部品
Arduino Nano (5V 16MHz)互換ボード
SPW2430搭載 シリコンMEMSマイクモジュール
円盤型 振動モーター(2個入)
導電糸
配線
マイクDC出力:A0
LED+:D5, D9
LED-:D12 (GND) 導電糸引き回し軽減のため
振動モーター:D3
スケッチ(Mic_DelayedReaction-nano12f)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
/* Sound sensing and delayed reaction using SPW2430 mic module */ const int mic_DC = A0; const int LED_GND = 12; const int EyeRight = 9; // Analog output pin that the LED is attached to const int EyeLeft = 5; // Analog output pin that the LED is attached to const int Tail =3; const int dataSize = 100, timeShiftSize = 50, historySize= 30; int data[dataSize], timeShift[timeShiftSize], vibHistory[historySize]; int TimePosSound,TimePosLED,TimePosVib; const int ShiftLED=40, ShiftVib=1, ThVib=100; const int MicCoeff=180, ThSound=30, ThLED=90; boolean vibQuiet; int ledout, soundValue, vibration; float loudness; int t_count=0; void setup() { analogReference(INTERNAL);//0-1.1V pinMode(LED_GND, OUTPUT); digitalWrite(LED_GND,LOW); inittimeShift(); initvibHistory(); Serial.begin(9600); } void loop() { TimePosSound=t_count % timeShiftSize; TimePosLED=(t_count + ShiftLED) % timeShiftSize; TimePosVib=(t_count + ShiftVib ) % timeShiftSize; readMic(); loudness = proc_sound()*MicCoeff; soundValue = constrain ((int)loudness,0,255); vibQuiet=vib_quiet(vibration); timeShift[TimePosSound] = 0; /* Serial.print(soundValue); Serial.print(" "); Serial.print(vibration); Serial.print(" "); Serial.println(vibQuiet); */ if((soundValue > ThSound) && vibQuiet){ timeShift[TimePosSound] = soundValue;} ledout =0; if (timeShift[TimePosLED] > ThLED){ ledout =timeShift[TimePosLED];} vibration = 0; if (timeShift[TimePosVib] > ThVib){ vibration = timeShift[TimePosVib];} analogWrite(EyeRight, ledout); analogWrite(EyeLeft, ledout); analogWrite(Tail, vibration); t_count++; } void readMic() { for (int i = 0; i < dataSize; i++) { data[i] = kill_noise(); } } int kill_noise(){ int s0,s1,s2; s0=analogRead(mic_DC); s1=analogRead(mic_DC); s2=analogRead(mic_DC); if((s1<=s0 && s0 <= s2)||(s2<=s0 && s0 <= s1)) return s0; if((s0<=s1 && s1 <= s2)||(s2<=s1 && s1 <= s0)) return s1; return s2; } float proc_sound() { float mean=0,std=0; for(int i = 0; i < dataSize; i++) mean = mean + (float)data[i]; mean = mean / dataSize; for(int i = 0; i < dataSize; i++) std = std + sq((float)data[i]-mean); std = sqrt(std/(dataSize-1)); return std; } boolean vib_quiet(int vib){ boolean Quiet=true; for(int i=historySize-1;i>0; i--){ vibHistory[i]=vibHistory[i-1]; } vibHistory[0]=vib; for(int i=0;i<historySize; i++){ if(vibHistory[i]>ThVib){ Quiet=false; } } return Quiet; } void inittimeShift() { for (int i = 0; i < timeShiftSize; i++) { timeShift[i]=0; } } void initvibHistory() { for (int i = 0; i < historySize; i++) { vibHistory[i]=0; } } |
ノイズ除去のために3回測定して中央値をデータとします。そのデータを要素100のdata[]に格納します。100個のデータから標準偏差を計算して音の大きさとします。
音に対するLEDと振動モーターの反応は、音を受けて間を置いてLEDが光り、さらに遅れて振動モーターが動作するようにしています。音の大きさを要素50個のtimeShift[]にリングバッファー状に格納します。LEDと振動モーターのデータは指標をシフトさせて読み込みます。
振動モーターが振動した音をマイクが拾って反応が止まらなくなりますので、要素30個のvibHistory[]に振動モーターへの出力を記録して振動モーターの動作中は音を格納しないようにします。