Last weekend I went to Tomorrowland 2013. I got the ticket months ago, in February. Ever since, I had been thinking about building something to stand out, something involving LEDs and an Arduino. As usual, I only decided what to build the day before the festival! I went to the mall and found a hat in discount. This would become my Tomorrowland LedHat 🙂

The build

The plan was to attach a bunch of LED strips and control them with an Arduino. Not only that, I wanted them to react to the music! A quick look through my electronic components collection made me wonder if I could do something with an LM324 op-amp. Le Goog pointed me into the direction of a movie by Afrotechmods. He showed a simple circuit to build an op-amp comparator. It filters the microphone input, amplifies it and compares the output voltage to a threshold. I quickly built this on my breadboard, added a potentiometer to set the sensitivity and voilà, I had a simple beat detector.

Next I attached the op-amp output to an analog input of an Arduino Mini Pro. Any Arduino would work, this was what I had laying around. It needed to fit in my hat, so my Arduinos Uno or Mega weren’t options. With 5V supplied to the op-amp, the maximum output I saw was about 3.8V. The analog pin translates a 0 to 5V input to an integer between 0 and 1024. Each loop the Arduino reads the pin value and compares it to a threshold. I chose 500 as the limit (about 2.5V).

The next step was controlling the LEDs. Attaching the LED strips directly to Arduino output pins isn’t a good idea. The Arduino can only handle that much amps. Furthermore my LED strips work on 12V, something the output pins can’t supply anyway. The ULN2003 Darlington array is built for this kind of applications. Supply 5V to one end and it will switch 12V on the other. It has 7 such gates and can sink a total of 500 mA, more than enough.

31-Jul-2013 11:24
 

By the time I had everything tested thoroughly on a breadboard and soldered it up on perfboard, it was already late in the evening. While my girlfriend was sewing everything in my hat, I started coding. Luckily I didn’t have to start from scratch! I could recycle my Discotheque() code. Quite some things had to be rewritten though. The function had to be called based on microphone input and everything about the remote control had to go. Also the sequence of LEDs was different. My quadcopter didn’t use all ULN2003 pins. Now I did, so I had to program some new patterns. Patterns consist of different steps. Each step is a 7 bit integer. The binary number tells which LEDs should be on or off. Each time the function is called (ideally on the beat), it executes the next step. I repeat every pattern three times before it goes to the next one.

This is how it looks:

27-Jul-2013 20:16, Canon Canon EOS 60D, 5.0, 50.0mm, 0.013 sec, ISO 1600
27-Jul-2013 20:16, Canon Canon EOS 60D, 5.0, 50.0mm, 0.008 sec, ISO 1600
27-Jul-2013 20:15, Canon Canon EOS 60D, 2.2, 50.0mm, 0.006 sec, ISO 500
 
31-Jul-2013 01:13, Canon Canon EOS 60D, 5.6, 50.0mm, 0.005 sec, ISO 1600
 

And here you can see me using it in Tomorrowland the next day:

I had the battery, a 2200 mAh 3S lipo, in my back pocket, with a wire running over my back to the hat. I had 4 batteries with me, with a total of 6600 mAh. I didn’t check in advance how much current the hat would need, but I ran it for about 3 hours and the battery still had 11.5V. A fully charged lipo has 12.6V and can be discharged to 9V maximum, so it can run PLENTY of hours on just one battery this size!

The code

Tomorrowland.ino


/*
 Tomorrowland rules!
 Copyright (c) 2013 Niek Hombrouckx
 */
#if defined(ARDUINO) && ARDUINO >= 100
#include &quot;<acronym class='c2c-text-hover' title='A small, programmable, electronic board that let&#039;s you interface with sensors and control motors, leds... For more info go to http://www.arduino.cc'>Arduino</acronym>.h&quot;
#else
#include &quot;WProgram.h&quot;
#endif

#include &quot;LedDiscotheque.h&quot;

unsigned long previousTime = 0;
unsigned long currentTime = 0;
unsigned long deltaTime = 0;

int MicPin = A0;

void setup() {

 pinMode(2, OUTPUT); // White
 pinMode(3, OUTPUT); // Red
 pinMode(4, OUTPUT); // Red
 pinMode(5, OUTPUT); // Green
 pinMode(6, OUTPUT); // Green
 pinMode(7, OUTPUT); // Blue
 pinMode(8, OUTPUT); // Blue
 digitalWrite(2, LOW);
 digitalWrite(3, LOW);
 digitalWrite(4, LOW);
 digitalWrite(5, LOW);
 digitalWrite(6, LOW);
 digitalWrite(7, LOW);
 digitalWrite(8, LOW);

}

void loop(){
 currentTime = millis();
 deltaTime = currentTime - previousTime;

if (analogRead(MicPin) &gt; 500 &amp;&amp; deltaTime &gt; 300) {
 Discotheque();
 previousTime = currentTime;
 }

}

LedDiscotheque.h


/*
Led Discotheque by Nikotine.
 v.1.0
 */

#ifndef _LED_DISCOTHEQUE_H_
#define _LED_DISCOTHEQUE_H_

