IMA5 2019/2020 P09
Sommaire
[masquer]- 1 Présentation générale
- 2 Préparation du projet
- 3 Etat de l'art
- 4 Réalisation du Projet
- 4.1 Semaine 1 : 09-15 Septembre
- 4.2 Semaine 2 : 16 - 22 Septembre
- 4.3 Semaine 3 : 23 - 29 Septembre
- 4.4 Semaine 4 : 30 Septembre - 6 Octobre
- 4.5 Semaines 5 et 6 : 7-20 Octobre
- 4.6 Semaine 7 : 21 Octobre - 3 Novembre
- 4.7 Semaine 8 - 11 : Mois Novembre
- 4.8 Semaines 12 & 13 : 2 - 15 Décembre
- 4.9 Semaine 14 : 16 - 22 Décembre (Soutenance 1)
- 4.10 Semaines 15 - 16 : 6 - 19 janvier
- 4.11 Semaines 17 et 18 : 20 Janvier - 2 février
- 4.12 Semaine 19 : 3 - 9 Février
- 4.13 Semaine 20 : 10 - 16 Février
- 4.14 Semaine 21 : 17 - 21 Février (Soutenance 2)
- 5 Documentation
- 6 Documents Rendus
Présentation générale
Sujet : Véhicule autonome pour cartographie
Etudiant : MEJBAR Lina
Encadrants : Alexandre Boé / Xavier Redon / Thomas Vantroys / Xavier Chenot
Description
Le secteur de l'intelligence artificielle a été beaucoup marqué durant la dernière décennie par une évolution du nombre de recherches et de publications scientifiques. Son but est de concevoir des systèmes capables de reproduire le comportement humain et son raisonnement. S'il est vrai que de domaine parait très abstrait, il possède de nombreux avantages lorsqu'on sait comment l'utiliser. Le retail, l'industrie ou encore la sécurité sont des secteurs qui deviennent de plus en plus performants lorsque l'intelligence artificielle est développée. L'objectif est de permettre une automatisation plus intelligente des tâches. Le machine learning est un champ d'étude de l'intelligence artificielle qui se fonde sur des approches statistiques pour donner aux ordinateurs la capacité d' « apprendre » à partir de données.
Objectifs
La mission sera de proposer un système autonome (véhicule mobile) capable de se déplacer dans une zone et de la cartographier. Le système doit pouvoir ensuite trouver le chemin adéquat pour se déplacer d’un point à un autre tout en évitant des obstacles fixes et/ou mobiles. Ce projet est proposé par l'entreprise Bonduelle. Le but final, serait de placer le robot dans leur entrepôt, et qu'il puisse déplacer une plaquette de produit d'un point A à un point B, tout en évitant les obstacles et en cartographiant la pièce.
Préparation du projet
Cahier des charges
Dans un contexte international de développement de projet innovants, il faudra proposer un système autonome (véhicule mobile) capable de se déplacer dans une zone et de la cartographier. Le système doit pouvoir ensuite trouver le chemin adéquat pour se déplacer d’un point à un autre tout en évitant des obstacles fixes et/ou mobiles.
Choix techniques : matériel et logiciel
Matériel mis à disposition par Polytech :
- VL6180X Distance Sensor
- Carte Raspberry Pi 3GB
Matériels mis à disposition par Bonduelle :
- Robot kit : Yahboom Professional 6WD UNO R3 smart robot kit compatible with Arduino
- Carte Arduino fournie dans le kit
- Carte Raspberry Pi 4GB et carte SD
- Kit pour déplacement caméra suivant deux axes
Questions
Cartographie :
→Quel taille de pièce vise-t-on ?
→ Combien de temps doit prendre la cartographie ?
→ Sous quel format doit être la cartographie ?
Intelligence Artificielle
→ Quelles formes doit reconnaitre le robot ?
Matériel
→ Proposition d'un capteur ultrason
Robot
→Trouver une solution pour le rendre plus robuste
Liste des tâches à effectuer
Tâche \ Heures | S01 | S02 | S03 | S04 | S05
S06 |
S07 | S08
S11 |
S12 | S13 | S14
Oral 1 |
S15
S16 |
S17
S18 |
S19 | S20 | S21
Oral 2 |
Total |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Analyse | ||||||||||||||||
Analyse du projet | 2 | 2 | 1 | 2 | 7 | |||||||||||
Recherches concernant le projet | 2 | 2 | 2 | 2 | 8 | |||||||||||
Montage du robot | 2 | 2 | ||||||||||||||
Modélisation et Impression 3D | 5 | 5 | ||||||||||||||
Formation - Documentation | ||||||||||||||||
Formation Machine Learning | 2 | 4 | 6 | |||||||||||||
Formation Partie Cartographie (LIDAR) | 4 | 2 | 3 | 9 | ||||||||||||
Formation Computer Vision | 10 | 10 | ||||||||||||||
Formation ROS | 4 | 10 | 8 | 22 | ||||||||||||
Code | ||||||||||||||||
Code Arduino | 3 | 3 | 2 | 7 | 3 | 2 | 2 | 19 | ||||||||
Code C++ : Lidar | 2 | 4 | 6 | |||||||||||||
Code du site Web | 3 | 4 | 4 | 2 | 2 | 2 | 17 | |||||||||
Code Python : Open CV | 8 | 8 | ||||||||||||||
Code ROS | 5 | 4 | 5 | 4 | 3 | 21 | ||||||||||
Rencontre Tuteurs | ||||||||||||||||
Rencontre Bonduelle | 1 | 1 | 2 | 2 | 4 | 4 | 4 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 32 | |
Documentation | ||||||||||||||||
Remplissage du wiki | 2 | 1 | 2 | 3 | 3 | 2 | 3 | 1 | 4 | 3 | 21 | |||||
Documentation pour Bonduelle | 2 | 1 | 3 | 3 | 9 | |||||||||||
Préparation Soutenance 1 | 3 | 2 | 4 | 9 | ||||||||||||
Préparation Soutenance 2 | 2 | 2 | ||||||||||||||
Rédaction du rapport (Interm et Final) | 4 | 4 | 2 | 4 | 2 | 16 | ||||||||||
Total | 11 | 6 | 12 | 12 | 20 | 13 | 43 | 15 | 8 | 12 | 26 | 15 | 15 | 23 | 7 |
Calendrier prévisionnel
Etat de l'art
- L’aspirateur robot IRobot I7+ est un aspirateur autonome nouvelle génération. Il se vide automatiquement dans un sac fermé pouvant contenir l’équivalent de 30 bacs. Le robot doit bien entendu récupérer la poussière, éviter les obstacles fixes (meubles, murs ..) et mobiles (personnes, animaux ..). Sa particularité est qu'il peut cartographier la maison après deux-trois passages. Ce robot est commercialisé 1200€.
- Un deuxième robot avec les mêmes caractéristiques que mon cahier des charges a vu le jour en 2017. C'est le robot mobile Apollo qui est l’une des meilleures bases mobiles du marché. Il est doté de plusieurs capteurs, un LIDAR, une caméra de profondeur, un capteur ultrason, un capteur de dénivelation et un SLAMWARE. Il a été pensé pour pouvoir évoluer de manière autonome dans des lieux publics et être capable de faire face à de nombreuses situations :
- - Contournement des obstacle,
- - Automatisation de la planification des trajets,
- - Rechargement autonome.
Réalisation du Projet
Semaine 1 : 09-15 Septembre
Je me suis rendue mercredi au sein de l'entreprise Bonduelle à Villeneuve d'Ascq. Pour la réalisation de ce projet, Bonduelle m'a fourni un robot en Kit. J'ai commencé par le monter en suivant les instructions du mode d'emploi.
Une fois le robot monté, j'ai fait des recherches concernant les différents domaines de mon sujet :
* Robot : De nos jours, on trouve de plus en plus de nombreux kits d'assemblage de robots programmables. C'est sur l'un d'entre eux, que je vais travailler dans le cadre de mon projet. Ce kit est commercialisé par la marque Yahboom. Ils vendent de nombreux modèles de robots : Char, Tank, des robots de 2 à des 6 roues. Celui sur lequel je vais travailler dans le cadre de mon projet est le robot Yahboom Professional 6WD UNO R3 smart robot kit compatible with Arduino Ce kit contient : Une caméra avant, 6 roues et 6 moteurs, une carte Arduino et une carte 6WD, une pile rechargeable.
*Carte 6WD :
Yahboom 6WD carte d'extension intelligente pour Uno et Raspberry Pi. La carte d'extension 6WD est conçue avec trois prises d'entraînement de moteur et supporte jusqu'à trois modules d'entraînement de moteur. Chaque module peut conduire deux moteurs. Chaque moteur peut être contrôlé indépendamment, et 6 moteurs peuvent produire 6 vitesses différentes en même temps, réalisation contrôle indépendant. La carte d'extension 6WD prend en charge quatre contrôleurs populaires, y compris Raspberry Pi, Arduino, STM32, 51, etc.
Semaine 2 : 16 - 22 Septembre
Pendant la deuxième semaine de projet, j'ai majoritairement fait des recherches sur internet concernant mon projet. Le projet étant porté sur l’IA (Intelligence artificielle) et notamment les réseaux de neurones artificiels, la formation actuelle en IMA ne donne pas les connaissances nécessaires. Je vais donc passer une bonne partie du temps à me former pour apprendre son fonctionnement.
Recherche Machine Learning
- Un neurone artificiel peut se décomposer en :
- - Des entrées
- - Une fonction d’activation
- - Une sortie
On appelle potentiel du neurone la somme des entrées pondérées par leurs poids.
Si l’on a Xi la i−ème entrée d’un neurone et Wi le poids qui lui est associé, alors le potentiel du neurone est :
Fichier:P09 ML1.png
Pour calculer la sortie du neurone, on applique au potentiel une fonction qui peut être continue ou non.
Il est donc possible de connecter la sortie d’un neurone à l’une des entrées d’un autre neurone, c’est de cette façon que l’on peut former un réseau de neurone.
- Il existe ensuite plusieurs fonctions d’apprentissage, qui permettent de modifier les poids des connexions entre les neurones. La modification des poids entraîne un changement dans la sortie du réseau de neurone. Il existe différents types d’apprentissage pour les réseaux de neurones :
- - Apprentissage supervisé : Plusieurs échantillons, représentant le contexte dans lequel se situe le neurone, sont présentés au réseau de neurones. Chaque échantillon est donné avec une sortie qui devrait être la même que la sortie calculée. Le réseau de neurone va alors se corriger selon la différence entre la sortie donnée et la sortie calculée par le réseau.
- - Apprentissage par renforcement : Plusieurs échantillons sont aussi présentés au réseau de neurones. Lorsque la sortie du réseau de neurone n’est pas celle voulue, le réseau est notifié de son erreur, mais aussi de sa réussite en cas de succès. Contrairement à l’apprentissage supervisé, le réseau ne peut pas connaître la valeur de son erreur en comparant sa sortie calculée avec une sortie donnée.
- - Apprentissage non supervisé : Lors de cet apprentissage, on présente aussi plusieurs échantillons. Cette fois-ci, le réseau essaye de dégager lui-même des caractéristiques communes à certaines entrées, pour répondre en conséquence. Le réseau établit lui-même différentes classes d’entrées.
Lecture de thèses
Construire une carte intérieure de façon autonome avec une auto localisation du robot dans la carte générée par ce dernier représente en ce moment un vrai point de recherche dans le domaine de la robotique mobile. Faire face à un environnement inconnu ou qui change est un problème qui se nomme SLAM (Simultaneous localization and mapping). C'est le sujet sur lequel porte cette recherche.
- Définition :
- - 'Odométrie ': Technique permettant d'estimer la position d'un véhicule en mouvement grâce à des capteurs embarqués permettant de mesurer le déplacement des roues du robot.
- Solution proposée par l'article : Faire correspondre les structures en utilisant la similarité des formes. Dans un premier temps, ils utilisent un laser range scanner (LIDAR/ Télémètre laser) qui génère un fichier de points. Par la suite ils font abstraction de la positions des points et utilisent les méthodes des tangentes et des histogrammes angulaires qui permettent de détecter les similitudes entre les scans.
- Définition :
- - Fuzzy Logic (FL) : Logique floue est une logique polyvalente où les valeurs de vérité des variables - au lieu d'être vrai ou faux - sont des réels entre 0 et 1. En ce sens, elle étend la logique booléenne classique avec des valeurs de vérités partielles. Elle consiste à tenir compte de divers facteurs numériques pour aboutir à une décision qui prend en compte plus de facteurs.
- - Adaptive neuro-fuzzy inference system (ANFIS) : Le système d'inférence neuro-fuzzy adaptatif ANFIS combine les avantages du réseau neuronal artificiel (ANN) et de la logique floue (FL), constituant ainsi un meilleur système d'approximation des fonctions non linéaires. Il a été proposé que ANFIS coopère avec EKF afin de réduire le déséquilibre entre la covariance théorique et réelle des séquences d’innovation. En fait, la qualité de l’estimation EKF est déterminée par les informations a priori des matrices de covariance de processus (Qk) et de bruit de mesure (Rk).
- - Simplified Complex-Value Neural Network (SCVNN) : La valeur complexe simplifiée Neuro-Floue égalise le nombre de couches de règles et de divisions dans la couche d'entrée. L'augmentation du nombre de paramètres d'entrée n'augmentera pas le nombre de règles. Dans l'intervalle, le format QNF simplifié permet à un réseau neuro-flou d'avoir une vitesse de calcul plus rapide avec moins de ressources occupées et un temps d'exécution moins important, indispensables à tout système informatique de grande taille en temps réel.
- - Extended Kalman Filter (EKF) : C'est une modélisation basée sur les fonctionnalités utilisant un algorithme de maximum de vraisemblance et une approche statistique pour l'association de données et l'association de données probabilistes. L'approche typique pour simuler la localisation et la cartographie en temps réel est généralement effectuée à l'aide de filtres de Kalman et de la méthode de Monte Carlo séquentielle, dans laquelle le résultat n'est pas satisfaisant en termes de quantité volumineuse d'entrées, de temps de traitement long et de performances médiocres en termes de précision. C'est depuis longtemps un algorithme populaire utilisé dans SLAM, en particulier avec les systèmes non linéaires.
- Solution proposée par l'article : Nouvelle approche pour la localisation du robot et la cartographie en vue d'améliorer le stockage des données d'entrées.
Semaine 3 : 23 - 29 Septembre
Premier pas du robot
Comment roule le robot ? Le robot possède 6 roues reliées à six moteurs à courant continu.
- - Un moteur à courant continu fonctionne à l'aide du principe de la PWM (Pulse Width Modulation), c'est de cette façon qu'il est possible d'agir sur la vitesse et le sens de rotation du moteur. Il faut utiliser les pins de sorties digitales de l'Arduino, on les reconnaît car elles ont le symbole " ~ ". On les commande avec une fonction de l'Arduino qui va prendre une valeur entre 0 et 255 :
analogWrite(pin,valeur);
où pin est le pin PWM choisi et mis en mode OUTPUT, et valeur est la valeur comprise entre 0 et 255 qui va définir la part de temps pendant laquelle le pin sera à l’état HAUT durant chaque intervalle (255 correspondra à 100% du temps d’intervalle à l’état HAUT)
- - Pour permettre le déplacement du robot, il faut lui fournir de l'énergie séparée pour l'Arduino et les moteurs. Ce principe est assez utilisé en électricité. Cela permet de séparer le circuit de commande et le circuit de puissance. Le circuit de commande envoie des informations binaires à une tension qui est celle de l'Arduino (+5 V) et un ampérage souvent faible (de l'ordre de 40 mA). L'alimentation de ce circuit est réalisée par une batterie (pile 9 V). Le circuit de puissance fournit l'énergie nécessaire pour faire fonctionner la charge.
Voici un gif qui montre les premiers déplacements du robot qui selon le code doit avancer reculer puis tourner:
Code
void setup(){ pinMode(pinMoteur,OUTPUT); } void loop(){ digitalWrite(pinMoteur,HIGH); //le moteur se lance delay(1000); digitalWrite(pinMoteur,LOW); //le moteur s'arrête delay(1000); }
Orientation du robot
Pour permettre le déplacement du robot, il faut actionner les moteurs. Ci-dessous, une photo du robot:
A côté de chaque de roue, il y a deux numéros.
Prenons par exemple la roue avant droite, on peut lire " 15 - 14 ". Ces numéros représentent les pinMoteur, il y a deux valeurs : la première permet à la roue de tourner dans le sens anti-horaire (15) et la seconde dans le sens horaire (14).
Pour avancer, il faudra donc donner ces valeurs aux moteurs:
//Arrière pwm.setPWM(8, 0, Speed); pwm.setPWM(9, 0, 0); pwm.setPWM(11, 0, Speed); pwm.setPWM(10, 0, 0);
//Milieu pwm.setPWM(0, 0, Speed); pwm.setPWM(1, 0, 0); pwm.setPWM(3, 0, Speed); pwm.setPWM(2, 0, 0);
//Avant pwm.setPWM(12, 0, Speed); pwm.setPWM(13, 0, 0); pwm.setPWM(15, 0, Speed); pwm.setPWM(14, 0, 0);
Pour tourner à gauche, il faudra donc donner ces valeurs aux moteurs:
//Arrière pwm.setPWM(8, 0, Speed); pwm.setPWM(9, 0, 0); pwm.setPWM(11, 0, 0); pwm.setPWM(10, 0, Speed);
//Milieu pwm.setPWM(0, 0, Speed); pwm.setPWM(1, 0, 0); pwm.setPWM(3, 0, 0); pwm.setPWM(2, 0, Speed);
/Avant pwm.setPWM(12, 0, Speed); pwm.setPWM(13, 0, 0); pwm.setPWM(15, 0, 0); pwm.setPWM(14, 0, Speed);
J'ai donc une dizaine de fonctions qui me permettent de déplacer le robot.
Rendez-vous Bonduelle
Nous avons décidé de remplacer l'Arduino par un ESP32, un microprocesseur qui possède deux coeurs, ce qui lui permet de gérer simultanément deux tâches à la fois. Nous avons défini les objectifs pour les prochaines semaines et pour la première soutenance. Dans un premier temps, il faudra que je me concentre sur la réception et le traitement des données du LIDAR.
Lidar
L'entreprise propose un logiciel avec le LIDAR X4 qui fonctionne uniquement sous Windows. Ce logiciel permet de visualiser les résultats du scan réalisé avec le LIDAR, avec une visualisation en 2D/3D des points. N'ayant pas de machine sous windows, il fallait trouver une autre façon de traiter les données.
Une autre méthode est de télécharger l'outil ROS (Robot Operating System) Kinetic. Cependant cet outil n'est pas opérationnel sous Debian, il est en cours d'expérimentation : le seul OS supporté est Ubuntu.
Un code est fourni avec le LIDAR et peut être téléchargé ici , voici les données récupérées :
On peut voir qu'un tour complet du LIDAR permet d'obtenir 656 valeurs de distances. Il y a donc en moyenne 1.8 mesures de distance par degrés.
Semaine 4 : 30 Septembre - 6 Octobre
Code Lidar
Cette semaine, l'objectif est de récupérer les données du LIDAR. J'ai modifié le fichier fourni par Ylidar afin d'afficher les valeurs de distances et d'angles. Ce fichier est codé en C++. C'est un langage que je ne connais pas encore, mais il s'apparente beaucoup au C, de nombreux sites tels que Stack Overflow me permettront de répondre à d'éventuelles questions.
Voici une partie du code qui permet de faire un Scan 360°, de l'arrêter et d'afficher les valeurs dans le terminal.
LaserScan scan; if(laser.doProcessSimple(scan, hardError )){ for(int i =0; i < scan.ranges.size(); i++ ){ float angle = (scan.config.min_angle + i*scan.config.ang_increment)*180/3.14; float dis = scan.ranges[I]; ydlidar::console.message("\tAngle: %.2f ° et Distance %.2f m ", angle,distance); } ydlidar::console.message("Scan received[%llu]: %u rangess",scan.self_time_stamp, (unsigned int)scan.ranges.size()); } else { ydlidar::console.warning("Failed to get Lidar Data"); }
Récupération des données
Voici ce que je récupère:
J'ai ensuite modifié le code pour créer un fichier .txt et le remplir ligne par ligne avec les valeurs. Voici comment se présente une ligne: angle_value/distance_value.
Traitement des points
L'affichage du traitement des points s'effectuera sur une interface web. Le but de cette partie est de placer un point en fonction de son angle et de sa distance à partir de l'origine O placé au centre de la page web.
Voici la fonction qui s'en charge. En paramètre, les deux valeurs envoyées par le LIDAR. Pour placer le point, il faut déterminer son abscisse et son ordonnée. Pour les obtenir, on doit d'abord se placer au centre de la page web, définir l'échelle (équivalence entre les pixels de la page et la distance réelle en mètre) et utiliser les formules de trigonométrie : SOH CAH TOA.
Positionnement d'un point |
---|
function placerPoint(angle,distance){ ctx.beginPath(); var abscisse = centre_page_x + échelle * Math.cos(-angle*Math.PI/180) * distance; var ordonnée = centre_page_y + échelle * Math.sin(-angle*Math.PI/180) * distance; ctx.beginPath(); ctx.arc(x, y, point_size, 0, 2 * Math.PI); ctx.fill(); } |
Affichage de la cartographie
Je suis en train de me former pour coder un site en HTML et Javascript.
Une fois les données envoyées par le Lidar, il faut les afficher sur l'interface web., voici une première version de la cartographie :
Conditions de la capture des données :
- Le Lidar était positionné en hauteur afin d'éviter d'avoir des distances faussées par les différents objets de la salle (Ordinateurs, tours..)
- Position exacte Zabeth05 (représenté par le point O sur la cartographie)
Cette première version a été réalisée à Polytech dans la salle E306. On reconnaît bien la disposition de la salle mais si ce n'est pas le cas voici ci-dessous l'image légendée pour se mieux visualiser la pièce.
Analyse de cette première version :
- Les angles morts ne sont pas traités (exemple : les armoires)
- Les fenêtres sont mal représentées car il n'y a pas de réflexion du laser.
Raspberry Pi
En fin de semaine, j'ai travaillé à Bonduelle. J'ai choisi de télécharger l'image Ubuntu Mate 18.05 parce que ROS n'est disponible que sous Ubuntu. J'ai installé tous les packages nécessaires.
J'ai ensuite récupéré les fichiers de code et réussi à les exécuter sur la Raspberry Pi. J'ai cartographie le bureau où je travaille à Bonduelle et en l'analysant je peux confirmer les premières observations faites dans la salle E306 : le Lidar a du mal à cartographier les vitres. Voici le résultat non commenté et commenté pour avoir une idée précise de la pièce.
Voici le résultat :
Semaines 5 et 6 : 7-20 Octobre
L'objectif de ces deux prochaines semaines est :
- de pouvoir lancer la cartographie à distance : sur un autre ordinateur connecté sur le même réseau
- d'améliorer le fonctionnement précédent : changer le format du fichier où l'on enregistre les données TXT -> JSON
- Premier croquis du site final
ROS
L'installation de ROS n'est finalement pas supportée sur UBUNTU Mate l'OS de la Raspberry pi. Ce n'est pas grave parce que l'objectif n'est pas de récupérer un outil qui fait déjà la cartographie, mais plutôt que je le réalise seule. Cependant voici ce que cet outil informatique est capable de faire :
[Lien] de la photo. Cartographer est un système qui assure la localisation et la cartographie simultanées (SLAM) en 2D et 3D sur plusieurs plates-formes et configurations de capteurs. Le rendu est assez impressionnant.
Lancer l'acquisition à distance
Voici le code qui me permet de lancer l'acquisition à distance (depuis mon ordinateur connecté sur le même réseau que la Raspberry Pi) :
- Fichier HTML
<body> <form action="lidar.php" method="post"> <input type="submit" name="lidar" value="Start"/> </form> </body>
- Fichier PHP
<?php define('LIDAR_ON','/home/lmejbar/Lidar/ydlidar-master/build/samples/ydlidar_test'); if(array_key_exists('lidar',$_REQUEST)){ $lidar=$_REQUEST['lidar']; if($lidar=="Lancer l'aquisition") exec(LIDAR_ON); header('Location: http://192.168.0.20/serial.html'); exit(); } ?>
Voici le fonctionnement :
Changement de fichier
Une fois que j'ai compris comment enregistrer des données (en TXT), les interpréter et dessiner les points sur un site, il est préférable maintenant de passer au format de données JSON. En effet cela me permettra de récupérer les données facilement et les enregistrer dans une structure automatiquement avec les méthodes prévues en JS. C'est assez simple d'utiliser JSON en C++. Il faut d'abord réfléchir à la structure de ses données, j'aimerais avoir la suivante:
{ "0" : { "angle" : "-180", "distance" : "2.08" }, "1" : { "angle" : "-179", "distance" : "2.0" }, ... }
Voici le code pour avoir cette structure :
#include <jsoncpp/json/json.h> file.open("lidar.json"); Json::StyledWriter styledWriter; Json::Value lidarValues; // boucle pour chaque valeur reçues lidarValues[to_string(i)]["angle"]=to_string(angle); lidarValues[to_string(i)]["distance"]=to_string(dis);
Pour compiler le fichier main.cpp, il faut ajouter la librairie 'ljsoncpp' dans la commande :
g++ -o profile profile.cpp -ljsoncpp
Cependant dans mon projet, j'ai un premier Makefile qui en lance un second qui en lance un Cmake, chaque fichier contient 400 lignes. Je n'avais pas vraiment la main pour ajouter cette librairie. J'ai fait pas mal de recherches et j'ai étudié tous les fichiers sans trouver comment ajouter cette librairie. J'ai alors repris le [git] du LIDAR et j'ai tout repris depuis le départ. Lorsqu'on clone le projet, il faut créer le dossier build, et lancer cette commande lorsqu'on se situe dans le dossier.
cmake ../sdk
Le fichier CMakeLists.txt était le seul que je n'avais pas étudié. C'est donc dans ce fichier qu'il faut rajouter la ligne:
target_link_libraries(ydlidar_driver ljsoncpp)
Croquis du site final
Voici un croquis du site que je souhaite réaliser :
Depuis la création du projet, j'ai choisi le nom du robot: SLAMiT. SLAM (simultaneous localization and mapping) fait référence à la cartographie et la localisation simultanée.
L'objectif serait d'avoir une interface simple dans un premier temps, qui permettrait de :
- Voir le retour caméra du robot
- Utiliser des flèches pour déplacer le robot à distance
- La cartographie de la pièce ou se trouve le robot
- Quelques boutons
Exemple d'utilisation :
L'utilisateur se rend sur la page du projet, il se connecte au robot avec le bouton n°1. Il voit alors le retour de la caméra du robot, et il peut aussi déplacer le robot. Lorsqu'il appuie sur lancer l'acquisition, il doit avoir la cartographie avec le point O qui représente la localisation du robot dans sa cartographie. Le but serait de superposer les cartographies pour avoir un rendu précis et régler le problème des angles morts.
Semaine 7 : 21 Octobre - 3 Novembre
Les objectifs de la 7ème semaine et la semaine de la Toussaint sont les suivants :
- Réaliser une première version du site en suivant l'idée du croquis
- Lancer l'acquisition de la cartographie à distance
- Déplacer le robot à distance
Réalisation du site
Voici une image du site:
Dans un premier temps, je ne m'intéresse pas au design du site. Je préfère travailler le fond avant la forme.
- Concernant la Raspberry Pi :
- Eteindre :
- Etant donné que je travaille maintenant à distance avec la RP, je dois l'arrêter proprement en exécutant la commande suivante 'sudo shutdown now '
- Eteindre :
- Concernant le robot, il y a 5 boutons:
- Se connecter et se déconnecter:
- Le titre de la page permet d'avoir des informations sur cette connexion. S'il est vert, la connexion est établie, sinon il faut cliquer sur le bouton 'se connecter'. Si l'on souhaite se déconnecter au robot, il faut cliquer sur le bouton 'se déconnecter', le titre devient alors rouge.
- Déplacement du robot :
- Il y a trois boutons pour le moment 'Avancer', 'Reculer', 'Tourner'. Ils permettront de commander le robot à distance.
- Se connecter et se déconnecter:
- Concernant la cartographie :
- Lancer l'acquisition :
- Le fonctionnement de ce bouton est expliqué dans la partie suivante [4.5.2].
- Lancer l'acquisition :
Cartographie
Le lancement de la cartographie la semaine dernière fonctionnait, mais il affichait le résultat de l'exécution du fichier PHP. Il faudrait maintenant que lorsque l'utilisateur appuie sur le bouton 'Lancer l'acquisition' :
- En arrière-plan : exécution du fichier .php qui permet au LIDAR de se lancer et d'enregistrer les données dans un fichier JSON
- Cette exécution en arrière-plan doit permettre à l'utilisateur de rester sur la page du site
- Lorsque le fichier est prêt le site affiche automatiquement la nouvelle cartographie.
Déplacement du robot
Pour permettre la communication entre le robot (Arduino) et la Raspberry Pi, je vais utiliser des Websockets. C'est un protocole qui permet de développer un canal de communication sur un socket TCP. Il permet donc d’ouvrir une connexion permanente entre le navigateur et le serveur.
- Code HTML
var localhost = '127.0.0.1:9000'; var ip_raspberry = '192.168.0.20:9000'; var websocket=new WebSocket('ws://'+ip_raspberry,'serial'); websocket.onopen=function(){ $('h1').css('color','green'); }; websocket.onerror=function(){ $('h1').css('color','red'); };
Les deux dernières lignes permettent d'informer l'utilisateur de la page
- - Si le titre est vert => la connexion entre le navigateur et la Raspberry Pi est fonctionnelle
- - Le titre sera rouge dans le cas contraire.
- Code C
J'ai eu l'occasion de travailler sur les websockets pour mon projet d'IMA3. J'ai récupéré le fichier C
Cf Git
Semaine 8 - 11 : Mois Novembre
Deuxième site : Distance
J'ai réalisé un deuxième site sur le serveur de la Raspberry Pi. Le but de ce site est de récupérer les valeurs des distances dans le canvas.
Fichier:P9 siteN2 distance.png
Ce deuxième permet à l'utilisateur d'avoir plus d'interactions avec la cartographie réalisée. En effet, lorsque l'utilisateur déplace la souris sur la cartographie, il obtient directement la valeur de la distance entre le pointeur et la position du robot. Pour ce faire, je garde le premier canvas où la cartographie est affichée, et j'en rajoute un second ou j'affiche du texte :
<canvas id="myCanvas2" width="200" height="30" style="border:1px solid #d3d3d3;"></canvas>
J'obtiens la position du curseur avec la fonction suivante :
function getMousePos(canvas, evt) { var rect = canvas.getBoundingClientRect(); return { x: evt.clientX - rect.left, y: evt.clientY - rect.top }; }
Le message que j'affiche est obtenu de cette façon :
var mousePos = getMousePos(c, evt); var xA = (mousePos.x - 400)/40; var yA = (mousePos.y - 400)/40; var distanceA = 'Distance : ' + Math.sqrt(Math.pow(xA,2)+Math.pow(yA,2));
Je réduis la position x et y de 400 pour avoir la valeur en fonction de l'origine (position du robot). Je divise par 40 parce que mon canvas mesure 800 px et permet de représenter 10m de chaque côté donc 800/20=40.
Open CV
Comme l'affichage des données est fonctionnel sur le site, j'ai cherché une façon d'exploiter mes résultats. J'ai choisi de creuser du côté du langage python parce qu'il possède une bibliothèque graphique libre pour le traitement d'images en temps réel. N'ayant pas de connaissance dans le domaine de Computer Vision, je me suis dans un premier temps fortement inspiré des codes déjà rédigés sur le site suivant :
Affichage de la cartographie
J'ai codé un premier code, qui permet de récupérer un fichier JSON et de placer les points en fonction de l'angle et de la distance. J'ai gardé le même principe que l'affichage des données en Javascript.
Sur cette photo, j'ai mis en parallèle une première cartographie, puis une seconde après le déplacement du robot dans la pièce. Le but est de pouvoir par la suite comparer deux versions afin de les superposer.
Extrait du code
J'utilise ces bibliothèques : import math // Pour avoir les fonctions Cos et Sin import matplotlib.pyplot as plt //Pour créer le graphique (=Cartographie) import json // Pour récupérer le fichier JSON from dataclasses import dataclass // Pour créer une classe Point
Voila la classe que j'ai codé qui me permet de définir un point avec les deux valeurs récupérées dans le fichier JSON @dataclass class P_Point: distance: float angle: float Fonction qui permet de récupérer les données du fichier et de les ajouter dans un tableau de P_Point def get_data(file, tb): with open(file) as json_file: data = json.load(json_file) for value in data: if (data[value]['distance'] != "0.000000" ): p= P_Point(float (data[value]['distance']),float (data[value]['angle'])) tb.append(p) Fonction qui permet d'afficher les points dans le graphique def plot_point(angle, length): endy = length * math.sin(math.radians(angle)) endx = length * math.cos(math.radians(angle)) ax = plt.subplot(111) ax.plot([0, endx], [0, endy]') plt.plot(0,0, color ="red", marker='.', linestyle='dashed', linewidth=5, markersize=10)
J'arrive aux mêmes résultats que l'affichage sur le site du projet, il faut maintenant exploiter la cartographie.
Tracé des murs
Pour tracer les murs, j'ai pensé à :
- Reconnaître la forme de la pièce,
- Relier les points récupérés par le LIDAR,
Mais le premier affichage de la cartographie ne donne rien. Python ne reconnaît pas les formes parce qu'il y a des endroits sans informations.
Résultats | Commentaires |
---|---|
Comme on peut voir sur l'image, les informations ne sont pas exploitables. J'ai donc changé la façon d'afficher les données en copiant l'affichage de ROS. Le principe serait de mettre un fond gris, et de tracer des lignes blanche entre la position du robot et l'obstacle détecté, voici le rendu du deuxième affichage ci-dessous. | |
Comme on peut voir, les endroits sans informations sont parfois complétés, et j'arrive maintenant à reconnaitre les formes afin de tracer les contours de la pièce. | |
Il reste à lisser les contours pour corriger les éventuelles erreur du LIDAR. J'ai trouvé une thèse intéressante à ce sujet sur le site suivant, voici quelques résultats de leurs recherches sur la photo ci-dessous. | |
Je trouve le résultat assez impressionnant, je pourrai reprendre l'idée pour combler le manque d'information et lisser les contours des pièces. |
Recherche de similitudes
Afin de pouvoir superposer deux cartographies, je dois trouver des keypoints communs aux deux photos. Pour y arriver je vais utiliser un outil disponible en Python qui est SURF, SIRF, et OBO. Pour comprendre comment fonctionne SURF j'ai regardé deux tutoriels sur YouTube :
- Feature detection (SIFT, SURF, ORB)
- Feature Matching (Brute-Force) – OpenCV 3.4 with python 3 Tutorial 26
Le code de cette partie se trouve ici : Lien.
Comment fonctionne-t-il ?
...
Voici le résultat de mes tests/ recherches:
J'ai remarqué que plus il y a d'informations sur les deux photos, plus python détecte des keypoints. Le principe de SURF est de comparer les keypoints des deux photos et regarder s'il y a des similitudes. Donc si les photos représentent seulement un rectangle par exemple, SURF a du mal à traiter les photos.
Résultats | Commentaires |
---|---|
Comme on peut voir sur cette image, Python n'a détecté que 2 Keypoints et ils sont faux ! | |
J'ai essayé avec deux cartographies, on peut voir que le résultat s'améliore puisqu'il y a beaucoup plus d'informations. Cependant il reste quelques erreurs (1 seule: ligne violette). | |
J'ai créé une forme avec beaucoup d'informations pour voir le résultat, on remarque à nouveau beaucoup de keypoints détectés et une fois de plus il n'y en a qu'un seul qui est faux. | |
J'ai pivoté une des deux photos, le résultat est impressionnant! Malgré la rotation, il y a toujours autant de keypoints et ils sont presque tous justes ! |
ROS
Comme dit précédemment, son installation est impossible sur la RP3 qui n'a que 1GB de RAM. Bonduelle m'a fourni la RP4 (4GB), j'ai donc réessayé l'installation de ROS. Après de longues heures d'installations et de nombreux problèmes qu'il fallait régler. L'installation fonctionne et ROS démarre !! Comme je l'ai fait sur trois RP, les problèmes sont récurrents, et aucun tutoriel sur internet n'est complet. Je vais donc en rédiger un, il servira à Bonduelle et aux autres étudiants qui travailleront sur RP4 avec ROS.
Fichier:P9 ROS Instructions.pdf
Configuration de ROS :
- Version : Mélodic
- Packages :
- Ylidar : [GItHub Ylidar ]
- Hector : [Github Hector ]
Pour lancer la cartographie, il faut ouvrir trois onglets du terminal avec les commandes suivantes :
$ roscore | C’est le noeud qui prépare le système ROS, il accepte les commandes. ROS est un système centralisé, un nœud maître (roscore) est toujours nécessaire pour les autres nœuds et doit être exécuté avant les autres nœuds. Roscore démarre ce noeud principal. |
$ roslaunch ylidar lidar.launch | Permet de démarrer l'acquisition des données du Lidar |
$ roslaunch hector_slam_launch tutorial.launch | Permet de démarrer Rviz et affiche les résultats du LIDAR en temps réel. |
Voici le résultat chez moi :
Sans Hector : ROS + YLIDAR | On peut voir que cette version s'apparente beaucoup à ce que j'obtiens sur le site du projet. ROS positionne seulement les points en fonction de l'angle et de la distance.. La seule différente non négligeable avec mon programme c'est le programme tourne en temps réel, donc les points s'actualisent si l'environnement a changé. | |
Avec Hector : ROS + YLIDAR + HECTOR | Dans cette version, ROS trace les murs en noir et trace le chemin parcouru en vert. Les deux lignes verte et rouge permettent de situer le robot dans la pièce. Cette version s'actualise en Temps réel aussi. |
Semaines 12 & 13 : 2 - 15 Décembre
Point avec Bonduelle : Modification
J'ai présenté mon avancement à Xavier CHENOT et Erwan NIQUET. Ils sont satisfaits de mon avancement, mais ils préfèrent que je me concentre seulement sur ROS. Ils pensent que c'est exactement l'outil qu'ils envisagent pour ce projet. Donc il faut que je trouve un outil qui permet d'enregistrer les données de la cartographie en temps réel, afin de les afficher sur le site du projet.
A la place de la recherche sur OpenCv, Erwan propose d'ajouter en fonction de l'avancement de mon projet en mi-janvier/ février du machine Learning. Pour le permettre sur la RP4, ils ont acheté Coral c'est un USB Accelerator.
ROS
Etant donné que je vais totalement me concentrer sur ROS pour la suite du projet, j'ai choisi de me former à l'aide du site Udemy. Voici le lien du cours que je suis : https://www.udemy.com/course/ros-essentials/
J'ai également regardé les trois vidéos suivantes : 1, 2 et 3. Ce sont des cours concernant ROS et plus précisément Hector SLAM, elles ont été réalisées par Paritosh Kelkar un diplômé de l'université de Pennsylvanie.
Ces cours m'ont vraiment aidés à mieux comprendre comment fonctionne ROS, ce qui m'a permis d'avancer dans mon projet.
Enregistrer des données de cartographie
rosbag record -a
Cette commande permet d'enregistrer toutes les données en cours dans un format '.bag'. Il faut maintenant savoir comment les extraire pour les analyser.
ROS Serial
Grâce aux cours que j'ai suivi, j'ai appris qu'il était possible de dialoguer en communication série entre Arduino et ROS.
cd <ws>/src git clone https://github.com/ros-drivers/rosserial.git cd .. catkin_make
<ws> est le répertoire catkin_ws.
Il faut ensuite se déplacer dans le dossier des libraires d'Arduino, pour ajouter la librairie de ROS:
cd <sketchbook>/libraries rm -rf ros_lib rosrun rosserial_arduino make_libraries.py .
Une fois la libraire ajoutée, il faut ouvrir Arduino, 'File', 'Example' et choisir dans un exemple depuis ros_lib.
Hello World
Dans un premier temps, j'ai choisi l'exemple 'Hello World' que j'ai téléversé. J'ai ouvert trois terminaux sur le bureau de la RP4 avec les commandes suivantes:
Terminal 1 | Terminal 2 |
---|---|
roscore | rosrun roserial-python serial_node.py /dev/ttyUSB1
Permet d'établir la communication série avec le port ttyUSB1 => Arduino |
Terminal 3 | |
rostopic echo /chatter
Affiche les messages envoyés par l'arduino (≃ minicom) |
Dans ce premier exemple, l'Arduino joue le rôle de Publisher et ROS le rôle de Subscriber. Le second exemple que j'ai suivi est 'Blink', son code permet de changer l'état d'un LED lorsque l'Arduino reçoit un message vide.
Blink Led
Terminal 1 | Terminal 2 |
---|---|
roscore | rosrun roserial-python serial_node.py /dev/ttyUSB1
Permet d'établir la communication série avec le port ttyUSB1 => Arduino |
Terminal 3 | |
rostopic pug toggle_led std_msgs/Empty --once
Permet d'envoyer un message vide sur la liaison série . |
Dans ce second exemple, l'Arduino joue le rôle de Subscriber et ROS le rôle de Publisher, parce que c'est un des noeuds de ROS qui envoie un message et c'est Arduino qui attend/écoute. Dans cet exemple, l'arudino attend un message vide. J'ai modifié le code pour qu'il attende la valeur 2. La commande du terminal 3 devient alors :
rostopic pug toggle_led std_msgs/Int32 2 --once
Déplacement du robot
Le robot est commandé à distance depuis le site du projet, pour y arriver j'utilise des websockets qui envoient des données en liaison série à l'arduino. Lorsqu'il reçoit '1' le robot avance, lorsqu'il reçoit '2', le robot recule et il tourne lorsqu'il reçoit '3'. J'ai donc continué la modification du code Blink pour faire apparaitre ces conditions. J'arrive à présent à déplacer mon Robot en utilisant ROS.
Semaine 14 : 16 - 22 Décembre (Soutenance 1)
Voici un aperçu de l'avancement de mon projet en vidéo:
Dans un premier temps, je lance ROS :
- roscore
- roslaunch ydlidar lidar.launch
- roslaunch hector_slam tutorial.launch
Ensuite, je permets la communication entre mon site => la Raspberry Pi => et le Robot (Arduino) à l'aide des websockets.
On peut enfin voir, que lorsque le robot se déplace la cartographie se construit en même temps.
Semaines 15 - 16 : 6 - 19 janvier
Problème de shift
La vidéo de la rubrique précédente montre que la cartographie fonctionne très bien lorsque qu'il avance en ligne droite. J'ai fait d'autres tests lorsque le robot tourne, voici le résultat :
Ce problème est dû à des mouvements brusques du robot, lorsqu'il va trop vite : le phénomène de shift. Cela arrive souvent lorsque le robot tourne de façon trop rapide. Mais c'est également dû au fait que le robot n'est pas "solide". Lorsqu'il avance avec une vitesse importante et qu'il freine subitement, la plateforme sur laquelle est fixée le Lidar ne reste pas parallèle au sol. C'est à cause des suspensions de mauvaise qualité, le lidar qui est placé sur le robot change de position et ne reste pas vraiment horizontal.
Autre piste de recherche : Exploitation des données du fichier .bag
Lorsque je cherchais à enregistrer les données de la cartographie, j'ai réussi à enregistrer un fichier sous le format .bag. En faisant des recherches sur internet, j'ai trouvé un script qui permet de convertir un fichier . bag en un fichier .csv. Je garde en tête cette piste, si je n'arrive pas déporté Vos sur mon site Web.
Contrôle à distance de la Rapberrypi
Depuis le début de ce projet, j'utilise le desktop de la RP plutôt que son contrôle uniquement par ligne de commandes en shh. L'un des inconvénients majeurs était que je devais toujours avoir un câble HMDI qui reliait le robot à un écran, mais ce n'est pas pratique lorsqu'on souhaite que le robot se déplace dans une pièce.
Screen Recorder
Dans un premier temps, j'ai travaillé en effectuant des enregistrements vidéos de mon écran avec l'application lorsqu'il n'était pas branché à mon écran. Ca fonctionne mais ce n'est pas pratique.
sudo apt-get update sudo apt-get install simplescreenrecorder
Export d'affichage par SSH
Ensuite, j'ai fait des recherches pour pouvoir me connecter en ssh à la RP mais avec l'affichage graphique.
ssh -X -Y pi@172.20.10.2
J'ai réussi à afficher mon bureau à distance sur mon ordinateur, mais lorsque je lançais ROS (RViz), j'avais un message d'erreur qui m'indiquait une incompatibilité du à un problème interne. Donc cette solution n'est pas envisageable.
Serveur VNC
Enfin, j'ai essayé une dernière solution : screen sharing depuis un Mac. Sur la RP :
Menu > Raspberry Pi Configuration > Activer VNC
Une fois que la raspberry a redémarré, une icône VNC est visible sur la barre du menu. Il faut la sélectionner : Sur RP - VNC :
Menu > Options > Sécurité Encryption = Prefer off Authentication = VNC Password
Enfin il faut choisir un mot de passe.
Sur le Mac : Il faut ouvrir l'application Partage d'écran et entrer l'adresse IP de la RP et le mot de passe qui a été crée dans les paramètres de VNC.
Macintosh HD ▸ Système ▸ Bibliothèque ▸ CoreServices ▸ Applications ▸ Partage d'écran (en Français ou Screen Sharing en Anglais).
J'ai donc réussi avec cette dernière option à contrôler à distance la RP et à lancer ROS depuis mon mac !
Formation ROS Turtlebot
TurtleBot est un kit de robot avec un logiciel open source. TurtleBot a été créé au Willow Garage par Melonee Wise et Tully Foote en novembre 2010. Ce robot est capable de circuler dans votre maison, de voir en 3D la carte de la pièce. L'objectif de cette formation est de pouvoir rendre mon robot compatible avec ROS et donc de pouvoir le contrôler directement depuis la plateforme de ROS. Voici la page où l'on trouve le dossier nécessaire. Pour les personnes n'ayant pas le robot Turtlebot, il existe une simulation. Dans un premier temps, il faut lancer :
$ roscore $ rosrun turtlesim turtlesim_node
L'objectif à présent est de déplacer cette tortue dans son environnement. Il est tout à fait possible de la déplacer en utilisant les touches ( up, down, right et left) avec la commande ci dessous :
$ rosrun turtlesim turtle_teleop_key
Mais cela ne fonctionnera pas avec un vrai robot par la suite. Pour que ROS puisse contrôler un robot il envoie les coordonnées dans un message de type Twist :
geometry_msgs/Vector3 linear geometry_msgs/Vector3 angular
C'est un message qui se compose de deux vecteurs, un vecteur linéaire avec trois valeurs et un second vecteur pour trois valeurs angulaires.
Il existe des limitations en ce qui concerne le robot:
- La navigation n'est possible que pour des robots "diferential drive" et des robots holonomiques. => J'ai donc besoin de rajouter des encodeurs à mes roues motrices.
- Le robot reçoit un message de type twist avec des vitesses X, Y et Thêta qui lui permettent de se déplacer. Si le robot n'est pas en mesure de les comprendre, il est possible créer un nœud ROS qui convertit un message vers un autre de type twist. => Il faut comprendre le fonctionnement des ces vecteurs sur le déplacement du robot.
Je vais donc opter pour le déplacement avec les deux vecteurs. J'ai fait des recherches concernant 'diferential drive' et je suis tombée sur ce site qui explique bien le fonctionnement mathématique avec un corrigé d'un exercice. J'ai remarqué que seules deux valeurs sur les 6 sont utiles. X permet d'avancer d'une distance et θz permet de tourner de l'angle indiqué.
Vecteur Linéaire | Vecteur angulaire |
---|---|
x y z |
θx θy θz |
Pour déplacer la tortue avec ce type de message :
$ rostopic pub /turtle1/cmd_vel geometry_msgs/Twist -1 -- '[ Xvalue, Yvalue, Zvalue ]' '[θXvalue, θYvalue, θZvalue ]'
Par exemple pour que le robot puisse se déplacer en réalisant la forme d'un carré, voici les commandes à réaliser quatre fois :
$ rostopic pub /turtle1/cmd_vel geometry_msgs/Twist -1 -- '[2,0,0]' '[0,0,0]' // Le robot avance de 2 $ rostopic pub /turtle1/cmd_vel geometry_msgs/Twist -1 -- '[0,0,0]' '[0,0,1.57]' // Le robot tourne sur lui même de Pi/2 (=1.57)
Contrôle du robot avec ROS
J'aimerai pour la suite du projet, pouvoir contrôler le robot avec l'interface graphique de ROS. Pour le moment je contrôle les moteurs du robot avec en imposant une valeur entre 0 et 255 à chaque roue. (Pour rappel, le robot est équipé de 6 moteurs à courant continu).
Avec ROS, la seule façon de contrôler un robot c'est en lui imposant les valeurs de vitesse x, y et θ. Mais je n'ai pas d'encodeur sur mes moteurs. Pour le moment, il faut que je trouve une solution pour controler mon robot en vitesse. A compléter
Semaines 17 et 18 : 20 Janvier - 2 février
Comme dit précédemment, pour contrôler mon robot, j'ai besoin d'encodeurs sur les roues motrices. J'ai récupéré celui ci de chez Monsieur Redon.
Encodeurs incrémentals
La plupart des encodeurs pour robots mobiles utilisent des capteurs optiques. L’idée est de placer un disque alternant des zones transparentes (ou tout simplement des trous) et opaques (le disque lui-même) entre un capteur de lumière et un émetteur de lumière. Ce dernier se place sur l'axe de rotation de la roue. La fréquence d’apparition des zones blanches et noires devant le capteur de lumière va indiquer la vitesse de rotation. Le schéma suivant présente le principe de fonctionnement basique de l’encodeur :
Modélisations
Le problème qui se pose est que je n'ai pas suffisamment de place pour positionner l'encodeur sur l'axe du moteur.
> Modélisation 1
Dans un premier temps, j'ai modélisé une pièce 3D qui permettait de rallonger l'axe : (cf Modélisation 1) Cette solution n'a pas fonctionnée parce que les valeurs sont tellement petites (0,3 cm de diamètre) que ça n'a pas abouti. L'imprimante 3D n'a pas une précision assez bonne.
> Modélisation 2
J'ai ensuite modélisé deux pièces, un support pour accrocher l'encodeur à la structure du robot et une roue à la bonne échelle pour qu'elle puisse tenir sur l'axe des coupleurs plutôt que sur l'axe du moteur. (cf Modélisation 2)
Sur internet, il n y a pas de documentations concernant cette version d'encodeur. Mais il y a trois pins :
- 5V
- GRND
- OUT : Ce qui indique qu'il un signal dès que la lumière de la LED est reçue par le capteur de lumière.
Voici le rendu :
J'ai imprimé les pièces en double afin de placer les encodeurs sur les deux roues à l'avant.
> Modélisation 3
[EDIT] Après avoir testé plusieurs fois, les résultats n'étaient pas convaincants, ils manquent de précisions. A force de déplacer les roues du robots. le centre du disque de l'encodeur s'élargie, ce qui implique qu'il ne tourne plus en même temps que la roue. Cela fausse donc les résultats. L'autre pièce est aussi problématique puisqu'elle s'accroche directement sur les suspensions du robot. Ce choix n'était pas judicieux puisque le robot est très peu droit. Il faut donc réaliser une nouvelle modélisation des pièces. (cf Modélisation 3)
Voici le rendu :
Récapitulatif
Modélisation 1 | Modélisation 2 | Modélisation 3 | |||||||||
|
|
|
Code Arduino
J'ai intégré le code de l'encodeur dans mon code Arduino qui permet de déplacer le robot.
#include "EncoderStepCounter.h" #define ENCODER_PIN1 2 #define ENCODER_INT1 digitalPinToInterrupt(ENCODER_PIN1) EncoderStepCounter encoder(ENCODER_PIN1, ENCODER_PIN1 );
// Dans la fonction setup(), on définit les interruptions sur fronts montants
encoder.begin();
attachInterrupt(ENCODER_INT1, interrupt, RISING);
// La fonction exécutée lorsqu'il y a une interruption
void interrupt() {
encoder.tick();
}
// Dans la fonction loop() detachInterrupt(ENCODER_INT1); signed char pos = encoder.getPosition(); if (pos != 0) { count += pos; encoder.reset(); Serial.print(count); Serial.println(" cm"); } if (count >= 100){ count=0; moveit(0,0); // fonction qui permet d'arrêter la rotation des roues du robot } attachInterrupt(ENCODER_INT1, interrupt, RISING);
J'affiche la distance parcourue à l'aide de ce calcul : Il ya 25 trous sur le disque, les roues ont un rayon de 4 cm donc une circonférence de 25 cm(2 π R). Donc à chaque interruption (à chaque détection d'un trou) le robot avance d'un cm. Le soucis avec ces encodeurs c'est qu'ils ne prennent pas en compte le sens de rotation du disque.
Ce code ne prend en compte qu'un encodeur sur deux. L'objectif est de l'adapter pour deux, de faire une moyenne du nombre d'interactions pour minimiser les erreurs. Pour le moment mon code me permet d'avancer d'un mètre et d'arrêter le robot. Après plusieurs essais, mon robot avance réellement d'une valeur comprise entre 80 cm et 120 cm. Cette solution fonctionne mais n'est pas très fiable.
Compas
Voici la référence de l'accéléromètre que je vais utiliser pour ce projet : Adafruit Triple-axis Accelerometer+Magnetometer (Compass) Board - LSM303 [ADA1120]
J'ai utilisé la datasheet pour en savoir plus sur ce composant. Il permet d'avoir 3 variables de champ magnétique et 3 variables d'accélération. Il utilise le bus I2C pour envoyer les données en liaison série.
Cablâge
Comme j'utilise déjà les pins SDA et SDL pour la carte extensive qui contrôle les moteurs du robot, je me suis renseignée sur internet pour trouver une solution. Sur ce site, j'ai trouvé une information intéressante : il est possible d'avoir à nouveau deux pins SDA et SDL en utilisant les pins A5 et A4.
"Ceux qui disposent de l'Arduino Uno ou d'une carte compatible utiliseront les connecteurs A4 pour SDA (les données) et A5 pour SCL (l'horloge)"
Donc en résumé :
- VCC : 5V
- GND : GND
- SDA : A4
- SDL : A5
Code Arduino
Une fois le câblage réalisé, j'ai récupéré une librairie du composant LSM303DHL sur le logiciel Arduino que j'ai inclus dans le code. J'ai exécuté un exemple qu'Arduino propose, voici le résultat du moniteur série :
Je récupère bien les données x, y et z. Mais pour ROS ce n'est pas le format de données qu'il me faut. Il y a une relation mathématique qui me permet de convertir ces trois données en une donnée en degré:
angle= 180*atan2(magy,magx)/PI | |
A présent, j'obtiens bien les données en degrés. Les valeurs sont comprises entre 0 et 360°. |
Semaine 19 : 3 - 9 Février
Liaison ROS et Robot pour commander le robot
> Comment est structuré ROS
ROS crée un réseau où tous les processus sont connectés. N'importe quel nœud du système peut accéder à ce réseau, interagir avec d'autres nœuds, voir les informations qu'ils envoient et transmettre des données au réseau:
Voici une liste des principaux éléments de ROS et quelques commandes utiles :
- Nodes (Nœuds): les nœuds sont des processus où le calcul est effectué. Pour avoir un processus qui peut interagir avec d'autres nœuds, il faut créer un nœud avec ce processus pour le connecter au réseau ROS. Habituellement, un système aura de nombreux nœuds pour contrôler différentes fonctions. Il est préférable d'avoir de nombreux nœuds qui ne fournissent qu'une seule fonctionnalité, plutôt que d'avoir un grand nœud qui fait tout dans le système. Les nœuds sont écrits avec une bibliothèque client ROS, par exemple, roscpp ou rospy.
rosnode info NODE // Affiche des informations sur un noeud rosnode kill NODE // Arrête un noeud en cours d'exécution rosnode list // Liste les noeuds actifs rosnode ping NODE // Teste la connexion avec le noeud
- Master (Le maître) : le maître fournit l'enregistrement des noms et le service de recherche au reste des nœuds. Il établit également des connexions entre les nœuds.
- Messages : les nœuds communiquent entre eux par le biais de messages. Un message contient des données qui fournissent des informations à d'autres nœuds. ROS propose de nombreux types de messages, et vous pouvez également développer votre propre type de message à l'aide de types de messages standard.
rosmsg list // Affiche tous les massages rosmsg package // Affiche les messages d'un package
- Topic : Chaque message doit avoir un nom pour être acheminé par le réseau ROS. Lorsqu'un nœud envoie des données, le nœud publie un sujet. Les nœuds peuvent recevoir des sujets d'autres nœuds en s'abonnant simplement au sujet. Un nœud peut s'abonner à un sujet même s'il n'y a aucun autre nœud publiant sur ce sujet spécifique. Il est important que les noms des sujets soient uniques pour éviter les problèmes et la confusion entre les sujets portant le même nom.
rostopic echo /topic // Affiche les messages rostopic find message_type // Trouver un Topic par son nom rostopic hz /topic // Affiche la fréquence d'affichage rostopic info /topic // Affiche des informations sur le topic, le type du message, le publishers et subscribers. rostopic list // Affiche les topics en cours rostopic pub /topic type args // Permet de publier une donnée dans un topic
- Bag : les bags sont un format pour enregistrer et lire les données des messages ROS. Les bags sont un mécanisme important pour stocker des données, telles que les données de capteurs, qui peuvent être difficiles à collecter mais qui sont nécessaires pour développer et tester des algorithmes.
rosbag // Permet d'enregistrer des données
> Première version de code ROS
A compléter
Déplacement non linéaire du robot
Lorsque je commande le robot pour qu'il avance d'un mètre vers l'avant, il a tendance à dévier vers la gauche. Ce qui n'est pas normal, puisque j'impose à chaque roue la même puissance. C'est possible que ça soit un problème du châssis, ou bien que certains coupleurs des moteurs ne soient pas bien visés. Je pense aussi que le problème pourrait venir de tous les éléments que j'ai rajouté sur le robot (batterie portable, Lidar, Raspberry Pi), leur poids doit avoir un impact sur l'inclinaison du robot ce qui pourrait imposer une force vers le bas d'un coté du robot. Pour essayer de voir si le problème vient de la dernière supposition, je vais modéliser un étage supplémentaire sur le robot. Cela permettra de mieux équilibrer les poids des équipements sur tout le robot.
Modélisations Voici le rendu :
Ce n'était pas le problème, puisqu'en équilibrant le poids sur le robot, le robot dérive tout de même vers la gauche. Pour corriger ce problème, je vais donc mettre plus de puissance sur les roues de gauche pour essayer de corriger le parcours du robot. Pour avoir un retour du parcours des roues des deux côtés, je place un deuxième encodeur sur la roue du milieu à gauche.
REMARQUE : Le disque de l'encodeur ne peut pas être imprimé avec du PLA blanc, il faut que ca soit une couleur sombre.
On remarque bien sur la première photo que les roues de droite effectuent plus de tours que celles de gauches, environ une dizaine de plus. En modifiant le code et en augmentant la puissance sur les roues de gauches, on obtient les résultats sur la deuxième photo. Le robot avance droit maintenant.
Problème Boussole
La semaine dernière quand j'avais testé la boussole (pas sur le robot), je pensais avoir des résultats assez cohérents. Mais cette semaine en la plaçant sur le robot, je me suis rendue compte que les valeurs étaient pas utilisables. J'ai récupéré les valeurs que j'obtenais en fonction de l'orientation du robot (cf image à droite). J'ai ensuite resté la boussole e, dehors du robot, (cf à gauche), j'obtiens des valeurs plus cohérentes mais ce n'est pas suffisant pour bien contrôler le robot (un quart de cercle représente 180° et les trois autres 180°). Le problème vient des champs magnétiques présents sur le robot qui perturbent la boussole.
Ajout de la caméra sur le site
pi@raspberrypi: ~/ sudo apt-get install motion pi@raspberrypi: ~/mkdir /home/pi/motion pi@raspberrypi: ~/chmod 755 /home/pi/motion
Il faut ensuite changer le fichier de configuration suivant :
pi@raspberrypi: ~/ sudo vim /etc/motion/motion.conf daemon on framerate 15 webcam_motion on webcam_localhost off
pi@raspberrypi: ~/ sudo vim /etc/default/motion // modifier start_motion_daemon=yes
Pour lancer le broadcast :
pi@raspberrypi: ~/ sudo service motion start
Il suffit d'aller sur le lien suivant : localhost:8080 pour accéder à l'image de la caméra.
Publication de la carte sur un site web
A compléter
Script bash pour lancer toutes les commandes
Pour lancer le noyau ROS, le Lidar, Hector, le serveur ROS, il y a 5 commandes a exécuter depuis le terminal. Pour améliorer le lancement, j'ai écris un script bash qui permet de tout lancer à distance. Il regroupe simplement les commandes suivantes :
roscore roslaunch ydlidar lidar.launch roslaunch hector_slam slamit.launch rosrun bridge server rosrun rosserial
Semaine 20 : 10 - 16 Février
Semaine 21 : 17 - 21 Février (Soutenance 2)
Documentation
Documents Rendus
Rapport intermédiaire : Fichier:P9 Rapport1 MEJBAR.pdf
Soutenance intermédiaire : Fichier:P9 RapportSoutenance MEJBAR.pdf
Rapport final : Fichier:P9 Rapport2 MEJBAR.pdf
Soutenance finale : Fichier:P9 Soutenance2 MEJBAR.pdf