Difference between revisions of "Real-Time Drum Lights"

From i3Detroit
Jump to: navigation, search
(Added documentation for V 1.0 of project)
 
 
(One intermediate revision by one user not shown)
Line 29: Line 29:
 
Common Anode 8000MCD Super Flux RGB LED (P/N G16721) <br>
 
Common Anode 8000MCD Super Flux RGB LED (P/N G16721) <br>
 
Ultra Small Electret Microphone (P/N G15220) <br>
 
Ultra Small Electret Microphone (P/N G15220) <br>
 +
 +
 +
Arduino Sketch <br>
 +
<nowiki>/*
 +
  mic_randeightcolors
 +
 
 +
  Flashes RGB LED's in a random color when the microphone detects a sound.
 +
 
 +
  The circuit:
 +
    RBG LEDs w/ MOSFET drivers, miniature microphone.
 +
   
 +
    Created 27 June 2009
 +
    By David Scholl
 +
*/
 +
 +
// the array index runs over the number of drums
 +
#include "WProgram.h"
 +
void setup();
 +
void loop();
 +
int numDrums = 5;
 +
int drum;
 +
 +
// the microphone is connected to an analog input at the specified pin number
 +
int micPin[] = {0, 1, 2, 3, 4};
 +
 +
// the microphone reading value is an integer, 0-1023
 +
int micValue[] = {0, 0, 0, 0, 0};
 +
 +
// the microphone signal is offset by its running average
 +
float micOffset[] = {511.0, 511.0, 511.0, 511.0, 511.0}; 
 +
 +
// the rate of change of the running average (offset), was 0.6
 +
float micOffsetRate[] = {0.6, 0.6, 0.6, 0.6, 0.6};
 +
 +
// sensitivity of microphone, use 180 outside of drum, 300 inside of drum
 +
int micThreshold[] = {295, 300, 285, 300, 265};
 +
 +
// the red LED is controlled by the digital outputs specified
 +
int redPin[] = {22, 28, 34, 40, 46};
 +
 +
// the green LED is controlled by the digital outputs specified
 +
int greenPin[] = {24, 30, 36, 42, 48};
 +
 +
// the blue LED is controlled by the digital outputs specified
 +
int bluePin[] = {26, 32, 38, 44, 50};
 +
 +
int ledDuration = 50;  // the LED flash lasts for ledDuration milliseconds
 +
 +
long seedValue;    // a seed value is required for randomness
 +
 +
int rgbColor;    // index to seven colors, 1-7
 +
 +
long stopMillis[] = {0, 0, 0, 0, 0};    // the time to stop the flash
 +
 +
int flashState[] = {0, 0, 0, 0, 0};    // 0 if flash off, 1 if flash on
 +
 +
// variables for approximate loop timing
 +
long loopCount = 0;
 +
long lastMillis = 0;
 +
long newMillis;
 +
long diffMillis;
 +
 +
// the setup method runs once to configure the digital output pins
 +
// and seed the random generator
 +
 +
void setup() {
 +
 
 +
  for (drum = 0; drum < numDrums; drum = drum + 1) {
 +
    // setup the digital outputs to drive the LEDs
 +
    pinMode(redPin[drum], OUTPUT);
 +
    pinMode(greenPin[drum], OUTPUT);
 +
    pinMode(bluePin[drum], OUTPUT);
 +
    digitalWrite(redPin[drum], LOW);
 +
    digitalWrite(greenPin[drum], LOW);
 +
    digitalWrite(bluePin[drum], LOW);
 +
  }
 +
  seedValue = analogRead(15);    // acquire a random seed from an unused input
 +
  randomSeed(seedValue);    // seed the random generator
 +
  //Serial.begin(9600);    // initialize the serial port for debugging messages
 +
}
 +
 +
// the loop method runs repeatedly as long as the Arduino has power
 +
 +
