For as long as I can remember, my family traveled (and still does) frequently to Walt Disney World. For many of those years, we would travel in the late Fall as it was one of the least busy times of the year there. However, that always meant that we were afforded to see ALL of the Disney holiday decorations. This included my favorite, the Osborne Family Spectacle of Dancing Lights.
If you never had the opportunity to see them, in their later years, they were lights synced to music and would “dance” when played all while it “snowed” in Florida. When I was a kid, this was pretty awesome and fun to see! However, as an engineer, I’ve ALWAYS been curious about what drives the show and if I could do something similar myself.
Fortunately for me, like many engineering problems, Google provides all clarity. You can find pages of results filled with videos, news articles, tutorials, and blog posts about other people who have done this to great success. Obviously, reinventing the wheel here wasn’t necessary, and I had a plethora of information to fall back on. It became clear that there was a pretty specific path to follow to have your own dancing lights:
- Choose a microcontroller: In my case, I chose an ESP32 development board that I had on hand. They are fast, have “tons” of memory and code space, run Arduino, and can get you moving quickly. Read more about ESP32 microcontrollers here: https://en.wikipedia.org/wiki/ESP32. You can find a slew of different types of ESP32 development boards on Amazon.
- Choose your lights: There are lots of addressable LED options out there. For this project, I went with WS2811 100-LED strands that I found for a semi-reasonable price on Amazon. I would recommend shopping around if you aren’t in a hurry like I was on this project. Here is an Amazon search that you can use to find some for yourself.
- Convert your logic: Originally, I planned to use a Metro Mini (ATmega328), but the on-board memory failed me for the number of lights I was driving. The power of Metro Mini is that by default, it has 5v logic. The ESP32 has only 3v logic. Ensure you’re paying attention to which logic level your lights require as it may require you to shift. In my case, I used a 74AHCT14 by Adafruit to get the job done.
- Choose a library: FastLED out of the box will handle all of the business logic required to drive the lights you bought. I’m focused on getting them dancing today — not learning how to be a firmware engineer writing my own.
- Organize your LEDs: I’ll jump into this further later, but the gist here is that after stringing up all of your LEDs, you need to know in physical space where they are so you can animate them. There are many solutions to this problem, and webcams are usually the answer, but they are slow and painful. I can fix that.
- Create animations: The last thing you need to do after setting everything up is to start animating on your LEDs. There are some built-in examples with FastLED to get your feet wet, but this part will be on you to figure out and create.
Having an idea of what I needed gave me a little bit of a jump start and, more importantly, the beginnings of a parts list I would need to build out this vision. Understanding what brought other people's successes (and failures) to their projects is an immediate learning exercise.
For this first year’s pass, I decided to start small and go with 500 of the WS2811 LEDs and strung them up in our Christmas tree.
Creating the circuit itself to drive the lights wasn’t overly complex. I need power, a microcontroller, a logic-level shifter (depending on your setup), and some wires. Anything else is optional. For me, I added a display and button to my circuit as well so there would be ways to switch into pre-configured modes that ship with FastLED and my custom live animation mode.
Here are a few iterations of my circuit:
As you can see, I was pretty committed to a two-board design at first. The ESP32 handled communications with a phone over BLE and then sent commands to the Atmega328 to drive the LEDs. I got frustrated with fighting the memory on the Atmega328 and dropped the board altogether in place of a logic level shifter.
Here it is driving our LEDs for the first time:
Four things on the list are done. Organization next.
Organizing LEDs is hard. Organized LEDs in a 3D space is even harder. In a case like Disney’s, they don’t care so much about 3D as the lights are put against flat surfaces for the most part. Simply choosing to do vertical or horizontal placement of the strands of LEDs can allow you to infer any LED position in the grid quickly. When you move into 3D space though, and are wrapping a tree, how do you let something know where those individual LEDs are at?
Well, most solutions you’ll find on the internet require a webcam. You point it at your tree, increment through every bulb, allow the webcam to try and see it and then infer it in a 2D space for that side of the tree and move on. After you finish all the bulbs, rotate the tree 90 degrees and repeat the process 3 more times. Then you’ll get an idea of where every bulb is in a 360 orientation around a tree.
This process definitely works, but it’s extremely time-consuming, and often there is a large amount of fixing LEDs the webcam was never able to see. I can do better. What if I could position these in 3D space with one pass and with the phone in my pocket? Well, I can.
Enter iOS with ARKit, SceneKit, and CoreBluetooth. ARKit is pretty self-explanatory; it’s a set of tools and features in iOS that allow developers to create awesome Augmented Reality (AR) experiences. SceneKit is one mechanism to display 3D scenes on iOS. CoreBluetooth is the underlying Bluetooth Low Energy (BTLE) framework that I can use to talk to our ESP32 as it supports BTLE out of the box.
I wrote an application that would allow me to connect to the ESP32, put it into a “configuration mode” for the LEDs, and increment one-by-one as I lined up an LED into a 3D sphere in ARKit and “captured” a bulb. It would register its location in 3D space based on ARKit’s origin. This saved an incredible amount of time and put capturing into a single pass through 500 bulbs as you simply walk around the tree lining up the sphere to the lit LED.
Unfortunately, I did not cover me going through the tree itself and marking every individual bulb, but here is an example of the app I wrote to perform this making “bulbs” in 3D space:
Once captured, since all of the points are based on ARKits origin, it no longer matters where the origin is, so all of these points can be moved to SceneKit and presented as spheres:
Now that the points are captured, I could start thinking about doing animations.
At this point, my personal time limit on this project was nearing a close. I needed to see something animating to show me that my organization worked fine. I picked a simple animation of a bar of lights moving up and down the tree. To make this happen, I went back to the same tool I was already using, the powerful testing app.
Back in SceneKit, I added a new object, a flat cube, to animate up and down through the tree. The beauty of SceneKit is that it has tons of tools under the hood to help with not only doing the animation but also alerting to collisions. When the cube collides with an LED, it will add it to the buffer. When the buffer is full, it sends that entire buffer over BTLE to the ESP32 to drive the LEDs. The animation is pre-programmed to make an LED go from off to full white and back to off again. In the app, the animation looks like this:
And in real life on the tree, it produces this:
Unfortunately, this is as far as a dying Christmas tree and the out-of-date decorations would take me. The board is being held in reserves for next year with the anticipation of organizing the LEDs and going immediately as soon as the tree goes up. When that happens, I’ll be sure to make a new post featuring a whole bunch of new animations that I have some ideas for.