Counting Pull-ups
I'm a big fan of my Fitbit pedometer because it does most of its work without any interaction. I clip it onto my pocket and it counts my steps and flights of stairs as I walk throughout the day, then automatically, wirelessly uploads the data to Fitbit's website whenever I'm within range of its USB dongle plugged into one of my computers. The whole thing works without having to think about it or plug anything in. The battery lasts for about a week, and when it finally runs low, my low battery notifier sends a message to my phone through Pushover telling me to put it on its charger for a few hours.
To add to my step data, I got a Withings scale last year which logs my weight and BMI on Withings' website automatically every time I step on the scale. Fitbit's website syncs this data from Withings, so now I'm able to track my steps, flights of stairs, weight, and BMI, all automatically, all on Fitbit's website. I use this data mainly as a motivation to walk more and not get fat, just as my Wii Fit motivated me to exercise every day by tracking all of the data. When I know my Fitbit is counting my steps, I'll avoid hopping on the bus or train to get home and just walk. A few times I've left the house and upon noticing my Fitbit wasn't there, walked all the way back and got it just so the steps I was going to take that day would "count".
Passing the Physical Fitness Test
Even with the data, though, my Wii Fit got kind of boring after a few years and I stopped exercising routinely. I didn't have room for a weight set and I was far too lazy to go to a gym every day, so I bought a pull-up bar. It was mounted at the top of a common doorway which meant it was out of the way, but still always available without having to pull out some piece of equipment and set it up. As I walked through the doorway throughout the day, I could do a few pull-ups and continue on my way. Ever since I got it, though, I've been thinking about how to automate the logging of those pull-ups.
A Video-based Prototype
Last year, I built a prototype using the tiny Alix board (running OpenBSD) I won at NYCBSDCon and a webcam mounted on the side of the door frame pointed at the pull-up bar. A ruby script read image data from the webcam using hornetseye-v4l2 and then tried to detect skin tones in the image to detect when my head had reached a particular height.
Unfortunately, the Ruby program on the 500 MHz processor of the Alix was unable to maintain a high-enough frame rate reading and processing data from the USB webcam, even with images as small as the one on the right. The webcam was also too sensitive to changes in light in the room to work accurately.
An Infrared-based Solution
While I might have been able to rewrite the program in a lower-level language on a dedicated board like an Arduino, I'm terrible with hardware and can't solder to save my life. Luckily, I recently discovered Phidgets, which are boards that interface with a variety of input and output sensors that just plug-in, and the boards interface with a host over USB. I bought their smallest 2x2 board and an infrared proximity sensor. Using infrared would mean much less sensitivity to light, and the logic of turning proximity into a numeric value would be done for me.
I mounted the IR sensor above the door frame and ran the wires along the door trim behind white electrical tape.
After a quick OpenBSD kernel modification to make the Phidget board appear as a ugen
device, and an OpenBSD port of libphidget, I was able to read sensor data from Ruby at a sufficient sample rate. This is a chart showing the values from the IR sensor while doing 5 pull-ups followed by an elevated hang for about 5 seconds.
I added some speakers to the Alix and made the program play a short sound every time it detected a pull-up so I know it's working. After integrating with Fitbit's API, it was able to log each pullup as an activity record on my account, which I can see on Fitbit's website or export through their API. Now my pull-ups are being counted and logged automatically, with no start button or manual iteration counter.
2012-04-25 14:56:02.830 - state is now idle (199)
2012-04-25 14:56:02.910 - state is now pulling_up (212)
2012-04-25 14:56:03.198 - state is now pulled_up (347)
2012-04-25 14:56:03.322 - logged to file pullup_log
2012-04-25 14:56:03.323 - logged pullup on fitbit (id 220768)
2012-04-25 14:56:03.926 - state is now idle (6)
I've released the source code to the Ruby program on Github.