Artificial Lightning

A while back, I ran across this page by Daniel Kennett, explaining how to make an Arduino control a set of Ikea Dioder LED lights. Very cool stuff, and I was able to use his work to build something similar.

So with Halloween fast approaching, I thought it would be neat to use this to create lightning. Tape a set of LED lights in the window at the front of the house, and make it make lightning flashes.

Long story short: pictures:

And video:


The Hardware

In case you can’t tell from looking at the pictures: each of the LED strips has three inputs — red, green, and blue — that can have between 0V and 12V, and one ground. Sending different voltages to the inputs allows you to control the color of each strip.

In my case, I used an Arduino Due, because it was the cheapest one I could find that had 12 analog output pins (three primary colors, times four strips).

For the power, I used a 12V transformer from Radio Shack, with a 2.1mm center-positive plug.

The next problem is controlling how much of that 12V goes to each LED input, given tha the analog pins on the Arduino only output 5V or so. The solution (thanks, Daniel!) is to use an appropriate Darlington array. Briefly, this means that you apply a small voltage to one end of the Darlington circuit, and that controls a much larger current. Kind of like how you can use a small amount of force on a gas pedal to control a 500 horsepower car. I used a pair of ULN2003 chips wired up pretty much the same way as Kennett does, so you may want to look at his circuit diagram.

Conceptually, it’s pretty simple: an analog pin on the Arduino is connected to the input of a Darlington transistor (one of the input pins on a ULN2003); the corresponding Darlingon output is connected to one of the inputs on an LED strip. As the voltage goes from 0V to 5V on the Arduino side, the LED receves 0V to 12V, and that controls the brightness of the corresponding color.

Now repeat this 12 times and there you go.

The Software

Now all we need is software to control this shebang and create lightning. Here’s what I wrote.

This code supports up to four LED strips. If you’re using an Arduino Uno or some other board that doesn’t have enough analog outputs, you can set NUM_LIGHTS to however many you have.

The lights table controls which pin is connected to which light: I figured it was easiest to just have each line go straight from one side to the other; from the rightmost pin on the Arduino to the rightmost Darlington input, to the rightmost LED strip input, and so on, without having wires cross over. But by convention, colors are always specified as {red, green, blue}, in that order, so I added the lights table to simplify that, by mapping {red, green, blue} to the order that the Dioder lights use.

The set_light() convenience function sets the color on a given light. It just makes the rest of the code that much simpler.

The main loop of the program, loop(), is pretty simple: it’s just make a lightning strike, wait for some random amount of time, and repeat.

The lightning_strike() function is where all the action is, really: it does all the heavy lifting of turning the lights on and off to make them flash.

Conceptually, a lightning strike here is in two parts: first, a big strike across all four bars, and then a series of secondary strikes. The first big strike is easy: set all bars to white, wait 50-300 ms, then set them all to black.

The secondary strikes are more interesting and have more randomness: one idea is that initially, all four bars are capable of having zero or more secondary strikes. But after each secondary strike, there’s a 50% chance that a given bar will stop flashing. This helps reduce the possibility of an infinite loop.

The other 50% of the time, we pick a delay before the bar flashes again. Once it flashes on, we’ll pick another delay until we turn it off. All this state is kept in the lights array of structs. This means that at any given time, we have an array of four lights and how long we need to wait until something happens. We find the smallest delay, wait that long, subtract the delay from all the delays, and do whatever’s necessary for the lights whose delay is now 0.

“Whatever’s necessary” simply means: if the light is currently on (as indicated by is_on), turn it off, and if it’s currently off, turn it on. If we’re turning it off, that means we’ve reached the end of a secondary strike for this particular light, so we toss a coin to see whether it’ll strike again, and repeat.

All this randomness gives it, I think, a fairly esthetic and somewhat natural feel, without a whole lot of complexity.