IMA5 2019/2020 P09

De Wiki de Projets IMA
Révision datée du 6 décembre 2019 à 08:51 par Lmejbar (discussion | contributions) (ROS Kinetic)

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 S15 S16 S17 S18 S19 S20 S21 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
Formation Machine Learning 2 2
Formation Partie Cartographie (LIDAR) 4 2 3 9
Formation Computer Vision 10 10
Formation ROS 4 4
Code
Code Arduino 3 3 6
Code C++ : Lidar 2 4 6
Code du site Web 3 4 4 2 13
Code Python : Open CV 8 8
Rencontre Tuteurs
Rencontre Bonduelle 1 1 2 2 4 4 4 18
Documentation
Remplissage du wiki 2 1 2 3 3 2 3 16
Documentation pour Bonduelle
Préparation Soutenance 1 3 3
Préparation Soutenance 2
Rédaction du rapport (Interm et Final)
Total 11 6 12 12 20 13 38

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.

Semaine 12 : 2 - 8 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'outils qu'ils envisageaient 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.

ROS Kinetic

Il faut que je trouve un package ou un outil fournit par ROS pour enregistrer la cartographie et l'envoyer sur le site du projet. 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

Semaine 13 : 9 - 15 Décembre

Semaine 14 : 16 - 22 Décembre (Soutenance 1)

Semaine 15 : 6 - 11 Janvier

Semaine 16 : 13 - 19 Janvier

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