void loop() {
 +
 
 +
  loopCount = loopCount + 1;    // used for approximate loop timing
 +
 
 +
  for (drum = 0; drum < numDrums; drum = drum + 1) {    // loop over drums
 +
 
 +
    micValue[drum] = analogRead(micPin[drum]);    // read the microphone signal
 +
    micValue[drum] = micValue[drum]-int(micOffset[drum]);    // subtract the offset (running average)
 +
   
 +
    // update the running average
 +
    micOffset[drum] = micOffset[drum]*(1.0-micOffsetRate[drum]);
 +
    micOffset[drum] = micOffset[drum]+(float(micValue[drum])*micOffsetRate[drum]);
 +
       
 +
    // the microphone signal should be centered around its running average
 +
    // if the distance from the average exceeds the threshold, flash the LED
 +
    if (flashState[drum] == 0) {
 +
      if (abs(micValue[drum]) > micThreshold[drum]) { 
 +
        // pick at random from the seven colors
 +
        rgbColor = int(random(1, 8));
 +
       
 +
        // set the LED driver outputs to the chosen color
 +
        switch (rgbColor) {
 +
          case 1:
 +
            digitalWrite(redPin[drum], HIGH);
 +
            break;
 +
          case 2:
 +
            digitalWrite(greenPin[drum], HIGH);
 +
            break;
 +
          case 3:
 +
            digitalWrite(bluePin[drum], HIGH);
 +
            break;
 +
          case 4:
 +
            digitalWrite(redPin[drum], HIGH);
 +
            digitalWrite(greenPin[drum], HIGH);
 +
            break;
 +
          case 5:
 +
            digitalWrite(redPin[drum], HIGH);
 +
            digitalWrite(bluePin[drum], HIGH);
 +
            break;
 +
          case 6:
 +
            digitalWrite(greenPin[drum], HIGH);
 +
            digitalWrite(bluePin[drum], HIGH);
 +
            break;
 +
          case 7:
 +
            digitalWrite(redPin[drum], HIGH);
 +
            digitalWrite(greenPin[drum], HIGH);
 +
            digitalWrite(bluePin[drum], HIGH);
 +
            break;
 +
        }
 +
        // keep the LED on enough to make a visible flash
 +
        stopMillis[drum] = millis() + 50;
 +
       
 +
        // remember that the flash is on
 +
        flashState[drum] = 1;
 +
      }
 +
    }
 +
    else { 
 +
      // turn all three colors off if the flash time is over
 +
      if (stopMillis[drum] < millis()) { 
 +
        digitalWrite(redPin[drum], LOW);
 +
        digitalWrite(greenPin[drum], LOW);
 +
        digitalWrite(bluePin[drum], LOW);
 +
        flashState[drum] = 0;
 +
      }
 +
    }
 +
  //Serial.println(micOffset[drum]);
 +
  //Serial.println(micValue[drum]);
 +
  }
 +
  if (loopCount % 1000 == 0) {
 +
    newMillis = millis();
 +
    diffMillis = newMillis - lastMillis;
 +
    lastMillis = newMillis;
 +
    //Serial.println(diffMillis);
 +
    //Serial.println(micOffset[3]);
 +
    //Serial.println(micValue[3]);
 +
    //Serial.println();
 +
  }
 +
}
 +
 +
 +
int main(void)
 +
{
 +
        init();
 +
 +
        setup();
 +
   
 +
        for (;;)
 +
                loop();
 +
       
 +
        return 0;
 +
} </nowiki>
  
  
 
V 2.0 <br>
 
V 2.0 <br>
 
TBD
 
TBD
 +
[[Category:Projects]][[Category:Member Projects]][[Category:Completed Projects]]

Latest revision as of 16:57, 24 June 2012

V 1.0
7/31/2009

Action Video made by my son's friend Max

Circuit Schematic
Photo of LED boards and microphone
Photo of controller board

This circuit uses an Arduino microcontroller board to flash colored lights inside a drum when the drum is played. A miniature electret microphone inside each drum detects when that drum is played. For a dramatic visual effect, you need the extra-bright LEDs that are used in flashlights, not the weaker type used as indicator lights on front panels. For each drum, you need one analog input and three digital outputs (one each for red, green, and blue). Each drum circuit is independent except for power supplies and ground, so you can use two or more Aduinos in parallel if you want to. I chose the Arduino Mega because I wanted to light five drums with one controller. For simplicity, the electronic schematic shows the circuit you would need for one drum with two RGB LEDs.

For testing or small installations, you can drive single LEDs directly from the digital outputs of the Arduino. However, multiple extra-bright LEDs add up to too much current for the Arduino digital outputs to sink to ground. The IRF530 MOSFETs are used to amplify the current-sink capability of the Arduino digital outputs. These IRF530 MOSFETs are overkill, as each one can sink many amps, (hundreds of LEDs). I picked them because they have a very low on-resistance, which makes the circuit design simpler. Also, I was certain that they would not need heatsinks.

