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.