Para quien no lo conozca, Roomba es un modelo de las aspiradoras inteligentes de
iRobot. Este tipo de dispositivos pretenden, a un coste bastante elevado, todo hay que decirlo, hacer la vida más cómoda al propietario, librándole de pasar la aspiradora manualmente.
No sé realmente si la razón de que estuviera detrás de una Roomba, era el mantener la casa limpia o el poder "meterle mano a la chacha" (en el buen sentido de la palabra, al ser un robot).
Así pues, y tras leer el libro "
Hacking Roomba" (muchas gracias por el ejemplar a
Raúl) me dije que esto, simplemente había que probarlo y si no, a las malas, tendría la casa más limpia.
Así pues encargué el
modelo 555, que permite programación manual utilizando una botonera en el propio aparato. Lo primero que pensé: "Esto lo programaré en remoto, sin agacharme!"
El objetivo principal era poder decirle a la Roomba: "
Ponte a aspirar AHORA" o "
Vete a tu base de carga YA!", desde el servidor de casa, controlando vía cron o de forma manual esas operaciones a voluntad.
Así pues, para hacer frente al problema se me pasaron por la cabeza
varias opciones. Existe un
mando a distancia por Radiofrecuencia que permite ejecutar las mismas operaciones desde cualquier parte de la casa, en la que tengas el mando. Sin embargo, no es compatible más que con el modelo superior: el 581. La siguiente alternativa era utilizar un
mando a distancia compatible con todas las roombas. En este caso, funciona mediante
Infrarrojos. por lo que podría hacer un cable al puerto serie con un diodo IR y mediante
LIRC, grabar la ejecución de cada operación y reproducirla después. Sin embargo, para poder controlar la roomba en toda su inmensidad, la opción más interesante, potente y versátil era utilizar un
interfaz bluetooth.
Para los que como yo, no seais muy manitas con el soldador y los cables, en
Sparkfun, venden interfaces bluetooth ya hechos, llamados
Rootooth que son "más o menos" plug & play….
Para meterle mano a la Roomba via Bluetooth, esto es lo que debéis hacer:
- Enchufar el dispositivo bluetooth a la Roomba. Consejo: sujetad con cinta aislante el cable y el conector, porque dado el movimiento de la roomba, puede sufrir daños. Al principio lo tenía como la foto que se puede ver en el avatar del post.
- En mi caso he utilizado Linux con un adaptador Bluetooth para poder conectarnos al Rootooth. Mediante hcitool buscamos el nuevo dispositivo Bluetooth y nos apuntamos la MAC.
[root@Carmen ~]# hcitool scan
Scanning ...
00:06:66:ZZ:XX:YY FireFly-XXYY
3.-) Probamos a
establecer una conexión mediante "rfcomm" que, una vez hecha la conexión, nos dejará un puerto en /dev/rfcommN al cuál podremos hablar como si de un puerto serie se tratara.
[root@Carmen ~]# rfcomm connect 2 00:06:66:ZZ:XX:YY
Connected /dev/rfcomm2 to 00:06:66:ZZ:XX:YY on channel 1
Press CTRL-C for hangup
4.-) Lo siguiente es
comprobar que el modem que incluye
Rootooth funciona correctamente a 115200 bps, para no tener errores en la comunicación. Para ello accedemos mediante "
minicom" y comprobamos que todo está correcto:
Welcome to minicom 2.00.0
OPCIONES: History Buffer, F-key Macros, Search History Buffer, I18n
Compilado en Feb 21 2005, 19:32:30.
Presione CTRL-A Z para obtener ayuda sobre teclas especiales
CMD
?
***Settings***
BTA=000666ZZXXYY
BTName=FireFly-XXYY
Baudrt=115K
Parity=None
Mode =Slav
Authen=0
Encryp=0
PinCod=1234
Bonded=0
Rem=NONE SET
END
Una vez que conecta, enviamos los caracteres "$$$"(3 símbolos del dólar, sin las comillas) para entrar en modo Comando al modem Bluetooth. Nos contestará con CMD si todo es correcto. Pulsando D y Enter, nos dará la info que se puede ver más arriba. Importante que esté a 115K, y Parity None. Si algo no está como debe, con la tecla H se accede a la ayuda y se configura para que quede así.
Una vez todo está correcto, pulsamos "---" (tres guiones seguidos, sin comillas) y devolverá END… Ya estamos fuera del modo command.
5.-) Después de
probar diversos programas (
RoombaCom,
Roomba-tilt.pl,
Roomba Status) rebuscando en Internet, que prometían controlar la Roomba en remoto, y ver que estaban todos obsoletos, decidí buscar documentación actualizada de la API de la Roomba para poder hablarle.
El
documento actualizado para las especificaciones Open Interface de la serie 500 se puede descargar de
aquí.
6.-) Manos a la obra… Bajo estas líneas pongo un script (por supuesto en Perl) que recibe como parámetro "clean" o "dock" y hacen que la roomba se ponga a limpiar o se ponga en modo Dock (o, ir a su base de carga)
Incluyo además el código necesario para que cada vez que lo ejecutemos, cree una conexión nueva contra Rootooth, no teniendo que mantener el rfcomm abierto todo el tiempo.
[root@Carmen tmp]# more /usr/local/bin/roomba.pl
#!/usr/bin/perl
use IPC::Open2;
$port="/dev/rfcomm2"; #el puerto serie a crear. Importante que no esté siendo usado ya
my $param=lc ($ARGV[0]); #capturo parámetro introducido y lo paso a minúsculas
my $rfcomm="rfcomm connect 2 00:06:66:ZZ:XX:YY"; #comando rfcomm para crear puerto
my $value;
if ($param eq "clean")
{#Si la orden es limpiar
$value=135;
}
elsif ($param eq "dock")
{#Si la orden es ir a base
$value=143;
}
else
{#El resto no está aceptado
die "$0 [CLEAN|DOCK]\n";
}
my $pid=open2 (\*READ,\*WRITE,$rfcomm); #lanzamos por un lado la conexión
sleep (10); #Le damos 10 segundos para que se establezca
system("stty -F $port 115200 raw -parenb -parodd cs8 -hupcl -cstopb clocal"); #Parámetros necesarios para configuración del puerto
my $roomba;
open $roomba, "+>$port" or die "couldn't open port: $!"; #Abrimos conexión al puerto
select $roomba; $| =1; #Eliminamos lo que hubiera en el buffer en la lectura
printf $roomba "%c",128; sleep 0.3; # START Necesario cada vez que le demos una orden a Roomba
printf $roomba "%c",132; sleep 1; # FULL Tomamos control completo sobre ella
printf $roomba "%c",$value; sleep 1; # CLEAN OR DOCK Ejecutamos lo ordenado
kill 9,$pid; #Matamos el proceso de rfcomm
exit (0); #bye bye
Pero claro, la idea (al menos la mía) es hacer un programa que dependiendo de un montón de factores como qué
horario es
aceptable para pasar la aspiradora,
control de presencia en casa (si estoy en casa, no la pases,… no sabéis el ruido que mete!), etc, etc,… puede ser interesante
obtener información sobre los sensores de la misma. En mi caso, me interesa saber: La
capacidad máxima de la
batería; el modo de carga (esperando, cargando, etc,..), la
carga actual de la batería, la
temperatura de la batería, y si está
conectada al cargador correctamente o no (si está en su base de carga o está dando vueltas por ahí). Para ello, el código se puede ver bajo estas líneas.
Importante: en este caso contamos con una conexión rfcomm ya hecha en otro terminal!
[root@Carmen tmp]# more roomba_sensors.pl
#!/usr/bin/perl
$port="/dev/rfcomm2"; #el puerto serie a crear. Importante que no esté siendo usado ya
system("stty -F $port 115200 raw -parenb -parodd cs8 -hupcl -cstopb clocal"); #Parámetros necesarios para configuración del puerto
my $roomba;
open $roomba, "+>$port" or die "couldn't open port: $!";
select $roomba; $| =1; #Eliminamos lo que hubiera en el buffer en la lectura
printf $roomba "%c",128; sleep 1; # START Necesario cada vez que le demos una orden a Roomba
printf $roomba "%c%c%c%c%c%c%c",149,5,21,25,26,34,24; sleep 1; # Roomba requiere el envío del opcode 149 + el número de sensorIDs a solicitar + cada sensorID
#Sin embargo, devuelve byte a byte. Con esto perdí muuuucho tiempo porque no lo ví documentado en ningún sitio!!!
for ($i=0; $i<7; $i++)
{
$k=getc($roomba);
$ok=ord ($k);
print STDOUT "$i $ok\n";
}
Al ejecutarlo vemos algo como:
----------
0 2
1 1
2 108
3 10
4 136
5 2
6 40
------
La primera columna es un contador, sin más y la segunda, el valor del byte devuelto por la Roomba.
Byte Explicación
0 Estado de carga: 4 significa que está en Waiting (aunque la pongamos en su base, no cargará)
y 2 es Full charge (que lo podemos poner a cargar)
1 Byte más significativo de carga actual de batería
2 Byte menos significativo de carga actual de batería
3 Byte más significativo de capacidad total de batería
4 Byte menos significativo de capacidad total de batería
5 Presencia de cargador (Fundamentalmente, si está la roomba en su base o no) Si el valor es 0 es
que no (está por ahí limpiando) y 2 es que está en la base
6 Temperatura en grados celsius de la batería (Interesante por si queremos monitorizarlo)
Los bytes 1 y 2, así como el 3 y 4 indican la carga actual y la capacidad máxima de carga de la batería. El byte más significativo, en mi caso va de 0 a 10 y el menos significativo va de 0 a 255 (lógicamente es lo que cabe en un byte). Cuando se está descargando la batería, los bytes 1 y 2 van disminuyendo y al cargarse aumentando, hasta llegar a 10/136 que es la carga máxima de la batería.
Conclusiones
Roomba no sé si me hará la vida más fácil o no, pero me lo he pasado bomba sacándole las tripas e
intentandole hablar y que me conteste. No he encontrado foros en España (o al menos en español) en los que se haga hacking de este tipo a Roomba. Lo más aproximado ha sido en los
foros.zackyfiles.com en los que fundamentalmente, se hace
hacking físico a los equipos para que aspiren mejor, y hacerles cierto tunning. Los que quieran ir más allá, pueden contar con
este foro en inglés en el que hay gente con estas mismas inquietudes y en el que
abrí un hilo pidiendo ayuda en mis problemas de comunicación con mi Roomba.
Para aquellos que tengáis un cacharro de estos y queráis meterle mano, os animo desde aquí a ello. Si os ponéis y se os atasca la situación, contad conmigo para ayudaros en todo lo que sea posible!
Por cierto, que después de tanta confianza que tengo con la Roomba, le he preguntado cuál es su blog de seguridad y hacking favorito y... bueno en la foto siguiente podéis ver cuál fue su respuesta :D