blinkm

This project demonstrates using an Arduino, a LM386N opamp circuit and multiple BlinkM LED units to create an audio visualization device. The audio is not pass-through so it requires a dedicated mono input. In the video demo, the Arduino enclosure is connected to the tape-out of a DX052 mixer and powered by USB by my previous DX052 power hack.The amplifier circuit is set to provide 50dB of gain for the line-level mono input mixed from the right and left channel. This signal is fed to the Arduino ADC which approximates RMS voltage from signal. Vrms is converted to dBV which is mapped to an intensity value for blue, green and red LEDS belonging to four BlinkM units. The alternate two LEDs are scaled to be less intense than the single primary color. Although all four BlinkMs can be controlled individually in this demonstration they are all sent the same intensity data mapped to the ADC.

Construction

Materials

  • 1 Arduino
  • 4 BlinkM units (salvaged from the wireless blinkm project)
  • 1 plastic case for the enclosure
  • lm386 low voltage power amplifier (overkill since i’m not driving anything but it’s the only opamp I had lying around)
  • prototype board, wires, resistors, caps, headers, standoffs, screws, sockets, connectors

This project is pretty expensive if you don’t have the components lying around already. The plastic enclosure was a container that used to have push-pins. Even if this is only used a few times it has a pretty neat looking case, that’s the important part.

case-before case-after

Circuit

The circuit below illustrates the connections between the amplifier, the Arduino and BlinkM LEDs. This does *not* include decoupling capacitors, don’t forget them! The amplifier circuit does a very nice job of driving a mid-sized speaker and the op-amp can provide 20db of gain with minimal external circuitry. This would make a great portable amp for playing music outside where the quality doesn’t matter as much. In this role however the amplifier is simply bringing the signal level up from line-levels to a voltage that can be sampled on the Arduino ADC. The BlinkM units are chained using a TWI connection using very short cables. Using wire length much longer than the one shows in the pictures will almost certainly cause problems as this connection is meant for circuit boards, not long cables.

blinkm music circuit

Prototype – Arduino

amp1 amp and arduino
arduino and case blinkm board
blinkm1 blinkm2

The finished amplifier circuit is mounted on top of the Arduino which is in turn screwed into the plastic push-pin box. Holes were cut for Arduino power and USB to allow it to be programmed in its enclosure. The mono audio input and the TWI connection cables are both socketed for easy removal.

Prototype – BlinkM

The BlinkM board has wires that fan out for ground and the TWI bus. In addition there are some voltage regulators that serve no other purpose except to stabalize the BlinkMs when they are plugged in to the female headers :)

Software – Cycling Throught All Three Colors With Effects

Below is the Arduino program used for the video. To convert peak to peak voltage on the ADC to an RMS value half the samples were used since the Arduino will only register readings above 0V.

The outer loop re-calibrates the peak and low reading for mapping the ADC. This is done so that if level of the signal changes it can automically adjust to a new range. In the main loop the arduino takes NUM_READINGS for CYCLE_LENTH times and sets the intensity of the blue LED as well as the green and red LED with a .02 scaling factor.

This program cycles through all three colors, red, green and blue. Before switching colors it does one of four light effects in the color it is about to switch to.


#include "Wire.h"
#include "BlinkM_funcs.h"
#include

#define MUSIC_PIN 0
#define CYCLE_LENGTH 5000
#define NUM_READINGS 100
#define GREEN_SCALING .02
#define RED_SCALING .02
#define BLUE_SCALING .02
#define CYCLE_DELAY 50
#define FADE_DELAY 500

enum colors {
  BLUE,
  RED,
  GREEN
}current_color;

enum effects {
  LIGHTS_ON,
  CYCLE_LIGHTS,
  CYCLE_LIGHT_SINGLE,
  FADE_ALL
}current_effect;

byte blinkm_addrs[]      = {   9,   10,   11,  12 };
void visualize(double value, double min_val, double max_val);
void lights_on(void);
void cycle_lights(void);
void cycle_light_single(void);
void fade_all(void);

unsigned int red_pos = 0x0F;
unsigned int green_pos = 0x0F;

void setup()
{

  BlinkM_begin();
  Serial.begin(9600);
  Serial.println("Here we go!");

  // stop any scripts in progress, set all to black, initalize params
  for (int i=0; i
    BlinkM_stopScript(blinkm_addrs[i]);
    BlinkM_setRGB(blinkm_addrs[i], 255,255,255);

    delay(1000);
  }
  current_color=BLUE;
  current_effect=LIGHTS_ON;

}

