Roomba Hack
Intro
At one point, I modified a roomba 560 to take commands via a Bluetooth controller so I could drive it around. I haven’t had it setup in years but some people still email me asking questions, so here’s the parts list and copy of the Python 2 code.
Parts List
- Raspberry Pi 3
- Moga Pro controller or Wii controller
- I originally used this cable but they made USB to Mini-DIN cables now if you don’t want to try to get power from the Roomba
Code
#Button Mappings
#
#00 : Select = Reset
#03 : Start = Failsafe
#12 : Triangle = Vaccum on/off
#13 : Circle = Spot Clean
import serial
import time
import pygame
import struct
import sys
MAX_TURN_RADIUS = 1000
controlRoomba = True
spotCleanActive = False
vacuumActive = False
#Open serial connection, 115200 is default Roomba BAUD rate
global ser
ser = serial.Serial('/dev/ttyUSB0', 115200)
def start():
# Start SCI - puts into safe mode
ser.write(bytes(chr(128), 'UTF-8'))
# Enable the safe mode
ser.write(bytes(chr(131), 'UTF-8'))
# this is required or the command may fail
#time.sleep(1)
def fix(num):
# format the number correctly in hex
num = struct.unpack('>BB', struct.pack('>h', num))
#print num
return num[0], num[1]
def move(vel, rad):
# velocity
vbit1, vbit2 = fix(vel)
#radius
rbit1, rbit2 = fix(rad)
# send to roomba
# Init move command
ser.write(bytes(chr(137), 'UTF-8'))
# you need this
ser.write(bytes(chr(vbit1), 'UTF-8'))
ser.write(bytes(chr(vbit2), 'UTF-8'))
ser.write(bytes(chr(rbit1), 'UTF-8'))
ser.write(bytes(chr(rbit2), 'UTF-8'))
def reset():
print ("Resetting Roomba...")
start()
move(0, 0)
ser.write(bytes(chr(139), 'UTF-8'))
ser.write(bytes(chr(63), 'UTF-8'))
ser.write(bytes(chr(32), 'UTF-8'))
ser.write(bytes(chr(255), 'UTF-8'))
time.sleep(1.5)
control()
def failsafe():
global vacuumActive
print ("Failsafe called")
ser.write(bytes(chr(131), 'UTF-8')) #Safe mode
move(0, 0) #Stop Moving
if (vacuumActive):
vacuum() # Disable vacuum
#Blink red light 3 times
ser.write(bytes(chr(139), 'UTF-8'))
ser.write(bytes(chr(0), 'UTF-8'))
ser.write(bytes(chr(255), 'UTF-8'))
ser.write(bytes(chr(255), 'UTF-8'))
time.sleep(0.7)
ser.write(bytes(chr(139), 'UTF-8'))
ser.write(bytes(chr(0), 'UTF-8'))
ser.write(bytes(chr(255), 'UTF-8'))
ser.write(bytes(chr(0), 'UTF-8'))
time.sleep(0.7)
ser.write(bytes(chr(139), 'UTF-8'))
ser.write(bytes(chr(0), 'UTF-8'))
ser.write(bytes(chr(255), 'UTF-8'))
ser.write(bytes(chr(255), 'UTF-8'))
time.sleep(0.7)
ser.write(bytes(chr(139), 'UTF-8'))
ser.write(bytes(chr(0), 'UTF-8'))
ser.write(bytes(chr(255), 'UTF-8'))
ser.write(bytes(chr(0), 'UTF-8'))
time.sleep(0.7)
ser.write(bytes(chr(139), 'UTF-8'))
ser.write(bytes(chr(0), 'UTF-8'))
ser.write(bytes(chr(255), 'UTF-8'))
ser.write(bytes(chr(255), 'UTF-8'))
time.sleep(0.7)
#Turn Roomba off
ser.write(bytes(chr(133), 'UTF-8'))
print ("Roomba now in failsafe mode")
def spotClean():
global spotCleanActive
if spotCleanActive == True:
#Stop spot clean
print ("Stopping spot clean.")
ser.write(bytes(chr(134), 'UTF-8'))
spotCleanActive = False
reset()
else:
#Start spot clean
print ("Starting spot clean.")
ser.write(bytes(chr(134), 'UTF-8'))
spotCleanActive = True
time.sleep(.25)
def vacuum():
global vacuumActive
if vacuumActive == True:
#Stop vacuuming
print ("Stopping vacuum.")
ser.write(bytes(chr(138), 'UTF-8'))
ser.write(bytes(chr(0), 'UTF-8'))
vacuumActive = False
time.sleep(1)
else:
#Start vacuuming
print ("Starting vacuum.")
ser.write(bytes(chr(138), 'UTF-8'))
ser.write(bytes(chr(1), 'UTF-8'))
ser.write(bytes(chr(138), 'UTF-8'))
ser.write(bytes(chr(2), 'UTF-8'))
ser.write(bytes(chr(138), 'UTF-8'))
ser.write(bytes(chr(3), 'UTF-8'))
vacuumActive = True
time.sleep(1)
def control():
global MAX_TURN_RADIUS
#turn light to green
ser.write(bytes(chr(139), 'UTF-8'))
ser.write(bytes(chr(0), 'UTF-8'))
ser.write(bytes(chr(0), 'UTF-8')) #Green
ser.write(bytes(chr(255), 'UTF-8'))
pygame.init()
pygame.joystick.init()
clock = pygame.time.Clock()
joystick = pygame.joystick.Joystick(0)
joystick.init()
#print joystick.get_name()
#print joystick.get_numaxes()
print ("Reset complete.")
while controlRoomba == True:
for event in pygame.event.get():
if event.type == pygame.JOYBUTTONUP:
print ('Button')
if joystick.get_button(0) == 1:
reset()
elif joystick.get_button(3) == 1:
failsafe()
elif joystick.get_button(12) == 1:
vacuum()
elif joystick.get_button(13) == 1:
spotClean()
else:
speed = -1*int(500*joystick.get_axis(1))
jsa = joystick.get_axis(2)
if (jsa > 0):
# Right, +1 as Max, Negative output
radius = -1*((MAX_TURN_RADIUS+1)-int(MAX_TURN_RADIUS*jsa))
elif (jsa == 0):
radius = 0
else:
# Left, -1 as Max, Positive output
radius = 1*((MAX_TURN_RADIUS+1)+int(MAX_TURN_RADIUS*jsa))
move(speed, radius)
clock.tick(20)
# do stuff
print ("Starting...")
#turn light to green
ser.write(bytes(chr(139), 'UTF-8'))
ser.write(bytes(chr(0), 'UTF-8'))
ser.write(bytes(chr(16), 'UTF-8'))
ser.write(bytes(chr(255), 'UTF-8'))
reset()
control()
print ('Exiting...')
pygame.quit()