Club robotique de Sophia-Antipolis

Accueil > POBOTpedia > Capteurs > Capteurs de position > iRobot Roomba : capteur infra-rouge

iRobot Roomba : capteur infra-rouge

comment décoder le signal du robot Roomba avec une Arduino

mercredi 16 mars 2011, par Frédéric Bernat

J’utilise des robots aspirateurs Roomba de la société iRobot depuis plusieurs années. A force de me rendre l’inestimable service de ne pas avoir à passer l’aspirateur (et donc de ne plus me faire engueuler quand j’avais le malheur d’oublier…) il a fallu procéder à quelques réparations. Dernière réparation en date, le changement du pare-choc. Il était tellement rayé que les capteurs infra-rouge de proximité ne voyaient plus les obstacles…

Refusant de jeter quoi que ce soit sans en avoir retiré tout ce qui pourrait m’être utile dans un avenir proche (hum ! c’est souvent lointain, très lointain), j’ai donc récupéré sur le pare-choc que je venais de changer pour cause de vieillissement prématuré, la petite tourelle du capteur infra-rouge.

L’idée m’est venue d’essayer de fabriquer un petit robot qui utiliserait cette petite tourelle pour venir se recharger automatiquement sur le chargeur du Roomba. La tourelle contient un capteur infra-rouge à démodulateur de 38KHz, son signal passant à 0 quand elle détecte un signal de cette fréquence.

Il en existe beaucoup dans le commerce, à commencer par le TSOP1838 de chez VISHAY ou celui de RadioShack (que j’ai testé avec une égale réussite).

Le codage

Première chose à faire trouver le codage du signal infra rouge. Est-ce du Sony, RC5, RC6, … ? Rien de tout cela malheureusement, ou plutôt heureusement puisque finalement c’est beaucoup plus facile à traiter.

Pour voir à quoi ressemble le signal infra-rouge j’ai utilisé le petit oscilloscope DSO Nano 2 de chez Seeeduino. Très pratique et surtout très facile d’utilisation pour quelqu’un qui a utilisé un oscilloscope pour la dernière fois en 1er année de fac (ah ouais, quand même…).

Après quelques recherches sur internet je suis tombé sur un petit article décrivant les codes des trames. Les codes sont justes pour la télécommande mais faux pour le dock de rechargement.

Remote control

Power : 10001010
Spot : 10000100
Clean : 10001000
Max : 10000101
Left : 10000001
Forward/Left : 10001011
Forward : 10000010
Forward/Right : 10001100
Right : 10000001
Pause : 10001001

Docking station - FAUX !

Behind : 11110010
Left : 11111010
Slightly left : 11111011
Middle : 11111110
Slightly right : 11110111
Right : 11110110

Pourquoi sont-ils faux ? Parce que le dock du Roomba n’a que 3 leds d’émission infra-rouge : une dans la tourelle et deux dans la petite fenêtre en dessous, donnant les signaux gauche et droite (séparés par une cloison), avec une petite astuce, un troisième signal est émis, par l’addition des signaux gauche et droite, qui sont émis simultanément, ce signal n’est visible uniquement si on est dans l’axe du dock(c-a-d dans le champ de visibilité des deux leds).

Cela donne plutôt le schéma ci-dessous :

Grâce au DSO Nano j’ai pu retrouver les codes qui m’intéressent :

Docking station - VRAI !

Dock Droit 10100100 -> 164
Dock Gauche 10101000 -> 168
Dock Milieu 10101100 -> 172
Dock Tourelle 10100001 -> 161

(Dock Droit | 10100100 ->164) OU (Dock Gauche | 10101000 ->168) = (Dock Milieu | 10101100 ->172 )

Ou plus visuellement :

Comment décoder le signal ?

Comme me l’a montré l’oscilloscope la durée totale de la trame dure 32 millisecondes ce qui donne 4 millisecondes par bit, puisqu’il s’agit d’un codage sur 8 bit.

La première milliseconde est toujours basse, puis les deux suivantes sont basses ou hautes et la dernière milliseconde est haute. Donc 3 millisecondes basses donne 1 et une milliseconde basse donne 0. (connaissant le code du bouton de la télécommande associé à la trame du signal).

Bien, maintenant que je connais la forme du signal et le codage de chaque trame, il ne me reste plus qu’à pondre le petit programme qui va bien. (pondre est le terme exact vu le temps que j’ai passé en salle de travail…)

Le petit programme qui va bien

La première idée qui m’est venue était d’utiliser la fonction PulseIn dans une interruption (fonction attachInterrupt(getIrKey(),LOW) - interruption sur passage niveau bas du signal).

Très pratique, cette fonction renvoie le nombre de microsecondes d’un signal bas ou haut.

Malheureusement, après plusieurs heures d’acharnement, je devais me rendre compte qu’à cause du time-out de 1ms du timer de l’interruption, il n’était pas possible d’utiliser cette fonction puisque 1 bit peut faire jusqu’à 3 millisecondes.

Je décide alors de calculer le temps entre un passage du niveau bas au niveau haut, donc une interruption déclenchée par un changement de niveau logique, un digitalRead pour voir quel est l’état du capteur, et la fonction micros pour connaitre le nombre de micro-secondes écoulées depuis le début du programme.

Il est vrai que la fonction digitalRead est une fonction qui est lente et pour cette raison il y a un risque de ne pas pouvoir lire les bits au bon moment. Avec une trame de 32ms et avec un bit 0 à 1 ms ça marche très bien. Pour un temps plus court le mieux est d’aller lire directement l’état du capteur sur le registre équivalent à la patte utilisée (PIND par exemple).

Voici le petit programme pour Arduino qui va vous permettre de capturer le code envoyé par la télécommande ou par le dock :


