Wednesday 23 October 2013

Roomba 620 infrared signals

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.

Roomba Docking Station, with three IR LEDs (and glare)
Roomba coming in to dock using infraredFrom Roomba iRobot Create Open Interface

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 byDec  HexBinaryMeaning
Remote Control1290x811000 0001Left
1300x821000 0010Forward
1310x831000 0011Right
1320x841000 0100Spot
1330x851000 0101Max / Dock
1340x861000 0110Small
1350x871000 0111Medium
1360x881000 1000Large / Clean
1370x891000 1001Pause
1380x8A1000 1010Power
1390x8B1000 1011Arc-forward-left
1400x8C1000 1100Arc-forward-right
1410x8D1000 1101Drive-stop
Scheduling Remote1420x8E1000 1110Download / Send All
1430x8F1000 1111Seek Dock
Roomba 400
Home Base
2400xF01111 0000Reserved
2420xF21111 0010Behind / Force Field
2440xF41111 0100Green Buoy (meaning Starboard, or Right)
2460xF61111 0110Right CloseGreen Buoy & Force Field
2480xF81111 1000Red Buoy (meaning Port, or Left)
2500xFA1111 1010Left CloseRed Buoy & Force Field
2520xFC1111 1100Middle / Red Buoy & Green Buoy
2540xFE1111 1110Middle CloseRed BuoyGreen 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 at 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 started 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)
(long pause)

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
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:
  • 10100001 - 161 - 0xA1
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 byDec  HexBinaryMeaning
Roomba 500/600
Drive-on charger/Home Base
1610xA11010 0001Force Field
1640xA41010 1000Green Buoy (meaning Starboard, or Right)
1680xA81010 0100Red Buoy (meaning Port, or Left)
1720xAC1010 1100Middle / Red Buoy & Green Buoy
Roomba 500 Virtual Wall1620xA21010 0010Virtual 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.

See also the next blog post, where I could control the Roomba with a Raspberry Pi and an IR LED.


  1. Hi,

    I've been able to make this work for a few commands (forward, left, right), but not Start or Clean on a Roomba 530. Do you know if the codes are different for that model?

  2. I'm on Roomba 620 and it seams to be 149 to Clean.

    If anyone has other tips, like for a virtual wall etc, please tell. They seam to differ from the guide above for some reason.

  3. Did anyone get success in ir commanding roomba 621 ? I use this arduino code ( but Roomba seems unwilling to start cleaning for any of the IR codes sent.

    I checked the following using oscilloscope :
    - Yes, LED is properly driven at 38 kHz (38.240)
    - Yes, 0 and 1 properly output as 1ms/3ms and 3ms/1ms ON/OFF
    - Yes, 136 code properly spells out as 10001000 from the LED
    - Yes, LEDs are functional (checked using webcam)
    - No, neither 850 or 940 nm LEDs were able to put the roomba to work

    Something might be wrong somewhere but I can’t seem to find out where. I could use some help if you have any idea.

  4. Roomba 616 - I had to use 3ms/1.1ms and repeat every code 15 times. And not every command send is properly recognized. I used code from and my IR shield

    I tried simple virtual wall and it works flawless.