void loop()
{

  float Vrms_min = 5;
  float Vrms_max = 0;

  // turn off all leds at the new cycle
  BlinkM_setFadeSpeed(0, 10);
  for (int i=0; i      BlinkM_fadeToRGB(blinkm_addrs[i], 0, 0, 0);
      delay(FADE_DELAY);
  }

  // set the next color

  switch (current_color) {
    case RED:
        current_color=GREEN;
        break;
    case GREEN:
        current_color=BLUE;
        break;
    case BLUE:
        current_color=RED;
        break;
  }

  // do a light effect for the next cycle

  switch (current_effect) {
    case LIGHTS_ON:
      lights_on();
      current_effect=CYCLE_LIGHTS;
      break;
    case CYCLE_LIGHTS:
      cycle_lights();
      current_effect=CYCLE_LIGHT_SINGLE;
      break;
    case CYCLE_LIGHT_SINGLE:
      cycle_light_single();
      current_effect=FADE_ALL;
      break;
    case FADE_ALL:
      fade_all();
      current_effect=LIGHTS_ON;
      break;
  }

  BlinkM_setFadeSpeed(0, 150);
  for ( unsigned int i=0; i
   double rms_voltage = 0;
   double dbV_voltage = 0;
   double dbV_min = 0;
   double dbV_max = 0;

    for ( unsigned int j=0; j Vrms_max ) ? ( Vrms_max = rms_voltage ) : 0 ;
    ( rms_voltage < Vrms_min ) ? ( Vrms_min = rms_voltage ) : 0 ;

    dbV_max = 20 * log(Vrms_max);
    dbV_min = 20 * log(Vrms_min);

    visualize ( dbV_voltage, dbV_min , dbV_max );

    if (i == CYCLE_LENGTH-1) {
        Serial.print ("Vrms  = ");    Serial.print (rms_voltage);
        Serial.print (" : dbV  = ");    Serial.print (dbV_voltage);
        Serial.print (" : dvB_max and dbV_min = ");    Serial.print (dbV_min);
        Serial.print (" / ");    Serial.print (dbV_max);
        Serial.print (" : Vrms_max and Vrms_min = ");    Serial.print (Vrms_min);
        Serial.print ( " / ");    Serial.println (Vrms_max);
    }

  }

}

void visualize(double value, double min_val, double max_val)
{

  // map the reading to a value between 0-255
  int blinkm_val = map (value, min_val, max_val, 0, 255);
  switch (current_color) {
    case BLUE:

  BlinkM_fadeToRGB(0,
                        RED_SCALING*blinkm_val,
                        GREEN_SCALING*blinkm_val,
                        blinkm_val);
         break;
    case GREEN:
  BlinkM_fadeToRGB(0,
                        RED_SCALING*blinkm_val,
                        blinkm_val,
                        BLUE_SCALING*blinkm_val);
          break;

     case RED:
  BlinkM_fadeToRGB(0,
                        blinkm_val,
                        GREEN_SCALING*blinkm_val,
                        BLUE_SCALING*blinkm_val);
          break;
  }

}

void cycle_lights()
{
  switch (current_color) {

    case RED:
        BlinkM_fadeToRGB(0, 100,0,0);
        delay(1000);
        for (int j=0; j          for (int i=0; i              BlinkM_setRGB(blinkm_addrs[i], 0,0,0);
              delay(CYCLE_DELAY);
          }
          for (int i=0; i              BlinkM_setRGB(blinkm_addrs[i], 100,0,0);
              delay(CYCLE_DELAY);
          }
        }

        break;
    case GREEN:
        BlinkM_fadeToRGB(0, 0,100,0);
        delay(1000);
        for (int j=0; j          for (int i=0; i              BlinkM_setRGB(blinkm_addrs[i], 0,0,0);
              delay(CYCLE_DELAY);
          }
          for (int i=0; i              BlinkM_setRGB(blinkm_addrs[i], 0,100,0);
              delay(CYCLE_DELAY);
          }
        }

        break;
    case BLUE:
        BlinkM_fadeToRGB(0, 0,0,100);
        delay(1000);
        for (int j=0; j          for (int i=0; i              BlinkM_setRGB(blinkm_addrs[i], 0,0,0);
              delay(CYCLE_DELAY);
          }
          for (int i=0; i              BlinkM_setRGB(blinkm_addrs[i], 0,0,100);
              delay(CYCLE_DELAY);
          }
        }

        break;
  }
}

void lights_on()
{
  switch (current_color) {

    case RED:
        for (int i=0; i            BlinkM_fadeToRGB(blinkm_addrs[i], 255,0,0);
            delay(1000);
        }
        break;
    case GREEN:
        for (int i=0; i            BlinkM_fadeToRGB(blinkm_addrs[i], 0,255,0);
            delay(1000);
        }

        break;
    case BLUE:
        for (int i=0; i            BlinkM_fadeToRGB(blinkm_addrs[i], 0,0,255);
            delay(1000);
        }

        break;
  }

}

void cycle_light_single()
{
  switch (current_color) {

    case RED:

        for (int j=0; j          for (int i=0; i              BlinkM_setRGB(blinkm_addrs[i], 100,0,0);
              delay(CYCLE_DELAY);
              BlinkM_setRGB(blinkm_addrs[i], 0,0,0);
          }
        }

        break;
    case GREEN:

        for (int j=0; j          for (int i=0; i              BlinkM_setRGB(blinkm_addrs[i], 0,100,0);
              delay(CYCLE_DELAY);
              BlinkM_setRGB(blinkm_addrs[i], 0,0,0);
          }
        }

        break;
    case BLUE:

        for (int j=0; j          for (int i=0; i              BlinkM_setRGB(blinkm_addrs[i], 0,0,100);
              delay(CYCLE_DELAY);
              BlinkM_setRGB(blinkm_addrs[i], 0,0,0);
          }
        }

        break;
  }
}

void fade_all()
{
  switch (current_color) {

    case RED:

        for (int j=0; j              delay(FADE_DELAY);
              BlinkM_fadeToRGB(0, 100,0,0);
              delay(FADE_DELAY);
              BlinkM_fadeToRGB(0, 0,0,0);

        }

        break;
    case GREEN:

        for (int j=0; j              delay(FADE_DELAY);
              BlinkM_fadeToRGB(0, 0,100,0);
              delay(FADE_DELAY);
              BlinkM_fadeToRGB(0, 0,0,0);

        }

        break;
    case BLUE:

        for (int j=0; j              delay(FADE_DELAY);
              BlinkM_fadeToRGB(0, 0,0,100);
              delay(FADE_DELAY);
              BlinkM_fadeToRGB(0, 0,0,0);

        }

        break;
  }
}