The Git Bell: post-commit → ruby → arduino → bell

13 February, 2009

A while back, why let loose with a tweet that made me sit up with a start:

post-commit → arduino → string → mannequin’s finger → harpsichord. it's very motivating.

I immediately knew that this was something I had to build; moreover, I knew just how. It was the perfect project to combine my growing Arduino knowledge with my growing git-fu.

What I didn't know was just how hard it would be to get the requisite parts. You can't just walk into a shop and buy a mannequin hand, it turns out, let alone a harpsichord. And while I've made some progress on that front, today I'd like to announce the results of some preliminary research: The Git Bell.

The Git Bell consists of three components:

  1. A Dorkboard controlling a pager motor and listening on serial
  2. A Ruby script that communicates with the Dorkboard over serial
  3. A git post-commit hook that triggers the Ruby script

The idea is that whenever you commit, the bell should ring. It works by using git's post-commit hook to send a serial message to the hardware which then rings the bell.

Here's a video showing all the pieces working together:

I'll go through these steps one-by-one.

Dorkboard bell ringer

Git Bell

After some early experiments with gear motors, I settled on the idea of using a pager motor to ring the bell. Pager motors are much quieter in their operation and don't need any additional gears or other actuator hardware. Once the pager motor is set up to dangle against the bell, turning it on produces a pleasant ring. (One of the parts of this project I'm most pleased with is the woodworking on the armature for holding the bell in place; normally my wood-stuff comes out all splintered and un-plumb with poking dangerous nails, but this one came out smooth and clean.)

Arduino controlling a DC Motor: circuit diagram
Pager motors take 1.5V, which is the output of a single AA battery. I wired up the battery and the motor with a Tip-120 transistor so that the Dorkboard could act as a switch to connect the two. It's a circuit I've used multiple times before and so I'm quite comfortable with it.

Dorkboard, who? The Dorkboard is an Arduino clone homegrown right here in Portland by Don Delmar Davis of the local Dorkbot group. It's a great board that features pretty much the smallest form factor into which you can squeeze an ATMega168 and a bootloader that provides really fast startup times after programming and new serial connections (something that came in very handy on this project). I built this one at the most recent Arduino Cult Induction session that Don ran. (Check out my pictures from the Induction.)

Once the Dorkboard was wired up, I wrote a RAD script that listened for serial input and then sent 5v to the output pin I'd plugged into the Tip-120. It came out looking like this:

Then, I connected to the Dorkboard's serial line using screen to send some messages and confirm that everything was working properly. Once that was done, it was time to write the Ruby code.

Bell.ring

Next up, I had to write a Ruby script that would send the a serial message to the Dorkboard. To make things all fancy-like, I wrapped the ruby-serialport functionality I needed in a nice little bit of Module syntax courtesy of Mr. Wanstrath:

The result is that if you require this file and if the bell hardware is plugged in, you can make it ring as simply as:
Bell.ring

The one gotcha in that bit of code is the five second sleep. That's there because the Dorkboard, though it's faster than the Arduino, still takes four or five seconds to start listening again after you initiate a serial connection with it. There's probably a way around this by telling it not to listen for reprogramming instructions (which is the reason for the delay), but I don't know what it is.

Post-commit

The last thing left to do was to get git to invoke this code after every commit. Again, Mr. Wanstrath has the post-commit hook knowledge. All you have to do is create an executable file in .git/hooks/post-commit that does what you want. In this case, what I wanted was super simple:

As you may have noticed earlier, Bell.ring is smart enough to catch the exception that gets thrown in the case that the hardware's not plugged in. So, this will return the successful "exit 0" status every time, guaranteed.

Once all the pieces were plugged in, I committed, and wham-o ring-o!