#define IR_PIN 2

unsigned long code[8] ;
unsigned long val ;
unsigned int ir_value=0 ;
int i ;

void setup()
pinMode(IR_PIN, INPUT) ;
Serial.begin(115200) ;
Serial.println("Ready...") ;
ir_value=0x00 ;
attachInterrupt(0,getIrKey,CHANGE) ;
i=0 ;

void getIrKey()
unsigned int j ;
if(i<8)
if( !digitalRead(IR_PIN)) // If the signal is HIGH
val=micros() ; //If pin2 LOW then store the time elapse since the program started
else
j=micros()-val ; //Else compute the length of Low signal
if((j>3200)||(j<900))
i=0 ; //if the length is not in the range of 1 or 3ms then reset
else
code[i++]=j>1700 ; //record the bit


void loop()

if(i==8)
i=0 ;
translate() ;

void translate()

ir_value = 0 ;
for(int j=0 ;j<8 ;j++)
if (code[7-j]) ir_value |= (1 << j) ; //compute the IR key value
code[7-j]=0 ;

switch (ir_value)
case 0b10000100:Serial.println("\rSpot") ;
break ;
case 0b10001000:Serial.println("\rClean") ;
break ;
case 0b10000101:Serial.println("\rMax") ;
break ;
case 0b10000001:Serial.println("\rLeftc") ;
break ;
case 0b10000010:Serial.println("\rForward") ;
break ;
case 0b10000011:Serial.println("\rRightc") ;
break ;
case 0b10100001:Serial.println("\rDock Behind") ;
break ;
case 0b10101000:Serial.println("\rDock Left") ;
break ;
case 0b10100100:Serial.println("\rDock Right") ;
break ;
case 0b10101100:Serial.println("\rDock Middle") ;
break ;
default:Serial.println( ir_value) ;


Voilà, on câble tout ça sur une Arduino MEGA 2560 (du travail de pro…) :

Reste plus qu’à compiler, charger, exécuter, croiser les doigts…

Et voilà le résultat obtenu :

Prochaine étape : l’algorithme permettant d’effectuer l’accostage du dock pour le rechargement du robot. A suivre...

Vos commentaires

  • Le 27 septembre 2016 à 21:23, par Ben En réponse à : iRobot Roomba : capteur infra-rouge

    Bonjour
    est ce que ces codes sont compatibles avec un roomba 770 ?
    merci

    • Le 16 octobre 2016 à 15:55, par Eric P. En réponse à : iRobot Roomba : capteur infra-rouge

      Il y a des chances, car les différents produits sont construits sur la même base. Ce sont les options qui les différencient. Mais nous n’avons jamais expérimenté sur ce modèle-là.

    Répondre à ce message

  • Le 29 janvier 2016 à 08:44, par Chris En réponse à : iRobot Roomba : capteur infra-rouge

    Salut j’aurais besoin de ton aide toi qqui a réussi a faire sa est ce que tu sais comment je pourrais faire, pour récupérer l’état de la batterie, sur une arduino, je suis élève de terminal et c’est pour mon projet merci d’avances de votre aide

    • Le 31 mars 2016 à 11:33, par Eric P. En réponse à : iRobot Roomba : capteur infra-rouge

      Bonjour,
      Ca s’appelle une entrée analogique (ADC). Si on y connecte une tension il y a tout ce qu’il faut dans la bibliothèque Arduino pour lire la valeur correspondante (chercher du côté de analogRead par exemple...). La lecture de la documentation Arduino et la consultation des exemples fournis avec l’environnement de programmation donnaient directement la réponse à ta question. As-tu pris le temps de les lire ?
      ATTENTION : le signal envoyé sur l’entrée ADC ne doit pas dépasser 5V. Il faut utiliser un pont diviseur le cas écéhant pour réduire la tension qu’on veut observer (Google est ton ami pour savoir ce qui est un pont diviseur, mais je pense que ce sont des choses qui sont déjà connues en Terminale).

    Répondre à ce message

  • Le 5 mars 2014 à 12:31, par Polidori En réponse à : iRobot Roomba : capteur infra-rouge

    Bonjour,

    Compte tenu de vos compétences (vu l’article) et les miennes (zéro dans ce domaine), je me prmets de vous exposer ma situation : je possède un aspirateur Irobot roomba 630 et voudrais pouvoir le commander avec mon ancien palm zire 72. Différents essai evec omniremote pro restent infructueux Auriez-vous une solution ?

    Merci

    FP

    • Le 7 mars 2014 à 11:12, par Frédéric Bernat En réponse à : iRobot Roomba : capteur infra-rouge

      Bonjour,
      Le codage et la fréquence du signal infra rouge ne sont pas compatible avec celles des télécommandes utilisées pour la hifi vidéo. Omniremote ne connait que les formats commerciaux standard.
      Cela ne peut donc pas fonctionner.

    • Le 7 mars 2014 à 11:14, par Frédéric Bernat En réponse à : iRobot Roomba : capteur infra-rouge

      La seule solution que je vois, c’est de construire une interface infrarouge spécifique et le programme qui va bien pour votre téléphone.

    Répondre à ce message

Un message, un commentaire ?

modération a priori

Attention, votre message n’apparaîtra qu’après avoir été relu et approuvé.

Qui êtes-vous ?

Pour afficher votre trombine avec votre message, enregistrez-la d’abord sur gravatar.com (gratuit et indolore) et n’oubliez pas d’indiquer votre adresse e-mail ici.

Ajoutez votre commentaire ici

Ce champ accepte les raccourcis SPIP {{gras}} {italique} -*liste [texte->url] <quote> <code> et le code HTML <q> <del> <ins>. Pour créer des paragraphes, laissez simplement des lignes vides.