So how can you control an iRobot Roomba vacuum with an Arduino board?
|I picked up a Roomba at the flea market for $15, and a week later got three more for $20 ... the old ones are starting to show up at a very low cost. And ... those made since some magic date in 2005 implement the open Serial Command Interface that iRobot provides. (iRobot has moved on to promote their "Create" device for amature robotics efforts, elimiating those parts of the vacuum that suck and adding more control, better interface, etc. -- $130US, which is not a bad price, but not quite the same as a $15 flea market find.) All of the models I aquired have a serial port (mini DIN 7-8 pin female connection), but different manufacture dates -- so some have the SCI interface, some don't. The best check at a flea market is the applicable patent dates showing on the bottom. The 2005 date here was positive (not assured since that is the transition year), the one I have with a 2004 date does not have the SCI interface.)
Once you have it home and with a bit of connections (described below) you can verify the mnfg date (even on older models) as it reports this when it powers up though the serial port. The two models I had showed "2004-09-03" (oops too early) and "2006-08-19" (yippiee!))
I did need to get a new battery for my first one ($25 ballpark for a 3rd party one)
|Checking the voltages on the wires. --ok, you need to understand I'm a software type (more on this later), with an awareness of hardware. A bit paranoid about destroying my $9 investment (4 roombas acquired for $35), or worse, my Arduino Uno board ($35) -- so I pulled out my analog volt meter, set it for DC 25v, and tried out the pins on the port. First I was surprised that the pins had voltage even with the Roomba off. So, as with many modern appliances, off is not really off, which also means that connecting things could damage things if not done carefully. My concerns were heightened in looking up things on the web and finding a "RooStick" (no longer available from Sparkfun) that adapted the Roomba serial port for USB connection (Roo232 from another supplier, seemingly out of stock), and sites asserting that they blew their Arduino board plugging it into the voltages on the Roomba. My volt meter indicated 20 volts on some pins, 10 on others, under 10 on others. For 5 volt Arduino operations, this sounded like it could be fried chips (not the side dish I was looking for.)
Networking to the rescue! --you may have noticed other comments on my web site about the value of professional society connections ...so here is an example -- I pinged my local IEEE colleagues about the problem, Rich Maynard (chair of the local IEEE Robotics Society chapter) basically said "come on over, let's get this working". So I did. Note: hardware folks have useful things like oscilloscopes, digital volt meters, and perhaps most useful, experience. We found that the signals were really about 17 volts on the Roomba power pin(s), and a nice friendly 5v on the signal pins.
Our approach was to use a software serial port for the Arduino to Roomba connection, and the USB port from the Arduino to the laptop. this also provided power to the Arduino from the laptop, avoiding the "would you like fried chips with that?" question. Note that the female connector in the Roomba provides an easy use of 'bread-board' wires that can run right to the Arduino (if it is close enough -- we put down some double sticky tape and stuck the board on the Roomba right by the serial port.)
Here's the connections we made initially:
That's it, three pins -- the wire colors are not necessarily the same as the ones you might find in an existing cable, so do continuity testing if you are trying that. Also, be aware that the male connector (the one with pins, you can figure it out) will have the opposite layout from the female -- so pins 7,4 and 2 will be swapped with 6, 3 and 1.
| Arduino Pin
|| Roomba Pin
|| 6 or 7
|| Always start with ground, and detach last
| 11 (Tx)
|| 3 (Rx)
|| Note in serial connections you cross the transmit and receive pins
| 10 (Rx)
|| 4 (Tx)
|| ditto (Rx receive, Tx transmit)
Using Digital Input/Output (DIO) pins (10,11) on the Arduino matches the default assignments made by the software serial port module, if you look at the code, you will see that this assignment can be changed in the SoftwareSerial object declaration.
Eventually we did hook up power (which is what shows in my un-tethered examples) That is Arduino pin Vin (not +5 or +3.3 ... otherwise you get fries with that, pin Vin has some power protection.) (Power connect in last, out first, and avoid shorting to ground)
A bit of care is needed to get the pins into the right spots on the Arduino -- always good to check this twice. Looking down at the Roomba, with the serial port slot towards you (outside edge) pin 3 is on your left, pin 4 on your right -- power is on the two pins furthest from the edge, and you really don't want to plug those into the DIO ports (I've run out of fried puns.) A little voltage checking before you plug things into your Arduino is advised. (If you don't swap Rx and Tx, things won't work but they won't fry either.)
If you are trying to do the most basic test, trying to get some signal from the Roomba into the Arduino -- you know, after a half hour of trying this and that, checking the software (my perspective) and the hardware (Rich's perspective) .. you may find you have the wires in the wrong DIO pin positions on the Arduino ... you know, maybe ... I wouldn't know anyone with this experience, but it is a possibility.
The really simple Arduino serial port sample software just does a read from the Roomba side, and sends it though the USB to the Serial Monitor (please check the Arduino references for how to use the compiler, downloader, serial monitor, etc.):
if (mySerial.available()) Serial.write(mySerial.read())
//mySerial is Tx from Roomba, Serial is USB to laptop
A few more lessons learned -- we started using the default baud (speed) rate of the Roomba, which is 57600 bits/second. We made sure to indicate this in the software serial.begin designation, and matched it in the serial.begin code, and finally in the setting on the Serial Monitor window (and of course had to make sure our COM port was right on the windows system, and they COM port was enabled -- I found that detaching the USB cord often required a disable/enable of the COM port from the Windows Command Panel System COM port control.) ... which gave us this output from the Roomba in the Monitor:
slept for 19 minutes 3724 ticks
Now, the Roomba is not swearing at us because we woke it up. Those of us with some experience watching the garbage that results from having either a serial speed mis-match, or an overflow recognize this.
We gave it a try using Rich's Arduino Mega -- yes, his is bigger than mine -- and has multiple hardware serial ports. This works very well at the relatively high speed (I know, your broadband connection is measured in millions or billions of bits per second, but 57600 is darn good for serial ports -- I learned at 300 baud ... that's just 440 hours to download a 20 minute TED.com video.) If we had been using my 2005 Roomba, we would have gotten:
slept for 258 minutes 2195 ticks
Roomba board revision: 7 (original-roombattery-current-quiescent-raw 527 battery-current-zero 513
Which shows how smart Roomba really is, I can't even spell quie--whatever.
When we got the Roomba to admit it's 2004 birthdate, we realized it wasn't likely to have the SCI interface, so I thanked Rich and headed back home. (Lesson: if you have a herd of Roombas, put them all in the car -- it costs nothing and you can switch between them if needed) (unrelated message: check your tires regularly, it is a pain to replace a flat in Rich's driveway, or elsewhere)
At home I found a 2005 dated Roomba (2006 birthdate reveled later), and started to duplicate the hookup. Being a software type, I downloaded the latest Arduino toolkit (compiler, libraries, down-loader, serial monitor, USB driver) and tried a simple program. The compile failed with a note that Serial.print(123, BYTE) was no longer a supported format. And in the process was also reminded that 'c' family languages are case-sensitive -- so 'Byte' is not the same as 'byte'. (Probably half of my compile errors were being lazy about capitalization.) So I checked the most recent language reference, and cleaned up my code. I should point out that I carefully held the power button down on the Roomba for an extended time until it played it's little "going to a lower baud rate" song. (See video) - At low baud rates I was able to get the wakeup message!
Data Rx Tx
Power and GND
Black/gnd is outermost
So, I figured I'd send it a "song" and play it. I tried this and that, but could not get it to sing.
So I did what guys always do when all else fails, RTFM (which means something like Read The Fine Manual). Actually I did something that can be very useful. Roomba has four "modes" which we engineering types like to call "states" -- so I created a state diagram.
Creating a state diagram causes you to become aware of the behaviour of the system, this is a good thing. It causes you to read the documentation, this is a good thing. It causes you to read that small, inconspicuous sentence "allow twenty milliseconds for a mode change", this is a very important thing. It also informs you that you can set sounds in Passive Mode, but you cannot play songs in Passive Mode, you must be in Safe or Full mode. This is why, in an earlier life, when I was doing customer support, we used the phrase "RTFM" a lot. Oh, yes, and did I point out in the diagram the transition that occurs (automatically) for "Exceptions" -- which is to say wheel drops, cliff detect, etc.?
Guess what? When you allow for the delay, put the wheels back on the table, and ask politely you get music! ... well sound at least.
So, being a software person, I figured I'd write a program to test out many of the interesting options available for controlling the Roomba. (see Program #1 ) This program contains artifacts of early testing (until I clean it up a bit), and also classic "software test points". Since it uses keyboard entries to test control sequences on the Roomba, it echos those back to the Serial Monitor. This confirms that a given action was attempted. Failures often indicate one of the unexpected state changes. For example, when "M" no longer plays music, it means you are no longer in the Safe mode (and other actions will fail as well). "I" to initialize often helps -- but sometimes you need a full reset of the Roomba which means pulling out the battery for a few seconds. (There is no obvious software "reset" code, no doubt there are undocumented codes however.)
Once I tried a bunch of songs, timings for circling loops (and radius changes) .. I found a sequence to demo the beast and isolated that into a single program. (See Program 2)
The result is also captured in a video. This program does not require any connection to the laptop, and since the Arduino stores the programs in a static flash memory, it resides in there between power up sequences. Now is when I connected the power from the Roomba (pins 1 or 2, nearest the core of the machine) to Vin, repeat, Vin pin for the Arduino. To get the Roomba to run the sequence, you just push the restart button on the Ardunio. Be aware that the Ardunio is running as long as there is power, draining your Roomba battery even with power "off", so I remove my battery when I'm not using it.
Suggested take home points:
I need to get myself a 7 pin mini-din plug so I can easily move the connection from one Roomba to another, and a packaging that will protect the Arduino attached to the Roomba from accidental damage/pin dislodging. And of course software is never quite right. I need to detect exceptions (cliffs, wheel drops) and take action on those events to keep things operational. Add more music options, etc. I notice that volume for the music appears to be lower with low notes, so the attempt at the Strange Encounters sequence is fairly audible, but the Jaws reference is not.
- Read the documentation -- maybe even translate it to a state diagram or whatever
- Check your connections twice, three times for any that might cause damage
(and check your car tire pressure regularly)
- Build in test points so you can verify "where you are" in the code
- Build in safety (timeouts, etc.) - so things don't run off the table as it were
- Take advantage of the knowledge of friends -- that's what networks are for
- Have Fun!