IMA5 2019/2020 P09

De Wiki de Projets IMA
Révision datée du 19 janvier 2020 à 11:37 par Lmejbar (discussion | contributions) (Contrôle à distance de la Rapberrypi)

Sommaire


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 :

  • 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 S1 S2 S3 S4 S5-S6 S7 S8-11 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
Formation - Documentation
Formation Machine Learning 2 2
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 15
Code C++ : Lidar 2 4 6
Code du site Web 3 4 4 2 13
Code Python : Open CV 8 8
Code ROS 5 4 5 14
Rencontre Tuteurs
Rencontre Bonduelle 1 1 2 2 4 4 4 2 2 2 24
Documentation
Remplissage du wiki 2 1 2 3 3 2 3 1 4 21
Documentation pour Bonduelle 2 2
Préparation Soutenance 1 3 2 4 9
Préparation Soutenance 2
Rédaction du rapport (Interm et Final) 4 4 8
Total 11 6 12 12 20 13 43 15 8 12 26

Calendrier prévisionnel

P9 calendrier.png

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€.
P9 IROBOT.jpg
  • 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.


Vidéo du robot

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.

Photo 1
Robot en montage.
Photo 2
Robot monté.

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 :

Photo 3
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 connections 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

Papier 1 : Robot Mapping for Rescue Robot, Chercheurs : Nagesh Adluru, Longin Jan Latecki, Rolf Lakaemper, Raj Madhavan - 2006

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.


P9 these1.png


Thèse 2 : Application of Simplified Complex-Value Adaptive Neuro-Fuzzy Inference System for Extended Kalman Filter in Robot Localization, Auteur : Nickolas Tsz Hong Lam - 2018

  • 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.


P9 these2.png

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:

P09-robot.gif

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:

P9 orientationRobot.jpeg

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 :

Photo 5
Exécution du fichier ./ylidar_test

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:

Photo 6 Affichage des valeurs : distance et angle


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
P9 repère.png
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.


P9cartographieE306.png
P9cartographieE306lengendee.png


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 :

P9CarthographieBonduelle.png P9CarthographieBonduelleAnalyse.png

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 :

Rendu de la cartographie en utilisant l'outils ROS


[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 :

P9 Foncitonnement acquisitionadistance.png


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:

Croquis du site

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ées.

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:

P9 Site.png

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 '


  • 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.


  • Concernant la cartographie :
Lancer l'acquisition :
Le fonctionnement de ce bouton est expliqué dans la partie suivante [4.5.2].

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 coté 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.

P9 printcanvas.png

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.

Comparaison des résultats
Résultats Commentaires
P9 relierPoints.png
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.
P9 printcanvasGray.png
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.
P9 printcanvasShape.png
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.
P9 TheseContour.png
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  :

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.


Comparaison des résultats
Résultats Commentaires
P9 SURF1.png
Comme on peut voir sur cette image, Python n'a détecté que 2 Keypoints et ils sont faux !
P9 SURF2.png
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).
P9 SURF3.png
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.
P9 SURF4.png
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 :

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
P9 ROS HECTOR1.png
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
P9 ROS HECTOR2.png
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.

P9 Coral.jpg

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/

P9 ROS UDEMY.png


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 :

P9 navigation shift.gif

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 un vitesse importante et qu'il freine subitement. 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 enregistrement 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).
P9 DesktopRPI.png

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 
P9 turttlesim.png

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)
P9 turtle1 carre.png

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

Semaine 17 : 20 - 26 Janvier

Semaine 18 : 27 Janv - 2 Février

Semaine 19 : 3 - 9 Février

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