I recently partook in Bike De'Lights, Omaha's two-wheeled tour of the Christmas lights on display in Midtown. Cyclists are encouraged to decorate their bikes with battery-powered lights, jingle bells, and get into the festive spirit.
I treat this as an opportunity to build an overly-complex hardware project. Last year I wired up an Arduino to generate remote-control signals to drive an LED light strip. It was fun, but there were some opportunities to make it better (or just further complect the system), which is what I did!
My goal for the project: hook up an LED light strip to my bike frame, and have it respond to my heart rate and pedaling cadence, using the ANT+ sensors on my bike. Specifically, I wanted the lights to change color from green to red as I pedaled faster, and have the lights blink in sync with my heart rate.
The core of the project:
- Raspberry Pi Zero and a 4GB micro SD card
- 5M Waterproof RGB LED Light Strip
- USB portable charger and micro-USB cable
To power the LED light strip:
- TIP120 Transistors (3x)
- 8 AA battery holder and 9V snap connector
- A handful of jumper wires and a prototyping board
To capture sensor input from the bike:
- ANT+ USB receiver
- Speed/Cadence Bike Sensor
- Heart Rate Monitor
- Micro-USB to USB adapter (the Pi Zero has micro-USB inputs)
I had most of these items on hand from previous projects, but had to buy the LED Light Strip and transistors. In total this project uses less than $20 of consumable parts.
Everything fit in my bike's saddle bag; this worked really well due to the super-tiny Pi Zero. I placed the Pi and the circuit board in a makeshift enclosure I made from a to-go container, and held it down using electrical tape.
The circuit to power the LEDs is pretty straightforward:
The Pi sends PWM signals to the red/green/blue input wires, and the 12V of batteries goes to the LED light strip.
Also note: the dimensions are off in the diagram - the circuitboard was actually bigger than the Raspberry Pi Zero!
The Raspberry Pi was running Raspbian and a program I wrote in Node.js.
I used Thomas Sarlandie's pi-blaster library to send PWM signals to the LED strip.
The library creates a
/dev/pi-blaster endpoint on the filesystem, which you write to and it send the signals to the GPIO pins.
There's even a Node.js wrapper which made adding it to my app super simple.
To capture ANT+ data, I used Alessandro Vergani's ant-plus library, which emits Node-style events when new sensor data comes in. This worked well, but only the heart rate monitor was supported out of the box. So the majority of the coding I did for the project was implementing the ANT+ speed/cadence sensor into the library. The pull request shows the fun involved there.
The actual code to integrate sensor input and have it drive the LEDs was another fun learning experience. Since the heart rate and cadence sensors produced a stream of events, I pulled in RxJS to treat them as Observables, and used reactive programming techniques to map the inputs into a stream that could "render" an LED strip. That's probably another blog post in itself.
Once I had a working protytpe, I configured a
systemd service to start the Node application when the Pi booted up.
This was especially useful as I had to reboot the Pi multiple times during the ride.
Running the Lights
Overall, I'd say the results were a solid B/B+. The lights were super bright, and lots of folks complemented them as I rode. It was especially cool to see the lights start flashing like crazy as we climbed a big hill and my heart rate spiked. But some parts could have worked better.
The cadence sensor connection was buggy as hell. About 50% of the time it wouldn't connect to the sensor on startup. I programmed the lights to fade to blue after 5 seconds any pedaling events, for times when I was coasting downhill or stopped. But when the sensor didn't connect, the lights stayed blue until I could stop, reboot the Pi, and try it again. I'm not sure why this happened. My guess is it had to do with interference from other sensors, since the problem was especially pronounced at stops and locations with lots of other cyclists.
I would also have fastened everything down better. Omaha streets are often potholed and bumpy, and there were several times when the batteries fell out of the enclosure, shutting all the lights off. I also just used jumper wires to connect the circuit board to the LED strip, and those fell out a number of times. A little more soldering and electrical tape would have fixed these issues. A shakedown ride or two would have also helped; most of my testing was done on an indoor bike trainer.
Also, I would have have given myself more time to build it out. I was working on the cadence sensor code until 4am the previous night, which probably contributed to the overall bugginess of the code.
All the code I used is on GitHub. If you use this as the basis for your project, shoot me a note, I'd love to hear how it goes!
Other pages I found useful: