Long exposure photography with Arduino and LEDs
This is a write up of how I built my light painter, going through the software, the materials, the design of the custom parts and putting everything together. Below are links to all the different sections, so you can skip to the bits you’re really interested in or you can continue for a more or less linear process.
- Introduction and goals
- Arduino sketch
- Enclosure and assembly
- Links and references
The main concept behind light painting (wikipedia article for more detailed info) is using a light source that is moved in front of a camera during a long exposure shot. The light source can be as simple as a hand held torch or a LED, but with a microcontroller, a LED strip and precise timing, we can create complex images and scenes.
Besides a LED strip and a micro controller, we need a portable power source and an easy way to load images. We will have to program our microcontroller to load an image, convert it into information that we can send to our LED strip and then drive the succession of lines to create a full image.
This has been done before, many, many times; and even commercially. But I wanted to build my own, both to learn in the process and because commercial options were out of my budget. I chose adafruit’s implementation as a starting point, because it worked on the hardware I already had and they have provided detailed instructions. I also wanted some additional features: I wanted to add a display and a menu system to be able to choose the image to display and adjust the settings (like brightness or speed). I also wanted to be able to turn off the brightness balancing that adafruit’s sketch did, because frame or animation painting wasn’t something I really needed. And most importantly, I adjusted the project to the materials I had at hand.
This is an outline of the materials I used (note: the following are affiliate links; they would help me out at no cost to you, but I understand if you’re not into the idea):
- Arduino UNO.
- LED strip, any flavor of RGB addressable will work; I used a WS2812 strip like this one.
- 8 AA batteries. I use eneloop rechargeable ones.
- 8xAA battery holder.
- Alternatively, you could use a LiPo battery, but then you would need protection and charge circuitry.
- UBEC or buck converter to get a stable 5V from our power source
- Micro SD card reader module. I used these.
- 1602 LCD + I2c LCD module, like this one.
- 24awg cable for Arduino and logic conecctions
- 20awg cable for UBEC to LED strip
- Momentary push buttons
- Slide switch
This is a pretty simple schematic of how everything goes together.
The battery pack feeds into the UBEC with a switch that’s our master power on/off. The UBEC feeds 5V to the LED strip, the Arduino and all the other components. The mini-SD reader connects to pins 10 through 13, and the LCD-I2C adapter connects to SDA and SCL. Apart from that, the buttons are wired to A1, A2 and A3, and the digital in for the LED strip is connected to pin 6.
3. Arduino sketch
This sketch is based on the the one written by Phil Burgess/Paint Your Dragon for Adafruit, that can be found here. A complete write-up with instructions and hardware design can be found on Adafruit’s website (where there’s also more in-depth info on some of the components and design choices).
What I did is add an LCD to the sketch, compartmentalize the functions so that the loop was mostly waiting and acting upon user input and implement a (probably quite crude) menu system. The output and menu system was constrained by the limitations of a 16×2 display, which was also fun to get around.
I wanted the sketch to be able to present a menu with the available files in the SD, but reading all the files and populating an array with the names would’ve meant using a prohibitive amount of memory. The workaround is to scan the files that we’re interested in and store their file index (a much smaller memory footprint). Then we pull up the names on the fly. But even with this we are limited to 30ish files.
The images we use are 24 bit bitmaps, because their file format is pretty straightforward to decode, unlike more CPU intensive formats like png or jpeg (we’re talking at the 8-bit microcontroller level here).
The Arduino isn’t powerful enough to decode the files on the go, so on init or brightness recalculation, the files are scanned and converted to a raw format that later can be dumped directly to the lcd strip without any conversion. All the file loading, conversion and dumping was already taken care of in Phil’s sketch, so all credit to him.
Memory was the main limitation throughout, and I constantly kept getting stack collisions while I was developing the sketch. I peeled away variables and code (like the whole Serial interface) until I got it to run smoothly. I’m not great at C, so I’m sure that there are multiple optimizations that could give a bit more breathing room or things that could be more efficient in their use of variables (and memory). If you spot something I’d love to hear your thoughts.
The menu is quite simple. We can select the image we want to trigger, the brightness (which triggers a file rescan), the speed at which the image is displayed and the delay before the display starts.
Additionally, we have the option to save the settings to EEPROM, so that our current settings are restored the next time we power on.
I’ve also changed some routines to make boot quicker by prompting the user if a complete rescan should take place and rationalizing the generation of the raw files. Though Phil had ingeniously managed to get 3 different settings with just a potentiometer and push button, all that is now handled by the menu.
Please check out the code on Github (Light-painter), and feel free to let me know if there’s anything that can be improved.
4. Enclosure and assembly
This is the part that will depend the most on the materials you have easier access to or the ones you feel more comfortable working with. I tried to keep things simple, so I used a beam of wood to support the LED strip and I decided to design a custom enclosure that I would 3D print.
I used FreeCAD for the design. There was some amount of swearing and starting over, but in the end I managed to get something pretty close to what I had imagined.
I made custom adapters for the battery holder as well, that leave spaces for cable routing. Admittedly, this could’ve been done differently, but this was the simplest option
You can download the STL files from Thingiverse: Light painter. However, after using the light painter, I have found a few issues with my designs. I might tackle these in future revisions:
- The screw tabs are not strong enough. They would need a thicker material or to be printed on the XY plane to have more tensile strength.
- The pins that hold the Arduino and the SD module in place are way too thin and long to be practical. They break. Easily. This could be fixed with thicker pins that narrow out at the point of contact.
- There is barely enough space inside the enclosure for all the cables. Make sure your cables are flexible. If I had to design the box again, I’d make it more roomy and leave enough space for the UBEC.
- I would add some kind of tab or latch to keep the bottom and top halves together. The two point fixture of the top half to the beam is not enough to close down (specially due to the previous point).
- The button system I designed is horrible. It’s impossible to keep it in place. Once installed it works, but this would be something to definitely improve.
That said, everything fits in snugly and closes down with a few coercive drops of superglue. The main enclosure goes onto the beam, as well as the battery pack. Everything is connected as in the schematic.
The UBEC lives on the outside. Not as elegant, but it probably gets much more adequate cooling there and it’s not like it takes up a lot of space.
The placing of the battery pack and the main enclosure could be optimized. I just placed it based on the beam where it looked right and made sense from a cable routing point of view, but I didn’t actually test to get the best balance. The light painter feels ok to handle; a bit top heavy but not unwieldy.
Overall this was a fun project. Most of the effort went into writing and testing the script while most of the components were plugged into a breadboard. Designing the enclosure and battery holder blocks was probably a bit overkill, specially since they were my first time ever in FreeCAD, which sometimes just doesn’t like your geometry but it doesn’t tell you why, so you have to keep iterating different ways to create the same geometries until it suddenly works.
But it was great to design from the ground up, integrating software and hardware until reaching a functional device.
I’d love to hear your thoughts: drop a comment if you have any questions or if you would’ve done something differently and why.