Récemment, on a acheté un aspirateur automatique Roomba et, à peine déballé, on a commencé à regarder comment le hacker. Le Roomba possède un port série qui permet de contrôler le robot. Ce port série utilise une prise Mini-DIN et fonctionne avec les niveaux TTL (incompatible avec un port RS-232). Ça tombe bien, on vient d'annoncer le Yocto-Serial: une interface série qui peut travailler avec les niveaux TTL.
Hacker un Roomba pour lui faire faire tout sauf le ménage est un grand classique. Mais c'est un très bon exemple d'utilisation du Yocto-Serial (de plus c'est assez fun). Étant donné qu'un Roomba qui est relié à un câble USB n'est pas très utilisable, on va brancher le Yocto-Serial à un YoctoHub-Wireless-g. De cette manière, on va pouvoir télécommander notre Roomba depuis notre réseau local.
La connectique
Le port OI (pour Open Interface) utilise une prise Mini-DIN 7 pins. Cette prise permet de faire passer:
- la masse.
- l’alimentation 14V
- l'entrée série du Roomba (RXD) qui travaille de 0 à 5V
- la sortie série du Roomba (TXD) qui travaille de 0 à 5V
- un signal (BRC) qui est utilisé pour maintenir le Roomba éveillé et changer la vitesse de transmission
Le diagrame de la prise du Roomba
Pour le branchement du Yocto-Serial au Roomba, on utilise le mapping suivant:
- la masse du Roomba sur la masse du Yocto-Serial
- le signal RXD du Roomba sur le signal TD du Yocto-Serial
- le signal TXD du Roomba le signal RD du Yocto-Serial
- (optionnel) le signal BRC du Roomba sur le signal RTS du Yocto-Serial
Les trois premiers branchements suffisent à établir une communication entre le Yocto-Serial et le Roomba. Le signal BRC permet à la fois de commuter la vitesse du port série et aussi d'empêcher l'aspirateur de passer en veille. Nous avons câblé le signal BRC du Roomba au signal RTS du Yocto-Serial pour pouvoir modifier l’état du signal BRC. Mais en pratique, cela ne sert à rien car le Yocto-Serial peut communiquer à 115200 baud.
Le cablage complet de notre montage
Il faut encore brancher le Yocto-Serial au YoctoHub-Wireless-g et alimenter ce dernier. Il ne faut ABSOLUMENT PAS brancher directement la sortie 14 volt du Roomba sur le YoctoHub: Tous nos modules travaillent en 5 volt. Il est donc nécessaire de réduire le voltage à l'aide d'un régulateur. Nous avons utilisé un régulateur D24V5F5 de Pololu qui peut utiliser n'importe quel voltage entre 5 et 36 volts pour fournir au maximum 500 milliampères à 5 volts. Ce régulateur est très simple à brancher car il travaille en terre commune, il suffit de brancher le 14v sur VIN et le YoctoHub sur VOUT. Le signal SHDN est laissé flottant car il n'est pas utilisé dans notre cas.
Tester la communication
Pour que le Yocto-Serial puisse communiquer avec le Roomba, il faut configurer le Yocto-Serial pour qu'il travaille de 0 à 5 volts et à la bonne vitesse. En se connectant à l'interface web du YoctoHub-Wireless-g, on peut accéder au panneau de configuration du Yocto-Serial et modifier ses paramètres. Par défaut, le Roomba communique à 115200 bauds avec un stop bit et aucun bit de parité (attention certains sites parlent de 57600 bauds mais c'est pour les vieux modèles). Il est possible de configurer le Yocto-Serial en mode "Frame-based binary" avec un intervalle de temps de 15ms. Ce mode sépare automatiquement les trames binaires en fonction de leur direction et d'un intervalle de temps, ce n'est pas indispensable mais cela permet d'afficher correctement le trafic dans l'interface du Yocto-Serial.
Le Yocto-Serial doit fonctionner en 5V à 115200 baud avec un stop bit et aucun bit de parité
Le protocole de communication est expliqué dans le document "iRobot Create 2 Open Interface (OI)" qui est disponible sur le site de iRobot. Il s'agit d'un échange de trames de bytes. Une trame correspond soit à une commande que le Roomba doit exécuter, soit à la réponse du Roomba à la dernière commande envoyée. Les commandes ont toutes le même format:
- 1 byte qui contient le numéro de la commande à exécuter (ex: nettoyer, avancer, lire l’état de la batterie, etc ).
- 0 à 15 bytes de paramètre de la fonction (ex: la vitesse, le numéro de la led, etc..)
Il est très important d'envoyer le bon nombre de bytes pour chaque commande sinon le Roomba va se désynchroniser et toutes les commandes suivantes seront mal interprétées. De la même manière, il faut lire le bon nombre de bytes que la fonction retourne, sinon on risque de mélanger les valeurs retournées.
Note: Quand le Roomba est en veille, l'interface OI est désactivée et les commandes sont ignorées. Pour sortir du mode veille, il faut envoyer la commande Start (code=128) qui fait sortir le Roomba de veille. Il est donc important de toujours envoyer la commande Start au début de l'application. Attention, le Roomba passe automatiquement en veille au bout de 5 minutes d'inactivité. Dans ce cas, il faut à nouveau envoyer la commande Start
Le Yocto-Wireless-G et le Yocto-Serial branché au Roomba
Piloter le Roomba depuis PHP
Nous avons écrit une Classe PHP "Roomba" qui formate les commandes à envoyer et décode les bytes des réponses reçues. Cette classe implémente une méthode pour chaque commande qu'il est possible d'envoyer au Roomba (Clean, Drive, Dock, etc),et une méthode pour lire chaque capteur du Roomba (état de charge, bumpeur, etc).
Le constructeur de cette classe prend en paramètre l’adresse IP du YoctoHub. Il établit la connexion avec le YoctoHub grâce à la méthode YAPI::RegisterHub, et stocke un pointeur sur l'objet YSerialPort qui correspond à notre Yocto-Serial. Grâce à cet objet, il configure les paramètres du Yocto-Serial (vitesse de communication, nombre de bit de parité, etc).
{
private $serial_port;
function __construct($addresse)
{
// Uses explicit error handling rather than exceptions
YAPI::DisableExceptions();
// Sets up the API to use the VirtualHub on local machine,
if(YAPI::RegisterHub($addresse, $errmsg) != YAPI_SUCCESS) {
die("Cannot contact $addresse");
}
/** @var YSerialPort $serialPort */
$this->serial_port = YSerialPort::FirstSerialPort();
if($this->serial_port == null)
die("No module found on $addresse (check USB cable)");
// sets up the serial parameter with the Roomba
// serie 600 and following communicate at 115200 bauds
$this->serial_port->set_serialMode("115200,8N1");
// lets the serial port wait 20ms between each writes
$this->serial_port->set_protocol("Frame:20ms");
// clears all buffers of the serial port
$this->serial_port->reset();
...
}
Toutes les méthodes de cet objet encodent les différents paramètres de la méthode en une trame à transmettre au Roomba. Ce tableau de bytes est transmit au Roomba à l'aide de la méthode writeArray de l'objet YSerialPort. Les méthodes qui attendent une réponse du Roomba attendent 50 millisecondes pour laisser au Roomba le temps de traiter la commande et lisent le nombre de bytes prévu.
{
$this->serial_port->writeArray($cmd);
if ($nbytes > 0) {
YAPI::Sleep(50);
return $this->serial_port->readArray($nbytes);
} else {
return array();
}
}
public function Motors($main_brush, $vacum, $side_brush)
{
$flags = 0;
if ($main_brush)
$flags |= 4;
if ($vacum)
$flags |= 2;
if ($side_brush)
$flags |= 1;
$this->sendCmd(array(138, $flags));
}
public function getVoltage()
{
$ret_bytes = $this->sendCmd(array(142,22), 2);
return $ret_bytes[0] * 256 + $ret_bytes[1];
}
Voici un exemple d'utilisation de la classe Roomba:
$roomba = new Roomba('192.168.1.88');
$roomba->Start();
...
$roomba->Clean();
...
$charge = $roomba->getBatteryCharge();
$capacity = $roomba->getBatteryCapacity();
print("Battery:" . ($charge*100 / $capacity ). "% \n");
...
$roomba->Dock()
...
$roomba->StopOI();
Lors de l'instanciation de l'objet $roomba, la communication HTTP avec le YoctoHub est établie et le Yocto-Serial est configuré, mais aucune commande n'est encore envoyée au Roomba. La première commande doit être Start pour sortir le Roomba du mode veille et activer l’interpréteur de commande OI. Ensuite, on peut envoyer n'importe quelle commande qui sera exécutée par le Roomba. Pour finir, on peut mettre en veille le Roomba immédiatement à l'aide de la commande Stop.
Une petite démo pour finir...
On a réalisé une petite application web en PHP qui permet de contrôler le Roomba. Cette application web utilise la classe Roomba décrite plus haut et un autre script PHP qui s'occupe de l'interface. L'utilisateur se connecte donc sur le serveur local avec un browser web, et c'est le serveur web qui transmet les ordres au Roomba en fonction des requêtes HTTP qu'il reçoit.
C'est le script PHP qui communique avec le Roomba
La page principale affiche l’état du Roomba et permet d'envoyer les commandes les plus basiques (nettoyer, retourner à la station, etc). Il est aussi possible d'envoyer des commandes un peu plus amusante (comme jouer de la musique, ou afficher un message avec les LEDs). Le code source de cette démo est disponible sur GitHub
Cette application est très sommaire mais le but de cette article était surtout d'illustrer l'utilisation du Yocto-Serial. Au final, ce qui prend le plus de temps, c'est de lire les specs du Roomba et d'écrire le code PHP correspondant. La partie communication entre le Roomba et le Yocto-Serial était la partie la plus facile.