BlinkM RGB LED and Flash
My garage door measures about 190 inches by 83 inches. If I space LED lights every three (3) inches across those dimensions, I’d have a resolution of 63 lights by 27 lights, for a total of 1701 lights. I know Christmas 2009 is now behind us, but what kind of crazy display could I have if my entire garage door was an LED sign? Could I play “Frosty the Snowman” in Flash, sample the pixels, and play it back across the LED lights on my garage? I don’t know, but here’s where things sit so far.
The Search
It turns out that controlling individual LED lights is a particularly challenging task. There’s power supply problems, brightness to control, resistors to configure, and a lot of wire. That doesn’t even account for addressing the individual LEDs to control them. For that you end up needing a lot of IO pins on a micro-controller. The LED array then turns into a byte array, and you shift around the bits to get the desired pattern.
At a high level this is called multiplexing, and there are LED drivers out there to help you with this task. This only gets you so far though. Remember that we’re talking about 1701 individual lights. Most LED drivers will get you up to 64, but that’s still a long stretch from 1701. This also assumes only one color LED. Since I potentially want to play back a movie, I’ll need RGB LED lights which means even more logistical problems.
It quickly became apparent to me that I’d need a modular system.
To date, the closest thing I’ve been able to find is the BlinkM RGB LED from ThingM. These little guys are nice and bright, and even have their own controller so you can program them outright and have them playback on their own. BlinkM LEDs are built on an I2C bus, which enables 127 lights to be controlled on a single two-wire network. In theory then, since the Arduino Mega has 16 analog inputs, I could reach my goal of 1701 RGB LEDs across my garage.

