BeatFlower With Digispark/ATtiny85 and WS2812b
BeatFlower With Digispark/ATtiny85 and WS2812b
In this tutorial, I'm going to show you how to build a BeatFlower: A flower shaped, USB powered "wall light" that doubles as a color display for e.g. music on your computer.
I use the following components in this tutorial:
- 5x 12 bit RGB LED ring using the WS2812b controller
- 1x ATtiny85 microcontroller on a Digispark USB Development Board
- 1x FT232R cable (FTDI for USB to serial)
- 2x Acrylic plate
Additionally, I'm using the following consumables:
- Wire (thin, mine is around 0.3mm)
- Solder (the regular one)
- Screws and nuts (mine are plastic, 2mm diameter)
I used these tools for completing the project:
- Soldering iron (a normal one suffices)
- Wire cutter
During the process of making the BeatFlower, I also used an external service for cutting my acrylic plates. You might want to consider doing it yourself it you have access to a laser cutter; I will go into detail in the respective step.
Testing the LED Rings
I got my LED rings through eBay for cheap from China (look for "ws2812b ring 12"). I got mine for around 2€ a pop (plus free shipping, yay). If you buy them from e.g. Adafruit they come in much more expensive, but of course you won't have to wait four weeks for them to arrive.
The controller used in these rings is a WS2812b. This neat little device has four pins and can be daisy-chained; you can control up to 1024 LEDs with one single line.
The four pins on it are:
- 5V: Your power supply. I tested 64 LEDs on full brightness with my regular USB power, worked just fine.
- GND: Ground of whatever power supply you use.
- DI: This is the "Data In" pin; you connect your microcontroller data pin to this.
- DO: This is the "Data Out" pin; if you daisy-chain these, this is what goes to the next element's DI pin.
So for our tests for now we just need the first three pins. I soldered all of them anyway, as you can see on the picture. For testing purposes, I connected it to my ATmega2560 (see pictures). Connect 5V and GND to the respective pins on your ATmega (or equivalent) and use this code for testing it. I configured it to use pin 5 on the ATmega, so if you don't change it in the code, connect your DI to your pin 5 as well.
This code uses the (GPLv3) NeoPixel library from Adafruit. I installed it via "Sketch/Include Library/Manage Libraries..." in my Arduino IDE. See the picture for the exact library to install; I used version 1.0.4. If your ring lights up like on the picture, you're set. If not, check if you mixed up DI and DO, check all connections for loose cables, reflash the code on your microcontroller, and try again.
Assembling the lights, adding an ATtiny85
For convenience, I used a Digispark USB Development Board (driven by an ATtiny85) rather than directly using an ATtiny85. I got the Digispark for around 1.50€ from eBay (from China again, so waiting time applies). The reason to use this is that its flashable easily using USB, and it brings its own pins.
As you can see on the pictures, I daisy-chained the five LED rings. As mentioned before, the output (DO) of one ring goes to the DI of the next. The first DI is fed directly by the ATtiny85. An important thing to note here is that the physical pins on the controller and the software pins you define in your code don't follow the same numbering. This article has a great schematic picture of it. So right now I'm using the software pin P0 (physical pin 5) as the output line. The Digispark actually has the software pins written onto its PCB to reduce confusion.
Besides DI and DO, you have to connect all 5V pins and all GND pins on the rings. Once you've done that, you're set. If you want to test this, you have to change the NUM parameter in the test code from 12 to 60 (5x12) so that the NeoPixel library knows what to send. If everything lights up as expected, you're good to go.
Making the frame for the flower
The flower frame itself consists of two parts: A black acrylic back plate, and a milky white, semi-translucent acrylic front plate. I let the awesome guys at FORMULOR* make these for me. The designs I sent them are available here; they are in exactly the format they accept. You'll have to open them with Inkscape (or similar) to see the very fine hair lines that the laser cutter expects. They take about a week to ship and the results are awesome.
You can see my exact order on the picture. All in all I paid roundabout 17€ for the material, the cutting, and shipping. Not too bad.
Note that the holes on the schematics are 2mm in diameter. I chose this because the mounting holes on the LED rings are that size. This is a non-standard size (usually the smallest you can get is M3, which measures 3mm). To make this work, I ordered special plastic screws and nuts from smartshapes. Specifically, I got the screws as M2 in length 5mm and 8mm. Also, I bought the nuts there. You'll need ten each, which luckily is exactly the amount they package. Plus shipping, this sums up to about 10€.
The back plate has an extra hole where the cables go out. You don't see it through the semi-translucent front plate, but the lights are well visible through the front plate.
Assembling the lights onto the front plate
To assemble the lights onto the front plate, simply push the longer 8mm screws through the holes, directly attach the LED rings onto them using the mounting holes, and put a nut on each.
Each LED ring has two mounting holes and all in all you'll have to attach ten nuts. The best is to arrange them in a circular, clock-wise order, starting with the top one (if you look at the front plate's shape, one sticks out; this is the top). This way, your design will be best compatible with the code I'm supplying for actually using it later on (in terms of numbering the rings when accessing them software-wise).
Also, the LED rings have four mounting holes. Use the outer two; this means, the cables go towards the center of the acrylic plate and are on the opposite side of the mounting holes you use. See the pictures for details.
It really is a bit of a squeeze with the cables I used, but they fit thanks to the distance nuts. You might consider making them shorter. Actually, after doing this, I realized that it might have been easier to first assemble the lights onto the front plate, then solder the cables. This way, the length of the cables would have been easier to estimate - plus, the LED rings are fixed and don't slip away during soldering.
Assembling the front and the back plate
After having fully assembled the front plate, we're going to fix it onto the back plate. In the first picture, you see how the nuts will be aligned. They will be fixed to the back plate using the 5mm screws.
Here is something I encountered because I haven't thought about it before: Neither the Digispark nor the connector I soldered to the wires fit through the hole in the back plate. I had to unsolder and resolder the cables in order to bring the cables through the hole.
After doing that, screw the nuts (that are currently on the front plate) to the back plate. It only fits in one way due to the one leaf of the flower sticking out. After assembling this, try the lights - it should resemble what you see in the video.
Adding a serial interface to control the lights
To control the lights from a computer and not only let them flicker like crazy, we're adding a serial interface, connected to the computer via USB. My USB to RS232 cable (got it from China, 1.39€) essentially looks like the one sold by Adafruit (also, see the picture). The pinout is as follows:
- Red wire: Power (5V)
- Black wire: Ground
- White wire: RX into USB port
- Green wire: TX out of USB port
Remember that the RX of this guy has to go into the TX of the ATtiny85, and vice versa.
One of the larger challenges in this project was that the ATtiny85 has a very limited flash storage. This means that not all combinations of software actually fit onto it. My goal is to combine Adafruit's Neopixel library and SoftwareSerial on it such that the LEDs can be controlled from a host computer through USB-to-serial. My initial implementation hit a wall with the flash storage when compiling for the Digispark though:
Sketch uses 6,586 bytes (109%) of program storage space. Maximum is 6,012 bytes.
This is a bit too much. I played around with using alternative LED libraries (e.g. FastLED), but that didn't much reduce the size (although it has other cool features on its own). Next, I tried to replace SoftSerial (which is basically Digispark-speak for SoftwareSerial; they added PCINT support). I ended up implementing a stripped-down version of SoftSerial which you can download here (just put the folder into your Arduino IDE's libraries folder). I completely removed all TX functionality because we only want to send data to the ATtiny, not receive any from it. With a bigger controller, I would argue that return values and current state are super useful, but with the ATtiny in mind, I'll go for this solution.
Anyway, with this RecvOnlySoftSerial library, things look brighter:
Sketch uses 5,910 bytes (98%) of program storage space. Maximum is 6,012 bytes.
The sketch (which you can download here) listens for input from the serial line and acts according to what it receives. Each command must be followed by a carriage return (CR, '\r'). A simple API overview is shown here:
- r%d: Select the ring with the index R. Use the range 0-4.
- l%d %d %d %d: Set the LED with the index of the first integer on the currently selected ring to the RGB color value defined by R, G, B (second through fourth integer value). Use the range 0-12 for the first, and 0-25 for the other values.
- c: ("commit") Apply the changes described by the former functions to the LEDs (before this, nothing changes on the LEDs).
For simplicity reasons, I wrote a small library that can interface the serial line and execute these commands (and even do a bit more). You can download it here.
The final result can be seen in the video. The code repository includes a file called demo.cpp that just runs through all rings, their individual LEDs, and lights them up in a random color, continuously. See the video for an impression.
I left the project at that stage. Everything seems to be working, but the interface still is a bit slow-ish. I will probably return to this at a later point to prepare a visualizer plugin for VLC or the like, but at its current state, this project is working and fine by itself.
Bottom line: Experiences, extensions, costs
Here, I will write down my thoughts on what I learned, what could have gone better, and what the overall project cost in terms of money and time.
What I learned
I definitely took away a lot about programming the ATtiny85, the role of the individual pins, and how to connect devices to it. This was a first for me. The same applies for programming the Digispark (which, frankly, is just making life easier).
Also, I gathered lots of experience in preparing assembly, designing sketches for laser cutters, and finding the right materials/consumables for putting it all together. There are also lots of details I had to re-do because I didn't think of them; just think of putting the connectors for the Digispark through the backplate hole.
Finally, I got a much better understanding of how long certain tasks take. Its easy to underestimate the effort for making things, so its safer to assume it'll gonna take a bit longer (or you have to start over in the middle because you realize you're a stupid moron and forgot something super important).
What could have gone better
Mounting holes: One thing I keep being annoyed by is that I didn't let the FORMULOR* guys make holes for mounting it somewhere. I can sure lean it against the wall, but to actually mount it somewhere I'd like some extra holes. Next time, I'll consider this. Maybe my next project will be a stand for this thing.
Cable length: The cables I used to connect the LED rings are pretty long; I should have made them shorter. I really didn't expect the mess under the front plate (although you don't really see them). This is more an aesthetic issue than anything else.
What it cost
I ordered/bought these parts:
- 5x LED rings: 9.50€
- Digispark USB Development Board: 1.39€
- USB to RS232 cable: 1.39€
- Acrylic plates + Cutting + Shipping: 16.85€
- Screws + Nuts + Shipping: 9.70€
- Wire: 1€
- Solder: 1€
All material considered, the BeatFlower cost somewhere around 40€. I'm not counting the ATmega2560 because that was really only for testing purposes and I already had it. I could have used the Digispark for that as well.
In terms of time, I roughly spent 2-3 hours on finding all the parts I needed, soldering (and resoldering) sums up to about two hours, programming (and testing) the controllers, LEDs, and the library is another 4-5 hours, and for the overall assembly I'd account 2 more hours. So all in all I'd say you're looking at the product of around 10-12 hours of work.
All in all, I'm very happy with the project's outcome. It was fun, had a cool result, and I learned a lot. I hope you enjoyed it as much as I did.
Acknowledgments, Credits, and Bibliography