To connect additional LEDs, you need to duplicate the circuitry shown in the dashed-line boxes on the right-hand side of the Arduino. RGB LEDs are just three separate LEDs in one convenient package, put close together so the colors mix better. They have four leads: one R, one G, one B, and one common, which can be all three anodes or all three cathodes. The circuit design shown here is for common-anode RGB LEDs, because they are simpler to drive with MOSFETS than the common cathode configuration. Each LED needs its own current-limiting resistor. The values of the current limiting resistors need to be selected such that the current through each diode is the maximum specified by the manufacturer (20 mA for our LEDs). Different color LEDs have different voltage drops, so they may need different resistor values. The resistor value also depends on the voltage you use to power the LEDs, which should be at least 4.5V, and can be higher. Our installation draws over 2 amps with all LEDs lit, so we use a separate regulated 9V supply just for the LEDs.

The microphone needs to be inside of the drum, to minimize interference from the noise coming from other drums. The remainder of the microphone circuit is outside on a prototype board, to make it more accessible if we needed to adjust the component values (which we did). Normally, microphones need preamps, but the sound inside the drums is so loud that we have plenty of amplitude with a direct connection. The blocking capacitor and the two 10k resistors allow us to capture both positive and negative peaks with the 0-5V A/D convertor on the Arduino.

The LEDs can be anywhere you like, but we installed them with the current limiting resistors on small circuit boards inside the drum. The circuit boards are mounted under the screws that hold the head-tuning brackets. We use six or eight LEDs per drum, depending on how many head-tuning brackets are there. You can run the wires through the vent hole in the side of the drum, but use thin wires. If you block the vent you will spoil the sound of the drum. We used Cat5 networking cable and removed the outer jacket on the part of the cable that passes through the vent hole. Using Cat5 cable also means that we can use robust and inexpensive RJ45 connectors to disconnect the circuit when we take the drum set apart to move it. We used the eight Cat5 wires that go into each drum as follows: microphone plus and minus, R, G, and B cathodes, and three wires in parallel to the common anodes.

For additional drums, you need to duplicate the microphone circuit drawn on the left side of the Arduino. The microphone circuits can share power and ground, but they each need their own analog input on the Arduino. For additional drums, you also need to duplicate the LED circuit on the right side of the Arduino. The drums can share power supply and ground wires, but each MOSFET needs its own digital output on the Arduino. Note that the ground wires for the microphone circuit and the LED circuit are separate except for one common point on the Arduino. This minimizes the possibility that the large LED currents will interfere with the microphone signal.

Parts List:

All resistors are carbon composition, 1/4W, 5%
The blocking capacitor in the microphone circuit is a 0.47 microfarad film capacitor.

From Electronic Goldmine (www.goldmine-elec.com):
IRF530 HEXFET Power MOSFET (P/N A10095)
Common Anode 8000MCD Super Flux RGB LED (P/N G16721)
Ultra Small Electret Microphone (P/N G15220)


Arduino Sketch

/*
  mic_randeightcolors
  
  Flashes RGB LED's in a random color when the microphone detects a sound.
  
  The circuit:
    RBG LEDs w/ MOSFET drivers, miniature microphone.
    
    Created 27 June 2009
    By David Scholl
*/

// the array index runs over the number of drums
#include "WProgram.h"
void setup();
void loop();
int numDrums = 5;
int drum;

// the microphone is connected to an analog input at the specified pin number
int micPin[] = {0, 1, 2, 3, 4};

// the microphone reading value is an integer, 0-1023
int micValue[] = {0, 0, 0, 0, 0};

// the microphone signal is offset by its running average
float micOffset[] = {511.0, 511.0, 511.0, 511.0, 511.0};   

// the rate of change of the running average (offset), was 0.6
float micOffsetRate[] = {0.6, 0.6, 0.6, 0.6, 0.6};

// sensitivity of microphone, use 180 outside of drum, 300 inside of drum
int micThreshold[] = {295, 300, 285, 300, 265};

// the red LED is controlled by the digital outputs specified
int redPin[] = {22, 28, 34, 40, 46};

