This post will be about the lighting (and mechatronics) solution we’ve started working on for the 1/12th. As with much of the project, we start with the 1/24th model.
The main objective of the first sprint would be to decide on what lighting components we’d build around. We were delighted (see what I did there?) to discover that the Adafruit Neopixel 7-element Jewel fit perfectly into the 1/24th engine, and the Jewel plus the 12-element Ring fit the 1/12th – a convenient way to scale up our solution. Using neopixel circular arrays for both models would mean we could scale the code and everything else pretty easily.
Beyond an initial spec and fit check, there wasn’t a ton more to do in CAD – it was really a matter of ordering parts and prototyping stuff. Initial prototypes were done on an Arduino Mega. They are easy to use and have a ton of general purpose I/O on board. I use them quite a bit in early stages of development. I can plug-in and swap around things quickly and it makes for a productive brainstorming tool. This iteration uses both the Ring and the Jewel as we would in the 1/12th setup as it allowed me to quickly toggle between the two scales for testing.
Along with hardware comes software. One of the challenges I have had with programing LED’s is that ramping from one color to the next does’t always look right – whether it’s interpolating around the color wheel in unexpected ways, or muddy transitional colors, it rarely feels right. I wanted something I could “paint” with. I found this project on the Adafruit site that uses a Python script to take an image, convert it to an array, and “play” through the sequence like a flip book once loaded onto an Arduino.
There were a few things I didn’t like about the existing code though. It contained affordances for doing similar trickery with audio files (which I didn’t need) and, in the interest of saving memory (I think?), it converts the colors into 4-bit per channel colors. It also didn’t support RGBW Neopixels.
Modifying the Python script to convert to 8-bit per channel was just a matter of not jettisoning half the precision. Converting to RGBW was a bit trickier. Fortunately, we had done a similar project at Teague where we (Felix Heibeck and I) used Processing to convert RGB to RGBW. And that was largely based on the math found here. There’s a nearly one-to-one relationship between RGB and CMY color spaces, and a jump to CMYK is easy from there. Turns out doing all this on an inverted image results in RGBW. Here’s the relevant conversion assuming an inverted image as input…
p = pixels[x, y] rrr = 1 - (p / 255) ggg = 1 - (p / 255) bbb = 1 - (p / 255) var_w = 1 if rrr < var_w : var_w = rrr if ggg < var_w : var_w = ggg if bbb < var_w : var_w = bbb if var_w == 1 : rrr = 0 ggg = 0 bbb = 0 else : rrr = (rrr - var_w) / (1 - var_w) ggg = (ggg - var_w) / (1 - var_w) bbb = (bbb - var_w) / (1 - var_w) www = var_w rrr *= 255 ggg *= 255 bbb *= 255 www *= 255 rgbw2hex(int(www),int(rrr),int(ggg),int(bbb))
Here is a link to a GitHub repository of the conversion scripts (RGB, and RGBW). They output a slightly different .h file than the original Adafruit code as my X-Wing Arduino code works a bit differently. I use the built-in Neopixel library for gamma correction, for instance. But if you’re playing around on GitHub, then I’m guessing you know what to do with them.
Speaking of Arduino code – that was the next part. I wanted a system in which I could load an image that represented the flip book animation, but we didn’t just want it to play end-to-end; we would also have a variety of states and transitions. For the X-Wing, we warm-up the engines, then throttle-up to a cruise state. When the wings open we transition into an attack mode. When the wings close, we go back to our cruise state.
I animated our source image (that would be later converted to an array of hex color values) in Apple Motion. I like the way Motion deals with 32-bit values for lighting effects. It’s quick, and renders in realtime. From there I output individual frames, wrote another Python script to ingest the frames, and concatenated them into a single image with all the frames end-to-end consecutively.
The Arduino code has a function that will play a certain number of frames then loop a frame for a determinate (or indeterminate) amount of time. It also has a procedural noise function such that I can pass a single color value to a group of pixels (say, the outer ring) and then add variability to the them as individual pixels. The whole animation fits into about 8k of memory. Certainly plenty of headroom to do more complex things in the future. Below is a video of our 1/12 (Ring + Jewel) test after a couple rounds of refinement.
From there it was a matter of integrating and miniaturizing the hardware. I moved from a Arduino Mega, to a Teensy 3.2, but then decided on the Adafruit M0 Trinket. The trinket has some fun lighting options built into the board that we would later leverage. But at first it was wires and prototyping breadboards. I started using 26 awg servo wire as it had what we needed for data, and power in a pre-terminated offering.
As mentioned, the M0 Trinket has some lights on it. We’ll install the M0 up near the cockpit console and repurpose its lights for instrumentation lighting. The green is just power on (so, not programmable), the red blinks when the wings are open, stays on when closed (it’s a digital out, so no fancy fading), the RGB light is programmed with a “CRT blue” color-sampled from the actual film, of course (I know it’s pink in the photo – we changed it later).
While playing with the breadboard, I started to imagine how I might package the connections for the final. Initially, I was going to just use perma-protoboard with the connectors perpendicular to the board – but once I got into routing the connections, it was too tight, and/or would have required too much effort to make multiples. If we were going to make a half-dozen of these, I’d need more space.
Moving to a flatter configuration offered more room and a friendlier form factor for sending signal and power out to each wing, but would still be tricky to wire from a circuit standpoint. So, we went for a custom board. I thought it would be a good opportunity to learn how to make my own PCB’s as the 1/12th solution would eventually be 2-3 times the complexity with it’s additional power and servo (gasp! spoiler…) requirements.
With the new PCB’s fresh from OSHPark, I was ready to solder-up the first full prototype.
And of course build a Lego test rig to fully emulate the working conditions…
The 1/24th scale model isn’t very smart. There are no mechatronics beyond the Arduino and the Neopixels. To sense if the wings are open or closed, we’re using a hall effect transistor and a magnet to simply detect if the wings are near each other or not. The 1/12th, as mentioned, will have a more automated system with servo control (that’s the plan anyway) which means we can animate the lights in-time with the motion, rather just being reactive to the physical wing state.
Last was the final testing before sending off to Jason. We’ll probably have another rev or two before it’s done, but here is the current state. This is the 1/24th scale version (4 x 7 LEDs) on the Lego rig diffused behind a piece of paper…
Next up is to get this fully integrated into Jason’s models. Then we do it all over again and then some for the 1/12th.