I've never been able to remember to update a to-do list consistently. I used to use them for a few days, usually when I had a particular need to track a lot of things -- but then I would stop using them once I didn't need them, even if other people needed to see my updated to-do list. This happened repeatedly and caused problems at a couple of the companies I've worked at.
When I was a kid, my parents would sometimes buy chocolate Advent calendars for Christmas: starting on December 1, each day you open a little door, and there's a piece of chocolate behind the door. And let me tell you, I never forgot to open that door in the morning, because the sugar reward strongly reinforced the habit. So I figured a neat way to get myself to remember to track the to-do items would be to give myself candy when I updated the to-do list.
I built a candy dispenser that sits on my desk, next to my computer. When I check an item off in Google Spreadsheets, it turns the motor, and an M&M is delivered to the chute. See a video of it in action!
I built it using a Raspberry Pi, which is a $35 single-board computer that runs a miniature Linux distribution called "Raspbian". The device is pretty awesome: it has a display port, an SD card slot, two USB ports, an ethernet port, and a good number of general-purpose I/O ports. It runs lots of Linux applications and has access to the Debian repositories, but I just use Python and an SSH server. It's also physically small -- about the size of a credit card, though since you plug things into it on all sides, it ends up taking up a lot more space than that.
I've used Arduino for projects like this in the past. Arduino is a similar computer-on-a-board, though it's substantially less powerful and flexible -- it just has the general-purpose I/O ports, and you program it using a USB cable, but it doesn't run an operating system. Because of this, the Pi ends up being a lot easier to hack on. Since I wanted to connect it to the internet, it was a no-brainer in this case. (You can get an ethernet peripheral for the Arduino but I didn't bother to find out how it would work, since it ends up being just as expensive as the Pi.)
The other core piece of the hardware design is an actuator of some kind, to dispense the candy. I decided to do this with a stepper motor, turning a wheel with holes in it; see the video for a demonstration. A stepper motor is a special kind of motor. With a normal motor, you just apply power and it starts spinning. But with a stepper motor, you control the electromagnetic coils of the motor with software. This means you have precise control over how much the motor turns.
I had never used a stepper motor before. I got the idea from this similar project by Kathryn McElroy. I bought this stepper motor for the Pi, which came as a kit -- a circuit board plus components to solder. There were about 70 joints to solder, which (I would guess) doubled the total number of joints I've soldered in my lifetime. Despite my soldering inexperience, it worked the first time!
After I got the Pi working and the motor working, it was down to the physical components. Actually, it still is, because all the rest of the design is currently made of paper or cardboard :) I want to redesign it but it's actually kind of a hard problem, figuring out how to make it in a robust way. I would like to prototype it with Lego, and 3d print the wheel, but that's a future post.
If you're interested in the software side of it, I put it together using a bunch of pieces.
First, the stepper motor driver. This code runs on the Pi. It just spins the stepper motor. step.py
Second, the fabric script, enabling me to run 'step.py' on the Pi easily from my desktop. It just copies 'step.py' to the raspberry pi via SSH ('rpi' in my ssh configuration) and runs the script. That way I can easily do 'fab step' and test the device, and I don't have to edit the code on the slow Pi itself. fabfile.py
Third, the 'rewardserver' -- it runs on my desktop and provides an endpoint at http://my-desktop-addr:48001/reward. When anybody makes a URL request to this endpoint, it triggers the fabric script, giving me the reward. This was the easiest way for me to setup the ability for external services to trigger rewards. rewardserver.py
Lastly, any external services that you want to trigger a reward. This stuff isn't checked into the repository, and it depends on the service as to how you want to deliver the reward. For Google Docs, I had to create a Google Apps script attached to my spreadsheet, and load the URL when the cell was edited. Unfortunately this kinda sucks -- Google Apps scripts are incredibly buggy and unreliable and hard to write. So I'm not even going to bother posting the current version of this, though I posted a prior version (which sent me a text) on the Akratics Anonymous list here.
Anyway: you're probably asking if it's actually working. So far, it seems to. I only started this project ten days ago, but I've continually updated my to-do list since then. So results are so far promising but inconclusive. Expect a followup in a few weeks!