Robots suiveurs 3 - Tableau de Bord
Sommaire
Description du simulateur
Le logiciel Webots est un simulateur robotique 3D OpenSource fonctionnant sous Windows, Mac OS et Linux.
Ce logiciel est très facile à prendre en main car il suffit de l'installer, de le lancer et de jouer avec les exemples livrés avec le logiciel.
Il existe aussi un tutoriel très facile d'accès, très documenté permettant de comprendre la logique du logiciel et d'être rapidement en capacité de créer sa propre simulation.
Ce qui en fait aussi un logiciel très facile d'accès est la possibilité de l'utiliser avec plusieurs langages de programmation grâce à des API complètes.
En effet, les robots peuvent être contrôlés via du C, C++, Python, Java et MATLAB. On peut aussi utiliser ROS.
Les tests sont aussi très agréables à réaliser puisqu'on peut interagir avec le robot et son environnement pendant le test.
Création d'un espace de test 3D
Le logiciel propose à l'utilisateur de créer un espace de test 3D en ajoutant toutes sortes d'éléments.
Ces éléments peuvent être des formes élémentaires : alors le travail fait par l'utilisateur se rapprochera d'un travail de CAO.
Ces éléments peuvent aussi être des objets existant dans la base fournie : du mobilier, des plantes, des fruits, des extincteurs, etc.
Pour tous ces éléments, on peut configurer de nombreuses propriétés : leur masse, leur densité, les frottements auxquels ils sont soumis, leur taille, etc.
De même, pour les robots, il est possible d'en créer un à partir de rien mais beaucoup sont proposés dans la base de robots : du petit robot éducatif Thymio au robot humanoïde Atlas de Boston Dynamics.
Et c'est la même chose pour les actionneurs et les capteurs : une base est fournie et décrite sur le site !
Utilisation d'un controller
Chaque robot peut être associé à un programme appelé controller dont le rôle est de définir le comportement du robot.
Ces controllers peuvent être écrits dans tous les langages supportés par Webots : C, C++, Python, Java, MATLAB. Dans les tutoriels, tous sont présentés mais nous avons choisi de travailler en C++ car tous les membres de l'équipe connaissaient ce langage. Notre objectif n'était pas d'apprendre un nouveau langage de programmation, et le C++ est tout de même très utilisé dans ce domaine.
Au lancement de la simulation, le logiciel lancera un processus par controller utilisé sur chaque robot. On ne peut associer qu'un controller par robot (c'est l’exécutable qui est utilisé) mais on peut utiliser le même controller pour plusieurs robots : dans ce cas, des processus distincts seront créés pour chaque robot.
Interface Graphique
L'interface graphique se découpe en plusieurs parties que l'on peut afficher dans différentes fenêtres.
La fenêtre 3D permet d'afficher et de dérouler la simulation dans l'espace 3D créé plus tôt. Dans cette fenêtre, même pendant une simulation, on peut encore déplacer des objets, les faire tourner, les faire interagir pour tester le comportement de notre robot simulé.
Le "Scene Tree" représente le monde 3D créé. Il comporte des blocs correspondant aux différents éléments créés ou importés tels que les objets ou les robots. En cliquant sur les flèches, il est possible de dérouler les propriétés accessibles sur un composant.
La console, affichée par défaut en bas de l'écran permet de lire des informations de débug ou les résultats de compilation.
On peut aussi retrouver un éditeur de texte permettant de compiler le code écrit afin de le tester dans la simulation.
Pour plus de détails sur les menus et l'interface graphique
Déplacements contrôlés au clavier
Introduction
L'objectif de cette partie est d’implémenter la possibilité de contrôler un robot avec les touches classiques zqsd afin de permettre la réalisation de tests. Pour ce faire, on faut créer un nouveau contrôleur : Wizards -> New Robot Controller. Notre contrôleur sera nommé Clavier_Control et codé en C++. Une fenêtre éditor s'ouvre alors. Pour gérer le contrôle des moteurs. Nous sommes partis de la base donnée en tutoriel à cette adresse.
Cette base donne les fondations pour pouvoir contrôler en vitesse les moteurs. C'est exactement ce dont nous avons besoin, puisque notre robot doit accélérer lorsqu'on le lui impose.
Code
Le code suivant est commenté pour les parties liées au clavier. Le tutoriel concernant la gestion des moteurs sera explicité sur cette page
L'idée générale derrière ce code est d'affecter aux moteurs une vitesse selon la touche enfoncée sur le clavier. On utilise Z et S pour respectivement avancer et reculer, Q et D pour pivoter à gauche ou à droite et enfin A et E pour avancer en pivotant légèrement. Pour cela, on utilise un objet Keyboard existant dans la bibliothèque proposée par Webots.
Utilisation
Le code du controller mis en place a pour but de permettre un contrôle manuel du robot. Cette fonction doit entre implantée en début de projet de façon assez rapide pour permettre aux autres équipes de réaliser des tests de façon simplifiée, en ayant la main sur les action du robot en développement.
Les fonctions introduites ne sont pour autant pas Immuable, celles-ci pouvant être modifiées selon les besoins requis, les mouvement pouvant être adaptés. On pourra de plus remarquer que l'utilisation du clavier nécessite d'avoir sélectionné la fenêtre de simulation 3D (en cliquant sur la scène 3D).
Robot Suiveur simple avec capteurs de distance
Description
Dans cette partie, on devait réaliser un robot suiveur rudimentaire en utilisant 2 capteurs de distance afin de comprendre leur fonctionnement. le logiciel webots nous fourni déjà des robots préfait possédant une multitude de capteurs. On a donc utilisé le robot E-puck, possédant 2 roues et 8 capteurs de distances autour de lui (ainsi qu'une caméra, un émetteur et un récepteur).
Fonctionnement
Afin d'avoir un robot simple, on utilise seulement les 2 capteurs à l'avant du robot (un plutôt à droite et l'autre plutôt à gauche). Ces capteurs servent à détecter le robot de devant. On fixe un seuil de distance activant ou non 2 booléens "robot_a_droite/gauche". On a donc 4 combinaisons différentes de ces booléens qui vont servir a commander notre robot:
| robot_a_droite | robot_a_gauche | résultat |
|---|---|---|
| faux | faux | avancer |
| faux | vrai | tourner à gauche |
| vrai | vrai | stop |
| vrai | faux | tourner à droite |
Résultats
Le résultat est plutôt satisfaisant vue sa simplicité. on remarque que les robots se suivent très bien les uns les autres vue qu'ils ont la même vitesse. Le comportement du premier robot est pas encore stable, mais comme il est censé suivre un humain, son fonctionnement va changer de toutes manières.
Suite
Les capteurs de distance on été utilisés ici pour suivre un robot, ou pourrait par la suite les utiliser pour éviter un obstacle. Il faudra pour cela éloigner les robots les uns des autres et leur faire suivre une commande à l'aide des autres parties réalisées.
Communication entre robots
Participants : Clément Luton et Thiago De Almeida Ribeiro
Cette section a pour but d’expliquer comment utiliser le logiciel Webots pour se faire suivre des robots en les faisant communiquer. La communication qui est permise par la simulation suit un protocole de communication série mais elle est transmise sans fil.
Les deux premières sous-sections comportent les résultats auxquels on est arrivé dans les dates indiquées, pendant que la dernière section comporte les résultats finaux, avec le niveau de détail nécessaire pour comprendre le fonctionnement du code et du logiciel. Avant de continuer, il serait intéressant d’avoir lu le tutoriel d’explication de code sur les bases de communication sur Webots et la description des nodes Emitter et Receiver, sur la page de description des capteurs.
Résultats initiaux (16/04/2020)
Pour configurer la communication entre deux robots, au tout début, il a fallu ajouter les robots au monde et exécuter la commande “Convert to Base Node(s)” (clique droit sur le robot dans le node tree). Cela a été nécessaire pour pouvoir changer quelques caractéristiques des robots, comme leur nom et la portée du signal émis (nécessaire pour le code en C mais pas pour celui en C++).
Pour faire le code, on est parti du controller emitter_receiver, existant en tant qu'exemple dans le logiciel. Nous avons eu deux démarches : une consistant à garder le code dans son langage, le C, est à l’adapter et une autre consistant à passer en C++ pour garder une cohésion avec le groupe entier qui code aussi en C++. Alors on a un code en C en un code en C++.
Dans les deux cas nous sommes arrivés à mettre en place une communication continue entre deux robots. Nous sommes capables de savoir si la communication se passe bien ou si elle est interrompue et nous avons réussi à transmettre au robot esclave la position relative (le robot esclave est utilisé comme origine d’un système de coordonnées) du robot maître. Nous allons utiliser ces données pour déplacer correctement le robot esclave. Dans ce moment, deux solutions s’offrent à nous :
- Se déplacer selon l’axe des X puis l’axe des Z.
- Se déplacer selon l’hypoténuse formée.
Résultats intérmédiaires (17/04/2020)
Après un peu plus de réflexion, on a décidé d’utiliser un troisième approche pour le comportement suiveur (détaillé sur la prochaine section). On est partie du code en C++ écrit avant pour écrire le code du robot maître et le code du robot esclave. On a pu contrôler le robot maître grâce au clavier et faire suivre le robot esclave grâce à la position du maître. La sphère blanche autour du robot maître représente la portée du signal de communication.
Résultats finaux (05/05/2020)
Maintenant on a deux robots esclaves et un robot maître. Le robot maître est contrôlé par le clavier et envoie sa position au premier esclave, celui-ci va suivre le maître et, à son tour, transmettre sa position au deuxième esclave, qui le suit.
Au tout début, il a fallu ajouter les 3 robots (e-pucks) à un monde créé préalablement. De plus, il est intéressant de réduire le pas de temps de la simulation (WorldInfo -> basicTimeStep -> 16) pour pouvoir augmenter sa précision et sa stabilité.
Comme les trois robots fonctionnent de façon différente, il a fallu créer trois contrôleurs distincts : "emitter", pour le robot maître, "emitter-receiver", pour le premier esclave, et "receiver", pour le deuxième esclave. Pour concevoir les codes, on est parti du contrôleur “emitter_receiver”, trouvé dans un monde de base homonyme. Comme ce dernier est écrit en C, il a fallu le traduire en C++ au préalable pour garder une cohésion avec le groupe.
Le contrôleur “emitter” utilise un bloc de code créé par d’autres intégrants du groupe pour permettre de contrôler le robot avec le clavier. De plus, il active et configure l'émetteur du robot et transmet un message quelconque. Le contrôleur “receiver” active et configure le récepteur du robot, affiche un message pour informer si la communication a été établie et permet de suivre un robot qui émet un message. Finalement, le contrôleur “emitter-receiver” est l'addition des deux contrôleurs antérieurs, sans la partie contrôle clavier.
Pour le comportement suiveur, on utilise deux fonctions de base : “getEmitterDirection()” et “getSignalStrength()”. La première permet d’obtenir la position de l'émetteur par rapport au système de coordonnées du récepteur (vecteur normalisé avec 3 composants) et la deuxième la force du signal. Le bloc de code suivant est responsable de ce comportement.
const double *position=receiver->getEmitterDirection();
double signal=receiver->getSignalStrength();
if(signal>150) //Stop the robot if it's too close to the master
{
left_motor->setVelocity(0);
right_motor->setVelocity(0);
}
else{
//Following behavior
if (position[0]<-0.1)
{
left_motor->setVelocity(0);
right_motor->setVelocity(MAX_SPEED);
}
else if(position[0]>0.1)
{
left_motor->setVelocity(MAX_SPEED);
right_motor->setVelocity(0);
}
else
{
left_motor->setVelocity(MAX_SPEED);
right_motor->setVelocity(MAX_SPEED);
}
}
À partir de la force du signal, il est possible de savoir si le récepteur est trop proche de l'émetteur, de façon à arrêter le robot esclave pour éviter une collision. En outre, la première coordonnée du vecteur position (axe rouge dans la figure ci dessous) permet de dire si le récepteur est approximativement derrière l'émetteur (-0,1 < position[0] < 0,1). Si c’est le cas, le robot doit aller tout droit, sinon, il doit tourner à gauche où à droite.
Le fonctionnement est illustré dans le GIF ci-dessous.
Jusqu’alors, les robots étaient considérés sans défauts. Cela veut dire que l'on n'avait pas pris en compte le bruit dans la communication. Le récepteur possède deux variables qui peuvent être modifiées afin d’y ajouter le bruit :
- signalStrengthNoise : écart-type du bruit gaussien ajouté à la force du signal renvoyé par “getSignalStrength()”. Le bruit est proportionnel à la force du signal, par exemple, un signalStrengthNoise de 0,1 ajoutera un bruit avec un écart-type de 0,1 pour une force de signal de 1 et de 0,2 pour une force de signal de 2.
- directionNoise : écart-type du bruit gaussien ajouté à chacune des composantes de la direction retournée par “getEmitterDirection()”. Le bruit ne dépend pas de la distance entre l'émetteur-récepteur.
Vu que le logiciel ne possède pas de fonction de base pour effectuer cette modification (comme setChannel() pour choisir le canal de communication, par exemple), on doit modifier le node du récepteur directement. Pour pouvoir le faire, on doit faire un clique droit sur le robot que l'on souhaite modifier dans la scene tree et après cliquer sur “Convert to Base Node(s)”. Après, il suffit d’aller sur “Robot > children > DEF EPUCK_RECEIVER Receiver” et modifier les champs signalStrengthNoise et/ou directionNoise.
Si on met un écart-type de 1 pour la direction, par exemple, on remarque que les robots continuent à se suivre mais cela se fait d’une façon plus lente et irrégulière. Cela pourrait être un problème puisque le robot maître pourrait trop s’écarter des esclaves et la communication entre eux serait alors coupée.
L’ajout du bruit associé à la force du signal ne doit pas affecter le comportement suiveur, mais pourrait permettre une collision entre les robots. Si on met, par exemple, la valeur de 0,1, on remarque que cela peut arriver :
Cela peut être réglé en mettant 80, par exemple, au lieu de 150, dans la ligne de code ci-dessous :
if(signal>150) //Stop the robot if it's too close to the master
Une deuxième solution serait d’utiliser les capteurs de distance du robot.
Enfin, il est important de prendre en compte les type de signaux possibles pour l'émetteur et le récepteur : "radio", "serial" ou "infra-red. Les signaux de type "radio" (par défaut) et "serial" sont transmis sans tenir compte des obstacles. Cependant, les signaux de type "infra-red" tiennent compte des obstacles potentiels entre l'émetteur et le récepteur. Tout objet solide (solide, robots, etc) avec un objet englobant défini est un obstacle potentiel à une communication "infra-red". La structure du robot émetteur ou récepteur lui-même ne bloquera pas une transmission "infra-red". Actuellement, il n'y a pas de différence d'implémentation entre les types "radio" et "serial".
Alors, si aucune modification n’est effectué, l'émetteur et le récepteur utilisent le type “radio” et les robots pourront communiquer même s’il y a un obstacle entre eux :
En choisissant le type “infra-red”, cela ne serait pas possible. Pour faire cette modification il suffit de changer les champs “type” dans “Robot > children > DEF EPUCK_RECEIVER Receiver” et “Robot > children > DEF EPUCK_EMITTER Emitter” (après avoir fait un “Change to Base Node(s)”.
Mise en place de la scène
Pour modifier la scène nous nous sommes aidé du tutoriel disponible à cette adresse.
Comme dit précédemment l'interface graphique est plutôt intuitive et il est donc facile de modifier la scène. Tout se fait via le bouton Plus (Add) en haut à gauche entouré en rouge.
Une fois qu'on a cliqué dessus on peut choisir un élément de base (base nodes) ou des éléments déjà existants (Proto Nodes). Dans les éléments existants il y a des objets, des robots, des véhicules... Une fois l'élément choisi il va être placé au centre du sol. La touche MAJ en même temps qu'un clic gauche de la souris permet de le déplacer là où l'on souhaite. Cette manipulation est aussi possible via la fenêtre de paramètre de l'objet (accolade en rouge sur la photo).
On peut ainsi choisir de déplacer l'objet via les paramètres de translation, de le tourner via la rotation et enfin de changer sa taille via scale.
Pour les objets déjà existants la méthode scale n'est pas directement accessible il faut faire un clic droit sur l'objet et sélectionner "convert to base nodes". Une fois cette opération effectuée, les paramètres scale seront accessibles.
Pour un objet de type solid on peut modifier la forme (Shape) via les paramètres (voir l'exemple du tutoriel situé en haut).
Pour changer le controller d'un robot voir le lien suivant.
Robot avec détection de couleur
Le but est ici d'utiliser la caméra du robot E-Puck afin de de pouvoir suivre un objet de couleur, que l'on pourrai par exemple placer à l'arrière d'un robot pour que celui de derrière puisse le suivre. Nous avons dans un premier temps fait en sorte que le robot suive un objet rouge. Par la suite nous avons amélioré le système afin d'avoir plusieurs robot qui se suivent.
Fonctionnement
Pour cela, nous utilisons des méthodes de la classe Camera permettant de capturer une image et de recueillir des informations sur le nombre de pixel rouge, vert ou bleu. Nous avons donc séparer l'image en 3 zones (milieu, gauche et droite) afin de compter le nombre de pixel d'une certaine couleur dans chacune de ces partie. Si ce derniers est supérieur au nombre de pixels des autres couleurs dans une zone, on effectue le déplacement correspondant (avancer, pivotage à gauche ou à droite). Nous avons aussi utiliser les capteurs de distance situés à l'avant du robot afin d’éviter une collision quand le robot se sera trop rapproché de l'objet qu'il suit. Voici notre premier essai, le robot suit uniquement un objet rouge qu'il faut déplacer à la main :
Nous avons ensuite ajouté des robots de couleurs différentes, dépendant tous d'un controller différent, afin que le premier robot (bleu) soit guidé par les commandes du clavier, que le deuxième (rouge) suive le robot bleu, le troisième (vert) suive le robot rouge, et le dernier (gris) suive le robot vert :
Nous avons rajouté une fonctionnalité qui permet aux robots suiveurs de savoir où se trouve l'objet qu'il suivent (gauche, droite, ou devant). Ainsi, si l'objet suivi est sort du champs de vision, le robot va tourner sur le lui même en fonction de la position précédente de l'objet suivi. Si l'objet disparaît et qu'il se trouvait sur la gauche avant de disparaître, le robot va tourner sur lui même sur la gauche jusqu'à retrouver l'objet. Voici les codes utilisés, comme le fonctionnement du des robots gris, vert et rouge est le même (seul la couleur à détecter change), nous ne mettons que le code du robot bleu (robot à suivre) et du robot rouge :
- Le premier robot se dirige avec les flèches, donc le Code de contrôle au clavier est implanté.
- Robots suiveurs : chaque robot est associé à un controller dont le code est semblable au Code de suivi d'un objet (robot) rouge, avec des changements pour la couleur.
Fusion des méthodes
Fusion de Code
Une fois l’ensemble des codes fonctionnel, nous nous sommes lancés dans la mise en place d’une simulation comprenant l’ensemble de ces derniers.
Pour cela, nous avons choisi d'exporter les robots édités des différentes simulations dans une nouvelle scène. Dans le monde où le robot a été créé, il faut faire un clic droit sur le nom du robot dans la scene tree et après cliquer sur “Export”. Cela crée un fichier .wbo à sauvegarder là où vous le voulez et, dans le nouveau monde, cliquer sur “Import...” dans la fenêtre d’ajout de nœuds pour aller chercher le fichier.
Nous avons ensuite implémenté les codes nécessaires à chacun des robots et harmonisé les fonctionnements. Plus précisément, il a fallu ajouter la partie de gestion de l'émission de message faite dans le controller "emitter" au controller utilisé par le robot maitre pour suivre le robot rouge (par détection de couleurs).
Une fois cette fusion faite, il manquait encore la fonction d’évitement des obstacles que nous avons mises en place à ce moment.
Evitement
Les robots, en fonction de leur position dans la file, ayant des fonctions différentes (suivi d’un robot par analyse colorimétrique ou suivi d’un robot par communication sans fil), il est nécessaire d’adapter le code d’évitement pour ne pas interférer avec les fonctions de suivi. Ainsi la fonction d'évitement se base toujours sur le même principe, mais l’implémentation se fait de façon différente pour chaque controller, avec des contraintes plus ou moins complexes.
Tous les robots évitent les obstacles grâce aux capteurs de distance, mais ils doivent différencier les robots qu’ils suivent des obstacles quelconques. Pour cela, le robot maître utilise la quantité de pixels rouges dans l’image de la câmera au moment de la détection de l’obstacle, pendant que le maître-esclave et l'esclave utilisent la force du signal de communication. Dans ce dernier cas, la vérification est faite même avant la détection des obstacles, de façon à arrêter les robots.
De plus, on a aussi implémenté une fonction pour réduire la vitesse des robots au fur et à mesure qu’ils s’approchent de leur but (robots à suivre), en utilisant un produit en croix.
À la fin de nos heures de travail, nous avions alors créé et mis en place les controllers suivants: RobotHumain, RobotCamera, RobotEmitterReceiver et RobotReceiver.
- Pseudo code d’évitement du robot caméra
- Pseudo code d’évitement des robots suiveurs avec recepteurs