// the green LED is controlled by the digital outputs specified
int greenPin[] = {24, 30, 36, 42, 48};

// the blue LED is controlled by the digital outputs specified
int bluePin[] = {26, 32, 38, 44, 50};

int ledDuration = 50;  // the LED flash lasts for ledDuration milliseconds

long seedValue;    // a seed value is required for randomness

int rgbColor;    // index to seven colors, 1-7

long stopMillis[] = {0, 0, 0, 0, 0};    // the time to stop the flash

int flashState[] = {0, 0, 0, 0, 0};    // 0 if flash off, 1 if flash on

// variables for approximate loop timing
long loopCount = 0;
long lastMillis = 0;
long newMillis;
long diffMillis;

// the setup method runs once to configure the digital output pins 
// and seed the random generator

void setup() {
  
  for (drum = 0; drum < numDrums; drum = drum + 1) {
    // setup the digital outputs to drive the LEDs
    pinMode(redPin[drum], OUTPUT);
    pinMode(greenPin[drum], OUTPUT);
    pinMode(bluePin[drum], OUTPUT);
    digitalWrite(redPin[drum], LOW);
    digitalWrite(greenPin[drum], LOW);
    digitalWrite(bluePin[drum], LOW);
  }
  seedValue = analogRead(15);    // acquire a random seed from an unused input
  randomSeed(seedValue);    // seed the random generator
  //Serial.begin(9600);    // initialize the serial port for debugging messages
}

// the loop method runs repeatedly as long as the Arduino has power

void loop() {
  
  loopCount = loopCount + 1;    // used for approximate loop timing
  
  for (drum = 0; drum < numDrums; drum = drum + 1) {    // loop over drums
  
    micValue[drum] = analogRead(micPin[drum]);    // read the microphone signal
    micValue[drum] = micValue[drum]-int(micOffset[drum]);    // subtract the offset (running average)
    
    // update the running average
    micOffset[drum] = micOffset[drum]*(1.0-micOffsetRate[drum]);
    micOffset[drum] = micOffset[drum]+(float(micValue[drum])*micOffsetRate[drum]);
        
    // the microphone signal should be centered around its running average
    // if the distance from the average exceeds the threshold, flash the LED
    if (flashState[drum] == 0) {
      if (abs(micValue[drum]) > micThreshold[drum]) {  
        // pick at random from the seven colors
        rgbColor = int(random(1, 8));
        
        // set the LED driver outputs to the chosen color
        switch (rgbColor) {
          case 1:
            digitalWrite(redPin[drum], HIGH);
            break;
          case 2:
            digitalWrite(greenPin[drum], HIGH);
            break;
          case 3:
            digitalWrite(bluePin[drum], HIGH);
            break;
          case 4:
            digitalWrite(redPin[drum], HIGH);
            digitalWrite(greenPin[drum], HIGH);
            break;
          case 5:
            digitalWrite(redPin[drum], HIGH);
            digitalWrite(bluePin[drum], HIGH);
            break;
          case 6:
            digitalWrite(greenPin[drum], HIGH);
            digitalWrite(bluePin[drum], HIGH);
            break;
          case 7:
            digitalWrite(redPin[drum], HIGH);
            digitalWrite(greenPin[drum], HIGH);
            digitalWrite(bluePin[drum], HIGH);
            break;
        }
        // keep the LED on enough to make a visible flash
        stopMillis[drum] = millis() + 50;
        
        // remember that the flash is on
        flashState[drum] = 1;
      }
    }
    else {   
      // turn all three colors off if the flash time is over
      if (stopMillis[drum] < millis()) {  
        digitalWrite(redPin[drum], LOW);
        digitalWrite(greenPin[drum], LOW);
        digitalWrite(bluePin[drum], LOW);
        flashState[drum] = 0;
      }
    }
  //Serial.println(micOffset[drum]);
  //Serial.println(micValue[drum]);
  }
  if (loopCount % 1000 == 0) {
    newMillis = millis();
    diffMillis = newMillis - lastMillis;
    lastMillis = newMillis;
    //Serial.println(diffMillis);
    //Serial.println(micOffset[3]);
    //Serial.println(micValue[3]);
    //Serial.println(); 
  }
}


int main(void)
{
        init();

        setup();
    
        for (;;)
                loop();
        
        return 0;
} 


V 2.0
TBD