Here’s a quick wrap-up post for The Door Wall project, which Jared Boone and I developed in 2013. It’s a permanent installation of 3,810 RGB LEDs:
We learned about this project through Michael Ossman, who saw the HypnoLamp, and introduced us to Danielle and David Hulton, the owners and operators of Ada’s Technical Books in Seattle. They were moving to a new storefront, and adding a partition made of reclaimed doors.
Together, we decided to run 2 parallel strips of WS2811 LED strips (60 LEDs/meter) around the edges of the Door Wall structure.
Jared and I tested some diffusers, and settled on SatinIce acrylic, which is designed specifically for light diffusion and transmission. The light is bright, with a nice sparkle.
Minutes before spending $1,000 on WS2811 LED strips, we discovered a newer, less expensive option, which also consumes less power: The WS2812b. We reviewed the data sheets; it looked legitimate, so we ordered 80 meters’ worth from Ray Wu’s store.
We debated using Python, and writing graphics directly to
/dev/fb0. This may have performed better, however I feared this would be messy to develop and maintain, resulting in a horde of other issues. (What if the device booted up using the wrong display resolution, or color space? Do not want.) We needed time-based animations in a sane graphical environment, more than the allure of magically improved performance.
Jared had the ingenious idea of sampling color values from the HDMI video feed. Here’s a link to Medusa, the FPGA-based board he designed for this purpose. It attaches to the Beaglebone Black, and streams color values to seven receiver boards (4 columns + 3 arches). The receiver boards generate the signals that the WS2812b LED strips need.
The LED strips support 24-bit color (8 bits each for red, green, and blue). However, the human eye perceives light in a non-linear way. An LED that pulses at 50% duty cycle will appear more like 75% or 80% of maximum brightness, to our eyes. This means that our LED strips have superb color resolution in the bright range, but fairly poor differentiation in the darker shades. There’s almost no visible difference between brightness levels 254 and 255, but there’s a stark change between levels 1 and 2.
The fix: Medusa uses a lookup table, to map HDMI pixel colors to LED brightness levels. This is known as gamma correction, and without this, our midtones would have appeared washed-out, and the colors desaturated. Gamma correction is your friend! This is the gamma lookup table that we used.
Animating on a 0.6562 DPI Display
There were many surprises while developing animations. The first round of animations looked great on the computer screen, but on LEDs the motion was too rapid and intense. At 00:15, the video shows an early version of the
SwarmsInTheCorners animation. The swarms appear harmless in the video, but in real life they’re blazing across a 14-foot high surface, right next to people’s faces, it’s too fast and bright! This was slowed down significantly later, and we added a speed control to the GUI.
OS X has an accessibility function which lets you zoom into the screen. The maximum zoom level is limited, my laptop can’t scale the animations up to 1:1 life size. Eventually I determined that if any motion was perceptible on the laptop’s screen, then that motion would appear too fast in real life. My trusty 17″ Macbook Pro is 133 dpi, whereas the LED strips are effectively 0.6562 dpi, so the LED strips are enlarged by a factor of over 200.
Large-scale animations weren’t as successful as I hoped. Some animations (
PondRipplesAnim) attempt to render large, cohesive shapes across the entire installation. The motion looks great on a computer screen, but in the store there are no vantage points where you can view every LED surface simultaneously, and it looks disjointed; it just doesn’t captivate your eyes. I gave up on nerdy, left-brained ideas, and instead focused on textures and smaller, independent motions. This looked and felt better.
It is possible to display animated gifs and videos on the LEDs, however they’re subject to the same aesthetic issues outlined above. Any details, like text or pixel art, aren’t recognizable. One day, we discovered a section of LEDs lit up bright white, with black dots on either side. Is it a software bug? A burnt-out LED strip?? … Nope! Someone left the mouse cursor sitting on the window.
Sometimes the hidden surfaces worked to our advantage. Certain animations draw one surface of pixels, then copy those pixels to another surface that’s out of sight from the first one. This boosted performance, and helped keep the FPS high on the Beaglebone.
If you look at the source code, you’ll find many different functions pertaining to LED layout. There’s a variety of movement and effects, so each animation stores the LEDs in different configurations.
ConveyorBeltsAnim arranges the LEDs into 5 long strips;
PondRipplesAnim sorts LEDs by the distances from the ripple origins.
We planned to install LEDs across the top of the Door Wall, near the ceiling. Ultimately we scrapped this idea, since the refracted LED colors wouldn’t be visible against the overhead lighting; yet those virtual LEDs are still defined in memory.
It’s Not Interactive… Yet
We also discussed making the installation interactive. I confess that I sided against adding interactivity. I’m writing this in 2016, and physical interaction with large installations often seems messy and vague. I feel like most projects of this size tack sensors onto the chassis, and it’s anyone’s guess whether your motion has a tangible effect on the light show. Also, the most obvious interactions (waving arms, or rushing through the arches) might disrupt the vibe of the bookstore. Imagine if people ran around the Door Wall, flailing their limbs, trying to make the lights flash?
Still, I wonder if we missed a great opportunity. I like the idea of using subtle interactions, and rewarding patience. Here’s one idea: Animations could idle at 30% intensity. If a person stood under an archway, the LEDs would flare up, starting from the ground and rising upward, burning at 100% intensity after 30 seconds. Then, when the person stepped out of the arch, the LEDs would slowly diminish to embers again. I like the message this conveys: “I’m glad you’re here!” and the light show is your reward, just for being present, and being who you are.
We also discussed adding a game to the installation, which people could play using their cell phones. This is interesting, but I feel like the right game hasn’t popped into my head. If you can think of a compelling game to play on this surface, please let me know. Remember, the effective resolution of the columns is 2×237 (that’s not a typo, it really is two by 237), and the pixel aspect ratio is something like 3.5:1. … I’m guessing that Tetris, Mario, and Flappy Bird would be undecypherable.
One issue (which still vexes my current projects) is the color palette. I used analogous color palettes for the Door Wall: a central color is chosen semi-randomly, and 2 or 4 more colors are added, equidistant from the central hue. Usually, this works great: red-orange-yellow is cozy, and blue-magenta-red is striking. There is one horrible exception: orange-yellow-lime is nobody’s friend, and I ensured it can never appear. Different hues have different personalities, so guided randomness is the way to go.
This is a beautiful installation. Jared and I were lucky to have this opportunity! This project was a great learning experience (both artistically and technically), and laid the foundation for the embedded graphics work I’m doing today. I have since worked on other LED installations, usually as a graphics programmer/animator (my strongest skill), and less on the hardware/fabrication side.
If you’re visiting Seattle, make sure you stop by Ada’s Technical Books. Besides the LEDs, they have great food, tons of books, and it’s the perfect place to chill out and do some laptopping.