Having been pondering it for a while, I recently bought an
iRobot Roomba vacuum cleaner - the Roomba 620 which is the current entry model. For fun I took some photos with an
infrared sensitive webcam (a trusty
XBox Live Vision), and then measured some of the IR signal codes with my
Raspberry Pi.
![]() | ![]() |
Note the four downward facing IR LEDs (cliff sensors) | Does the Roomba use IR illumination to follow walls? |
Initially it might seem like the Roomba explores blindly until it bumps into things, but it does have some open space detection as you can obverse speed changes. Having seen how it lights up where it is going with four IR LEDs (and another four pointing down which I assume are the cliff detectors) this is less mysterious.
Roomba Home Base
I've already done some background reading, so I was expecting to be able to see three IR LEDs on the Roomba Home Base or "Docking Station" - the top one is a unidirectional emitter visible from all sides of the dock (and behind it) referred to as the "Force Field" which normally repels the Roomba. The other two emit angled beams used to guide the Roomba to its "Home Base" for recharging.
This works like the port and starboard (red and green)
lateral buoys in used to guide ships into harbour. By keeping the "Green buoy" to port (left), and the "Red Buoy" to starboard (right), the Roomba can find its way home. Of course, here the LEDs are not different colours (although I'd guess the original prototypes probably were), rather they emit different pulsed signals - which I should now be able to detect and decode with my newly fitted
Raspberry Pi infrared receiver.
Published Roomba IR Codes
I used
iRobot Create Open Interface v2 (PDF) to compile the following table, specifically page 18 which has the above diagram, and which covers the remote codes indirectly when talking about the Roomba serial interface - iRobot have been very positive about people hacking their robots for technology projects.
Each of these remote codes is 8 bits (1 bytes) which can be represented as a decimal number, a hexadecimal number, or a string of eight bits (hereafter the first bit in the signal being the most significant bit in the numerical code).
Sent by | Dec | Hex | Binary | Meaning |
Remote Control | 129 | 0x81 | 1000 0001 | Left |
130 | 0x82 | 1000 0010 | Forward |
131 | 0x83 | 1000 0011 | Right |
132 | 0x84 | 1000 0100 | Spot |
133 | 0x85 | 1000 0101 | Max / Dock |
134 | 0x86 | 1000 0110 | Small |
135 | 0x87 | 1000 0111 | Medium |
136 | 0x88 | 1000 1000 | Large / Clean |
137 | 0x89 | 1000 1001 | Pause |
138 | 0x8A | 1000 1010 | Power |
139 | 0x8B | 1000 1011 | Arc-forward-left |
140 | 0x8C | 1000 1100 | Arc-forward-right |
141 | 0x8D | 1000 1101 | Drive-stop |
Scheduling Remote | 142 | 0x8E | 1000 1110 | Download / Send All |
143 | 0x8F | 1000 1111 | Seek Dock |
Roomba 400 Home Base | 240 | 0xF0 | 1111 0000 | Reserved |
242 | 0xF2 | 1111 0010 | Behind / Force Field |
244 | 0xF4 | 1111 0100 | Green Buoy (meaning Starboard, or Right) |
246 | 0xF6 | 1111 0110 | Right Close / Green Buoy & Force Field |
248 | 0xF8 | 1111 1000 | Red Buoy (meaning Port, or Left) |
250 | 0xFA | 1111 1010 | Left Close / Red Buoy & Force Field |
252 | 0xFC | 1111 1100 | Middle / Red Buoy & Green Buoy |
254 | 0xFE | 1111 1110 | Middle Close / Red Buoy, Green Buoy & Force Field |
The IR codes from the Home Base make sense with a bit each for the
"Red Buoy" (Port, right LED beam),
"Green Buoy" (Starboard, left LED beam) and the
"Force Field" (unidirectional close range LED).
It would be my guess that the composite signals are not actually broadcast explicitly, but are the overlap of the output from the two to three separate LEDs which must therefore be time synchronised. Time to find out…
Recording Roomba 620 Home Base IR codes
I recently setup an
infrared receiver in my Raspberry Pi which can be used to record IR signals from remote controls. I was able to use the same procedure to record the signals from the each of the three separate LEDs of the Roomba Home Base by blocking the others with card and tape.
The IR codes are documented as emitted 940nm using a form of pulse-width modulation (PWM), modulated with a carrier frequency around 38KHz. Each code consists of a sequence of eight bits, encoded as:
- Bit 0 - 1ms on, 3 ms off
- Bit 1 - 3ms on, 1 ms off
I stated by watching just the "Force Field" LED, from the back (while Roomba was away in another room), it was clear that (with some variation in the long pauses), there was a simple repeating pattern. For example, where the numbers are in micro-seconds (1000 is 1ms):
$ mode2 -d /dev/lirc0 ... space 33098 pulse 2947 space 965 pulse 1016 space 2865 pulse 3086 space 826 pulse 1044 space 2869 pulse 1015 space 2894 pulse 1015 space 2868 pulse 1035 space 2873 pulse 2953 space 99558 pulse 2947 space 969 ... | (long pause) 1 . 0 . 1 . 0 . 0 . 0 . 0 . 1 (long pause) 1 . |
This repeating pattern was 1010 0001, or 161 (decimal), or 0xA1 in hex, which is
not is listed in the current iRobot documentation (see table above).
Decoding that by hand was tedious, so I wrote a little
Python script to decode the Roomba IR codes for me:
$ mode2 -d /dev/lirc0 | python decode_roomba_ir.py 10100001 - 161 - 0xA1 10100001 - 161 - 0xA1 10100001 - 161 - 0xA1 10100001 - 161 - 0xA1 ... |
Attempting to watch the "Force Field" IR LED only, from the back, gave a nice clean simple repeat. Using some tape to securely mask the two buoy LEDs I could get the same clean signal from the front of the dock:
With just the right LED and the top LED, there were apparently two codes:
- 10100001 - 161 - 0xA1
- 10101000 - 168 - 0xA8
Just the left LED and the top LED, again I saw two codes:
- 10100001 - 161 - 0xA1
- 10100100 - 164 - 0xA4
All three LEDs from front, in some locations it was hard to decode the 5 and 6th bits - but usually there was a blend of 0xA4 and 0xA8 giving 0xAC as a recognisable code:
- 10100001 - 161 - 0xA1
- 10101100 - 172 - 0xAC
It seems that with the 600 series Roomba have changed the Home Base IR codes (compared to the Roomba 400 series). While the left and right IR LEDs seem to be synchronised so that when you see both their individual signals 0xA1 and 0xA4 overlap to register as 0xAC, I wasn't able to get them to blend with the "Force Field" LED as well - maybe my sensor is at the wrong height?
Sent by | Dec | Hex | Binary | Meaning |
Roomba 500/600 Drive-on charger/Home Base | 161 | 0xA1 | 1010 0001 | Force Field |
164 | 0xA4 | 1010 1000 | Green Buoy (meaning Starboard, or Right) |
168 | 0xA8 | 1010 0100 | Red Buoy (meaning Port, or Left) |
172 | 0xAC | 1010 1100 | Middle / Red Buoy & Green Buoy |
Roomba 500 Virtual Wall | 162 | 0xA2 | 1010 0010 | Virtual Wall |
The first four bits match
João Figueiredo's Roomba Virtual Wall (1010 0010, or 162 decimal, 0xA2 in hex), which seems to hint at a new scheme. Curious.
Update - More official documentation
I've now found the
iRobot Roomba 500 Open Interface Specification online (
alternative link), which confirms these codes - and indicated I should be able to get a blend of the three IR LEDs.