Let's control the mouth animation dynamically with a little Arduino and an electret microphone.
I prefer to adjust the gain on the microphone... although you could do it in code.
Here's how I hooked up the mouth LEDs to the Arduino.
- yellow wire to pin 9: drives the LEDs on the far right and left
- blue wire to pin 10: drives the LEDs between the center and outside
- purple wire to pin 11: drives the LED in the center of the mouth
- green wire to ground
And this is the sketch that drives the LEDs based on the sound levels captured by the microphone.
There are some settings in there like HI_CUT, LO_CUT, and DC_OFFSET that you might have to adjust depending on what kind of audio you intend to drive the microphone with and how you've hooked it up.
As-is, this sketch works pretty well with the mic attached to your shirt just below the mouth.
// Connect LED positive to pins 9, 10, 11 with common ground. #define MIC_PIN A0 // connected to the out pin on the mic #define DC_OFFSET 3.3 // mic is plugged into 3.3v const byte HI_CUT = 255; // upper brightness limit const byte LO_CUT = 40; // lower iimit turns LEDs off // sample window width in mS (50 mS = 20Hz) const int sampleWindow = 50; unsigned int sample; int LED_CENTER = 11; // LED at center of the mouth int LED_MIDDLE = 10; // LEDs between the center and outside int LED_OUTSDE = 9; // LEDs on the outside of the mouth void setup() { // Serial.begin(9600); // remove comment for debugging pinMode( LED_CENTER, OUTPUT ); pinMode( LED_MIDDLE, OUTPUT ); pinMode( LED_OUTSDE, OUTPUT ); } void loop() { unsigned long startMillis= millis(); // start of sample window unsigned int peakToPeak = 0; // peak-to-peak level unsigned int signalMax = 0; unsigned int signalMin = 1024; double lvl = 0; // collect data for 50 mS within a reasonable range while (millis() - startMillis < sampleWindow) { sample = analogRead(MIC_PIN); if (sample < 1024) { if (sample > signalMax) { signalMax = sample; } else if (sample < signalMin) { signalMin = sample; } } } lvl = signalMax - signalMin; // max - min = peak-peak amplitude lvl = ( lvl * DC_OFFSET ); // reduce operational range lvl = ( lvl < LO_CUT ? 0 : lvl ); // low cut filter for noise lvl = ( lvl > HI_CUT ? HI_CUT : lvl ); // high cut filter for clipping analogWrite( LED_CENTER, lvl ); // 100% brightness analogWrite( LED_MIDDLE, lvl * .8 ); // 80% brightness of center analogWrite( LED_OUTSDE, lvl * .3 ); // 30% brightness of center // Serial.println(lvl); // remove comment for debugging }
Have fun with your new robotic friend!
Page last edited March 08, 2024
Text editor powered by tinymce.