A First Test
Every great journey begins with but a single step however, and I recently purchased two BlinkM units to start testing my theory. With an available Arduino Duemilanove, I took to a simple test example. Could I make the RGB LED produce the color I wanted from Flash? The surprisingly easy answer was, yes, and here is how it went.
When I got the BlinkM units, I headed over to the ThingM site to take a look at the documentation. One of the videos there shows plugging the BlinkM directly into the Arduino analog inputs. I figured that was a good first test. The tutorials focus on programming the embedded controller on the BlinkM, but I want to control them directly.
A little digging through the examples revealed a small header file that gives a more low-level access to the lights. This header included functions like “BlinkM_setToRGB()” which takes a byte to address which LED you want, and then three more bytes for the red, green and blue values. A few minutes later and I had an RGB LED changing color randomly.
Connecting to Flash
Note: I’ve written extensively in other posts about how to configure the proxy between Flash and the Arduino. If you need more information on that topic, I suggest having a look at some of my past posts.
The next step then is to tell the Arduino to expect a certain series of values over serial. Given that this is just one light (so far), I figured I could omit the LED address value. That means I need three values for red, green and blue. In the following sketch, I assume that values will come in pairs of three. The first byte is stored as red, the second as blue, and the third as green, which then calls the aforementioned BlinkM method, and resets the value counter.
#include "BlinkM_funcs.h" #include "Wire.h" int blinkm_addr = 9; int blue = 0; int green = 0; int incoming_byte = 0; int place = 0; int red = 0; void setup() { BlinkM_beginWithPower(); BlinkM_stopScript( blinkm_addr ); Serial.begin( 9600 ); } void loop() { if( Serial.available() > 0 ) { incoming_byte = Serial.read(); if( place == 0 ) { red = incoming_byte; place = 1; } else if( place == 1 ) { green = incoming_byte; place = 2; } else if( place == 2 ) { blue = incoming_byte; BlinkM_fadeToRGB( blinkm_addr, red, green, blue ); place = 0; } } }
That’s it! Less than forty (40) lines of code and you’re good on the Arduino side. From the Flash side, the most challenging part is just in figuring out what user interface you want to present to make a color selection. Since I am interested in video, I figured that I’d sample from the web camera on my system.
In the following ActionScript code, I sample 100 pixels (10 x 10) from the center of the video. I then draw each of those pixels on the screen at a size calculated to fill in any realty. While I’m drawing the pixels, I’m also averaging them to result in a single color value. With the drawing and averaging complete, I break out the red, green and blue values, and send those via socket to the Arduino.
protected function doFrame( event:Event ):void { var bmpd:BitmapData = new BitmapData( 10, 10, false ); var matrix:Matrix = new Matrix(); var avgb:uint = 0; var avgg:uint = 0; var avgr:uint = 0; var blue:uint = 0; var green:uint = 0; var pixel:uint = 0; var red:uint = 0; var space:Number = Math.round( ( stage.stageHeight - ( 10 + video.height + 10 + 10 ) ) / 10 ); // Capture matrix.translate( -1 - ( highlight.x - video.x ), -1 - ( highlight.y - video.y ) ); bmpd.draw( video, matrix, null, null, new Rectangle( 0, 0, 10, 10 ) ); // Blow up zoom.graphics.clear(); zoom.graphics.lineStyle( 1, 0xFF0000, 0 ); for( var row:Number = 0; row < 10; row++ ) { for( var col:Number = 0; col < 10; col++ ) { pixel = bmpd.getPixel( col, row ); // Sample red = pixel >> 16 & 0xFF; green = pixel >> 8 & 0xFF; blue = pixel & 0xFF; avgr = avgr + red; avgg = avgg + green; avgb = avgb + blue; // Draw zoom zoom.graphics.beginFill( pixel ); zoom.graphics.drawRect( col * space, row * space, space, space ); zoom.graphics.endFill(); } } // Average avgr = avgr / 100; avgg = avgg / 100; avgb = avgb / 100; pixel = ( avgr << 16 | avgg << 8 | avgb ); // Draw sample sample.graphics.clear(); sample.graphics.lineStyle( 1, 0xFF0000, 0 ); // Bounding sample.graphics.beginFill( 0xFFFFFF ); sample.graphics.drawRect( 0, 0, 20, 20 ); sample.graphics.endFill(); // Color sample.graphics.beginFill( pixel ); sample.graphics.drawRect( 2, 2, 18, 18 ); sample.graphics.endFill(); // Show on LED socket.writeByte( avgr ); socket.writeByte( avgg ); socket.writeByte( avgb ); // Position zoom.x = Math.round( ( stage.stageWidth - zoom.width ) / 2 ); }
What Next?
What I’ve essentially done then is down-sample a live video to a much smaller resolution, and display a pixel of that content in real time on an RGB LED. That’s one pixel down and 1700 to go. Somewhere between you’ll find numerous applications for small arrays of LED lights. ThingM has a neat color coded wine rack, called WineM, that when coupled with RFID provides you the perfect selection for your meal.
Perhaps the most compelling piece for me is the user interface. In this case they’re using a device to present a screen to assist you in your selection. You choose the characteristics of the wine you are interested in, and the portable device tells the wine rack to light up appropriately. Since Flash is quickly becoming available on every screen, it stands to reason that Flash would make the perfect selection for the user interface.
Conclusion
The results of this little experiment aren’t particularly impressive just yet. One pixel. I think my next step will probably be to emulate the WineM idea, so somewhere around nine to sixteen RGB LED lights. Maybe make something portable to take to conferences, or find a local retailer willing to sponsor letting me try it out inside their store. In the meantime I’ve recorded a video of the results of this one pixel in action, and you can download the code as well.
Yes, I am fully aware that if you run this out to its natural conclusion, the price tag quickly becomes overwhelming. It’s far cheaper to buy a screen and drape that over the surface of an open garage, and then purchase a projector for that screen. I want to be perfectly clear here – that is not the point (smile). Some mountains must be climbed simply because they exist. It just happens that my mountain takes the form of a pile of LED lights.
January 22nd, 2010 at 12:35 pm
1701 leds * $12 each BlinkM led = your garage door will be pretty expensive
February 15th, 2010 at 3:57 pm
It was extremely interesting for me to read this post. Thanks for it. I like such themes and everything that is connected to this matter. I definitely want to read a bit more soon.
Best wishes
February 15th, 2010 at 5:34 pm
This is pretty cool! It has me pretty inspired for a little LED fun, would love to talk more with you about it. Cheers for the great write up and video!
March 21st, 2010 at 3:19 pm
Fantastic blogpost, I bookmarked your blog post so I can visit again in the future, Thanks