#define mSizeof(x) sizeof(x)/sizeof(int)
#define NUMBER_OF_LEDS 7 // 7 outputs on ULN2003

int figurenumber = 0;
int figurerepeat = 3; // amount of times you want a certain pattern to repeat
int figureversion = 1; // current amount of times a certain pattern has been played
int figuresize = 0;
int figurestep = 0;
int amountoffigures = 0;

boolean LedsDisco= false;
long LedSwitchTime = 0;

//Blue2, Blue1, Green2, Green1, Red2, Red1, White

int LedCircle[] = {
 B0000010,
 B0001000,
 B0100000,
 B0010000,
 B1000000,
 B0001000,
 B0000100,
 B0010000
};
int LedPolice[] = {
 B0000111,
 B1100000,
 B0000111,
 B1100000,
 B0000111,
 B1100000,
 B0000111,
 B1100000
};
int LedAdditiveCircle[] = {
 B0000010,
 B0001010,
 B0101010,
 B0111010,
 B1111010,
 B1111110,
 B0000000
};

int LedRRGGBB[] = {
 B0000011,
 B0000010,
 B0000101,
 B0000100,
 B0001001,
 B0001000,
 B0010001,
 B0010000,
 B0100001,
 B0100000,
 B1000001,
 B1000000
};

int LedAllOnOff[] = {
 B1111111,
 B0000001,
 B1111111,
 B0000001,
 B1111111,
 B0000001,
 B1111111,
 B0000001
};

int LedOppositeCircle[] = {
 B0100010,
 B0011000,
 B1000100
};

int LedPinkBeat[] = {
 B1100110,
 B0000001,
 B1100110,
 B0000001,
 B1100110,
 B0000001,
 B1100110,
 B0000001
};

int* figurename[] = {
 LedCircle,
 LedPolice,
 LedAdditiveCircle,
 LedRRGGBB,
 LedAllOnOff,
 LedOppositeCircle,
 LedPinkBeat
};
int sizeoffigures[] = {
 mSizeof(LedCircle),
 mSizeof(LedPolice),
 mSizeof(LedAdditiveCircle),
 mSizeof(LedRRGGBB),
 mSizeof(LedAllOnOff),
 mSizeof(LedOppositeCircle),
 mSizeof(LedPinkBeat)
 };

 void Discotheque() {

amountoffigures = sizeof(figurename)/sizeof(int);

 figuresize = sizeoffigures[figurenumber];

byte data = figurename[figurenumber][figurestep];
 for (byte y=0; y<NUMBER_OF_LEDS; y++) {
 if (data & (1<<y)) {
 digitalWrite(2+y, HIGH);
 }
 else {
 digitalWrite(2+y, LOW);
 }
 }

figurestep++;
 if (figurestep > figuresize-1) {
 figurestep = 0;
 figureversion++;
 if (figureversion > figurerepeat) {
 figureversion = 1;
 figurenumber++;
 if (figurenumber > amountoffigures-1) {
 figurenumber = 1;
 }
 }

 }
}

#endif // _LED_DISCOTHEQUE_H_

Room for improvement

Considering the LedHat came from concept in my head to a product in just one day, it worked relatively well. But it can be improved considerably!

  1. The LM324 has four op-amps, but I only needed two of them, so you save some space by using an LM358.
  2. This device needs both 5V for the microphone and Arduino, and 12V for the LEDs. Technically the Arduino could run on 12V (using the RAW input), but I didn’t want it to run hot on top of my head. I used a 5A switching UBEC from Hobbyking to convert 12V to 5V. It’s a great device, but it’s not an elegant solution. I tried to use an LM317 but I got some crazy results, the solder fumes must have confused my mind…
  3. It works great in my home with music coming out of my stereo. The beats are well defined and there is no background noise. On a festival you’ve got not only the screaming crowd, but a MUCH bigger stereo 🙂 The microphone was swamped constantly and I couldn’t get the potentiometer set sensitively enough to get distinct beats. Remember this is only doing some basic filtration, it reacts to sound, not to just bass. A better filter should be used.
  4. Alternatively, I could replace R4 and R5 by one potentiometer to change the amplification of the microphone input. I’ll have to test this. EDIT: I don’t think this will work after all. In fact, quite the opposite, as the wave amplitude will be smaller, it will be even more difficult to detect beats.
  5. During testing at home, I noticed that one beat would sometimes be detected as several spikes. This made the animation go to quickly, so to filter that out, I only had the function be called every 300 ms maximum. This is about 180 BPM, which is drum&bass stuff, not the kind of festival I was going to 🙂 This had another advantage, by coincidence actually: while the microphone was being swamped by sound in Tomorrowland, and no distinct beats could be detected, the animation would just continue, with 300 ms between each step. If I hadn’t done that, the LEDs would just stop moving, which would have been a boring hat.
  6. The function could be greatly improved by doing some BPM calculation. For example, measure the time between two high peaks and calculate a rolling average BPM. When a part of music doesn’t have distinct beats, the program can continue using the BPM it calculated…
  7. I had 7 patterns, but I needed more! And strobes! And smoke and lasers! 😀

I’ve got a year before the next Tomorrowland festival, which I will most certainly attend!! Let’s see what I can come up with…