Think this, with bigger, knobbier tires, two speakers on the front, and one speaker on either side:
I had recently seen this article on Hack a Day, which lead me to this article, which lead down a rabbit hole of researching the MSGEQ7, RGB LED strip control, code examples, etc.
So I got some money from the coworker to order some parts and start development. Still have to move it to a PCB, figure out an enclosure, get a panel mount switch and pot, probably some screw terminals for power in and LED lead out, and mount everything to the cooler.
Ran into a couple challenges, mainly related to noise from the PWM interfering with the audio ground, causing a feedback loop which kept one of the LEDs lit. Ended up eliminating that by altering the timers on the Arduino to move the PWM frequency out of the range of audible frequencies. Also learned a bit about ground loops and how to eliminate them.
From the youtube video, a description on what everything does:
Arduino controlling an analog 5050 RGB LED strip, using one button and one pot for manual control, and a MSGEQ7 to input the audio. Controller has 7 modes, which are cycled through by pressing the one button.
1) Audio visualization. Uses audio input from a headphone jack to change the value of the red, green and blue LEDs based upon low, mid, and high EQ values.
2) Solid color. (2:25) Uses pot to cycle through colors, varying RGB values based upon position.
3) Pulse. (2:47) Pulses last color chosen during setting 2, at a speed based upon pot position.
4) Color cycle. (3:12) Automatically cycles between red, green, and blue, and all the colors in between. Speed of cycle is based upon pot position.
5) Random color cycle. (3:35) "Random" values of RGB are chosen, then transitioned to.
6) Campfire mode. (3:53) Color and flicker programmed to simulate campfire. I still think it's a little too orange, but still tweaking.
7) White. (4:05) Sets red, green and blue to the same value to generate "white" light. Brightness is set by pot position.
8) Off. (4:22) All LEDs set to zero.
Once the button is pushed again, the controller cycles back to the first option.
A bad fritzing diagram of how everything is hooked up. Links to sources for each part are in the code block below.
The single RGB LED represents the strip, source voltage to the top rail is 12v, bottom rail is 5v.
/*
RGB LED music controller
8 modes: music reaction, color select, color pulse, R>G>B cycle, random cycle, campfire simulation, all white, and off
By Russell Milling 2013-08-31
Large portions of code, wiring diagrams, and other help borrowed from:
Markus Ulfberg
http://genericnerd.blogspot.com/2011/12/arduino-mood-light-controller-v3.html
n00bsys0p
http://www.n00bsys0p.co.uk/blog/2012/07/09/arduinomsgeq7-audio-spectrum-led-display
J. Skoba
http://nuewire.com/info-archive/msgeq7-by-j-skoba/
Tyler Cooper
http://learn.adafruit.com/rgb-led-strips
Those who edit articles on the Arduino Playground
http://playground.arduino.cc/Main/TimerPWMCheatsheet
The DIY & Hobbies forum on SomethingAwful
http://forums.somethingawful.com/showthread.php?threadid=2734977&pagenumber=223#post418931935
Thanks to: Ladyada, Tom Igoe and
everyone at the Arduino forum for excellent
tutorials and everyday help.
*/
/* stuff to smooth out the pot readings
Define the number of samples to keep track of. The higher the number,
the more the readings will be smoothed, but the slower the output will
respond to the input. Using a constant rather than a normal variable lets
use this value to determine the size of the readings array.
*/
const int numReadings = 10;
int readings[numReadings]; // the readings from the analog input
int index = 0; // the index of the current reading
int total = 0; // the running total
int average = 0; // the average
// set the ledPins
int ledRed = 9;
int ledGreen = 10;
int ledBlue = 11;
// color selector pin
int potPin = 0;
// lightMode selector switch pin
int switchPin = 2;
// light mode variable
// initial value 0 = music
int lightMode = 0;
// LED Power variables
byte redPwr = 0;
byte greenPwr = 0;
byte bluePwr = 0;
byte ledPwr = 0;
// Variables for lightMode 2
// variables for keeping pulse color
byte redPulse;
byte greenPulse;
byte bluePulse;
int pulseSpeed;
// Set pulse to down initially
byte pulse = 0;
// floating variables needed to be able to pulse a fixed color
float redFloat;
float greenFloat;
float blueFloat;
// the amount R,G & B should step up/down to display an fixed color
float redKoff;
float greenKoff;
float blueKoff;
// Variables for lightMode 3
// set the initial random colors
byte redNew = random(255);
byte greenNew = random(255);
byte blueNew = random(255);
// Variables for cycleColor
int truColor = 0;
// misc interface variables
// potVal store the value of the potentiometer for various needs
int potVal;
// value from the button (debounce)
int switchVal;
int switchVal2;
// buttonState registers if the button has changed
int buttonState;
// MSGEQ7 stuff for music
int analogPin = 3; // MSGEQ7 OUT
int strobePin = 4; // MSGEQ7 STROBE
int resetPin = 7; // MSGEQ7 RESET
int spectrumValue[7]; // store the 7 eq band values
// MSGEQ7 OUT pin produces values around 50-80
// when there is no input, so use this value to
// filter out a lot of the chaff.
int filterValue = 80;
// variable to control the max intensity of the LEDs when in music mode
int filterMax = 255;
void setup()
{
pinMode(ledRed, OUTPUT);
pinMode(ledGreen, OUTPUT);
pinMode(ledBlue, OUTPUT);
pinMode(potPin, INPUT);
pinMode(switchPin, INPUT);
buttonState = digitalRead(switchPin);
// serial for debugging purposes only
// Serial.begin(9600);
// pot smoothing
for (int thisReading = 0; thisReading < numReadings; thisReading++)
readings[thisReading] = 0;
// Read from MSGEQ7 OUT
pinMode(analogPin, INPUT);
// Write to MSGEQ7 STROBE and RESET
pinMode(strobePin, OUTPUT);
pinMode(resetPin, OUTPUT);
// Set analogPin's reference voltage
analogReference(DEFAULT); // 5V
// Set startup values for pins
digitalWrite(resetPin, LOW);
digitalWrite(strobePin, HIGH);
// set the Arduino timers to crazyfast values for pins 3, 9, 10, and 11 so that PWM doesn't cause audible hum or feedback in the audio circuit.
//If changing code to use a second LED strip on the other 3 PWM pins, make sure to set TCCR0B as well, but be mindful that it will effect system timer values
// such as delay(), millis(), micros(), etc
// See: http://playground.arduino.cc/Main/TimerPWMCheatsheet for more information
TCCR1B = TCCR1B & 0b11111000 | 0x01;
TCCR2B = TCCR2B & 0b11111000 | 0x01;
}
void loop()
{
switchVal = digitalRead(switchPin); // read input value and store it in val
delay(10); // 10 milliseconds is a good amount of time
switchVal2 = digitalRead(switchPin); // read the input again to check for bounces
if (switchVal == switchVal2) { // make sure we got 2 consistant readings!
if (switchVal != buttonState) { // the button state has changed!
if (switchVal == LOW) { // check if the button is pressed
switch (lightMode) { // light is initially in music react mode
case 0:
lightMode = 1; // light is on and responds to pot to choose color
break;
case 1:
lightMode = 2; // light pulsates in the latest color from pot
break;
case 2:
lightMode = 3; // light cycles thru colors
break;
case 3:
lightMode = 4; // light changes randomly
break;
case 4:
lightMode = 5; // simulated fire
break;
case 5:
lightMode = 6; // all white
break;
case 6:
lightMode = 7; // lights off
break;
case 7:
lightMode = 0; // music react
break;
} // END switch (lightMode)
} // END if (switchVal == LOW)
} // END if (switchVal != buttonState)
buttonState = switchVal; // save the new state in our variable
} // END if (switchVal == switchVal2)
// Debug
//Serial.print("lightMode: ");
//Serial.println(lightMode);
switch (lightMode) {
case 0:
musicEQ();
break;
case 1:
colorControl();
break;
case 2:
pulsateColor();
break;
case 3:
cycleColor();
break;
case 4:
randomColor();
break;
case 5:
lightMyFire();
break;
case 6:
allWhite();
break;
case 7:
lightsOff();
break;
}
} // END loop()
// lightMode 7
void lightsOff() {
redPwr = 0;
greenPwr = 0;
bluePwr = 0;
colorDisplay();
}
// lightMode 1
void colorControl() {
// read the potentiometer position
getPot();
potVal = average;
// RED > ORANGE > YELLOW
if (potVal > 0 && potVal < 170) {
redPwr = 255;
bluePwr = 0;
greenPwr = map(potVal, 0, 170, 0, 255);
}
// YELLOW > LIME?? > GREEN
if (potVal > 170 && potVal < 341) {
greenPwr = 255;
bluePwr = 0;
redPwr = map(potVal, 341, 170, 0, 255);
}
// GREEN > TURQOUISE
if (potVal > 341 && potVal < 511) {
greenPwr = 255;
redPwr = 0;
bluePwr = map(potVal, 341, 511, 0, 255);
}
// TURQOUISE > BLUE
if (potVal > 511 && potVal < 682) {
bluePwr = 255;
redPwr = 0;
greenPwr = map(potVal, 682, 511, 0, 255);
}
// BLUE > PURPLE
if (potVal > 682 && potVal < 852) {
bluePwr = 255;
greenPwr = 0;
redPwr = map(potVal, 682, 852, 0, 255);
}
// PURPLE > RED
if (potVal > 852 && potVal < 1023) {
redPwr = 255;
greenPwr = 0;
bluePwr = map(potVal, 1023, 852, 0, 255);
}
redFloat = float(redPwr);
greenFloat = float(greenPwr);
blueFloat = float(bluePwr);
redKoff = redFloat / 255;
greenKoff = greenFloat / 255;
blueKoff = blueFloat / 255;
redPulse = redPwr;
greenPulse = greenPwr;
bluePulse = bluePwr;
/*
// Debug
Serial.print("redFLoat: ");
Serial.print(redFloat, DEC);
Serial.print(" redPwr: ");
Serial.print(redPwr, DEC);
Serial.print(" greenFloat: ");
Serial.print(greenFloat, DEC);
Serial.print(" greenPwr: ");
Serial.print(greenPwr, DEC);
Serial.print(" blueFloat: ");
Serial.print(blueFloat, DEC);
Serial.print(" bluePwr: ");
Serial.println(bluePwr, DEC);
// End debug
*/
// Display colors
colorDisplay();
}
// lightMode 2
void pulsateColor() {
// get colors from colorControl
redPwr = int(redFloat);
greenPwr = int(greenFloat);
bluePwr = int(blueFloat);
// Read speed from potentiometer
getPot();
potVal = average;
pulseSpeed = map(potVal, 0, 1023, 0, 200);
//display the colors
colorDisplay();
// set speed of change
delay(pulseSpeed);
// pulse down
if (pulse == 0) {
if (redFloat > 10) {
redFloat = redFloat - redKoff;
}
if (greenFloat > 10) {
greenFloat = greenFloat - greenKoff;
}
if (blueFloat > 10) {
blueFloat = blueFloat - blueKoff;
}
// If all xFloat match 10 get pulse up
if (byte(redFloat) <= 10) {
if (byte(greenFloat) <= 10) {
if (byte(blueFloat) <= 10) {
pulse = 1;
}
}
}
}
// Pulse up
if (pulse == 1) {
if (redFloat < redPulse) {
redFloat = redFloat + redKoff;
}
if (greenFloat < greenPulse) {
greenFloat = greenFloat + greenKoff;
}
if (blueFloat < bluePulse) {
blueFloat = blueFloat + blueKoff;
}
// If all Pwr match Pulse get pulse down
if (byte(redFloat) == redPulse) {
if (byte(greenFloat) == greenPulse) {
if (byte(blueFloat) == bluePulse) {
pulse = 0;
}
}
}
}
/*
// Debug
Serial.print("redFloat: ");
Serial.print(redFloat, DEC);
Serial.print(" redPulse: ");
Serial.print(redPulse, DEC);
Serial.print(" greenFloat: ");
Serial.print(greenFloat, DEC);
Serial.print(" greenPulse: ");
Serial.print(greenPulse, DEC);
Serial.print(" blueFloat: ");
Serial.print(blueFloat, DEC);
Serial.print(" bluePulse: ");
Serial.print(bluePulse, DEC);
Serial.print(" pulse: ");
Serial.println(pulse, DEC);
// End debug
*/
} // pulsateColor END
// lightMode 3
void cycleColor() { // Cycles through colors
switch(truColor) {
// RED > ORANGE > YELLOW
case 0:
redPwr = 255;
bluePwr = 0;
greenPwr++;
if (greenPwr > 254) {
truColor = 1;
}
break;
// YELLOW > LIME?? > GREEN
case 1:
greenPwr = 255;
bluePwr = 0;
redPwr--;
if (redPwr < 1) {
truColor = 2;
}
break;
// GREEN > TURQOUISE
case 2:
greenPwr = 255;
bluePwr++;
redPwr = 0;
if (bluePwr > 254) {
truColor = 3;
}
break;
// TURQOUISE > BLUE
case 3:
greenPwr--;
bluePwr = 255;
redPwr = 0;
if (greenPwr < 1) {
truColor = 4;
}
break;
// BLUE > PURPLE
case 4:
greenPwr = 0;
bluePwr = 255;
redPwr++;
if (redPwr > 254) {
truColor = 5;
}
break;
// PURPLE > RED
case 5:
greenPwr = 0;
bluePwr--;
redPwr = 255;
if (bluePwr < 1) {
truColor = 0;
}
break;
}
// START SPEED
getPot();
potVal = average;
pulseSpeed = map(potVal, 0, 1023, 0, 200);
//display the colors
colorDisplay();
// set speed of change
delay(pulseSpeed);
// END SPEED
} // END cycleColor
// lightMode 4
void randomColor() { // randomize colorNew and step colorPwr to it
if (redPwr > redNew) {
redPwr--;
}
if (redPwr < redNew) {
redPwr++;
}
if (greenPwr > greenNew) {
greenPwr--;
}
if (greenPwr < greenNew) {
greenPwr++;
}
if (bluePwr > blueNew) {
bluePwr--;
}
if (bluePwr < blueNew) {
bluePwr++;
}
// If all Pwr match New get new colors
if (redPwr == redNew) {
if (greenPwr == greenNew) {
if (bluePwr == blueNew) {
redNew = random(254);
greenNew = random(254);
blueNew = random(254);
}
}
}
getPot();
potVal = average;
pulseSpeed = map(potVal, 0, 1023, 0, 200);
//display the colors
colorDisplay();
// set speed of change
delay(pulseSpeed);
} // END randomColor
// lightMode 5
void lightMyFire() {
// Flicker will determine how often a fast flare will occur
int flicker;
// set flicker randomness
flicker = random(1800);
// Set random colors,
// constrain green to red and blue to green
// in order to stay within a red, blue, white spectrum
redPwr = random(220, 240);
greenPwr = random(20, 40);
// when flicker occur, the colors shine brighter
// adding blue creates a white shine
if (flicker > 1750) {
redPwr = 254;
greenPwr = random(60, 80);
bluePwr = random(10, 40);
} else {
bluePwr = 0;
}
// display Colors
colorDisplay();
// Set speed of fire
delay(80);
} // END lightMyFire
// lightMode 6
void allWhite() {
// Smoothing out the pot readings. Will replace later with getPot()
getPot();
// map the smoothed pot value to LED pwm
ledPwr = map(average, 0, 1023, 0, 255);
redPwr = ledPwr;
greenPwr = ledPwr;
bluePwr = ledPwr;
colorDisplay();
} // End allWhite
// Begin lightMode 0
void musicEQ() {
getPot();
filterMax = map(average, 0, 1023, 0, 255);
// Set reset pin low to enable strobe
digitalWrite(resetPin, HIGH);
digitalWrite(resetPin, LOW);
// Get all 7 spectrum values from the MSGEQ7
for (int i = 0; i < 7; i++)
{
digitalWrite(strobePin, LOW);
delayMicroseconds(30); // Allow output to settle
spectrumValue[i] = analogRead(analogPin);
// Constrain any value above 1023 or below filterValue
spectrumValue[i] = constrain(spectrumValue[i], filterValue, 1023);
// Remap the value to a number between 0 and 255
spectrumValue[i] = map(spectrumValue[i], filterValue, 1023, 0, filterMax);
// Remove serial stuff after debugging
//Serial.print(spectrumValue[i]);
//Serial.print(" ");
digitalWrite(strobePin, HIGH);
}
//Serial.println();
/* Spectrum Value Frequencies:
0: 63 Hz
1: 160 Hz
2: 400 Hz
3: 1000 Hz
4: 2500 Hz
5: 6250 Hz
6: 16000 Hz
1, 4, and 6 seem to offer best combination using only 3 LEDs
If using 6 LEDs, 1-6 or 1-3 and 4-6 depending on music.
*/
redPwr = spectrumValue[1];
greenPwr = spectrumValue[4];
bluePwr = spectrumValue[6];
colorDisplay();
}
// Displays the colors when called from other functions
void colorDisplay() {
analogWrite(ledRed, redPwr);
analogWrite(ledGreen, greenPwr);
analogWrite(ledBlue, bluePwr);
}
// Smooths out the pot readings.
void getPot() {
// subtract the last reading:
total= total - readings[index];
// read from the sensor:
readings[index] = analogRead(potPin);
// add the reading to the total:
total= total + readings[index];
// advance to the next position in the array:
index = index + 1;
// if we're at the end of the array...
if (index >= numReadings)
// ...wrap around to the beginning:
index = 0;
// calculate the average:
average = total / numReadings;
// send it to the computer as ASCII digits
// Serial.println(average);
delay(1); // delay in between reads for stability
}
A partial parts list for what I used other than the Arduino:
220k ohm resistor
http://www.taydaelectronics.com/resistors/1-4w-metal-film-resistors/220k-ohm-1-4w-1-metal-film-resistor.html
.01uf capacitor
http://www.taydaelectronics.com/capacitors/ceramic-disc-capacitors/10-x-0-01uf-50v-ceramic-disc-capacitor-pkg-of-10.html
(2) .1uf capacitor
http://www.taydaelectronics.com/capacitors/ceramic-disc-capacitors/10-x-0-1uf-50v-ceramic-disc-capacitor-pkg-of-10.html
33pf capacitor
http://www.taydaelectronics.com/capacitors/ceramic-disc-capacitors/10-x-33pf-50v-ceramic-disc-capacitor-pkg-of-10.html
3x N channel mosfets:
http://www.mouser.com/ProductDetail/STMicroelectronics/STP16NF06L/?qs=RC432zO33OqodrhO5g7gPg%3d%3d
2x
Headphone jack
http://www.mouser.com/ProductDetail/Kobiconn/161-3402-E/?qs=%2fha2pyFaduiyB%252bLCpU7TZoJ3cfVHPgazskZ0wf2sV%252bg%3d
A push button. Can be as simple as this, or as fancy as you want. Make sure to get normally open, single pole, single throw in a panel mount package.
http://www.taydaelectronics.com/electromechanical/switches-key-pad/push-button/pb-11d02-push-button-panel-mount-spst-no-pb-11d02-th1r00.html
A 1K ohm linear potentiometer. Again, get a panel mount part, and you can go fancy or simple with a knob for it if you want.
http://www.taydaelectronics.com/potentiometer-variable-resistors/rotary-potentiometer/linear/1k-ohm-linear-taper-potentiometer-with-solder-lugs.html
http://www.ebay.com/sch/i.html?_odkw=1k+linear+potentiometer&_fspt=1&_sop=12&_osacat=0&_mPrRngCbx=1&_trksid=p2045573.m570.l1313.TR12.TRC2.A0.Xpotentiometer+knob&_nkw=potentiometer+knob&_sacat=0&_from=R40
RGB LED strip. This is the one I ordered. Comes with a controller, but not a power brick. It's not hard to find a 12v power brick that you can use with these laying around with old electronics.
http://www.ebay.com/itm/290954092203?ssPageName=STRK:MEWNX:IT&_trksid=p3984.m1497.l2649
MSGEQ7, which is the chip that takes the audio in and turns it into something the microcontroller can use:
http://www.ebay.com/sch/items/?_nkw=msgeq7&_sacat=&_ex_kw=&_mPrRngCbx=1&_udlo=&_udhi=&_sop=12&_fpos=&_fspt=1&_sadis=&LH_CAds=