Intro: Kinetic Light Work With Servo-controlled Laser Modules
This describes how I built the Laser Fan, an interactive kinetic artwork using servos and lasers. This was my first piece completed for my Pier 9 residency, and I'm pretty pleased with how it turned out! The active elements of the Laser Fan consists of eight servos that individually steer laser modules, controlling the angle the laser beam makes on a nearby wall. The lasers used here have a special "line lenses" that spread the laser beams into a lines: these form patterns and angles as they are projected. Lasers and servos were purchased off-the-shelf; the piece has three fabricated components we will describe in more detail.
Video: Charlie Nordstrom
Step 1: Designing the Cardioid Face Plate
I had planned to mock up the entire piece in Autodesk Inventor, including motion. That proved unnecessarily ambitious, but it was very handy in designing the fixed parts of the piece.
The shape of the Laser Fan's front is a mathematical curve called a cardioid, from the Latin for "heart." Inventor has this great feature where you can just enter a mathematical equation, even in a parametric form, and it will create a curve of this shape. The cardioid curve is especially simple in parametrized form, so it was easy to generate a mathematically pure yet still interesting shape. By scaling the Y dimension to be twice the X, I "squished" the shape to have a tall aspect ratio: once again easy using math. I put the lobes of the cardioid at the bottom, forming, yes, "butt cheeks." If you're not OK with this I'm afraid we can't be friends.
Once I had the face plate, it was time to position the servos. I'm using "9-gram" micro servos that are tiny and inexpensive; I found an Inventor-format solid model which helped me get the dimensions right. Unfortunately I could not figure out how to automatically align or evenly distribute the servos along the cardioid curve, so I just eyeballed it, carefully hand-positioning four then using the Mirror command to ensure they were symmetrically placed. (If I was less clever about using fancy curves, I could have used a Pattern command to automatically place and space them on a circle.)
I have to say that I spent far too much time on what should have been an straightforward design; Inventor seems to be buggy (or at least poorly documented) about how dimensions are projected between parts in an assembly and I spent a lot of time recreating things that either got blown up when the geometry changed or that I constructed in the wrong scope to start with.
Step 2: Designing the Legs
In Inventor, it was straightforward to make matching legs. These have tabs which fit in slots in the faceplate, and are held in place by M2.5 bolts with captured nuts. In the second image above I added a nut model to sanity-check the dimensions of the nut slot. The legs also have mounting holes for the circuit board brackets. (The circuit board is installed between the legs: it's visible as the purple plane in the rendering above.)
Step 3: Designing the Laser Mounts
This piece uses laser line modules obtained, surprisingly inexpensively, on Ebay. I needed a way to attach these to the servos, so again I used Inventor to design mounts that let the servos turn the lasers while while pointing them at an angle in the direction of the wall.
I was fortunate to have access to the Objet 3D printers at Pier 9, which have the neat capability of mixing different kinds of resin. The "Vero" resins are hard while the "Tango" variety are soft and pliable; I used a rubbery mix on the top of the part to grip the laser, and pure hard Vero resin on the bottom for stability and a good mate with the servo. I did not try to model the servo splines; I made the mating hole round and about the same diameter as the outside of the splines so I was not constrained to the fixed angles of the spline. A screw through each mount into the servo keeps them flush and set at the right angle.
Step 4: Construction and Dimension Checking
Once the faceplate and legs were designed, I test-cut them from cardboard using a laser cutter to check dimensions. The micro servo model was accurate so holes and servo slots lined up precisely, always a good feeling! Then I cut the faceplate and legs from acrylic and dry-assembled them to check the tab mating and screw capture. I also test-installed a servo with laser mount and laser to test clearances, check! Everything fit on the first try, which repaid somewhat the hours spent in Inventor.
Step 5: Designing the Control Electronics
For the brains of the system, I used a Teensy 3.1 microcontroller board. This is an inexpensive yet powerful ARM processor and is easily programmable using the Arduino toolchain which has a wide variety of useful libraries. Most importantly, it supports up to 12 servo channels right out of the box! Having written this kind of microcontroller code based on interrupts and timer functional units, not needing to reinvent that wheel is a definite bonus. (Also many people these days don't fully appreciate the convenience of a USB bootloader over expensive programming hardware, but trust me: it's great!)
Because there were eight lasers and eight servos to connect to the Teensy, I designed a printed circuit board to simplify connections. (From my experience, connections are the weak point in any electronics project so the more they can be replaced with robust solder joints the better.) I used EagleCAD to design the PCB because I have a lot of experience with it and am used to its quirks.
Layout was fairly straightforward: I used ULN2803a Darlington high-current drivers to control the lasers from the Teensy digital outputs. The ULN2803a has 8 drivers so I could use one IC for all 8 lasers (or so I thought!) and lets me control the brightness of each individual laser using PWM output (
AnalogWrite()) . An added feature is that the lasers are specified at 3.3V input voltage; since I'm driving them from 5V the double Vce drop across the Darlington pair drops the 5V input voltage down to about that level.
Because servos and motor drivers can generate a lot of noise on the power rails, I specifically designed the PCB to combat that. Servo power and ground are low-impedance pours on the top and bottom copper. To isolate the Teensy I designed in a separate voltage regulator but wound up not needing it (the Teensy has an inboard 3.3V regulator so it's still pretty isolated from the 5V servo power.) I did add a lot of power supply filter capacitance: each group of 4 servos got a 100uF bypass capacitor; perhaps overkill but the board worked fine.
I had the PCB fabricated at OSH Park, my favorite board service: quite inexpensive for small quantities, great quality results with gold plating for easy soldering and their trademark purple soldermask. Another benefit of OSH Park is that they accept EagleCAD files with no need for generating Gerber and drill CAM files. Turnaround is reasonably quick: I think these boards took less than a week.
Step 6: Assembling the Electronics
Once I had the PCB finished, it was a straightforward matter to "stuff" it -- or so I thought! It only has a few parts and connectors, how hard could it be? Well a couple goofs set me back a little but they proved nothing catastrophic. There were a lot of connectors, including eight 3-pin servo headers. The top picture shows my trick for soldering four of those all at once: to keep them straight and aligned I stuck them in a solderless protoboard then put the PCB upside down to solder the header pins. This means you need to align all the connectors on a .1" grid when you design the PCB, usually a good idea so you can stack a perfboard on top if you need to add or rework things.
My first goof was soldering the Teensy to the board using just a solder header shown on the second photo. This made the USB connection a little tight, and did not leave much room for the laser wires to come out of the board. So I added a female header sockets to give the Teensy some more vertical clearance, shown in the last picture.
My last goof was thinking I had a stash of 8-channel ULN2803 drivers when I actually had ULN2003a chips in hand. These are nearly the same IC, except the ULN2003 only has seven drivers instead of the eight I needed for the eight lasers. To save the few days it would have taken to get the right ICs ordered and delivered, my hack was to glue an additional ULN2003 chip on top of the one already there, and connect the extra driver to the PCB using flying wires as shown in the last photo. The macro shot here makes this look much bigger than it is: the actual wires are quite delicate! This hack could also be used to increase the current drive by putting two drivers in parallel.
Step 7: Final Assembly
Final assembly went pretty quickly. The servo mounting holes were just a smooch too small for a M2.5 screw so I tapped them to a M2.5 thread. The plastic is not great and the tapping was not that deep so I wouldn't recommend this trick where there is much torque on the servos, but here it worked just fine and saved me from having to fiddle with 16 tiny nuts on the back.
Because the servo cables plugged right in to the mating headers, the most tedious electronics task was soldering the 16 laser wires. These were just an oontz too short to reach the PCB; instead of soldering on 16 more extensions, I used a bit of perfboard and a hacked 10-pin female header which I had in my pile. This managed to fit perfectly, soldering the wires into the perfboard was easy, and the extra two centimeters it gave me was perfect for giving the laser wires clearance without too much left over.
I also found I had enough length on the servo wires that I could loop those down underneath the board to take up the slack. The back turned out remarkably tidy given there are a total of 40 wires coming out of the board!
Step 8: Coding, Motion, and Interactivity
I went back and forth over how the piece would activate. I could have put everything on an automatic pattern, either repeating or evolving, but I I didn't want the servos constantly active; if nothing else the gear noise would prove annoying. So I decided to make the servo motion interactive, but keep the lasers on when the piece was idle.
The idle pattern for the lasers is to sinusoidally brighten and dim each symmetric pair of lasers together; each of the four pairs has a slightly different period (fade rate) so they go slowly in and out of phase for an ever-changing pattern. (It does eventually repeat but I guarantee you will lose patience waiting for it!)
To trigger the servo motion, I considered several sensor types (infrared, ultrasonic) but finally went with a button that the user can push. This is both more consensual -- the piece will not interact with you without explicit consent -- and obvious (as well as simple to implement). To enable motion the user needs to press and hold the button down; the motion lasts as long as the button is held down. Every time the button is pressed, a new pattern is generated. There are four laser patterns and three motion patterns: each button press selects the next pattern in the cycle, so there are 12 possible combinations that all get exercised. I judge this is more patterns than the average viewer will care to explore.
Each pattern for both laser brightness and angle is based on sinusoidal variation; changing the relative phase and frequencies gives interesting motion and symmetries to the piece. For the motion, I needed to implement a state machine that would bring the servos gently back to a home position between patterns (when the button is not pressed) so that they could progress smoothly between patterns without a distracting twitch.
All this code was written in the Arduino environment using
cos8() from the FastLED library for the sinusoidal calculations. Among other things, this has a 256-unit input range so I could use integer math that just incremented without needing to roll over at the 2π mark.
The Arduino code and schematic can be found on Github at https://github.com/headrotor/laser_fan