<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="fr">
		<id>https://wiki-ima.plil.fr/mediawiki//api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Tdanel</id>
		<title>Wiki d'activités IMA - Contributions de l’utilisateur [fr]</title>
		<link rel="self" type="application/atom+xml" href="https://wiki-ima.plil.fr/mediawiki//api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Tdanel"/>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php/Sp%C3%A9cial:Contributions/Tdanel"/>
		<updated>2026-04-24T23:59:37Z</updated>
		<subtitle>Contributions de l’utilisateur</subtitle>
		<generator>MediaWiki 1.29.2</generator>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=Projets_IMA5_2015/2016&amp;diff=27928</id>
		<title>Projets IMA5 2015/2016</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=Projets_IMA5_2015/2016&amp;diff=27928"/>
				<updated>2016-02-27T16:47:44Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Répartition des binômes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Merci de référencer vos pages de projets ici. Merci aussi d'uniformiser vos formats que ce soit en regardant la présentation des projets déjà créés ou en allant modifier le format des précédents si votre façon de faire vous semble la meilleure. Dans tous les cas un minimum de communication entre les binômes est conseillée.&lt;br /&gt;
&lt;br /&gt;
Toutes les sources doivent être déposées sur notre archive GIT. Le service est disponible à l'URL [https://archives.plil.fr archives.plil.fr]. Connectez-vous avec vos identifiants Polytech'Lille. Sauf indication contraire de vos encadrants, rendez le projet public et mettez le lien sur votre Wiki. Vous pouvez trouver de la documentation sur ce système d'archives sur ce [https://git-scm.com/book/fr/v1 site].&lt;br /&gt;
&lt;br /&gt;
== Répartition des binômes ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table border=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;th&amp;gt;Projet&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th&amp;gt;Elèves&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th&amp;gt;Encadrant Ecole&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th&amp;gt;Rapport décembre&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th&amp;gt;Rapports finaux&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th&amp;gt;Vidéo&amp;lt;/th&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[P1 Convertisseur DC/DC pour réseau MTDC]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Mehmet Ilter &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Philippe DELARUE &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[P2 Data Logger]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Hidéo VINOT&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Alexandre Boé / Thomas Vantroys &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; 15/12/2015 12;00&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; 23/02/2016 12:18, [[Fichier: Dossier_soutenance_P2_Data_Logger_Hideo_VINOT_IMA5SC_2015.pdf]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; mercredi 24 février à 10h avec L. Engels&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[P4 Jukebox multi-pièces]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Alexandre Jouy / Julien hérin &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Rodolphe Astori / Xavier Redon / Alexandre Boé / Thomas Vantroys &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; [[Fichier:Pre_soutenance_PFE_Jouy_herin.pdf]] &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; [[Fichier:Rapport PFE P4 Julien HERIN.pdf]] [[Fichier:Rapport_PFE_Jouy.zip]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; RDV pris le 23/02 avec L. Engels&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[P9 Système d'hébergement domestique]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Romain Libaert / Timothée Teneur &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Xavier Redon / Alexandre Boé / Thomas Vantroys &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; 15/12/2015, 10:21, [[Fichier:P9_LIBAERT_TENEUR_DEC15.pdf]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; [[Fichier:PFE_Final_TENEUR_LIBAERT.pdf]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Tournée le 22/02 par M. Engels&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[P10 LILLIAD: Connected Learning Center | P10 LILLIAD: learning center connecté]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Mageshwaran Sekar &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Alexandre Boé / Thomas Vantroys &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; 15/12/2015,07:48, [[Fichier:P10_FYP_December_Report_M_SEKAR.pdf]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; [[Fichier:FYP-P10-Lilliad-MSEKAR.pdf]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Fait maison&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[P11 Spectateur augmenté]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Teresa Tumbragel &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Alexandre Boé / Thomas Vantroys &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; [[Fichier:Teresa Tumbragel-Rapport Spectateur Augmente.pdf]] &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; NA &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[P12 Capteurs enfouis pour vieillissement du béton]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; JULITA Alex &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Alexandre Boé / Thomas Vantroys &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[P14 Localisation dans le corps humain]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Matthieu Marcadet &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Alexandre Boé / Thomas Vantroys &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; 15/12/2015, 10:52, [[Fichier:Rapport_intermediaire_PFE_Marcadet.pdf]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; [[Fichier:Rapport_PFE_P14_Matthieu_Marcadet.pdf]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; RDV pris le 24/02 avec L. Engels&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[P18 Meuble intelligent]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Kevin Colautti / Benjamin Lefort &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Rémy Bernard / Alexandre Boé / Xavier Redon / Thomas Vantroys &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; 14/12/2015, 14:44, [[Fichier:P18_pre_soutenance.pdf]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; [[Fichier:Rapport_P18_COLAUTTI_LEFORT.pdf]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Tournée le 22/02 par M. Engels&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[Automatic Soldering System Project|P20 Placeur de composants sur PCB]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Jean Wasilewski &amp;amp; Pierre Letousey &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Xavier Redon / Thomas Vantroys / Alexandre Boé &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; [[Fichier:P20_ASSP.pdf]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; [[Fichier:IMA5-ASSP-JWPL.pdf]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Rendez-vous pris avec M. Engels le vendredi 25 Février à 10h &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[P24 Nuage pour sites Web]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Jeremie Denechaud / Thibaut Scholaert &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Xavier Redon / Thomas Vantroys &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; 15/12/2015, 12:02, [[Fichier:P24_Denechaud_Scholaert.pdf| Rapport intermédiaire de projet]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; [[Fichier:PFE_DENECHAUD_SCHOLAERT.pdf]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Fait Maison&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[P25 Architecture ROS pour des véhicules autonomes intelligents]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Jean-Michel Tournier / Cyril Smagghe &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Vincent Coelen et Rochdi Merzouki &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; 15/12/2015,09:04, [[Fichier:P25-2015_Smagghe_Tournier_decembre.pdf]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; [[Fichier:Rapport_final_P25_Smagghe_Tournier.pdf]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;RDV mercredi 24 15h &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[P26 Robot de forgeage et d’usinage]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Bertrand Yvernault / Louis Thebault &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Rochdi Merzouki &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; 14/12/2015, 17:51&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Tournée le 22/02 par M. Engels &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[P27 Robot de fraiseuse]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Flavien Royer / Maxime Morisse &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Rochdi Merzouki &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; 14/12/2015, 19:06, [[Fichier:Rapport_Royer_Morisse.pdf]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[Fichier:RapportPFE_ROYER_MORISSE.pdf]] &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; mardi 23 février à 11h15 avec Laurent Engels&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[P30 Thermostat connecté et intelligent]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; TISSOT Elise / TIRABY Céline &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Guillaume Renault / Alexandre Boé / Xavier Redon &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;15/12/2015, 00:35, [[Fichier:Rapport_PFE_TISSOT_TIRABY.pdf‎ ]] &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; [[Fichier:Rapport_final_PFE_TISSOT_TIRABY.pdf]] &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Tournée le 19/02 par L. Engels &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[P32 Récupération d'énergie pour balise BLE]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Quentin Sultana &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Frédéric Giraud / Alexandre Boé / Thomas Vantroys &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; 13/12/2015, 19:31, [[Fichier:CR Miprojet_Sultana.pdf]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; [[Fichier:Rapport_P32_Sultana.pdf]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; RDV L. Engels le 24/02 &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[P33 Réalisations en faveur de l'accessibilité de jeux vidéos]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Jérôme Bailet / Mehdi Zeggaï &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; GAPAS / Laurent Grisoni / Thomas Vantroys &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; 14/12/2015, 10:54, [[Fichier:PFE_IMA5_Rapport_intermediaire_Bailet_Zeggai.pdf]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; [[Fichier:PFE_IMA5_P33_Rapport_final_Bailet_Zeggai.pdf]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; RDV L. Engels le 25/02 &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[P35 Robot de test pour le sport de Golf]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Deborah Saunders &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Rochdi Merzouki &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; 15/12/2015, 12:07&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Vu avec M.Engels pour montage des videos avec voix off&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[P34 Optimisation de trajectoire pour un robot de curiethérapie]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Sandra HAGE CHEHADE / Thomas DANEL &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Vincent COELEN / Rochdi MERZOUKI &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; 15/12/2015, 12:02&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; 23/02/2016, 12:36&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Tournée le 25/02 avec L. Engels&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[P40 Maquette mécatronique durcie d'ascenseur 5 étages]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Louis CHAUCHARD / Romain IMBERT &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Blaise CONRARD &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; 14/12/2015, 19:21&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; [[Fichier:IMA5_P40_Chauchard_Imbert_RapportFinal.pdf‎]] &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; RDV L. Engels le 23/02 &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[P13 Plateforme expérimentation IOT]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; ROCHE François &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Alexandre Boé / Thomas Vantroys &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; 14/12/2015, 19:37, [[Fichier:PFE_P13_Plateforme_expérimentation_IOT.pdf]] &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; [[Fichier:PFE_P13-Plateforme_expérimentation.pdf]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Tournée le 22/02 par M. Engels &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[Implantation d'un filtre FIR-FX-LMS sur FPGA pour l'annulation de Bruit Acoustique]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Bown Alexander / Piat Valentin &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Alexandre Boé / Thomas Vantroys &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; NA &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[Pilulier automatique]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Manouk Simon / Corentin Duplouy &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Alexandre Boé / Thomas Vantroys &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; NA &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; [[Fichier:Rapport Duplouy Simon.pdf]] &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; RDV L. Engels le 23/02 &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=P34_Optimisation_de_trajectoire_pour_un_robot_de_curieth%C3%A9rapie&amp;diff=21434</id>
		<title>P34 Optimisation de trajectoire pour un robot de curiethérapie</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=P34_Optimisation_de_trajectoire_pour_un_robot_de_curieth%C3%A9rapie&amp;diff=21434"/>
				<updated>2015-09-24T11:56:40Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : Page créée avec « ==Cahier des charges== ===Présentation générale du projet===  ====Contexte====  ====Objectif du projet====  ====Description du projet====   ====Choix techniques : matérie... »&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Cahier des charges==&lt;br /&gt;
===Présentation générale du projet===&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
 &lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
==Étapes du projet==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Partie 1 : &amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Partie 2 : &amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Partie 3 : &amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Suivi de l'avancement du Projet==&lt;br /&gt;
&lt;br /&gt;
===Semaine 1 (21/09/2015)===&lt;br /&gt;
&lt;br /&gt;
===Semaine 2 (28/09/2015)===&lt;br /&gt;
===Semaine 3 (05/10/2015)===&lt;br /&gt;
===Semaine 4 (12/10/2015)===&lt;br /&gt;
===Semaine 5 (19/10/2015)===&lt;br /&gt;
===Semaine 6 (26/10/2015)===&lt;br /&gt;
===Semaine 7 (02/11/2015)===&lt;br /&gt;
===Semaine 8 (09/11/2015)===&lt;br /&gt;
===Semaine 9 (16/11/2015)===&lt;br /&gt;
===Semaine 10 (23/11/2015)===&lt;br /&gt;
===Semaine 11 (30/11/2015)===&lt;br /&gt;
===Semaine 12 (07/12/2015)===&lt;br /&gt;
===Semaine 13 (14/12/2015)===&lt;br /&gt;
===Semaine 14 (04/01/2016)===&lt;br /&gt;
===Semaine 15 (11/01/2016)===&lt;br /&gt;
===Semaine 16 (18/01/2016)===&lt;br /&gt;
===Semaine 17 (25/01/2016)===&lt;br /&gt;
===Semaine 18 (01/02/2016)===&lt;br /&gt;
===Semaine 19 (08/02/2016)===&lt;br /&gt;
===Semaine 20 (15/02/2016)===&lt;br /&gt;
===Semaine 21 (22/02/2016)===&lt;br /&gt;
&lt;br /&gt;
== Fichiers Rendus ==&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=Projets_IMA5_2015/2016&amp;diff=21433</id>
		<title>Projets IMA5 2015/2016</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=Projets_IMA5_2015/2016&amp;diff=21433"/>
				<updated>2015-09-24T11:54:56Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Merci de référencer vos pages de projets ici. Merci aussi d'uniformiser vos formats que ce soit en regardant la présentation des projets déjà créés ou en allant modifier le format des précédents si votre façon de faire vous semble la meilleure. Dans tous les cas un minimum de communication entre les binômes est conseillée.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Répartition des binômes ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table border=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;th&amp;gt;Projet&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th&amp;gt;Elèves&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th&amp;gt;Encadrant Ecole&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th&amp;gt;Rapport décembre&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th&amp;gt;Rapports finaux&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th&amp;gt;Vidéo&amp;lt;/th&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[P1 Convertisseur DC/DC pour réseau MTDC]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Mehmet Ilter &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Philippe DELARUE &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[P9 Système d'hébergement domestique]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Romain Libaert / Timothée Teneur &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Xavier Redon / Alexandre Boé / Thomas Vantroys &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[P10 LILLIAD: learning center connecté]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Mageshwaran Sekar &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Alexandre Boé / Thomas Vantroys &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[P24 Nuage pour sites Web]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Jeremie Denechaud / Thibaut Scholaert &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Xavier Redon / Thomas Vantroys &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[P25 Architecture ROS pour des véhicules autonomes intelligents]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Jean-Michel Tournier / Cyril Smagghe &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Vincent Coelen et Rochdi Merzouki &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[P33 Réalisations en faveur de l'accessibilité de jeux vidéos]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Jérôme Bailet / Mehdi Zeggaï &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; GAPAS / Alexandre Boé / Thomas Vantroys &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[P35 Robot de test pour le sport de Golf]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Deborah Saunders &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Rochdi Merzouki &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[P34 Optimisation de trajectoire pour un robot de curiethérapie]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Sandra HAGE CHEHADE / Thomas DANEL &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; Vincent COELEN / Rochdi MERZOUKI &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=Projets_IMA4_SC_%26_SA_2014/2015&amp;diff=21177</id>
		<title>Projets IMA4 SC &amp; SA 2014/2015</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=Projets_IMA4_SC_%26_SA_2014/2015&amp;diff=21177"/>
				<updated>2015-05-11T23:18:24Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Notes sur les projets */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Merci de référencer vos pages de projets ici. Merci aussi d'uniformiser vos formats que ce soit en regardant la présentation des projets déjà créés ou en demandant une modification du format des précédents si votre façon de faire vous semble la meilleure. Dans tous les cas un minimum de communication entre les binômes est conseillée.&lt;br /&gt;
&lt;br /&gt;
== Répartition des binômes ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Projet !! Encadrants école !! Elèves&lt;br /&gt;
|-&lt;br /&gt;
| P1 [[Brique Lego augmentée]]&lt;br /&gt;
| Alexandre Boé / Thomas Vantroys / Xavier Redon / Emmanuelle Pichonat &lt;br /&gt;
| Alex JULITA / Déborah SAUNDERS &lt;br /&gt;
|-&lt;br /&gt;
| P4 [[Tracabilité hopital|Amélioration de la traçabilité en milieu hospitalier]]&lt;br /&gt;
| Alexandre Boé / Thomas Vantroys&lt;br /&gt;
| Julian BONVILLE / François ROCHE&lt;br /&gt;
|-&lt;br /&gt;
| P6 [[Vêtements intelligents]]&lt;br /&gt;
| Alexandre Boé / Thomas Vantroys&lt;br /&gt;
| Alexander BOWN / Valentin PIAT&lt;br /&gt;
|-&lt;br /&gt;
| P10 [[Malette Arduino éducative I]]&lt;br /&gt;
| Emmanuelle Pichonat / Thomas Vantroys / Alexandre Boé&lt;br /&gt;
| Yuqian HU&lt;br /&gt;
|-&lt;br /&gt;
| P10bis [[Malette Arduino éducative II]]&lt;br /&gt;
| Emmanuelle Pichonat / Thomas Vantroys / Alexandre Boé&lt;br /&gt;
| Mehmet ILTER&lt;br /&gt;
|-&lt;br /&gt;
| P11 [[Fabricarium - partage simplifié]]&lt;br /&gt;
| Alexandre Boé / Thomas Vantroys / Xavier Redon / Rodolphe Astori&lt;br /&gt;
| Jérémie DENECHAUD / Julien HERIN &lt;br /&gt;
|-&lt;br /&gt;
| P12 [[Art embarqué]]&lt;br /&gt;
| Alexandre Boé / Thomas Vantroys&lt;br /&gt;
| Thibaut SCHOLAERT / Jean-michel TOURNIER&lt;br /&gt;
|-&lt;br /&gt;
| P14 [[Aimant intelligent]]&lt;br /&gt;
| Alexandre Boé / Thomas Vantroys&lt;br /&gt;
| Louis THEBAULT / Bertrand YVERNAULT&lt;br /&gt;
|-&lt;br /&gt;
| P15 [[Thetweekproject|Machine à café]]&lt;br /&gt;
| Xavier Redon &lt;br /&gt;
| Jean WASILEWSKI / Pierre LETOUSEY&lt;br /&gt;
|-&lt;br /&gt;
| P17 [[Drone autonome]]&lt;br /&gt;
| Xavier Redon &lt;br /&gt;
| Kévin COLAUTTI / Benjamin LEFORT&lt;br /&gt;
|-&lt;br /&gt;
| P20 [[Balise de suivi de polluant]]&lt;br /&gt;
| Alexandre Boé / Thomas Vantroys&lt;br /&gt;
| Maxime MORISSE / Timothée TENEUR&lt;br /&gt;
|-&lt;br /&gt;
| P21 [[Réseau informatique et musique]]&lt;br /&gt;
| Xavier Redon&lt;br /&gt;
| Mageshwaran SEKAR	 &lt;br /&gt;
|-&lt;br /&gt;
| P23 [[Motorisation d'un véhicule électrique]]&lt;br /&gt;
| Walid Boughanmi&lt;br /&gt;
| Shuai HE / Quentin SULTANA&lt;br /&gt;
|-&lt;br /&gt;
| P24 [[Dé électronique communiquant]]&lt;br /&gt;
| Thomas Vantroys / Alexandre Boé&lt;br /&gt;
| Corentin DUPLOUY / Méhdi ZEGGAI&lt;br /&gt;
|-&lt;br /&gt;
| P26 [[Synthetiseur]]&lt;br /&gt;
| Thomas Vantroys / Alexandre Boé&lt;br /&gt;
| Alexis VINOT / Lu XIA&lt;br /&gt;
|-&lt;br /&gt;
| P28 [[e-theremin ]]&lt;br /&gt;
| Thomas Vantroys / Alexandre Boé&lt;br /&gt;
| Louis CHAUCHARD / Romain IMBERT&lt;br /&gt;
|-&lt;br /&gt;
| P30 [[Dessin 3D|Dessin 3D en environnement immersif]]&lt;br /&gt;
| Laurent Grisoni&lt;br /&gt;
| Alexandre JOUY / Romain LIBAERT&lt;br /&gt;
|-&lt;br /&gt;
| P31 [[Visualisation Open Data]]&lt;br /&gt;
| Alexandre Boé / Thomas Vantroys / Xavier Redon&lt;br /&gt;
| Elise TISSOT / Beatriz ODRIOZOLA&lt;br /&gt;
|-&lt;br /&gt;
| P33 [[Surveillance passive du sommeil]]&lt;br /&gt;
| Alexandre Boé / Thomas Vantroys&lt;br /&gt;
| Jérôme BAILET / Manouk SIMON&lt;br /&gt;
|-&lt;br /&gt;
| P34 [[Robot déformable|Console de contrôle pour robot déformable]]&lt;br /&gt;
| Jérémie Dequidt&lt;br /&gt;
| Ghada ELBEZ / Céline TIRABY&lt;br /&gt;
|-&lt;br /&gt;
| P35 [[RoboCup 2015]]&lt;br /&gt;
| Vincent Coelen / Rochdi Merzouki&lt;br /&gt;
| Sandra HAGE CHEHADE / Cyril SMAGGHE&lt;br /&gt;
|-&lt;br /&gt;
| P36 [[RoboCup 2015 - Pyro Team]]&lt;br /&gt;
| Vincent Coelen / Rochdi Merzouki&lt;br /&gt;
| Thomas DANEL / Romain KRIKORIAN &lt;br /&gt;
|-&lt;br /&gt;
| P37 [[Interaction Homme Robot]]&lt;br /&gt;
| Emmanuelle Grangier / Rochdi Merzouki&lt;br /&gt;
| Arnaud DESHAYS / Flavien ROYER&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Matériel à acquérir ==&lt;br /&gt;
&lt;br /&gt;
* P6 : Olimex platine ECG&lt;br /&gt;
&lt;br /&gt;
==  Notes sur les projets ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
| Projet || Mini-cahier des charges || Mi-parcours || Fin de parcours || Wiki terminé || Rapport || Vidéo&lt;br /&gt;
|-&lt;br /&gt;
| P1 [[Brique Lego augmentée]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Un cahier des charges très correct.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Wiki à jour. Déjà une réalisation (3 briques). Veillez à équilibrer le travail et à rendre compte systématiquement à l'encadrant.&lt;br /&gt;
| Wiki à jour permettant de suivre l'état d'avancement du travail. Bien !&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| RdV le 23/04/2015&lt;br /&gt;
|-&lt;br /&gt;
| P4 [[Tracabilité hopital|Amélioration de la traçabilité en milieu hospitalier]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Un cahier des charges très correct.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Wiki assez complet. Capture des datamatrix avancé. Passez-vous de l'utilitaire &amp;lt;tt&amp;gt;motion&amp;lt;/tt&amp;gt;. Il faut penser à concevoir l'application Web (base de données et interface). Quelles technologies Web comptez-vous utiliser ?&lt;br /&gt;
| Wiki presque à jour. Vous auriez pu mettre un mot de votre réalisation d'un serveur WebSocket. Diminuez la taille de vos captures d'écran pour rendre la lecture du Wiki plus agréable.&lt;br /&gt;
|Oui&lt;br /&gt;
|[[Fichier:Dossier_projet_S8_Bonville_Roche.pdf]]&lt;br /&gt;
| Vidéo tournée (L. Engels)&lt;br /&gt;
|-&lt;br /&gt;
| P6 [[Vêtements intelligents]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: lightgreen;&amp;quot;&amp;gt;Un cahier des charges à peu près correct.&amp;lt;/span&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: red;&amp;quot;&amp;gt;Le wiki n'est pas à jour à mi-parcours (rien sur la semaine 5). Des réalisations assez limités pour l'instant (lecture de capteur avec un Arduino et une application Android basique). Des inquiétudes sur la finalisation du projet. Sauf erreur de ma part, aucune information supplémentaire en semaine 7, Wiki toujours au même point. Projet a priori compromis.&amp;lt;/span&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: red;&amp;quot;&amp;gt;Wiki totalement abandonné, juste quelques lignes sur les 4 premières semaines.&amp;lt;/span&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| Vidéo maison&lt;br /&gt;
|-&lt;br /&gt;
| P10 [[Malette Arduino éducative I]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Un cahier des charges très correct.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Le Wiki est assez mal tenu, pour la partie programme les commentaires sont trop succints, il manque la réalisation de la semaine 5 pour la partie routage. Le travail pour la partie bibliothèque est bien avancé, il reste l'ordonnanceur à faire fonctionner avec les périphériques disponibles. Yuqian Hu envisage de commencer la seconde partie (malette éducative) durant les vacances. Manque de communication avec les encadrants en semaine 7 (pour les deux parties du projet).&lt;br /&gt;
| Le Wiki a été mis à jour en catastrophe. Il contient des indications sur les jeux programmés pour la seconde partie du projet. Pas de cahier des charges négociés avec les encadrants pour cette seconde partie. Rien sur la recherche de systèmes de programmation graphique des Arduino (demandé dans le cahier des charges oral de la seconde partie).&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| RdV non pris&lt;br /&gt;
|-&lt;br /&gt;
| P10bis [[Malette Arduino éducative II]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Un cahier des charges très correct.&amp;lt;/span&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: red;&amp;quot;&amp;gt;Le Wiki très mal tenu. Aucune rédaction, uniquement des schémas. Rien pour la semaine 5. A mi-parcours le PCB, pourtant basique, n'est même pas routé. Agravation du problème en semaine 7. Projets 10 et 10bis dissociés pour éviter de pénaliser la binôme.&amp;lt;/span&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: red;&amp;quot;&amp;gt;Wiki totalement abandonné à la semaine 6, documents obsolètes sur le PCB ordonnanceur, rien d'autre. Peu de retours, une première version non satisfaisante du PCB ordonnanceur a été livrée. Des directives envoyées par courriel pour corriger le tir.&amp;lt;/span&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| RdV non pris&lt;br /&gt;
|-&lt;br /&gt;
| P11 [[Fabricarium - partage simplifié]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Un cahier des charges tout à fait correct.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Wiki correct. Les réflexions sur la nature de la boite ont pris beaucoup de temps. Il y a assez peu de réalisations concrètes pour l'instant. Cela dit, avec des efforts, vous devez pouvoir terminer le projet en fournissant un prototype fonctionnel.&lt;br /&gt;
| Wiki presque à jour et un peu trop succint.&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| Vidéo par le club vidéo&lt;br /&gt;
|-&lt;br /&gt;
| P12 [[Art embarqué]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Un cahier des charges très correct.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Wiki mal tenu (manquent deux semaines dans la chronologie). Impossible de juger du travail réalisé. Non respect de la consigne notée, il sera pris en compte dans la notation finale. Inquiètude levée sur la qualité du travail (par les élèves et par l'encadrant) en semaine 6. Wiki mis à jour.&lt;br /&gt;
| Wiki tout à fait à jour même s'il n'est pas super détaillé. Alors comme ça ça marche mieux sous Linux ?&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| Vidéo maison&lt;br /&gt;
|-&lt;br /&gt;
| P14 [[Aimant intelligent]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Un cahier des charges complet.&amp;lt;/span&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: red;&amp;quot;&amp;gt;Wiki complet mais avec des coquilles. Une certaine inquiétude sur la possibilité de mener le travail à bien. Ni la conception de l'aimant ni la réalisation de l'application Android ne sont très avancés. Rien n'incite à l'optimisme en semaine 7 (rien sur le Wiki, pas de nouvelle des élèves).&amp;lt;/span&amp;gt;&lt;br /&gt;
| Wiki presque à jour et plutôt détaillé et illustré. Merci de corriger les nombreuses coquilles. Beaucoup plus d'optimisme sur la réalisation du projet.&lt;br /&gt;
|&lt;br /&gt;
|[[Média:Rapport_projet_YT.pdf]]&lt;br /&gt;
|&lt;br /&gt;
| RdV non pris&lt;br /&gt;
|-&lt;br /&gt;
| P15 [[Thetweekproject|Machine à café]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Un cahier des charges très complet, parfait.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Wiki très détaillé et bien rédigé. Une réalisation bien avancé. Pas d'inquiétude sur la quantité de travail (en particulier durant les vacances). Par contre le projet est très ambitieux, il est toujours difficile de prévoir s'il pourra être mené à bien.&lt;br /&gt;
| Le Wiki commence à être en décalage avec la réalisation, merci de le mettre à jour. Indiquez ce qui est fait et ce qu'il reste à faire.&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| [https://www.youtube.com/watch?v=GXPjxfLEy3o Disponible sur Youtube]&lt;br /&gt;
|-&lt;br /&gt;
| P17 [[Drone autonome]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Cahier des charges correct.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Wiki très correct, illustré mais avec quelques coquilles. Le matériel est déjà complètement pris en main à mi-parcours. Il reste à concevoir l'infrastructure de contrôle de la route du drône. Il est probable que le projet puisse être mené à bien.&lt;br /&gt;
| Wiki à jour mais les informations sont rares. Essayez de dresser un bilan des réalisation et une liste des tâches qui restent à réaliser. Au vu des retours IRL toutes les difficultés techniques semblent aplanies, confirmez cela dans le Wiki.&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| Vidéo tournée (L. Engels)&lt;br /&gt;
|-&lt;br /&gt;
| P20 [[Balise de suivi de polluant]]&lt;br /&gt;
| &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;Cahier des charges propre et complet avec les étapes à réaliser. Très bien.&amp;lt;/font&amp;gt;&lt;br /&gt;
| Le Wiki serait très correct s'il était à jour (rien sur la semaine 5 contrairement à la consigne). Le Wiki ne dit rien sur l'avancement de réalisation de la balise. C'est un peu inquiétant, un prototype fonctionnel pourra-t-il être présenté en fin de projet ? Une partie des inquiétudes est levée en semaine 6. Oubliez les deux Arduinos, faites fonctionner les deux shields sur le même. Demandez conseil à ce sujet à vos encadrants.&lt;br /&gt;
| Wiki à jour et très détaillé. L'avancé des travaux est parfaitement décrite.&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| RdV le 23/04/2015&lt;br /&gt;
|-&lt;br /&gt;
| P21 [[Réseau informatique et musique]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Bon cahier des charges.&amp;lt;/span&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: red;&amp;quot;&amp;gt;Le Wiki n'est absolument pas tenu à jour. Pas de contact avec l'encadrement depuis 15 jours. Le projet semble abandonné, vous vous dirigez droit vers une catastrophe. Pas mieux en semaine 7 malgré une discussion avec l'élève.&amp;lt;/span&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: red;&amp;quot;&amp;gt;Le Wiki est un peu mieux tenu mais toujours pas à jour, peu d'informations dans ce Wiki. Pas de rapport oral.&amp;lt;/span&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| RdV non pris&lt;br /&gt;
|-&lt;br /&gt;
| P23 [[Motorisation d'un véhicule électrique]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Très bon cahier des charges avec un planning prévisionnel précis.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Excellent Wiki, bien illustré et à jour. Vous semblez rencontrer un problème technique mais vous semblez aussi travailler à sa résolution. Il parait probable que vous soyez entrain de prendre du retard par rapport à votre planning.&lt;br /&gt;
| Wiki pratiquement à jour et détaillé. Les difficultés de mi-parcours semblent avoir été surmontées.&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| RdV non pris&lt;br /&gt;
|-&lt;br /&gt;
| P24 [[Dé électronique communiquant]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Un cahier des charges correct.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Wiki bien tenu, très bien illustré. Le travail réalisé est bien décrit. Vous semblez rencontrer un problème par rapport à la plateforme de développement. Conntinuez-vous avec un MBED, ou passez-vous sur un Arduino ? Il faut peut être en discuter avec votre encadrant.&lt;br /&gt;
| Wiki mis à jour en catastrophe (sans les illustrations) le 12 avril pour les semaines 6 à 10. Wiki plutôt complet expliquant bien le travail effectué. Il n'est pas encore clair que le projet puisse aboutir.&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| RdV sollicité&lt;br /&gt;
|-&lt;br /&gt;
| P26 [[Synthetiseur]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Un cahier des charges assez original.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Wiki bien tenu, très bien illustré, des informations intéressantes. Par contre laissez tomber l'idée farfelue de la Fedora sur vos PC. SMEWS s'installe à merveille sur une Debian. La remarque sur ActiveX me semble totalement hors sujet, que voulez-vous faire avec un ActiveX ? Attention au travail non coordonné entre la partie SMEWS et la partie contrôle de l'électronique analogique. Vous n'utilisez pas le même environnement (C++ pour l'IDE Web et C pur pour SMEWS). Vérifiez que vous pouvez intégrer les deux parties. Attention aussi concernant les PCB que vous souhaitez réaliser. Vu les délais et les problèmes de réalisation de PCB, le routage doit être fait au plus tôt (dans la semaine de la rentrée). Beaucoup de points délicats, la réalisation d'un prototype fonctionnel n'est pas assurée. Des efforts supplémentaires sont nécessaires.&lt;br /&gt;
| Wiki pratiquement à jour, bien illustré, correctement détaillé. Etat d'avancement très satisfaisant mais encore du travail à effectuer.&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| RdV le 22/04/2015&lt;br /&gt;
|-&lt;br /&gt;
| P28 [[e-theremin ]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Cahier des charges en dernière limite.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Wiki très correct, très bien illustré. Vous semblez rencontrer un problème de traitement de signal. Veuillez le caractériser précisément et consulter un de vos enseignants dans le domaine. Si vous devez concevoir un PCB pour la partie électronique analogique faite le de suite (dans la semaine de la rentrée).&lt;br /&gt;
| Le Wiki est plutôt à jour mais les informations données sont un peu maigres. Votre circuit fonctionne-t-il ? Pouvez-vous décrire plus précisément le développement de l'application X11 ?&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| RdV le 22/04/2015&lt;br /&gt;
|-&lt;br /&gt;
| P30 [[Dessin 3D|Dessin 3D en environnement immersif]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Cahier des charges correct en dernière limite.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Wiki très correct, illustré, travail effectué très bien décrit. Une première application autonome testée. Si j'ai bien compris il vous faut encore inclure cette application à Unity.&lt;br /&gt;
| Wiki un peu en décalage mais avec des informations détaillées. Une vidéo de démonstration, ce n'est pas particulièrement spectaculaire mais au moins cela montre qu'un prototype existe. Vous en êtes où actuellement ? Qu'on donné les tests ?&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| Vidéo maison&lt;br /&gt;
|-&lt;br /&gt;
| P31 [[Visualisation Open Data]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Un cahier des charges.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Wiki à jour, peu illustré, en particulier un schéma du système à réaliser serait le bienvenu. Le problème de la liste des gares avec le changement de syntaxe semble traité un peu rapidement. Vous semblez avoir tous les éléments pour un premier prototype, mettez le en place rapidement.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: red;&amp;quot;&amp;gt; Le Wiki n'est pas à jour. Effort important des encadrants pour remettre ce projet sur les rails. Aucune production des élèves à deux semaines de la fin du projet malgré une feuille de route précise. &amp;lt;/span&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| RdV non pris&lt;br /&gt;
|-&lt;br /&gt;
| P33 [[Surveillance passive du sommeil]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Cahier des charges très complet. Parfait.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Wiki complet et clair. Le bilan à mi-parcours est une bonne idée, il pourrait englober votre avancement sur le programme Android. Un schéma du fonctionnement global du système serait le bienvenu. Vous semblez être dans les temps pour présenter un prototype fonctionnel en fin de projet.&lt;br /&gt;
| Le Wiki n'est pas vraiment à jour. Description précise du travail. &lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| RdV non pris&lt;br /&gt;
|-&lt;br /&gt;
| P34 [[Robot déformable|Console de contrôle pour robot déformable]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Cahier des charges très correct.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Un wiki très complet et très précis. Par contre certains des problèmes que vous rencontrez semblent pouvoir se résoudre facilement. Essayez de solliciter vos encadrants quand cela vous arrive. En particulier le problème de port série que vous décrivez semble être facile à corriger.&lt;br /&gt;
| Wiki à jour, détaillé et vous avez fait un réel effort de correction des coquilles. Sur le fond vous parlez surtout des absences de votre encadrant ou de la lenteur des mises à jour, pas passionnant.&lt;br /&gt;
|&lt;br /&gt;
|[[Média:Rapport_final_tiraby_elbez.pdf]]&lt;br /&gt;
| Vidéo avec Jérémie Dequidt&lt;br /&gt;
|-&lt;br /&gt;
| P35 [[RoboCup 2015]]&lt;br /&gt;
| &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;Trés bon cahier des charges.&amp;lt;/font&amp;gt;&lt;br /&gt;
| Excellent Wiki très précis et bien illustré. Par contre le travail décrit semble être assez théorique (algorithmes). Un test sur le robotino est-il prévu pour valider la correction des algorithmes ?&lt;br /&gt;
| Wiki toujours très détaillé et illustré, pas tout à fait à jour.&lt;br /&gt;
| &lt;br /&gt;
| [[Fichier:RapportProjetSmaggheHage.pdf]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| P36 [[RoboCup 2015 - Pyro Team]]&lt;br /&gt;
| &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;Parfait.&amp;lt;/font&amp;gt;&lt;br /&gt;
| Excellent Wiki, très précis, très bien illustré. Le travail semble être déjà très avancé.&lt;br /&gt;
| Toujours excellent, pratiquement à jour.&lt;br /&gt;
|&lt;br /&gt;
| [[Fichier:RapportProjetDanelKrikorian.pdf]]&lt;br /&gt;
| Video à la fin du wiki&lt;br /&gt;
|-&lt;br /&gt;
| P37 [[Interaction Homme Robot]]&lt;br /&gt;
| &amp;lt;font color=&amp;quot;lightgreen&amp;quot;&amp;gt;Un cahier des charges minimal en dernière limite.&amp;lt;/font&amp;gt;&lt;br /&gt;
| Wiki à jour, peu illustré. A vu de néophyte, 5 semaines pour arriver à envoyer les premiers ordres au Nao via le serveur TCP intégré semble être un délai un peu long. Il vous reste la moitié du projet pour obtenir des résultats. Inquiétudes levées après discussion avec Flavien ROYER. Une vidéo de démonstration montre une nette progression dans le projet. Probable dissociation des notes.&lt;br /&gt;
| Wiki à jour, travail correctement décrit.&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| RdV non pris&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=Fichier:RapportProjetDanelKrikorian.pdf&amp;diff=21176</id>
		<title>Fichier:RapportProjetDanelKrikorian.pdf</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=Fichier:RapportProjetDanelKrikorian.pdf&amp;diff=21176"/>
				<updated>2015-05-11T23:03:49Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=Projets_IMA4_SC_%26_SA_2014/2015&amp;diff=21175</id>
		<title>Projets IMA4 SC &amp; SA 2014/2015</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=Projets_IMA4_SC_%26_SA_2014/2015&amp;diff=21175"/>
				<updated>2015-05-11T23:03:13Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Notes sur les projets */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Merci de référencer vos pages de projets ici. Merci aussi d'uniformiser vos formats que ce soit en regardant la présentation des projets déjà créés ou en demandant une modification du format des précédents si votre façon de faire vous semble la meilleure. Dans tous les cas un minimum de communication entre les binômes est conseillée.&lt;br /&gt;
&lt;br /&gt;
== Répartition des binômes ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Projet !! Encadrants école !! Elèves&lt;br /&gt;
|-&lt;br /&gt;
| P1 [[Brique Lego augmentée]]&lt;br /&gt;
| Alexandre Boé / Thomas Vantroys / Xavier Redon / Emmanuelle Pichonat &lt;br /&gt;
| Alex JULITA / Déborah SAUNDERS &lt;br /&gt;
|-&lt;br /&gt;
| P4 [[Tracabilité hopital|Amélioration de la traçabilité en milieu hospitalier]]&lt;br /&gt;
| Alexandre Boé / Thomas Vantroys&lt;br /&gt;
| Julian BONVILLE / François ROCHE&lt;br /&gt;
|-&lt;br /&gt;
| P6 [[Vêtements intelligents]]&lt;br /&gt;
| Alexandre Boé / Thomas Vantroys&lt;br /&gt;
| Alexander BOWN / Valentin PIAT&lt;br /&gt;
|-&lt;br /&gt;
| P10 [[Malette Arduino éducative I]]&lt;br /&gt;
| Emmanuelle Pichonat / Thomas Vantroys / Alexandre Boé&lt;br /&gt;
| Yuqian HU&lt;br /&gt;
|-&lt;br /&gt;
| P10bis [[Malette Arduino éducative II]]&lt;br /&gt;
| Emmanuelle Pichonat / Thomas Vantroys / Alexandre Boé&lt;br /&gt;
| Mehmet ILTER&lt;br /&gt;
|-&lt;br /&gt;
| P11 [[Fabricarium - partage simplifié]]&lt;br /&gt;
| Alexandre Boé / Thomas Vantroys / Xavier Redon / Rodolphe Astori&lt;br /&gt;
| Jérémie DENECHAUD / Julien HERIN &lt;br /&gt;
|-&lt;br /&gt;
| P12 [[Art embarqué]]&lt;br /&gt;
| Alexandre Boé / Thomas Vantroys&lt;br /&gt;
| Thibaut SCHOLAERT / Jean-michel TOURNIER&lt;br /&gt;
|-&lt;br /&gt;
| P14 [[Aimant intelligent]]&lt;br /&gt;
| Alexandre Boé / Thomas Vantroys&lt;br /&gt;
| Louis THEBAULT / Bertrand YVERNAULT&lt;br /&gt;
|-&lt;br /&gt;
| P15 [[Thetweekproject|Machine à café]]&lt;br /&gt;
| Xavier Redon &lt;br /&gt;
| Jean WASILEWSKI / Pierre LETOUSEY&lt;br /&gt;
|-&lt;br /&gt;
| P17 [[Drone autonome]]&lt;br /&gt;
| Xavier Redon &lt;br /&gt;
| Kévin COLAUTTI / Benjamin LEFORT&lt;br /&gt;
|-&lt;br /&gt;
| P20 [[Balise de suivi de polluant]]&lt;br /&gt;
| Alexandre Boé / Thomas Vantroys&lt;br /&gt;
| Maxime MORISSE / Timothée TENEUR&lt;br /&gt;
|-&lt;br /&gt;
| P21 [[Réseau informatique et musique]]&lt;br /&gt;
| Xavier Redon&lt;br /&gt;
| Mageshwaran SEKAR	 &lt;br /&gt;
|-&lt;br /&gt;
| P23 [[Motorisation d'un véhicule électrique]]&lt;br /&gt;
| Walid Boughanmi&lt;br /&gt;
| Shuai HE / Quentin SULTANA&lt;br /&gt;
|-&lt;br /&gt;
| P24 [[Dé électronique communiquant]]&lt;br /&gt;
| Thomas Vantroys / Alexandre Boé&lt;br /&gt;
| Corentin DUPLOUY / Méhdi ZEGGAI&lt;br /&gt;
|-&lt;br /&gt;
| P26 [[Synthetiseur]]&lt;br /&gt;
| Thomas Vantroys / Alexandre Boé&lt;br /&gt;
| Alexis VINOT / Lu XIA&lt;br /&gt;
|-&lt;br /&gt;
| P28 [[e-theremin ]]&lt;br /&gt;
| Thomas Vantroys / Alexandre Boé&lt;br /&gt;
| Louis CHAUCHARD / Romain IMBERT&lt;br /&gt;
|-&lt;br /&gt;
| P30 [[Dessin 3D|Dessin 3D en environnement immersif]]&lt;br /&gt;
| Laurent Grisoni&lt;br /&gt;
| Alexandre JOUY / Romain LIBAERT&lt;br /&gt;
|-&lt;br /&gt;
| P31 [[Visualisation Open Data]]&lt;br /&gt;
| Alexandre Boé / Thomas Vantroys / Xavier Redon&lt;br /&gt;
| Elise TISSOT / Beatriz ODRIOZOLA&lt;br /&gt;
|-&lt;br /&gt;
| P33 [[Surveillance passive du sommeil]]&lt;br /&gt;
| Alexandre Boé / Thomas Vantroys&lt;br /&gt;
| Jérôme BAILET / Manouk SIMON&lt;br /&gt;
|-&lt;br /&gt;
| P34 [[Robot déformable|Console de contrôle pour robot déformable]]&lt;br /&gt;
| Jérémie Dequidt&lt;br /&gt;
| Ghada ELBEZ / Céline TIRABY&lt;br /&gt;
|-&lt;br /&gt;
| P35 [[RoboCup 2015]]&lt;br /&gt;
| Vincent Coelen / Rochdi Merzouki&lt;br /&gt;
| Sandra HAGE CHEHADE / Cyril SMAGGHE&lt;br /&gt;
|-&lt;br /&gt;
| P36 [[RoboCup 2015 - Pyro Team]]&lt;br /&gt;
| Vincent Coelen / Rochdi Merzouki&lt;br /&gt;
| Thomas DANEL / Romain KRIKORIAN &lt;br /&gt;
|-&lt;br /&gt;
| P37 [[Interaction Homme Robot]]&lt;br /&gt;
| Emmanuelle Grangier / Rochdi Merzouki&lt;br /&gt;
| Arnaud DESHAYS / Flavien ROYER&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Matériel à acquérir ==&lt;br /&gt;
&lt;br /&gt;
* P6 : Olimex platine ECG&lt;br /&gt;
&lt;br /&gt;
==  Notes sur les projets ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
| Projet || Mini-cahier des charges || Mi-parcours || Fin de parcours || Wiki terminé || Rapport || Vidéo&lt;br /&gt;
|-&lt;br /&gt;
| P1 [[Brique Lego augmentée]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Un cahier des charges très correct.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Wiki à jour. Déjà une réalisation (3 briques). Veillez à équilibrer le travail et à rendre compte systématiquement à l'encadrant.&lt;br /&gt;
| Wiki à jour permettant de suivre l'état d'avancement du travail. Bien !&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| RdV le 23/04/2015&lt;br /&gt;
|-&lt;br /&gt;
| P4 [[Tracabilité hopital|Amélioration de la traçabilité en milieu hospitalier]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Un cahier des charges très correct.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Wiki assez complet. Capture des datamatrix avancé. Passez-vous de l'utilitaire &amp;lt;tt&amp;gt;motion&amp;lt;/tt&amp;gt;. Il faut penser à concevoir l'application Web (base de données et interface). Quelles technologies Web comptez-vous utiliser ?&lt;br /&gt;
| Wiki presque à jour. Vous auriez pu mettre un mot de votre réalisation d'un serveur WebSocket. Diminuez la taille de vos captures d'écran pour rendre la lecture du Wiki plus agréable.&lt;br /&gt;
|Oui&lt;br /&gt;
|[[Fichier:Dossier_projet_S8_Bonville_Roche.pdf]]&lt;br /&gt;
| Vidéo tournée (L. Engels)&lt;br /&gt;
|-&lt;br /&gt;
| P6 [[Vêtements intelligents]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: lightgreen;&amp;quot;&amp;gt;Un cahier des charges à peu près correct.&amp;lt;/span&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: red;&amp;quot;&amp;gt;Le wiki n'est pas à jour à mi-parcours (rien sur la semaine 5). Des réalisations assez limités pour l'instant (lecture de capteur avec un Arduino et une application Android basique). Des inquiétudes sur la finalisation du projet. Sauf erreur de ma part, aucune information supplémentaire en semaine 7, Wiki toujours au même point. Projet a priori compromis.&amp;lt;/span&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: red;&amp;quot;&amp;gt;Wiki totalement abandonné, juste quelques lignes sur les 4 premières semaines.&amp;lt;/span&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| Vidéo maison&lt;br /&gt;
|-&lt;br /&gt;
| P10 [[Malette Arduino éducative I]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Un cahier des charges très correct.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Le Wiki est assez mal tenu, pour la partie programme les commentaires sont trop succints, il manque la réalisation de la semaine 5 pour la partie routage. Le travail pour la partie bibliothèque est bien avancé, il reste l'ordonnanceur à faire fonctionner avec les périphériques disponibles. Yuqian Hu envisage de commencer la seconde partie (malette éducative) durant les vacances. Manque de communication avec les encadrants en semaine 7 (pour les deux parties du projet).&lt;br /&gt;
| Le Wiki a été mis à jour en catastrophe. Il contient des indications sur les jeux programmés pour la seconde partie du projet. Pas de cahier des charges négociés avec les encadrants pour cette seconde partie. Rien sur la recherche de systèmes de programmation graphique des Arduino (demandé dans le cahier des charges oral de la seconde partie).&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| RdV non pris&lt;br /&gt;
|-&lt;br /&gt;
| P10bis [[Malette Arduino éducative II]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Un cahier des charges très correct.&amp;lt;/span&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: red;&amp;quot;&amp;gt;Le Wiki très mal tenu. Aucune rédaction, uniquement des schémas. Rien pour la semaine 5. A mi-parcours le PCB, pourtant basique, n'est même pas routé. Agravation du problème en semaine 7. Projets 10 et 10bis dissociés pour éviter de pénaliser la binôme.&amp;lt;/span&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: red;&amp;quot;&amp;gt;Wiki totalement abandonné à la semaine 6, documents obsolètes sur le PCB ordonnanceur, rien d'autre. Peu de retours, une première version non satisfaisante du PCB ordonnanceur a été livrée. Des directives envoyées par courriel pour corriger le tir.&amp;lt;/span&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| RdV non pris&lt;br /&gt;
|-&lt;br /&gt;
| P11 [[Fabricarium - partage simplifié]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Un cahier des charges tout à fait correct.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Wiki correct. Les réflexions sur la nature de la boite ont pris beaucoup de temps. Il y a assez peu de réalisations concrètes pour l'instant. Cela dit, avec des efforts, vous devez pouvoir terminer le projet en fournissant un prototype fonctionnel.&lt;br /&gt;
| Wiki presque à jour et un peu trop succint.&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| Vidéo par le club vidéo&lt;br /&gt;
|-&lt;br /&gt;
| P12 [[Art embarqué]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Un cahier des charges très correct.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Wiki mal tenu (manquent deux semaines dans la chronologie). Impossible de juger du travail réalisé. Non respect de la consigne notée, il sera pris en compte dans la notation finale. Inquiètude levée sur la qualité du travail (par les élèves et par l'encadrant) en semaine 6. Wiki mis à jour.&lt;br /&gt;
| Wiki tout à fait à jour même s'il n'est pas super détaillé. Alors comme ça ça marche mieux sous Linux ?&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| Vidéo maison&lt;br /&gt;
|-&lt;br /&gt;
| P14 [[Aimant intelligent]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Un cahier des charges complet.&amp;lt;/span&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: red;&amp;quot;&amp;gt;Wiki complet mais avec des coquilles. Une certaine inquiétude sur la possibilité de mener le travail à bien. Ni la conception de l'aimant ni la réalisation de l'application Android ne sont très avancés. Rien n'incite à l'optimisme en semaine 7 (rien sur le Wiki, pas de nouvelle des élèves).&amp;lt;/span&amp;gt;&lt;br /&gt;
| Wiki presque à jour et plutôt détaillé et illustré. Merci de corriger les nombreuses coquilles. Beaucoup plus d'optimisme sur la réalisation du projet.&lt;br /&gt;
|&lt;br /&gt;
|[[Média:Rapport_projet_YT.pdf]]&lt;br /&gt;
|&lt;br /&gt;
| RdV non pris&lt;br /&gt;
|-&lt;br /&gt;
| P15 [[Thetweekproject|Machine à café]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Un cahier des charges très complet, parfait.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Wiki très détaillé et bien rédigé. Une réalisation bien avancé. Pas d'inquiétude sur la quantité de travail (en particulier durant les vacances). Par contre le projet est très ambitieux, il est toujours difficile de prévoir s'il pourra être mené à bien.&lt;br /&gt;
| Le Wiki commence à être en décalage avec la réalisation, merci de le mettre à jour. Indiquez ce qui est fait et ce qu'il reste à faire.&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| [https://www.youtube.com/watch?v=GXPjxfLEy3o Disponible sur Youtube]&lt;br /&gt;
|-&lt;br /&gt;
| P17 [[Drone autonome]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Cahier des charges correct.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Wiki très correct, illustré mais avec quelques coquilles. Le matériel est déjà complètement pris en main à mi-parcours. Il reste à concevoir l'infrastructure de contrôle de la route du drône. Il est probable que le projet puisse être mené à bien.&lt;br /&gt;
| Wiki à jour mais les informations sont rares. Essayez de dresser un bilan des réalisation et une liste des tâches qui restent à réaliser. Au vu des retours IRL toutes les difficultés techniques semblent aplanies, confirmez cela dans le Wiki.&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| Vidéo tournée (L. Engels)&lt;br /&gt;
|-&lt;br /&gt;
| P20 [[Balise de suivi de polluant]]&lt;br /&gt;
| &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;Cahier des charges propre et complet avec les étapes à réaliser. Très bien.&amp;lt;/font&amp;gt;&lt;br /&gt;
| Le Wiki serait très correct s'il était à jour (rien sur la semaine 5 contrairement à la consigne). Le Wiki ne dit rien sur l'avancement de réalisation de la balise. C'est un peu inquiétant, un prototype fonctionnel pourra-t-il être présenté en fin de projet ? Une partie des inquiétudes est levée en semaine 6. Oubliez les deux Arduinos, faites fonctionner les deux shields sur le même. Demandez conseil à ce sujet à vos encadrants.&lt;br /&gt;
| Wiki à jour et très détaillé. L'avancé des travaux est parfaitement décrite.&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| RdV le 23/04/2015&lt;br /&gt;
|-&lt;br /&gt;
| P21 [[Réseau informatique et musique]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Bon cahier des charges.&amp;lt;/span&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: red;&amp;quot;&amp;gt;Le Wiki n'est absolument pas tenu à jour. Pas de contact avec l'encadrement depuis 15 jours. Le projet semble abandonné, vous vous dirigez droit vers une catastrophe. Pas mieux en semaine 7 malgré une discussion avec l'élève.&amp;lt;/span&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: red;&amp;quot;&amp;gt;Le Wiki est un peu mieux tenu mais toujours pas à jour, peu d'informations dans ce Wiki. Pas de rapport oral.&amp;lt;/span&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| RdV non pris&lt;br /&gt;
|-&lt;br /&gt;
| P23 [[Motorisation d'un véhicule électrique]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Très bon cahier des charges avec un planning prévisionnel précis.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Excellent Wiki, bien illustré et à jour. Vous semblez rencontrer un problème technique mais vous semblez aussi travailler à sa résolution. Il parait probable que vous soyez entrain de prendre du retard par rapport à votre planning.&lt;br /&gt;
| Wiki pratiquement à jour et détaillé. Les difficultés de mi-parcours semblent avoir été surmontées.&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| RdV non pris&lt;br /&gt;
|-&lt;br /&gt;
| P24 [[Dé électronique communiquant]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Un cahier des charges correct.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Wiki bien tenu, très bien illustré. Le travail réalisé est bien décrit. Vous semblez rencontrer un problème par rapport à la plateforme de développement. Conntinuez-vous avec un MBED, ou passez-vous sur un Arduino ? Il faut peut être en discuter avec votre encadrant.&lt;br /&gt;
| Wiki mis à jour en catastrophe (sans les illustrations) le 12 avril pour les semaines 6 à 10. Wiki plutôt complet expliquant bien le travail effectué. Il n'est pas encore clair que le projet puisse aboutir.&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| RdV sollicité&lt;br /&gt;
|-&lt;br /&gt;
| P26 [[Synthetiseur]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Un cahier des charges assez original.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Wiki bien tenu, très bien illustré, des informations intéressantes. Par contre laissez tomber l'idée farfelue de la Fedora sur vos PC. SMEWS s'installe à merveille sur une Debian. La remarque sur ActiveX me semble totalement hors sujet, que voulez-vous faire avec un ActiveX ? Attention au travail non coordonné entre la partie SMEWS et la partie contrôle de l'électronique analogique. Vous n'utilisez pas le même environnement (C++ pour l'IDE Web et C pur pour SMEWS). Vérifiez que vous pouvez intégrer les deux parties. Attention aussi concernant les PCB que vous souhaitez réaliser. Vu les délais et les problèmes de réalisation de PCB, le routage doit être fait au plus tôt (dans la semaine de la rentrée). Beaucoup de points délicats, la réalisation d'un prototype fonctionnel n'est pas assurée. Des efforts supplémentaires sont nécessaires.&lt;br /&gt;
| Wiki pratiquement à jour, bien illustré, correctement détaillé. Etat d'avancement très satisfaisant mais encore du travail à effectuer.&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| RdV le 22/04/2015&lt;br /&gt;
|-&lt;br /&gt;
| P28 [[e-theremin ]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Cahier des charges en dernière limite.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Wiki très correct, très bien illustré. Vous semblez rencontrer un problème de traitement de signal. Veuillez le caractériser précisément et consulter un de vos enseignants dans le domaine. Si vous devez concevoir un PCB pour la partie électronique analogique faite le de suite (dans la semaine de la rentrée).&lt;br /&gt;
| Le Wiki est plutôt à jour mais les informations données sont un peu maigres. Votre circuit fonctionne-t-il ? Pouvez-vous décrire plus précisément le développement de l'application X11 ?&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| RdV le 22/04/2015&lt;br /&gt;
|-&lt;br /&gt;
| P30 [[Dessin 3D|Dessin 3D en environnement immersif]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Cahier des charges correct en dernière limite.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Wiki très correct, illustré, travail effectué très bien décrit. Une première application autonome testée. Si j'ai bien compris il vous faut encore inclure cette application à Unity.&lt;br /&gt;
| Wiki un peu en décalage mais avec des informations détaillées. Une vidéo de démonstration, ce n'est pas particulièrement spectaculaire mais au moins cela montre qu'un prototype existe. Vous en êtes où actuellement ? Qu'on donné les tests ?&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| Vidéo maison&lt;br /&gt;
|-&lt;br /&gt;
| P31 [[Visualisation Open Data]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Un cahier des charges.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Wiki à jour, peu illustré, en particulier un schéma du système à réaliser serait le bienvenu. Le problème de la liste des gares avec le changement de syntaxe semble traité un peu rapidement. Vous semblez avoir tous les éléments pour un premier prototype, mettez le en place rapidement.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: red;&amp;quot;&amp;gt; Le Wiki n'est pas à jour. Effort important des encadrants pour remettre ce projet sur les rails. Aucune production des élèves à deux semaines de la fin du projet malgré une feuille de route précise. &amp;lt;/span&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| RdV non pris&lt;br /&gt;
|-&lt;br /&gt;
| P33 [[Surveillance passive du sommeil]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Cahier des charges très complet. Parfait.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Wiki complet et clair. Le bilan à mi-parcours est une bonne idée, il pourrait englober votre avancement sur le programme Android. Un schéma du fonctionnement global du système serait le bienvenu. Vous semblez être dans les temps pour présenter un prototype fonctionnel en fin de projet.&lt;br /&gt;
| Le Wiki n'est pas vraiment à jour. Description précise du travail. &lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| RdV non pris&lt;br /&gt;
|-&lt;br /&gt;
| P34 [[Robot déformable|Console de contrôle pour robot déformable]]&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color: green;&amp;quot;&amp;gt;Cahier des charges très correct.&amp;lt;/span&amp;gt;&lt;br /&gt;
| Un wiki très complet et très précis. Par contre certains des problèmes que vous rencontrez semblent pouvoir se résoudre facilement. Essayez de solliciter vos encadrants quand cela vous arrive. En particulier le problème de port série que vous décrivez semble être facile à corriger.&lt;br /&gt;
| Wiki à jour, détaillé et vous avez fait un réel effort de correction des coquilles. Sur le fond vous parlez surtout des absences de votre encadrant ou de la lenteur des mises à jour, pas passionnant.&lt;br /&gt;
|&lt;br /&gt;
|[[Média:Rapport_final_tiraby_elbez.pdf]]&lt;br /&gt;
| Vidéo avec Jérémie Dequidt&lt;br /&gt;
|-&lt;br /&gt;
| P35 [[RoboCup 2015]]&lt;br /&gt;
| &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;Trés bon cahier des charges.&amp;lt;/font&amp;gt;&lt;br /&gt;
| Excellent Wiki très précis et bien illustré. Par contre le travail décrit semble être assez théorique (algorithmes). Un test sur le robotino est-il prévu pour valider la correction des algorithmes ?&lt;br /&gt;
| Wiki toujours très détaillé et illustré, pas tout à fait à jour.&lt;br /&gt;
| &lt;br /&gt;
| [[Fichier:RapportProjetSmaggheHage.pdf]]&lt;br /&gt;
| Prise de vues pendant la robocup&lt;br /&gt;
|-&lt;br /&gt;
| P36 [[RoboCup 2015 - Pyro Team]]&lt;br /&gt;
| &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;Parfait.&amp;lt;/font&amp;gt;&lt;br /&gt;
| Excellent Wiki, très précis, très bien illustré. Le travail semble être déjà très avancé.&lt;br /&gt;
| Toujours excellent, pratiquement à jour.&lt;br /&gt;
|&lt;br /&gt;
| [[Fichier:RapportProjetDanelKrikorian.pdf]]&lt;br /&gt;
| Prise de vues pendant la robocup&lt;br /&gt;
|-&lt;br /&gt;
| P37 [[Interaction Homme Robot]]&lt;br /&gt;
| &amp;lt;font color=&amp;quot;lightgreen&amp;quot;&amp;gt;Un cahier des charges minimal en dernière limite.&amp;lt;/font&amp;gt;&lt;br /&gt;
| Wiki à jour, peu illustré. A vu de néophyte, 5 semaines pour arriver à envoyer les premiers ordres au Nao via le serveur TCP intégré semble être un délai un peu long. Il vous reste la moitié du projet pour obtenir des résultats. Inquiétudes levées après discussion avec Flavien ROYER. Une vidéo de démonstration montre une nette progression dans le projet. Probable dissociation des notes.&lt;br /&gt;
| Wiki à jour, travail correctement décrit.&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| RdV non pris&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=21174</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=21174"/>
				<updated>2015-05-11T23:00:37Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Vocabulaire */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
*Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
*Recherches de solutions pour la localisation (SLAM)&lt;br /&gt;
*Recherche de solution pour la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - vidéo====&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les résultats de la détection des machines nous avons utiliser l'interface graphique disponible avec ROS, RVIZ. Nous visualisons alors le scan laser (points blancs), le résultat de la détection de segments (en rouge) et les positions des machines trouvées (en vert). Un premier test a été fait sur le scan originel, celui sur lequel nous avons travaillé depuis le début.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=XSn4s1y-XT0 Visualisation des machines]&lt;br /&gt;
&lt;br /&gt;
On rencontre un problème quand le robot est exactement parallèle ou perpendiculaire à un mur. Après vérification dans le programme, il s'avère que la détection ne fonctionne pas pour ces cas. Ce bug est maintenant corrigé :&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=rKeqewpuLoQ Correction du bug]&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
La première étape consiste juste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;br /&gt;
&lt;br /&gt;
la matrice correspondant au changement (laser -&amp;gt; robot) est la suivante : &lt;br /&gt;
&lt;br /&gt;
 0   -1    0&lt;br /&gt;
 1    0  0.2&lt;br /&gt;
 0    0    1&lt;br /&gt;
&lt;br /&gt;
la matrice 2x2 en haut à gauche correspond à la rotation de 90°, et le vecteur (0, 0.2) correspond à la translation.&lt;br /&gt;
&lt;br /&gt;
Celle du changement (robot -&amp;gt; global) avec alpha angle mesuré par le gyroscope depuis la position initiale (angle 0) :&lt;br /&gt;
&lt;br /&gt;
 cos(alpha)   -sin(alpha)    posInit.x&lt;br /&gt;
 sin(alpha)    cos(alpha)    posInit.y&lt;br /&gt;
          0             0            1&lt;br /&gt;
&lt;br /&gt;
l'étape suivante est de vérifier si les machines vues par le laser sont bien des machines, c'est-à-dire si les positions mesurées à partir des données lasers correspond aux zones occupées par des machines envoyées par la Referee Box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Grid Map====&lt;br /&gt;
&lt;br /&gt;
L'autre objectif de cette semaine a été de coder le noeud qui génère la map. La map est générée sous forme d'OccupancyGrid. Ce type est constitué d'un seul vecteur dont la première case correspond à la case en bas à gauche de la map. D'autres paramètres sont réglable comme l'origine et la taille.&lt;br /&gt;
&lt;br /&gt;
Pour la taille on choisit de diviser la map en case de 10 cm et l'origine choisie est le x du centre de la map et en y l'abscisse du premier mur (voir la map ci-dessous). Afin d'expliquer comment est constituée cette map, prenons le code et analysons les différentes fonctions ainsi que le main :&lt;br /&gt;
&lt;br /&gt;
Ce vecteur de Pose2D (x, y et theta (angle de la machine)) va permettre d'enregistrer la position des machines, c'est une variable global qui sera mise à jour avec le Callback :&lt;br /&gt;
&lt;br /&gt;
 std::vector&amp;lt;geometry_msgs::Pose2D&amp;gt; tab;&lt;br /&gt;
&lt;br /&gt;
*Récupération des machines envoyées par le noeud du SLAM (sur le topic /landmarks):&lt;br /&gt;
&lt;br /&gt;
 void Poses_Machine_Callback(const deplacement_msg::LandmarksConstPtr &amp;amp;machines)&lt;br /&gt;
 {&lt;br /&gt;
          tab=machines-&amp;gt;landmarks;&lt;br /&gt;
          for (int i=0; i&amp;lt;tab.size(); i++)&lt;br /&gt;
          {&lt;br /&gt;
     	     tab[i].x = tab[i].x*1000;&lt;br /&gt;
     	     tab[i].y = tab[i].y*1000;&lt;br /&gt;
 	  }&lt;br /&gt;
    &lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
*Création d'une map vide de taille 14m sur 8m. Chaque case est initialisée à une valeur nulle, on remplit également les autres paramètres de OccupancyGrid:&lt;br /&gt;
(On rappelle que la technique utilisée est un vecteur qui représente chaque case auxquelles il associe une probabilité 100 c'est un point interdit et 0 quand c'est un point sans danger pour le passage du robot)&lt;br /&gt;
&lt;br /&gt;
 void Create_Empty_Map(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      Map.info.origin.position.x=-7000;&lt;br /&gt;
      Map.info.origin.position.y=-1000;&lt;br /&gt;
      Map.info.origin.position.z=0;&lt;br /&gt;
      Map.info.origin.orientation.x=0;&lt;br /&gt;
      Map.info.origin.orientation.y=0;&lt;br /&gt;
      Map.info.origin.orientation.z=0;&lt;br /&gt;
      Map.info.origin.orientation.w=1;&lt;br /&gt;
      Map.info.map_load_time=ros::Time::now();&lt;br /&gt;
      Map.info.resolution=100;&lt;br /&gt;
      Map.info.width=140;&lt;br /&gt;
      Map.info.height=80;&lt;br /&gt;
      Map.data.assign(Map.info.width*Map.info.height, 0);                   //map vide&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
*Construction des points fixes de la map donc les murs (probabilité 100) et les zones à risques (probabilité 50):&lt;br /&gt;
&lt;br /&gt;
 void Set_Wall(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
    for (int i=0;i&amp;lt;80;i++)&lt;br /&gt;
    {&lt;br /&gt;
       for (int j=0;j&amp;lt;140;j++)&lt;br /&gt;
       {&lt;br /&gt;
          if ((i&amp;lt;13)||(i&amp;gt;67))) Map.data[j+i*140]=100;&lt;br /&gt;
          if ((j&amp;lt;13)||(j&amp;gt;127)) Map.data[j+i*140]=100;&lt;br /&gt;
       }&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Nous ne mettons pas tout le code de cette fonction étant donné qu'il est long et répétitif puisque c'est le remplissage des données connues, donc en &amp;quot;dur&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Calcul des positions machines: &lt;br /&gt;
&lt;br /&gt;
Lorsqu'on reçoit une position machine, c'est en fait son centre et son orientation par rapport à x que l'on reçoit. Etant donné que les machines doivent être des rectangles de 110cm sur 75cm (réellement 70 x 35 mais on compte la moitié du robot en plus par sécurité), on décide d'abord de déterminer un des coins du rectangle et plus précisément le coin en bas à droite de ce dernier:&lt;br /&gt;
&lt;br /&gt;
 void Get_One_Point_Of_The_Rectangle(float x, float &amp;amp;xA, float y, float &amp;amp;yA, float theta, float largeur, float longueur)&lt;br /&gt;
 {&lt;br /&gt;
      float x1,y1;&lt;br /&gt;
      x1 = x - cos(theta)*longueur;&lt;br /&gt;
      y1 = y - sin(theta)*longueur; &lt;br /&gt;
      xA = x1 + sin(M_PI_2-theta)*largeur;&lt;br /&gt;
      yA = y1 - cos(M_PI_2-theta)*largeur;&lt;br /&gt;
  &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
*Remplissage des positions sur la map :&lt;br /&gt;
&lt;br /&gt;
On met alors tous les points de ce rectangle à une probabilité 100 dans le vecteur Map. Pour les calculs on différencie le cas ou l'angle de la machine est entre 0 et pi/2 et le cas où il est entre pi/2 et pi. L'algorithme est le suivant : &lt;br /&gt;
&lt;br /&gt;
 A partir du coin, on incrémente x et y de sorte à longer le grand coté et de remplir chaque case (incrémentation de 5 cm).&lt;br /&gt;
 Une fois arrivé au bout, on incrémente x et y de 5cm sur la largeur à partir du coin et on recommence l'opération précédente.&lt;br /&gt;
 Ceci jusqu'à remplir le complètement le rectangle.&lt;br /&gt;
&lt;br /&gt;
Afin d'établir les probabilités correspondantes aux cases de ce rectangle, nous utilisons la fonctions floor() pour &amp;quot;convertir&amp;quot; nos flottants en entier et accéder à la case correspondante. On notera aussi que la case 1470 correspond à l'origine de notre map.&lt;br /&gt;
&lt;br /&gt;
 void Set_Machines_In_Map(float rank, float theta, float xA, float yA, nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      float x=xA;&lt;br /&gt;
      float y=yA;&lt;br /&gt;
      if (theta&amp;lt;=M_PI_2)&lt;br /&gt;
      {&lt;br /&gt;
            for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
            {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++) &lt;br /&gt;
                  {&lt;br /&gt;
                      Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                      x = x + cos(theta)*50;&lt;br /&gt;
                      y = y + sin(theta)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(M_PI_2-theta)*50;&lt;br /&gt;
                  y = yA + j*sin(M_PI_2-theta)*50;&lt;br /&gt;
            }	&lt;br /&gt;
       }&lt;br /&gt;
       if (theta&amp;gt;M_PI_2)&lt;br /&gt;
       {&lt;br /&gt;
             for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
             {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++)&lt;br /&gt;
                  {&lt;br /&gt;
                        Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                        x = x - sin(theta-M_PI_2)*50;&lt;br /&gt;
                        y = y + cos(theta-M_PI_2)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(theta-M_PI_2)*50;&lt;br /&gt;
                  y = yA - j*sin(theta-M_PI_2)*50;&lt;br /&gt;
              }	&lt;br /&gt;
        }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Ci dessous on a les mains, avec les différentes fonctions appelées et la syntaxe particulière à ROS. &lt;br /&gt;
&lt;br /&gt;
*Noeud général pour le traitement et le remplissage de la map :   &lt;br /&gt;
                 &lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
     ros::init(argc, argv, &amp;quot;server&amp;quot;);&lt;br /&gt;
     ros::NodeHandle n;&lt;br /&gt;
     ros::Subscriber sub_poses_machine    = n.subscribe(&amp;quot;/machines&amp;quot;, 1000, Poses_Machine_Callback);   // Récupération des machines&lt;br /&gt;
     ros::Publisher Map_Pub = n.advertise&amp;lt;nav_msgs::OccupancyGrid&amp;gt;(&amp;quot;/map&amp;quot;, 1000);                     // Préparation de la publication de la map&lt;br /&gt;
     ROS_INFO(&amp;quot;Ready to Generate the Map&amp;quot;);&lt;br /&gt;
     float xA,yA;&lt;br /&gt;
     ros::Rate loop_rate(1);&lt;br /&gt;
     while(ros::ok())&lt;br /&gt;
     {&lt;br /&gt;
        nav_msgs::OccupancyGrid Map;&lt;br /&gt;
        Create_Empty_Map(Map);&lt;br /&gt;
        Set_Wall(Map);&lt;br /&gt;
        for (int z=0;z&amp;lt;tab.size();z++)&lt;br /&gt;
        {&lt;br /&gt;
           Get_One_Point_Of_The_Rectangle(tab[z].x, xA, tab[z].y, yA, tab[z].theta, 275, 450);&lt;br /&gt;
 	   Set_Machines_In_Map(100, tab[z].theta, xA, yA, Map);&lt;br /&gt;
        }&lt;br /&gt;
        Map_Pub.publish(Map);                                                                   // publication de la map&lt;br /&gt;
        ros::spinOnce();&lt;br /&gt;
        loop_rate.sleep();&lt;br /&gt;
     }&lt;br /&gt;
     return 0;&lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Noeud test qui publie 2 positions de machines : &lt;br /&gt;
&lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
    ros::init(argc, argv, &amp;quot;test&amp;quot;);&lt;br /&gt;
    ros::NodeHandle n;&lt;br /&gt;
    ros::Publisher Pose_Machines_Pub = n.advertise&amp;lt;deplacement_msg::Landmarks&amp;gt;(&amp;quot;/machines&amp;quot;, 1000);&lt;br /&gt;
    ROS_INFO(&amp;quot;Ready to send poses machines&amp;quot;);&lt;br /&gt;
    int xA,yA;&lt;br /&gt;
    ros::Rate loop_rate(1);&lt;br /&gt;
    while(ros::ok())&lt;br /&gt;
    {&lt;br /&gt;
       deplacement_msg::Landmarks machines_msgs;&lt;br /&gt;
       geometry_msgs::Pose2D tab;&lt;br /&gt;
       tab.x=-2;&lt;br /&gt;
       tab.y=2;&lt;br /&gt;
       tab.theta=0;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       tab.x=5;&lt;br /&gt;
       tab.y=4;&lt;br /&gt;
       tab.theta=2.5;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       Pose_Machines_Pub.publish(machines_msgs);&lt;br /&gt;
       ros::spinOnce();&lt;br /&gt;
       loop_rate.sleep();&lt;br /&gt;
    }&lt;br /&gt;
    return 0;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On visualise le résultat grâce au logiciel RVIZ qui peut lire les topics publiés et donc le topic /map :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Mapcompet.PNG|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
===Semaine 9===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
l'objectif de cette semaine sera de coder toutes les fonctions nécessaires à l'implémentation finale du [http://fr.wikipedia.org/wiki/Filtre_de_Kalman#Filtre_de_Kalman_.C3.A9tendu filtre de Kalman étendu] :&lt;br /&gt;
&lt;br /&gt;
*initialisations des différents éléments&lt;br /&gt;
*étape de prédiction&lt;br /&gt;
*étape de mise à jour&lt;br /&gt;
*publication des positions machines et du robot dans le repère global via un topic ROS&lt;br /&gt;
&lt;br /&gt;
Le schéma ci-dessous nous montre les deux étapes du filtre de Kalman :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Kalman.png | center]]&lt;br /&gt;
&lt;br /&gt;
le code pour la partie ''prédiction'' :&lt;br /&gt;
&lt;br /&gt;
 //on ressort la position du robot pour l'état n+1&lt;br /&gt;
 //les paramètres sont le vecteurs où on a la position du robot à l'état n, la matrice P, les commandes en vitesses et le temps à l'état n&lt;br /&gt;
 Vector3d prediction(VectorXd xMean, MatrixXd &amp;amp;P, geometry_msgs::Pose2D cmdVel, ros::Time &amp;amp;temps){&lt;br /&gt;
   ros::Duration duree = ros::Time::now() - temps;&lt;br /&gt;
   double periode = duree.toSec();&amp;lt;br&amp;gt;&lt;br /&gt;
   Vector3d cmdVelVect = Pose2DToVector(cmdVel);&lt;br /&gt;
   //le xMean.topLeftCorner(3,1) correspond à la position du robot&lt;br /&gt;
   Vector3d xPredicted = xMean.topLeftCorner(3,1) + periode*cmdVelVect;&amp;lt;br&amp;gt;&lt;br /&gt;
   MatrixXd Fx;&lt;br /&gt;
   Fx = MatrixXd::Identity(P.rows(), P.cols());&lt;br /&gt;
   Fx(0,0) = xPredicted(0);&lt;br /&gt;
   Fx(1,1) = xPredicted(1);&lt;br /&gt;
   Fx(2,2) = xPredicted(2);&amp;lt;br&amp;gt;&lt;br /&gt;
   //mise à jour de P&lt;br /&gt;
   P = Fx*P*(Fx.transpose());&amp;lt;br&amp;gt;&lt;br /&gt;
   //mise à jour du temps&lt;br /&gt;
   temps = ros::Time::now();&amp;lt;br&amp;gt;&lt;br /&gt;
   return xPredicted;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
le code pour la partie ''correction'' :&lt;br /&gt;
&lt;br /&gt;
 void correction(VectorXd &amp;amp;xMean, MatrixXd &amp;amp;P, Vector3d xPredicted, geometry_msgs::Pose2D m){&lt;br /&gt;
   int taille = P.rows();&lt;br /&gt;
   //on vérifie si la machine est présente ou pas dans le vecteur d'état&lt;br /&gt;
   int i = checkStateVector(xMean, m);&amp;lt;br&amp;gt;&lt;br /&gt;
   if (i != 0){&lt;br /&gt;
     //calcul de H&lt;br /&gt;
     MatrixXd H(3, taille);&lt;br /&gt;
     H = buildH(taille, i);&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul de Pm&lt;br /&gt;
     MatrixXd Pm(taille, taille);&lt;br /&gt;
     Pm = buildPm(P, i);&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul de Z&lt;br /&gt;
     MatrixXd Z(taille, taille);&lt;br /&gt;
     Z = H*Pm*(H.transpose());	&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul du gain de Kalman&lt;br /&gt;
     MatrixXd K(taille, taille);&lt;br /&gt;
     K = P*(H.transpose())*(Z.inverse());&amp;lt;br&amp;gt;&lt;br /&gt;
     //mise à jour du vecteur xMean&lt;br /&gt;
     xMean = xMean + K*(xMean.block(xMean.rows()-3,0,3,1) - xPredicted);&amp;lt;br&amp;gt;&lt;br /&gt;
     //mise à jour de la matrice P&lt;br /&gt;
     P = P - K*Z*(K.transpose());&lt;br /&gt;
   }&lt;br /&gt;
   else {&lt;br /&gt;
     addMachine(m, xMean, P);&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Pour notre cas, on doit ajouter des nouvelles machines, alors que pour un EKF classique on observe juste des machines déjà répertoriées. Il faut donc une fonction qui permet d'ajouter une machine dans le vecteur d'état. La voilà :&lt;br /&gt;
&lt;br /&gt;
 void addMachine(geometry_msgs::Pose2D machine, VectorXd &amp;amp;xMean, MatrixXd &amp;amp;P){&lt;br /&gt;
   //on redimensionne xMean et P pour accueillir la nouvelle machines&lt;br /&gt;
   xMean.conservativeResize(xMean.rows() + 3);&lt;br /&gt;
   P.conservativeResize(P.rows()+3,P.cols()+3);&amp;lt;br&amp;gt;&lt;br /&gt;
   //on remplit avec les coordonnées de la nouvelle machine&lt;br /&gt;
   xMean(xMean.rows()-3) = machine.x;&lt;br /&gt;
   xMean(xMean.rows()-2) = machine.y;&lt;br /&gt;
   xMean(xMean.rows()-1) = machine.theta;&amp;lt;br&amp;gt;&lt;br /&gt;
   //calcul de tous les PLi&lt;br /&gt;
   //initialisation des PLi à 0&lt;br /&gt;
   P.block(P.rows() - 3, 0, 3, P.cols()).setZero();&lt;br /&gt;
   P.block(0, P.cols() - 3, P.rows(), 3).setZero();&amp;lt;br&amp;gt;&lt;br /&gt;
   for (int j = 0; j &amp;lt; xMean.rows(); j = j + 3){&lt;br /&gt;
     //position de la nouvelle machines par rapport au robot et à toutes les autres&lt;br /&gt;
     double x 	 = xMean(xMean.rows()-3) - xMean(j  );&lt;br /&gt;
     double y 	 = xMean(xMean.rows()-2) - xMean(j+1);&lt;br /&gt;
     double theta = xMean(xMean.rows()-1) - xMean(j+2);&amp;lt;br&amp;gt;&lt;br /&gt;
     P(P.rows()-3, j  ) = x;&lt;br /&gt;
     P(P.rows()-2, j+1) = y;&lt;br /&gt;
     P(P.rows()-1, j+2) = theta;&amp;lt;br&amp;gt;&lt;br /&gt;
     P(j  , P.rows()-3) = x;&lt;br /&gt;
     P(j+1, P.rows()-2) = y;&lt;br /&gt;
     P(j+2, P.rows()-1) = theta;&amp;lt;br&amp;gt;&lt;br /&gt;
     P(j  , j  ) = xMean(j  ) - xMean(0);&lt;br /&gt;
     P(j+1, j+1) = xMean(j+1) - xMean(1);&lt;br /&gt;
     P(j+2, j+2) = xMean(j+2) - xMean(2);&amp;lt;br&amp;gt;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 10===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
La partie '''prédiction''' du filtre marche parfaitement, quelques corrections ont dues être faites au niveau de la commande vitesse. En effet, Nous avions oublié de la transposer dans le repère global. Pour la partie '''correction''', nous rencontrons un problème de divergence du filtre, qui est probablement due à une mauvaise initialisation. En effet, nous utilisons des enregistrements faits sur notre piste (1/4 de la vraie) avec des initialisations correspondant à la piste originale. Le filtre ne peut donc pas converger car la position de départ est fausse.&lt;br /&gt;
&lt;br /&gt;
===Semaine 11===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
Des corrections sont en cours de validation. Nous essayons de définir une initialisation avec les paramètres de notre piste, ce qui n'est pas évident. Les programmes permettant d'extraire les positions machines du filtres ont été réalisé, ainsi qu'un launch pour pouvoir lancer tous les noeuds de la localisation.&lt;br /&gt;
&lt;br /&gt;
===Semaine 12===&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - mise en place====&lt;br /&gt;
&lt;br /&gt;
Pendant les deux jours de mise en place, nous avons continué à travailler sur la localisation, qui est une partie critique et nécessaire à notre participation. Le filtre en lui même est fonctionnel et permet de corriger la position du robot, ainsi que celle des machines. Cependant, et ce n'est pas un petit &amp;quot;cependant&amp;quot;... Le fait que l'on ajoute des machines en cours de jeu perturbe fortement notre algorithme.&lt;br /&gt;
&lt;br /&gt;
En effet, le filtre de Kalman est optimal si la position des repères est connu, or, un ajout de machine crée un recalage forcé, et si l'on voit plusieurs machines... C'est la '''catastrophe'''. L'ajout de machines est une partie sensible qui nécessite des tests sur la position mesurée, avec un changement de repère à partir de la position du robot, si celle ci dérive, tout dérive. Chaque machine initialisée à la mauvaise position, ou chaque élément détecté comme machine mais n'en étant pas une (faux positif) perturbe le recalage.&lt;br /&gt;
&lt;br /&gt;
De nombreux tests ayant été fait sur la piste officiel avec différentes configurations nous ont permis de vérifier que l'odométrie mesurée ne dérivait que très peu. Il a donc été décidé de n'utiliser que l'odométrie et le scan laser pour la partie '''exploration'''. En effet, chaque machine mesurée est envoyée à un noeud ROS qui va créer une carte et la compléter au fur et à mesure de la partie. Le robot est donc repéré rien qu'avec son odométrie. Le fait que la phase d'exploration (découverte du terrain) ne dure que '''4 minutes''' nous a convaincu pour n'utiliser que cette mesure.&lt;br /&gt;
&lt;br /&gt;
De plus, la carte créée sera utilisée pour la phase suivante, la phase de '''production'''. Cette phase consiste, au niveau de la localisation, à se repérer sur la piste et atteindre la machine demandée par l'exécuteur de tâches. Pour cette phase qui dure '''15 minutes''', l'utilisation du filtre est nécessaire. Donc, avec les coordonnées des machines mesurées pendant la première phase, on peut créer le vecteur d'état et la matrice faisant le lien entre les machines. De là, la taille de ces deux éléments ne variant plus, on peut corriger uniquement la position du robot et le filtre sera efficace.&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - 1er jour====&lt;br /&gt;
&lt;br /&gt;
Durant ce premier jour, nous avons commencé à ''merger'' nos branches respectives pour pouvoir faire tourner tous nos programmes. Cette phase est laborieuse et nous a pris du temps. De toute façon, toutes les équipes ne sont pas prêtes, les organisateurs non plus. La '''Referee Box''' n'est pas fonctionnel pour la phase de production, ce qui veut dire que nous nous concentrons actuellement sur l'exploration. Les matchs joués aujourd'hui ne nous rapporte donc pas de points. Les tests nous ont permis de valider individuellement chacun des algos, il ne reste &amp;quot;plus qu'à&amp;quot; rejoindre le tout.&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - 2eme jour====&lt;br /&gt;
&lt;br /&gt;
Niveau '''localisation''', la navigation à l'odométrie et la détection de machine sont fonctionnelles. Cependant, le moyennage fait sur les positions machines (on moyenne toutes les positions trouvées appartenant à une même machine pour n'avoir qu'un seul point) fait que le point correspondant peut être perturbé par des mesures aberrantes. C'est le cas lorsque le robot se déplace à vitesse élevée.&lt;br /&gt;
&lt;br /&gt;
La détection de machine a été améliorée afin de ne rajouter QUE les machines, et pas les murs de la même taille. Nous allons donc retester le '''filtre de Kalman Etendu''' avec cette amélioration. Cependant, ce ne sera fait qu'après la compétition, puisque d'autres problèmes ont nécessité la présence de l'équipe sur certaines parties sensibles du déplacement.&lt;br /&gt;
&lt;br /&gt;
Sur la piste nous avons fait des mesures, qui nous donnent la carte suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:PisteSamediSoir.PNG | center]]&lt;br /&gt;
&lt;br /&gt;
La visualisation du trajet pour découvrir ces machines est le suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DetectionSamediSoir.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Et les positions machines, ainsi que leur orientation sont les suivantes :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:MachinesBagtestSamediSoir.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - 3eme et dernier jour====&lt;br /&gt;
&lt;br /&gt;
L'architecture choisie pour la localisation est la suivante :&lt;br /&gt;
*Navigation à l'odométrie&lt;br /&gt;
*Détection de machines et moyennage&lt;br /&gt;
*Quand on a vu toutes nos machines, on utilise la symétrie pour compléter les machines restantes&lt;br /&gt;
*Navigation et Localisation avec l'EKF (correction des positions machines et du robot)&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
Après de longs tests et des corrections importantes au niveau de l'ajout des machines dans le filtre, ce qui était la partie critique... Le meilleur résultat que l'on ait pu avoir avec l'EKF est celui ci dessous. Les machines étant en &amp;lt;span style=&amp;quot;color:#9966CC&amp;quot;&amp;gt;violet&amp;lt;/span&amp;gt;, la trajectoire calculée par l'EKF en &amp;lt;span style=&amp;quot;color:#00FF00&amp;quot;&amp;gt;vert&amp;lt;/span&amp;gt; et la trajectoire mesurée par les codeurs en &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;rouge&amp;lt;/span&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:BestResultWithEKF.PNG | center]]&lt;br /&gt;
&lt;br /&gt;
Nous rappelons que tous nos codes sont disponibles sur notre [https://github.com/PyroTeam/robocup-pkg/tree/navigation-devel/navigation/localisation GIT].&lt;br /&gt;
&lt;br /&gt;
====Video====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enfin, afin d'illustrer nos résultats de manière ludique et attrayante, voici une vidéo qui vous donnera goût à la RoboCup !&lt;br /&gt;
&lt;br /&gt;
https://www.youtube.com/watch?v=PB6g2krvCFI&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=20767</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=20767"/>
				<updated>2015-05-07T14:50:32Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Localisation - Extended Kalman Filter */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
*Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
*Recherches de solutions pour la localisation (SLAM)&lt;br /&gt;
*Recherche de solution pour la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - vidéo====&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les résultats de la détection des machines nous avons utiliser l'interface graphique disponible avec ROS, RVIZ. Nous visualisons alors le scan laser (points blancs), le résultat de la détection de segments (en rouge) et les positions des machines trouvées (en vert). Un premier test a été fait sur le scan originel, celui sur lequel nous avons travaillé depuis le début.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=XSn4s1y-XT0 Visualisation des machines]&lt;br /&gt;
&lt;br /&gt;
On rencontre un problème quand le robot est exactement parallèle ou perpendiculaire à un mur. Après vérification dans le programme, il s'avère que la détection ne fonctionne pas pour ces cas. Ce bug est maintenant corrigé :&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=rKeqewpuLoQ Correction du bug]&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
La première étape consiste juste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;br /&gt;
&lt;br /&gt;
la matrice correspondant au changement (laser -&amp;gt; robot) est la suivante : &lt;br /&gt;
&lt;br /&gt;
 0   -1    0&lt;br /&gt;
 1    0  0.2&lt;br /&gt;
 0    0    1&lt;br /&gt;
&lt;br /&gt;
la matrice 2x2 en haut à gauche correspond à la rotation de 90°, et le vecteur (0, 0.2) correspond à la translation.&lt;br /&gt;
&lt;br /&gt;
Celle du changement (robot -&amp;gt; global) avec alpha angle mesuré par le gyroscope depuis la position initiale (angle 0) :&lt;br /&gt;
&lt;br /&gt;
 cos(alpha)   -sin(alpha)    posInit.x&lt;br /&gt;
 sin(alpha)    cos(alpha)    posInit.y&lt;br /&gt;
          0             0            1&lt;br /&gt;
&lt;br /&gt;
l'étape suivante est de vérifier si les machines vues par le laser sont bien des machines, c'est-à-dire si les positions mesurées à partir des données lasers correspond aux zones occupées par des machines envoyées par la Referee Box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Grid Map====&lt;br /&gt;
&lt;br /&gt;
L'autre objectif de cette semaine a été de coder le noeud qui génère la map. La map est générée sous forme d'OccupancyGrid. Ce type est constitué d'un seul vecteur dont la première case correspond à la case en bas à gauche de la map. D'autres paramètres sont réglable comme l'origine et la taille.&lt;br /&gt;
&lt;br /&gt;
Pour la taille on choisit de diviser la map en case de 10 cm et l'origine choisie est le x du centre de la map et en y l'abscisse du premier mur (voir la map ci-dessous). Afin d'expliquer comment est constituée cette map, prenons le code et analysons les différentes fonctions ainsi que le main :&lt;br /&gt;
&lt;br /&gt;
Ce vecteur de Pose2D (x, y et theta (angle de la machine)) va permettre d'enregistrer la position des machines, c'est une variable global qui sera mise à jour avec le Callback :&lt;br /&gt;
&lt;br /&gt;
 std::vector&amp;lt;geometry_msgs::Pose2D&amp;gt; tab;&lt;br /&gt;
&lt;br /&gt;
*Récupération des machines envoyées par le noeud du SLAM (sur le topic /landmarks):&lt;br /&gt;
&lt;br /&gt;
 void Poses_Machine_Callback(const deplacement_msg::LandmarksConstPtr &amp;amp;machines)&lt;br /&gt;
 {&lt;br /&gt;
          tab=machines-&amp;gt;landmarks;&lt;br /&gt;
          for (int i=0; i&amp;lt;tab.size(); i++)&lt;br /&gt;
          {&lt;br /&gt;
     	     tab[i].x = tab[i].x*1000;&lt;br /&gt;
     	     tab[i].y = tab[i].y*1000;&lt;br /&gt;
 	  }&lt;br /&gt;
    &lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
*Création d'une map vide de taille 14m sur 8m. Chaque case est initialisée à une valeur nulle, on remplit également les autres paramètres de OccupancyGrid:&lt;br /&gt;
(On rappelle que la technique utilisée est un vecteur qui représente chaque case auxquelles il associe une probabilité 100 c'est un point interdit et 0 quand c'est un point sans danger pour le passage du robot)&lt;br /&gt;
&lt;br /&gt;
 void Create_Empty_Map(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      Map.info.origin.position.x=-7000;&lt;br /&gt;
      Map.info.origin.position.y=-1000;&lt;br /&gt;
      Map.info.origin.position.z=0;&lt;br /&gt;
      Map.info.origin.orientation.x=0;&lt;br /&gt;
      Map.info.origin.orientation.y=0;&lt;br /&gt;
      Map.info.origin.orientation.z=0;&lt;br /&gt;
      Map.info.origin.orientation.w=1;&lt;br /&gt;
      Map.info.map_load_time=ros::Time::now();&lt;br /&gt;
      Map.info.resolution=100;&lt;br /&gt;
      Map.info.width=140;&lt;br /&gt;
      Map.info.height=80;&lt;br /&gt;
      Map.data.assign(Map.info.width*Map.info.height, 0);                   //map vide&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
*Construction des points fixes de la map donc les murs (probabilité 100) et les zones à risques (probabilité 50):&lt;br /&gt;
&lt;br /&gt;
 void Set_Wall(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
    for (int i=0;i&amp;lt;80;i++)&lt;br /&gt;
    {&lt;br /&gt;
       for (int j=0;j&amp;lt;140;j++)&lt;br /&gt;
       {&lt;br /&gt;
          if ((i&amp;lt;13)||(i&amp;gt;67))) Map.data[j+i*140]=100;&lt;br /&gt;
          if ((j&amp;lt;13)||(j&amp;gt;127)) Map.data[j+i*140]=100;&lt;br /&gt;
       }&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Nous ne mettons pas tout le code de cette fonction étant donné qu'il est long et répétitif puisque c'est le remplissage des données connues, donc en &amp;quot;dur&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Calcul des positions machines: &lt;br /&gt;
&lt;br /&gt;
Lorsqu'on reçoit une position machine, c'est en fait son centre et son orientation par rapport à x que l'on reçoit. Etant donné que les machines doivent être des rectangles de 110cm sur 75cm (réellement 70 x 35 mais on compte la moitié du robot en plus par sécurité), on décide d'abord de déterminer un des coins du rectangle et plus précisément le coin en bas à droite de ce dernier:&lt;br /&gt;
&lt;br /&gt;
 void Get_One_Point_Of_The_Rectangle(float x, float &amp;amp;xA, float y, float &amp;amp;yA, float theta, float largeur, float longueur)&lt;br /&gt;
 {&lt;br /&gt;
      float x1,y1;&lt;br /&gt;
      x1 = x - cos(theta)*longueur;&lt;br /&gt;
      y1 = y - sin(theta)*longueur; &lt;br /&gt;
      xA = x1 + sin(M_PI_2-theta)*largeur;&lt;br /&gt;
      yA = y1 - cos(M_PI_2-theta)*largeur;&lt;br /&gt;
  &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
*Remplissage des positions sur la map :&lt;br /&gt;
&lt;br /&gt;
On met alors tous les points de ce rectangle à une probabilité 100 dans le vecteur Map. Pour les calculs on différencie le cas ou l'angle de la machine est entre 0 et pi/2 et le cas où il est entre pi/2 et pi. L'algorithme est le suivant : &lt;br /&gt;
&lt;br /&gt;
 A partir du coin, on incrémente x et y de sorte à longer le grand coté et de remplir chaque case (incrémentation de 5 cm).&lt;br /&gt;
 Une fois arrivé au bout, on incrémente x et y de 5cm sur la largeur à partir du coin et on recommence l'opération précédente.&lt;br /&gt;
 Ceci jusqu'à remplir le complètement le rectangle.&lt;br /&gt;
&lt;br /&gt;
Afin d'établir les probabilités correspondantes aux cases de ce rectangle, nous utilisons la fonctions floor() pour &amp;quot;convertir&amp;quot; nos flottants en entier et accéder à la case correspondante. On notera aussi que la case 1470 correspond à l'origine de notre map.&lt;br /&gt;
&lt;br /&gt;
 void Set_Machines_In_Map(float rank, float theta, float xA, float yA, nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      float x=xA;&lt;br /&gt;
      float y=yA;&lt;br /&gt;
      if (theta&amp;lt;=M_PI_2)&lt;br /&gt;
      {&lt;br /&gt;
            for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
            {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++) &lt;br /&gt;
                  {&lt;br /&gt;
                      Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                      x = x + cos(theta)*50;&lt;br /&gt;
                      y = y + sin(theta)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(M_PI_2-theta)*50;&lt;br /&gt;
                  y = yA + j*sin(M_PI_2-theta)*50;&lt;br /&gt;
            }	&lt;br /&gt;
       }&lt;br /&gt;
       if (theta&amp;gt;M_PI_2)&lt;br /&gt;
       {&lt;br /&gt;
             for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
             {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++)&lt;br /&gt;
                  {&lt;br /&gt;
                        Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                        x = x - sin(theta-M_PI_2)*50;&lt;br /&gt;
                        y = y + cos(theta-M_PI_2)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(theta-M_PI_2)*50;&lt;br /&gt;
                  y = yA - j*sin(theta-M_PI_2)*50;&lt;br /&gt;
              }	&lt;br /&gt;
        }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Ci dessous on a les mains, avec les différentes fonctions appelées et la syntaxe particulière à ROS. &lt;br /&gt;
&lt;br /&gt;
*Noeud général pour le traitement et le remplissage de la map :   &lt;br /&gt;
                 &lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
     ros::init(argc, argv, &amp;quot;server&amp;quot;);&lt;br /&gt;
     ros::NodeHandle n;&lt;br /&gt;
     ros::Subscriber sub_poses_machine    = n.subscribe(&amp;quot;/machines&amp;quot;, 1000, Poses_Machine_Callback);   // Récupération des machines&lt;br /&gt;
     ros::Publisher Map_Pub = n.advertise&amp;lt;nav_msgs::OccupancyGrid&amp;gt;(&amp;quot;/map&amp;quot;, 1000);                     // Préparation de la publication de la map&lt;br /&gt;
     ROS_INFO(&amp;quot;Ready to Generate the Map&amp;quot;);&lt;br /&gt;
     float xA,yA;&lt;br /&gt;
     ros::Rate loop_rate(1);&lt;br /&gt;
     while(ros::ok())&lt;br /&gt;
     {&lt;br /&gt;
        nav_msgs::OccupancyGrid Map;&lt;br /&gt;
        Create_Empty_Map(Map);&lt;br /&gt;
        Set_Wall(Map);&lt;br /&gt;
        for (int z=0;z&amp;lt;tab.size();z++)&lt;br /&gt;
        {&lt;br /&gt;
           Get_One_Point_Of_The_Rectangle(tab[z].x, xA, tab[z].y, yA, tab[z].theta, 275, 450);&lt;br /&gt;
 	   Set_Machines_In_Map(100, tab[z].theta, xA, yA, Map);&lt;br /&gt;
        }&lt;br /&gt;
        Map_Pub.publish(Map);                                                                   // publication de la map&lt;br /&gt;
        ros::spinOnce();&lt;br /&gt;
        loop_rate.sleep();&lt;br /&gt;
     }&lt;br /&gt;
     return 0;&lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Noeud test qui publie 2 positions de machines : &lt;br /&gt;
&lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
    ros::init(argc, argv, &amp;quot;test&amp;quot;);&lt;br /&gt;
    ros::NodeHandle n;&lt;br /&gt;
    ros::Publisher Pose_Machines_Pub = n.advertise&amp;lt;deplacement_msg::Landmarks&amp;gt;(&amp;quot;/machines&amp;quot;, 1000);&lt;br /&gt;
    ROS_INFO(&amp;quot;Ready to send poses machines&amp;quot;);&lt;br /&gt;
    int xA,yA;&lt;br /&gt;
    ros::Rate loop_rate(1);&lt;br /&gt;
    while(ros::ok())&lt;br /&gt;
    {&lt;br /&gt;
       deplacement_msg::Landmarks machines_msgs;&lt;br /&gt;
       geometry_msgs::Pose2D tab;&lt;br /&gt;
       tab.x=-2;&lt;br /&gt;
       tab.y=2;&lt;br /&gt;
       tab.theta=0;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       tab.x=5;&lt;br /&gt;
       tab.y=4;&lt;br /&gt;
       tab.theta=2.5;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       Pose_Machines_Pub.publish(machines_msgs);&lt;br /&gt;
       ros::spinOnce();&lt;br /&gt;
       loop_rate.sleep();&lt;br /&gt;
    }&lt;br /&gt;
    return 0;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On visualise le résultat grâce au logiciel RVIZ qui peut lire les topics publiés et donc le topic /map :&lt;br /&gt;
&lt;br /&gt;
===Semaine 9===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
l'objectif de cette semaine sera de coder toutes les fonctions nécessaires à l'implémentation finale du [http://fr.wikipedia.org/wiki/Filtre_de_Kalman#Filtre_de_Kalman_.C3.A9tendu filtre de Kalman étendu] :&lt;br /&gt;
&lt;br /&gt;
*initialisations des différents éléments&lt;br /&gt;
*étape de prédiction&lt;br /&gt;
*étape de mise à jour&lt;br /&gt;
*publication des positions machines et du robot dans le repère global via un topic ROS&lt;br /&gt;
&lt;br /&gt;
Le schéma ci-dessous nous montre les deux étapes du filtre de Kalman :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Kalman.png | center]]&lt;br /&gt;
&lt;br /&gt;
le code pour la partie ''prédiction'' :&lt;br /&gt;
&lt;br /&gt;
 //on ressort la position du robot pour l'état n+1&lt;br /&gt;
 //les paramètres sont le vecteurs où on a la position du robot à l'état n, la matrice P, les commandes en vitesses et le temps à l'état n&lt;br /&gt;
 Vector3d prediction(VectorXd xMean, MatrixXd &amp;amp;P, geometry_msgs::Pose2D cmdVel, ros::Time &amp;amp;temps){&lt;br /&gt;
   ros::Duration duree = ros::Time::now() - temps;&lt;br /&gt;
   double periode = duree.toSec();&amp;lt;br&amp;gt;&lt;br /&gt;
   Vector3d cmdVelVect = Pose2DToVector(cmdVel);&lt;br /&gt;
   //le xMean.topLeftCorner(3,1) correspond à la position du robot&lt;br /&gt;
   Vector3d xPredicted = xMean.topLeftCorner(3,1) + periode*cmdVelVect;&amp;lt;br&amp;gt;&lt;br /&gt;
   MatrixXd Fx;&lt;br /&gt;
   Fx = MatrixXd::Identity(P.rows(), P.cols());&lt;br /&gt;
   Fx(0,0) = xPredicted(0);&lt;br /&gt;
   Fx(1,1) = xPredicted(1);&lt;br /&gt;
   Fx(2,2) = xPredicted(2);&amp;lt;br&amp;gt;&lt;br /&gt;
   //mise à jour de P&lt;br /&gt;
   P = Fx*P*(Fx.transpose());&amp;lt;br&amp;gt;&lt;br /&gt;
   //mise à jour du temps&lt;br /&gt;
   temps = ros::Time::now();&amp;lt;br&amp;gt;&lt;br /&gt;
   return xPredicted;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
le code pour la partie ''correction'' :&lt;br /&gt;
&lt;br /&gt;
 void correction(VectorXd &amp;amp;xMean, MatrixXd &amp;amp;P, Vector3d xPredicted, geometry_msgs::Pose2D m){&lt;br /&gt;
   int taille = P.rows();&lt;br /&gt;
   //on vérifie si la machine est présente ou pas dans le vecteur d'état&lt;br /&gt;
   int i = checkStateVector(xMean, m);&amp;lt;br&amp;gt;&lt;br /&gt;
   if (i != 0){&lt;br /&gt;
     //calcul de H&lt;br /&gt;
     MatrixXd H(3, taille);&lt;br /&gt;
     H = buildH(taille, i);&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul de Pm&lt;br /&gt;
     MatrixXd Pm(taille, taille);&lt;br /&gt;
     Pm = buildPm(P, i);&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul de Z&lt;br /&gt;
     MatrixXd Z(taille, taille);&lt;br /&gt;
     Z = H*Pm*(H.transpose());	&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul du gain de Kalman&lt;br /&gt;
     MatrixXd K(taille, taille);&lt;br /&gt;
     K = P*(H.transpose())*(Z.inverse());&amp;lt;br&amp;gt;&lt;br /&gt;
     //mise à jour du vecteur xMean&lt;br /&gt;
     xMean = xMean + K*(xMean.block(xMean.rows()-3,0,3,1) - xPredicted);&amp;lt;br&amp;gt;&lt;br /&gt;
     //mise à jour de la matrice P&lt;br /&gt;
     P = P - K*Z*(K.transpose());&lt;br /&gt;
   }&lt;br /&gt;
   else {&lt;br /&gt;
     addMachine(m, xMean, P);&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Pour notre cas, on doit ajouter des nouvelles machines, alors que pour un EKF classique on observe juste des machines déjà répertoriées. Il faut donc une fonction qui permet d'ajouter une machine dans le vecteur d'état. La voilà :&lt;br /&gt;
&lt;br /&gt;
 void addMachine(geometry_msgs::Pose2D machine, VectorXd &amp;amp;xMean, MatrixXd &amp;amp;P){&lt;br /&gt;
   //on redimensionne xMean et P pour accueillir la nouvelle machines&lt;br /&gt;
   xMean.conservativeResize(xMean.rows() + 3);&lt;br /&gt;
   P.conservativeResize(P.rows()+3,P.cols()+3);&amp;lt;br&amp;gt;&lt;br /&gt;
   //on remplit avec les coordonnées de la nouvelle machine&lt;br /&gt;
   xMean(xMean.rows()-3) = machine.x;&lt;br /&gt;
   xMean(xMean.rows()-2) = machine.y;&lt;br /&gt;
   xMean(xMean.rows()-1) = machine.theta;&amp;lt;br&amp;gt;&lt;br /&gt;
   //calcul de tous les PLi&lt;br /&gt;
   //initialisation des PLi à 0&lt;br /&gt;
   P.block(P.rows() - 3, 0, 3, P.cols()).setZero();&lt;br /&gt;
   P.block(0, P.cols() - 3, P.rows(), 3).setZero();&amp;lt;br&amp;gt;&lt;br /&gt;
   for (int j = 0; j &amp;lt; xMean.rows(); j = j + 3){&lt;br /&gt;
     //position de la nouvelle machines par rapport au robot et à toutes les autres&lt;br /&gt;
     double x 	 = xMean(xMean.rows()-3) - xMean(j  );&lt;br /&gt;
     double y 	 = xMean(xMean.rows()-2) - xMean(j+1);&lt;br /&gt;
     double theta = xMean(xMean.rows()-1) - xMean(j+2);&amp;lt;br&amp;gt;&lt;br /&gt;
     P(P.rows()-3, j  ) = x;&lt;br /&gt;
     P(P.rows()-2, j+1) = y;&lt;br /&gt;
     P(P.rows()-1, j+2) = theta;&amp;lt;br&amp;gt;&lt;br /&gt;
     P(j  , P.rows()-3) = x;&lt;br /&gt;
     P(j+1, P.rows()-2) = y;&lt;br /&gt;
     P(j+2, P.rows()-1) = theta;&amp;lt;br&amp;gt;&lt;br /&gt;
     P(j  , j  ) = xMean(j  ) - xMean(0);&lt;br /&gt;
     P(j+1, j+1) = xMean(j+1) - xMean(1);&lt;br /&gt;
     P(j+2, j+2) = xMean(j+2) - xMean(2);&amp;lt;br&amp;gt;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 10===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
La partie '''prédiction''' du filtre marche parfaitement, quelques corrections ont dues être faites au niveau de la commande vitesse. En effet, Nous avions oublié de la transposer dans le repère global. Pour la partie '''correction''', nous rencontrons un problème de divergence du filtre, qui est probablement due à une mauvaise initialisation. En effet, nous utilisons des enregistrements faits sur notre piste (1/4 de la vraie) avec des initialisations correspondant à la piste originale. Le filtre ne peut donc pas converger car la position de départ est fausse.&lt;br /&gt;
&lt;br /&gt;
===Semaine 11===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
Des corrections sont en cours de validation. Nous essayons de définir une initialisation avec les paramètres de notre piste, ce qui n'est pas évident. Les programmes permettant d'extraire les positions machines du filtres ont été réalisé, ainsi qu'un launch pour pouvoir lancer tous les noeuds de la localisation.&lt;br /&gt;
&lt;br /&gt;
===Semaine 12===&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - mise en place====&lt;br /&gt;
&lt;br /&gt;
Pendant les deux jours de mise en place, nous avons continué à travailler sur la localisation, qui est une partie critique et nécessaire à notre participation. Le filtre en lui même est fonctionnel et permet de corriger la position du robot, ainsi que celle des machines. Cependant, et ce n'est pas un petit &amp;quot;cependant&amp;quot;... Le fait que l'on ajoute des machines en cours de jeu perturbe fortement notre algorithme.&lt;br /&gt;
&lt;br /&gt;
En effet, le filtre de Kalman est optimal si la position des repères est connu, or, un ajout de machine crée un recalage forcé, et si l'on voit plusieurs machines... C'est la '''catastrophe'''. L'ajout de machines est une partie sensible qui nécessite des tests sur la position mesurée, avec un changement de repère à partir de la position du robot, si celle ci dérive, tout dérive. Chaque machine initialisée à la mauvaise position, ou chaque élément détecté comme machine mais n'en étant pas une (faux positif) perturbe le recalage.&lt;br /&gt;
&lt;br /&gt;
De nombreux tests ayant été fait sur la piste officiel avec différentes configurations nous ont permis de vérifier que l'odométrie mesurée ne dérivait que très peu. Il a donc été décidé de n'utiliser que l'odométrie et le scan laser pour la partie '''exploration'''. En effet, chaque machine mesurée est envoyée à un noeud ROS qui va créer une carte et la compléter au fur et à mesure de la partie. Le robot est donc repéré rien qu'avec son odométrie. Le fait que la phase d'exploration (découverte du terrain) ne dure que '''4 minutes''' nous a convaincu pour n'utiliser que cette mesure.&lt;br /&gt;
&lt;br /&gt;
De plus, la carte créée sera utilisée pour la phase suivante, la phase de '''production'''. Cette phase consiste, au niveau de la localisation, à se repérer sur la piste et atteindre la machine demandée par l'exécuteur de tâches. Pour cette phase qui dure '''15 minutes''', l'utilisation du filtre est nécessaire. Donc, avec les coordonnées des machines mesurées pendant la première phase, on peut créer le vecteur d'état et la matrice faisant le lien entre les machines. De là, la taille de ces deux éléments ne variant plus, on peut corriger uniquement la position du robot et le filtre sera efficace.&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - 1er jour====&lt;br /&gt;
&lt;br /&gt;
Durant ce premier jour, nous avons commencé à ''merger'' nos branches respectives pour pouvoir faire tourner tous nos programmes. Cette phase est laborieuse et nous a pris du temps. De toute façon, toutes les équipes ne sont pas prêtes, les organisateurs non plus. La '''Referee Box''' n'est pas fonctionnel pour la phase de production, ce qui veut dire que nous nous concentrons actuellement sur l'exploration. Les matchs joués aujourd'hui ne nous rapporte donc pas de points. Les tests nous ont permis de valider individuellement chacun des algos, il ne reste &amp;quot;plus qu'à&amp;quot; rejoindre le tout.&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - 2eme jour====&lt;br /&gt;
&lt;br /&gt;
Niveau '''localisation''', la navigation à l'odométrie et la détection de machine sont fonctionnelles. Cependant, le moyennage fait sur les positions machines (on moyenne toutes les positions trouvées appartenant à une même machine pour n'avoir qu'un seul point) fait que le point correspondant peut être perturbé par des mesures aberrantes. C'est le cas lorsque le robot se déplace à vitesse élevée.&lt;br /&gt;
&lt;br /&gt;
La détection de machine a été améliorée afin de ne rajouter QUE les machines, et pas les murs de la même taille. Nous allons donc retester le '''filtre de Kalman Etendu''' avec cette amélioration. Cependant, ce ne sera fait qu'après la compétition, puisque d'autres problèmes ont nécessité la présence de l'équipe sur certaines parties sensibles du déplacement.&lt;br /&gt;
&lt;br /&gt;
Sur la piste nous avons fait des mesures, qui nous donnent la carte suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:PisteSamediSoir.PNG | center]]&lt;br /&gt;
&lt;br /&gt;
La visualisation du trajet pour découvrir ces machines est le suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DetectionSamediSoir.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Et les positions machines, ainsi que leur orientation sont les suivantes :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:MachinesBagtestSamediSoir.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - 3eme et dernier jour====&lt;br /&gt;
&lt;br /&gt;
L'architecture choisie pour la localisation est la suivante :&lt;br /&gt;
*Navigation à l'odométrie&lt;br /&gt;
*Détection de machines et moyennage&lt;br /&gt;
*Quand on a vu toutes nos machines, on utilise la symétrie pour compléter les machines restantes&lt;br /&gt;
*Navigation et Localisation avec l'EKF (correction des positions machines et du robot)&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
Après de longs tests et des corrections importantes au niveau de l'ajout des machines dans le filtre, ce qui était la partie critique... Le meilleur résultat que l'on ait pu avoir avec l'EKF est celui ci dessous. Les machines étant en &amp;lt;span style=&amp;quot;color:#9966CC&amp;quot;&amp;gt;violet&amp;lt;/span&amp;gt;, la trajectoire calculée par l'EKF en &amp;lt;span style=&amp;quot;color:#00FF00&amp;quot;&amp;gt;vert&amp;lt;/span&amp;gt; et la trajectoire mesurée par les codeurs en &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;rouge&amp;lt;/span&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:BestResultWithEKF.PNG | center]]&lt;br /&gt;
&lt;br /&gt;
Nous rappelons que tous nos codes sont disponibles sur notre [https://github.com/PyroTeam/robocup-pkg/tree/navigation-devel/navigation/localisation GIT].&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=20610</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=20610"/>
				<updated>2015-05-04T15:19:56Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Etablissement du cahier des charges */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
*Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
*Recherches de solutions pour la localisation (SLAM)&lt;br /&gt;
*Recherche de solution pour la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - vidéo====&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les résultats de la détection des machines nous avons utiliser l'interface graphique disponible avec ROS, RVIZ. Nous visualisons alors le scan laser (points blancs), le résultat de la détection de segments (en rouge) et les positions des machines trouvées (en vert). Un premier test a été fait sur le scan originel, celui sur lequel nous avons travaillé depuis le début.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=XSn4s1y-XT0 Visualisation des machines]&lt;br /&gt;
&lt;br /&gt;
On rencontre un problème quand le robot est exactement parallèle ou perpendiculaire à un mur. Après vérification dans le programme, il s'avère que la détection ne fonctionne pas pour ces cas. Ce bug est maintenant corrigé :&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=rKeqewpuLoQ Correction du bug]&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
La première étape consiste juste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;br /&gt;
&lt;br /&gt;
la matrice correspondant au changement (laser -&amp;gt; robot) est la suivante : &lt;br /&gt;
&lt;br /&gt;
 0   -1    0&lt;br /&gt;
 1    0  0.2&lt;br /&gt;
 0    0    1&lt;br /&gt;
&lt;br /&gt;
la matrice 2x2 en haut à gauche correspond à la rotation de 90°, et le vecteur (0, 0.2) correspond à la translation.&lt;br /&gt;
&lt;br /&gt;
Celle du changement (robot -&amp;gt; global) avec alpha angle mesuré par le gyroscope depuis la position initiale (angle 0) :&lt;br /&gt;
&lt;br /&gt;
 cos(alpha)   -sin(alpha)    posInit.x&lt;br /&gt;
 sin(alpha)    cos(alpha)    posInit.y&lt;br /&gt;
          0             0            1&lt;br /&gt;
&lt;br /&gt;
l'étape suivante est de vérifier si les machines vues par le laser sont bien des machines, c'est-à-dire si les positions mesurées à partir des données lasers correspond aux zones occupées par des machines envoyées par la Referee Box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Grid Map====&lt;br /&gt;
&lt;br /&gt;
L'autre objectif de cette semaine a été de coder le noeud qui génère la map. La map est générée sous forme d'OccupancyGrid. Ce type est constitué d'un seul vecteur dont la première case correspond à la case en bas à gauche de la map. D'autres paramètres sont réglable comme l'origine et la taille.&lt;br /&gt;
&lt;br /&gt;
Pour la taille on choisit de diviser la map en case de 10 cm et l'origine choisie est le x du centre de la map et en y l'abscisse du premier mur (voir la map ci-dessous). Afin d'expliquer comment est constituée cette map, prenons le code et analysons les différentes fonctions ainsi que le main :&lt;br /&gt;
&lt;br /&gt;
Ce vecteur de Pose2D (x, y et theta (angle de la machine)) va permettre d'enregistrer la position des machines, c'est une variable global qui sera mise à jour avec le Callback :&lt;br /&gt;
&lt;br /&gt;
 std::vector&amp;lt;geometry_msgs::Pose2D&amp;gt; tab;&lt;br /&gt;
&lt;br /&gt;
*Récupération des machines envoyées par le noeud du SLAM (sur le topic /landmarks):&lt;br /&gt;
&lt;br /&gt;
 void Poses_Machine_Callback(const deplacement_msg::LandmarksConstPtr &amp;amp;machines)&lt;br /&gt;
 {&lt;br /&gt;
          tab=machines-&amp;gt;landmarks;&lt;br /&gt;
          for (int i=0; i&amp;lt;tab.size(); i++)&lt;br /&gt;
          {&lt;br /&gt;
     	     tab[i].x = tab[i].x*1000;&lt;br /&gt;
     	     tab[i].y = tab[i].y*1000;&lt;br /&gt;
 	  }&lt;br /&gt;
    &lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
*Création d'une map vide de taille 14m sur 8m. Chaque case est initialisée à une valeur nulle, on remplit également les autres paramètres de OccupancyGrid:&lt;br /&gt;
(On rappelle que la technique utilisée est un vecteur qui représente chaque case auxquelles il associe une probabilité 100 c'est un point interdit et 0 quand c'est un point sans danger pour le passage du robot)&lt;br /&gt;
&lt;br /&gt;
 void Create_Empty_Map(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      Map.info.origin.position.x=-7000;&lt;br /&gt;
      Map.info.origin.position.y=-1000;&lt;br /&gt;
      Map.info.origin.position.z=0;&lt;br /&gt;
      Map.info.origin.orientation.x=0;&lt;br /&gt;
      Map.info.origin.orientation.y=0;&lt;br /&gt;
      Map.info.origin.orientation.z=0;&lt;br /&gt;
      Map.info.origin.orientation.w=1;&lt;br /&gt;
      Map.info.map_load_time=ros::Time::now();&lt;br /&gt;
      Map.info.resolution=100;&lt;br /&gt;
      Map.info.width=140;&lt;br /&gt;
      Map.info.height=80;&lt;br /&gt;
      Map.data.assign(Map.info.width*Map.info.height, 0);                   //map vide&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
*Construction des points fixes de la map donc les murs (probabilité 100) et les zones à risques (probabilité 50):&lt;br /&gt;
&lt;br /&gt;
 void Set_Wall(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
    for (int i=0;i&amp;lt;80;i++)&lt;br /&gt;
    {&lt;br /&gt;
       for (int j=0;j&amp;lt;140;j++)&lt;br /&gt;
       {&lt;br /&gt;
          if ((i&amp;lt;13)||(i&amp;gt;67))) Map.data[j+i*140]=100;&lt;br /&gt;
          if ((j&amp;lt;13)||(j&amp;gt;127)) Map.data[j+i*140]=100;&lt;br /&gt;
       }&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Nous ne mettons pas tout le code de cette fonction étant donné qu'il est long et répétitif puisque c'est le remplissage des données connues, donc en &amp;quot;dur&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Calcul des positions machines: &lt;br /&gt;
&lt;br /&gt;
Lorsqu'on reçoit une position machine, c'est en fait son centre et son orientation par rapport à x que l'on reçoit. Etant donné que les machines doivent être des rectangles de 110cm sur 75cm (réellement 70 x 35 mais on compte la moitié du robot en plus par sécurité), on décide d'abord de déterminer un des coins du rectangle et plus précisément le coin en bas à droite de ce dernier:&lt;br /&gt;
&lt;br /&gt;
 void Get_One_Point_Of_The_Rectangle(float x, float &amp;amp;xA, float y, float &amp;amp;yA, float theta, float largeur, float longueur)&lt;br /&gt;
 {&lt;br /&gt;
      float x1,y1;&lt;br /&gt;
      x1 = x - cos(theta)*longueur;&lt;br /&gt;
      y1 = y - sin(theta)*longueur; &lt;br /&gt;
      xA = x1 + sin(M_PI_2-theta)*largeur;&lt;br /&gt;
      yA = y1 - cos(M_PI_2-theta)*largeur;&lt;br /&gt;
  &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
*Remplissage des positions sur la map :&lt;br /&gt;
&lt;br /&gt;
On met alors tous les points de ce rectangle à une probabilité 100 dans le vecteur Map. Pour les calculs on différencie le cas ou l'angle de la machine est entre 0 et pi/2 et le cas où il est entre pi/2 et pi. L'algorithme est le suivant : &lt;br /&gt;
&lt;br /&gt;
 A partir du coin, on incrémente x et y de sorte à longer le grand coté et de remplir chaque case (incrémentation de 5 cm).&lt;br /&gt;
 Une fois arrivé au bout, on incrémente x et y de 5cm sur la largeur à partir du coin et on recommence l'opération précédente.&lt;br /&gt;
 Ceci jusqu'à remplir le complètement le rectangle.&lt;br /&gt;
&lt;br /&gt;
Afin d'établir les probabilités correspondantes aux cases de ce rectangle, nous utilisons la fonctions floor() pour &amp;quot;convertir&amp;quot; nos flottants en entier et accéder à la case correspondante. On notera aussi que la case 1470 correspond à l'origine de notre map.&lt;br /&gt;
&lt;br /&gt;
 void Set_Machines_In_Map(float rank, float theta, float xA, float yA, nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      float x=xA;&lt;br /&gt;
      float y=yA;&lt;br /&gt;
      if (theta&amp;lt;=M_PI_2)&lt;br /&gt;
      {&lt;br /&gt;
            for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
            {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++) &lt;br /&gt;
                  {&lt;br /&gt;
                      Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                      x = x + cos(theta)*50;&lt;br /&gt;
                      y = y + sin(theta)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(M_PI_2-theta)*50;&lt;br /&gt;
                  y = yA + j*sin(M_PI_2-theta)*50;&lt;br /&gt;
            }	&lt;br /&gt;
       }&lt;br /&gt;
       if (theta&amp;gt;M_PI_2)&lt;br /&gt;
       {&lt;br /&gt;
             for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
             {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++)&lt;br /&gt;
                  {&lt;br /&gt;
                        Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                        x = x - sin(theta-M_PI_2)*50;&lt;br /&gt;
                        y = y + cos(theta-M_PI_2)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(theta-M_PI_2)*50;&lt;br /&gt;
                  y = yA - j*sin(theta-M_PI_2)*50;&lt;br /&gt;
              }	&lt;br /&gt;
        }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Ci dessous on a les mains, avec les différentes fonctions appelées et la syntaxe particulière à ROS. &lt;br /&gt;
&lt;br /&gt;
*Noeud général pour le traitement et le remplissage de la map :   &lt;br /&gt;
                 &lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
     ros::init(argc, argv, &amp;quot;server&amp;quot;);&lt;br /&gt;
     ros::NodeHandle n;&lt;br /&gt;
     ros::Subscriber sub_poses_machine    = n.subscribe(&amp;quot;/machines&amp;quot;, 1000, Poses_Machine_Callback);   // Récupération des machines&lt;br /&gt;
     ros::Publisher Map_Pub = n.advertise&amp;lt;nav_msgs::OccupancyGrid&amp;gt;(&amp;quot;/map&amp;quot;, 1000);                     // Préparation de la publication de la map&lt;br /&gt;
     ROS_INFO(&amp;quot;Ready to Generate the Map&amp;quot;);&lt;br /&gt;
     float xA,yA;&lt;br /&gt;
     ros::Rate loop_rate(1);&lt;br /&gt;
     while(ros::ok())&lt;br /&gt;
     {&lt;br /&gt;
        nav_msgs::OccupancyGrid Map;&lt;br /&gt;
        Create_Empty_Map(Map);&lt;br /&gt;
        Set_Wall(Map);&lt;br /&gt;
        for (int z=0;z&amp;lt;tab.size();z++)&lt;br /&gt;
        {&lt;br /&gt;
           Get_One_Point_Of_The_Rectangle(tab[z].x, xA, tab[z].y, yA, tab[z].theta, 275, 450);&lt;br /&gt;
 	   Set_Machines_In_Map(100, tab[z].theta, xA, yA, Map);&lt;br /&gt;
        }&lt;br /&gt;
        Map_Pub.publish(Map);                                                                   // publication de la map&lt;br /&gt;
        ros::spinOnce();&lt;br /&gt;
        loop_rate.sleep();&lt;br /&gt;
     }&lt;br /&gt;
     return 0;&lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Noeud test qui publie 2 positions de machines : &lt;br /&gt;
&lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
    ros::init(argc, argv, &amp;quot;test&amp;quot;);&lt;br /&gt;
    ros::NodeHandle n;&lt;br /&gt;
    ros::Publisher Pose_Machines_Pub = n.advertise&amp;lt;deplacement_msg::Landmarks&amp;gt;(&amp;quot;/machines&amp;quot;, 1000);&lt;br /&gt;
    ROS_INFO(&amp;quot;Ready to send poses machines&amp;quot;);&lt;br /&gt;
    int xA,yA;&lt;br /&gt;
    ros::Rate loop_rate(1);&lt;br /&gt;
    while(ros::ok())&lt;br /&gt;
    {&lt;br /&gt;
       deplacement_msg::Landmarks machines_msgs;&lt;br /&gt;
       geometry_msgs::Pose2D tab;&lt;br /&gt;
       tab.x=-2;&lt;br /&gt;
       tab.y=2;&lt;br /&gt;
       tab.theta=0;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       tab.x=5;&lt;br /&gt;
       tab.y=4;&lt;br /&gt;
       tab.theta=2.5;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       Pose_Machines_Pub.publish(machines_msgs);&lt;br /&gt;
       ros::spinOnce();&lt;br /&gt;
       loop_rate.sleep();&lt;br /&gt;
    }&lt;br /&gt;
    return 0;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On visualise le résultat grâce au logiciel RVIZ qui peut lire les topics publiés et donc le topic /map :&lt;br /&gt;
&lt;br /&gt;
===Semaine 9===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
l'objectif de cette semaine sera de coder toutes les fonctions nécessaires à l'implémentation finale du [http://fr.wikipedia.org/wiki/Filtre_de_Kalman#Filtre_de_Kalman_.C3.A9tendu filtre de Kalman étendu] :&lt;br /&gt;
&lt;br /&gt;
*initialisations des différents éléments&lt;br /&gt;
*étape de prédiction&lt;br /&gt;
*étape de mise à jour&lt;br /&gt;
*publication des positions machines et du robot dans le repère global via un topic ROS&lt;br /&gt;
&lt;br /&gt;
Le schéma ci-dessous nous montre les deux étapes du filtre de Kalman :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Kalman.png | center]]&lt;br /&gt;
&lt;br /&gt;
le code pour la partie ''prédiction'' :&lt;br /&gt;
&lt;br /&gt;
 //on ressort la position du robot pour l'état n+1&lt;br /&gt;
 //les paramètres sont le vecteurs où on a la position du robot à l'état n, la matrice P, les commandes en vitesses et le temps à l'état n&lt;br /&gt;
 Vector3d prediction(VectorXd xMean, MatrixXd &amp;amp;P, geometry_msgs::Pose2D cmdVel, ros::Time &amp;amp;temps){&lt;br /&gt;
   ros::Duration duree = ros::Time::now() - temps;&lt;br /&gt;
   double periode = duree.toSec();&amp;lt;br&amp;gt;&lt;br /&gt;
   Vector3d cmdVelVect = Pose2DToVector(cmdVel);&lt;br /&gt;
   //le xMean.topLeftCorner(3,1) correspond à la position du robot&lt;br /&gt;
   Vector3d xPredicted = xMean.topLeftCorner(3,1) + periode*cmdVelVect;&amp;lt;br&amp;gt;&lt;br /&gt;
   MatrixXd Fx;&lt;br /&gt;
   Fx = MatrixXd::Identity(P.rows(), P.cols());&lt;br /&gt;
   Fx(0,0) = xPredicted(0);&lt;br /&gt;
   Fx(1,1) = xPredicted(1);&lt;br /&gt;
   Fx(2,2) = xPredicted(2);&amp;lt;br&amp;gt;&lt;br /&gt;
   //mise à jour de P&lt;br /&gt;
   P = Fx*P*(Fx.transpose());&amp;lt;br&amp;gt;&lt;br /&gt;
   //mise à jour du temps&lt;br /&gt;
   temps = ros::Time::now();&amp;lt;br&amp;gt;&lt;br /&gt;
   return xPredicted;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
le code pour la partie ''correction'' :&lt;br /&gt;
&lt;br /&gt;
 void correction(VectorXd &amp;amp;xMean, MatrixXd &amp;amp;P, Vector3d xPredicted, geometry_msgs::Pose2D m){&lt;br /&gt;
   int taille = P.rows();&lt;br /&gt;
   //on vérifie si la machine est présente ou pas dans le vecteur d'état&lt;br /&gt;
   int i = checkStateVector(xMean, m);&amp;lt;br&amp;gt;&lt;br /&gt;
   if (i != 0){&lt;br /&gt;
     //calcul de H&lt;br /&gt;
     MatrixXd H(3, taille);&lt;br /&gt;
     H = buildH(taille, i);&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul de Pm&lt;br /&gt;
     MatrixXd Pm(taille, taille);&lt;br /&gt;
     Pm = buildPm(P, i);&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul de Z&lt;br /&gt;
     MatrixXd Z(taille, taille);&lt;br /&gt;
     Z = H*Pm*(H.transpose());	&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul du gain de Kalman&lt;br /&gt;
     MatrixXd K(taille, taille);&lt;br /&gt;
     K = P*(H.transpose())*(Z.inverse());&amp;lt;br&amp;gt;&lt;br /&gt;
     //mise à jour du vecteur xMean&lt;br /&gt;
     xMean = xMean + K*(xMean.block(xMean.rows()-3,0,3,1) - xPredicted);&amp;lt;br&amp;gt;&lt;br /&gt;
     //mise à jour de la matrice P&lt;br /&gt;
     P = P - K*Z*(K.transpose());&lt;br /&gt;
   }&lt;br /&gt;
   else {&lt;br /&gt;
     addMachine(m, xMean, P);&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Pour notre cas, on doit ajouter des nouvelles machines, alors que pour un EKF classique on observe juste des machines déjà répertoriées. Il faut donc une fonction qui permet d'ajouter une machine dans le vecteur d'état. La voilà :&lt;br /&gt;
&lt;br /&gt;
 void addMachine(geometry_msgs::Pose2D machine, VectorXd &amp;amp;xMean, MatrixXd &amp;amp;P){&lt;br /&gt;
   //on redimensionne xMean et P pour accueillir la nouvelle machines&lt;br /&gt;
   xMean.conservativeResize(xMean.rows() + 3);&lt;br /&gt;
   P.conservativeResize(P.rows()+3,P.cols()+3);&amp;lt;br&amp;gt;&lt;br /&gt;
   //on remplit avec les coordonnées de la nouvelle machine&lt;br /&gt;
   xMean(xMean.rows()-3) = machine.x;&lt;br /&gt;
   xMean(xMean.rows()-2) = machine.y;&lt;br /&gt;
   xMean(xMean.rows()-1) = machine.theta;&amp;lt;br&amp;gt;&lt;br /&gt;
   //calcul de tous les PLi&lt;br /&gt;
   //initialisation des PLi à 0&lt;br /&gt;
   P.block(P.rows() - 3, 0, 3, P.cols()).setZero();&lt;br /&gt;
   P.block(0, P.cols() - 3, P.rows(), 3).setZero();&amp;lt;br&amp;gt;&lt;br /&gt;
   for (int j = 0; j &amp;lt; xMean.rows(); j = j + 3){&lt;br /&gt;
     //position de la nouvelle machines par rapport au robot et à toutes les autres&lt;br /&gt;
     double x 	 = xMean(xMean.rows()-3) - xMean(j  );&lt;br /&gt;
     double y 	 = xMean(xMean.rows()-2) - xMean(j+1);&lt;br /&gt;
     double theta = xMean(xMean.rows()-1) - xMean(j+2);&amp;lt;br&amp;gt;&lt;br /&gt;
     P(P.rows()-3, j  ) = x;&lt;br /&gt;
     P(P.rows()-2, j+1) = y;&lt;br /&gt;
     P(P.rows()-1, j+2) = theta;&amp;lt;br&amp;gt;&lt;br /&gt;
     P(j  , P.rows()-3) = x;&lt;br /&gt;
     P(j+1, P.rows()-2) = y;&lt;br /&gt;
     P(j+2, P.rows()-1) = theta;&amp;lt;br&amp;gt;&lt;br /&gt;
     P(j  , j  ) = xMean(j  ) - xMean(0);&lt;br /&gt;
     P(j+1, j+1) = xMean(j+1) - xMean(1);&lt;br /&gt;
     P(j+2, j+2) = xMean(j+2) - xMean(2);&amp;lt;br&amp;gt;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 10===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
La partie '''prédiction''' du filtre marche parfaitement, quelques corrections ont dues être faites au niveau de la commande vitesse. En effet, Nous avions oublié de la transposer dans le repère global. Pour la partie '''correction''', nous rencontrons un problème de divergence du filtre, qui est probablement due à une mauvaise initialisation. En effet, nous utilisons des enregistrements faits sur notre piste (1/4 de la vraie) avec des initialisations correspondant à la piste originale. Le filtre ne peut donc pas converger car la position de départ est fausse.&lt;br /&gt;
&lt;br /&gt;
===Semaine 11===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
Des corrections sont en cours de validation. Nous essayons de définir une initialisation avec les paramètres de notre piste, ce qui n'est pas évident. Les programmes permettant d'extraire les positions machines du filtres ont été réalisé, ainsi qu'un launch pour pouvoir lancer tous les noeuds de la localisation.&lt;br /&gt;
&lt;br /&gt;
===Semaine 12===&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - mise en place====&lt;br /&gt;
&lt;br /&gt;
Pendant les deux jours de mise en place, nous avons continué à travailler sur la localisation, qui est une partie critique et nécessaire à notre participation. Le filtre en lui même est fonctionnel et permet de corriger la position du robot, ainsi que celle des machines. Cependant, et ce n'est pas un petit &amp;quot;cependant&amp;quot;... Le fait que l'on ajoute des machines en cours de jeu perturbe fortement notre algorithme.&lt;br /&gt;
&lt;br /&gt;
En effet, le filtre de Kalman est optimal si la position des repères est connu, or, un ajout de machine crée un recalage forcé, et si l'on voit plusieurs machines... C'est la '''catastrophe'''. L'ajout de machines est une partie sensible qui nécessite des tests sur la position mesurée, avec un changement de repère à partir de la position du robot, si celle ci dérive, tout dérive. Chaque machine initialisée à la mauvaise position, ou chaque élément détecté comme machine mais n'en étant pas une (faux positif) perturbe le recalage.&lt;br /&gt;
&lt;br /&gt;
De nombreux tests ayant été fait sur la piste officiel avec différentes configurations nous ont permis de vérifier que l'odométrie mesurée ne dérivait que très peu. Il a donc été décidé de n'utiliser que l'odométrie et le scan laser pour la partie '''exploration'''. En effet, chaque machine mesurée est envoyée à un noeud ROS qui va créer une carte et la compléter au fur et à mesure de la partie. Le robot est donc repéré rien qu'avec son odométrie. Le fait que la phase d'exploration (découverte du terrain) ne dure que '''4 minutes''' nous a convaincu pour n'utiliser que cette mesure.&lt;br /&gt;
&lt;br /&gt;
De plus, la carte créée sera utilisée pour la phase suivante, la phase de '''production'''. Cette phase consiste, au niveau de la localisation, à se repérer sur la piste et atteindre la machine demandée par l'exécuteur de tâches. Pour cette phase qui dure '''15 minutes''', l'utilisation du filtre est nécessaire. Donc, avec les coordonnées des machines mesurées pendant la première phase, on peut créer le vecteur d'état et la matrice faisant le lien entre les machines. De là, la taille de ces deux éléments ne variant plus, on peut corriger uniquement la position du robot et le filtre sera efficace.&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - 1er jour====&lt;br /&gt;
&lt;br /&gt;
Durant ce premier jour, nous avons commencé à ''merger'' nos branches respectives pour pouvoir faire tourner tous nos programmes. Cette phase est laborieuse et nous a pris du temps. De toute façon, toutes les équipes ne sont pas prêtes, les organisateurs non plus. La '''Referee Box''' n'est pas fonctionnel pour la phase de production, ce qui veut dire que nous nous concentrons actuellement sur l'exploration. Les matchs joués aujourd'hui ne nous rapporte donc pas de points. Les tests nous ont permis de valider individuellement chacun des algos, il ne reste &amp;quot;plus qu'à&amp;quot; rejoindre le tout.&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - 2eme jour====&lt;br /&gt;
&lt;br /&gt;
Niveau '''localisation''', la navigation à l'odométrie et la détection de machine sont fonctionnelles. Cependant, le moyennage fait sur les positions machines (on moyenne toutes les positions trouvées appartenant à une même machine pour n'avoir qu'un seul point) fait que le point correspondant peut être perturbé par des mesures aberrantes. C'est le cas lorsque le robot se déplace à vitesse élevée.&lt;br /&gt;
&lt;br /&gt;
La détection de machine a été améliorée afin de ne rajouter QUE les machines, et pas les murs de la même taille. Nous allons donc retester le '''filtre de Kalman Etendu''' avec cette amélioration. Cependant, ce ne sera fait qu'après la compétition, puisque d'autres problèmes ont nécessité la présence de l'équipe sur certaines parties sensibles du déplacement.&lt;br /&gt;
&lt;br /&gt;
Sur la piste nous avons fait des mesures, qui nous donnent la carte suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:PisteSamediSoir.PNG | center]]&lt;br /&gt;
&lt;br /&gt;
La visualisation du trajet pour découvrir ces machines est le suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DetectionSamediSoir.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Et les positions machines, ainsi que leur orientation sont les suivantes :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:MachinesBagtestSamediSoir.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - 3eme et dernier jour====&lt;br /&gt;
&lt;br /&gt;
L'architecture choisie pour la localisation est la suivante :&lt;br /&gt;
*Navigation à l'odométrie&lt;br /&gt;
*Détection de machines et moyennage&lt;br /&gt;
*Quand on a vu toutes nos machines, on utilise la symétrie pour compléter les machines restantes&lt;br /&gt;
*Navigation et Localisation avec l'EKF (correction des positions machines et du robot)&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
Après de longs tests et des corrections importantes au niveau de l'ajout des machines dans le filtre, ce qui était la partie critique... Le meilleur résultat que l'on ait pu avoir avec l'EKF est celui ci dessous. Les machines étant en &amp;lt;span style=&amp;quot;color:#9966CC&amp;quot;&amp;gt;violet&amp;lt;/span&amp;gt;, la trajectoire calculée par l'EKF en &amp;lt;span style=&amp;quot;color:#00FF00&amp;quot;&amp;gt;vert&amp;lt;/span&amp;gt; et la trajectoire mesurée par les codeurs en &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;rouge&amp;lt;/span&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:BestResultWithEKF.PNG | center]]&lt;br /&gt;
&lt;br /&gt;
Nous rappelons que tous nos codes sont disponibles sur notre [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM GIT].&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=20538</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=20538"/>
				<updated>2015-04-30T13:05:21Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Localisation - Extended Kalman Filter */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - vidéo====&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les résultats de la détection des machines nous avons utiliser l'interface graphique disponible avec ROS, RVIZ. Nous visualisons alors le scan laser (points blancs), le résultat de la détection de segments (en rouge) et les positions des machines trouvées (en vert). Un premier test a été fait sur le scan originel, celui sur lequel nous avons travaillé depuis le début.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=XSn4s1y-XT0 Visualisation des machines]&lt;br /&gt;
&lt;br /&gt;
On rencontre un problème quand le robot est exactement parallèle ou perpendiculaire à un mur. Après vérification dans le programme, il s'avère que la détection ne fonctionne pas pour ces cas. Ce bug est maintenant corrigé :&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=rKeqewpuLoQ Correction du bug]&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
La première étape consiste juste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;br /&gt;
&lt;br /&gt;
la matrice correspondant au changement (laser -&amp;gt; robot) est la suivante : &lt;br /&gt;
&lt;br /&gt;
 0   -1    0&lt;br /&gt;
 1    0  0.2&lt;br /&gt;
 0    0    1&lt;br /&gt;
&lt;br /&gt;
la matrice 2x2 en haut à gauche correspond à la rotation de 90°, et le vecteur (0, 0.2) correspond à la translation.&lt;br /&gt;
&lt;br /&gt;
Celle du changement (robot -&amp;gt; global) avec alpha angle mesuré par le gyroscope depuis la position initiale (angle 0) :&lt;br /&gt;
&lt;br /&gt;
 cos(alpha)   -sin(alpha)    posInit.x&lt;br /&gt;
 sin(alpha)    cos(alpha)    posInit.y&lt;br /&gt;
          0             0            1&lt;br /&gt;
&lt;br /&gt;
l'étape suivante est de vérifier si les machines vues par le laser sont bien des machines, c'est-à-dire si les positions mesurées à partir des données lasers correspond aux zones occupées par des machines envoyées par la Referee Box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Grid Map====&lt;br /&gt;
&lt;br /&gt;
L'autre objectif de cette semaine a été de coder le noeud qui génère la map. La map est générée sous forme d'OccupancyGrid. Ce type est constitué d'un seul vecteur dont la première case correspond à la case en bas à gauche de la map. D'autres paramètres sont réglable comme l'origine et la taille.&lt;br /&gt;
&lt;br /&gt;
Pour la taille on choisit de diviser la map en case de 10 cm et l'origine choisie est le x du centre de la map et en y l'abscisse du premier mur (voir la map ci-dessous). Afin d'expliquer comment est constituée cette map, prenons le code et analysons les différentes fonctions ainsi que le main :&lt;br /&gt;
&lt;br /&gt;
Ce vecteur de Pose2D (x, y et theta (angle de la machine)) va permettre d'enregistrer la position des machines, c'est une variable global qui sera mise à jour avec le Callback :&lt;br /&gt;
&lt;br /&gt;
 std::vector&amp;lt;geometry_msgs::Pose2D&amp;gt; tab;&lt;br /&gt;
&lt;br /&gt;
*Récupération des machines envoyées par le noeud du SLAM (sur le topic /landmarks):&lt;br /&gt;
&lt;br /&gt;
 void Poses_Machine_Callback(const deplacement_msg::LandmarksConstPtr &amp;amp;machines)&lt;br /&gt;
 {&lt;br /&gt;
          tab=machines-&amp;gt;landmarks;&lt;br /&gt;
          for (int i=0; i&amp;lt;tab.size(); i++)&lt;br /&gt;
          {&lt;br /&gt;
     	     tab[i].x = tab[i].x*1000;&lt;br /&gt;
     	     tab[i].y = tab[i].y*1000;&lt;br /&gt;
 	  }&lt;br /&gt;
    &lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
*Création d'une map vide de taille 14m sur 8m. Chaque case est initialisée à une valeur nulle, on remplit également les autres paramètres de OccupancyGrid:&lt;br /&gt;
(On rappelle que la technique utilisée est un vecteur qui représente chaque case auxquelles il associe une probabilité 100 c'est un point interdit et 0 quand c'est un point sans danger pour le passage du robot)&lt;br /&gt;
&lt;br /&gt;
 void Create_Empty_Map(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      Map.info.origin.position.x=-7000;&lt;br /&gt;
      Map.info.origin.position.y=-1000;&lt;br /&gt;
      Map.info.origin.position.z=0;&lt;br /&gt;
      Map.info.origin.orientation.x=0;&lt;br /&gt;
      Map.info.origin.orientation.y=0;&lt;br /&gt;
      Map.info.origin.orientation.z=0;&lt;br /&gt;
      Map.info.origin.orientation.w=1;&lt;br /&gt;
      Map.info.map_load_time=ros::Time::now();&lt;br /&gt;
      Map.info.resolution=100;&lt;br /&gt;
      Map.info.width=140;&lt;br /&gt;
      Map.info.height=80;&lt;br /&gt;
      Map.data.assign(Map.info.width*Map.info.height, 0);                   //map vide&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
*Construction des points fixes de la map donc les murs (probabilité 100) et les zones à risques (probabilité 50):&lt;br /&gt;
&lt;br /&gt;
 void Set_Wall(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
    for (int i=0;i&amp;lt;80;i++)&lt;br /&gt;
    {&lt;br /&gt;
       for (int j=0;j&amp;lt;140;j++)&lt;br /&gt;
       {&lt;br /&gt;
          if ((i&amp;lt;13)||(i&amp;gt;67))) Map.data[j+i*140]=100;&lt;br /&gt;
          if ((j&amp;lt;13)||(j&amp;gt;127)) Map.data[j+i*140]=100;&lt;br /&gt;
       }&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Nous ne mettons pas tout le code de cette fonction étant donné qu'il est long et répétitif puisque c'est le remplissage des données connues, donc en &amp;quot;dur&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Calcul des positions machines: &lt;br /&gt;
&lt;br /&gt;
Lorsqu'on reçoit une position machine, c'est en fait son centre et son orientation par rapport à x que l'on reçoit. Etant donné que les machines doivent être des rectangles de 110cm sur 75cm (réellement 70 x 35 mais on compte la moitié du robot en plus par sécurité), on décide d'abord de déterminer un des coins du rectangle et plus précisément le coin en bas à droite de ce dernier:&lt;br /&gt;
&lt;br /&gt;
 void Get_One_Point_Of_The_Rectangle(float x, float &amp;amp;xA, float y, float &amp;amp;yA, float theta, float largeur, float longueur)&lt;br /&gt;
 {&lt;br /&gt;
      float x1,y1;&lt;br /&gt;
      x1 = x - cos(theta)*longueur;&lt;br /&gt;
      y1 = y - sin(theta)*longueur; &lt;br /&gt;
      xA = x1 + sin(M_PI_2-theta)*largeur;&lt;br /&gt;
      yA = y1 - cos(M_PI_2-theta)*largeur;&lt;br /&gt;
  &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
*Remplissage des positions sur la map :&lt;br /&gt;
&lt;br /&gt;
On met alors tous les points de ce rectangle à une probabilité 100 dans le vecteur Map. Pour les calculs on différencie le cas ou l'angle de la machine est entre 0 et pi/2 et le cas où il est entre pi/2 et pi. L'algorithme est le suivant : &lt;br /&gt;
&lt;br /&gt;
 A partir du coin, on incrémente x et y de sorte à longer le grand coté et de remplir chaque case (incrémentation de 5 cm).&lt;br /&gt;
 Une fois arrivé au bout, on incrémente x et y de 5cm sur la largeur à partir du coin et on recommence l'opération précédente.&lt;br /&gt;
 Ceci jusqu'à remplir le complètement le rectangle.&lt;br /&gt;
&lt;br /&gt;
Afin d'établir les probabilités correspondantes aux cases de ce rectangle, nous utilisons la fonctions floor() pour &amp;quot;convertir&amp;quot; nos flottants en entier et accéder à la case correspondante. On notera aussi que la case 1470 correspond à l'origine de notre map.&lt;br /&gt;
&lt;br /&gt;
 void Set_Machines_In_Map(float rank, float theta, float xA, float yA, nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      float x=xA;&lt;br /&gt;
      float y=yA;&lt;br /&gt;
      if (theta&amp;lt;=M_PI_2)&lt;br /&gt;
      {&lt;br /&gt;
            for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
            {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++) &lt;br /&gt;
                  {&lt;br /&gt;
                      Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                      x = x + cos(theta)*50;&lt;br /&gt;
                      y = y + sin(theta)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(M_PI_2-theta)*50;&lt;br /&gt;
                  y = yA + j*sin(M_PI_2-theta)*50;&lt;br /&gt;
            }	&lt;br /&gt;
       }&lt;br /&gt;
       if (theta&amp;gt;M_PI_2)&lt;br /&gt;
       {&lt;br /&gt;
             for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
             {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++)&lt;br /&gt;
                  {&lt;br /&gt;
                        Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                        x = x - sin(theta-M_PI_2)*50;&lt;br /&gt;
                        y = y + cos(theta-M_PI_2)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(theta-M_PI_2)*50;&lt;br /&gt;
                  y = yA - j*sin(theta-M_PI_2)*50;&lt;br /&gt;
              }	&lt;br /&gt;
        }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Ci dessous on a les mains, avec les différentes fonctions appelées et la syntaxe particulière à ROS. &lt;br /&gt;
&lt;br /&gt;
*Noeud général pour le traitement et le remplissage de la map :   &lt;br /&gt;
                 &lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
     ros::init(argc, argv, &amp;quot;server&amp;quot;);&lt;br /&gt;
     ros::NodeHandle n;&lt;br /&gt;
     ros::Subscriber sub_poses_machine    = n.subscribe(&amp;quot;/machines&amp;quot;, 1000, Poses_Machine_Callback);   // Récupération des machines&lt;br /&gt;
     ros::Publisher Map_Pub = n.advertise&amp;lt;nav_msgs::OccupancyGrid&amp;gt;(&amp;quot;/map&amp;quot;, 1000);                     // Préparation de la publication de la map&lt;br /&gt;
     ROS_INFO(&amp;quot;Ready to Generate the Map&amp;quot;);&lt;br /&gt;
     float xA,yA;&lt;br /&gt;
     ros::Rate loop_rate(1);&lt;br /&gt;
     while(ros::ok())&lt;br /&gt;
     {&lt;br /&gt;
        nav_msgs::OccupancyGrid Map;&lt;br /&gt;
        Create_Empty_Map(Map);&lt;br /&gt;
        Set_Wall(Map);&lt;br /&gt;
        for (int z=0;z&amp;lt;tab.size();z++)&lt;br /&gt;
        {&lt;br /&gt;
           Get_One_Point_Of_The_Rectangle(tab[z].x, xA, tab[z].y, yA, tab[z].theta, 275, 450);&lt;br /&gt;
 	   Set_Machines_In_Map(100, tab[z].theta, xA, yA, Map);&lt;br /&gt;
        }&lt;br /&gt;
        Map_Pub.publish(Map);                                                                   // publication de la map&lt;br /&gt;
        ros::spinOnce();&lt;br /&gt;
        loop_rate.sleep();&lt;br /&gt;
     }&lt;br /&gt;
     return 0;&lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Noeud test qui publie 2 positions de machines : &lt;br /&gt;
&lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
    ros::init(argc, argv, &amp;quot;test&amp;quot;);&lt;br /&gt;
    ros::NodeHandle n;&lt;br /&gt;
    ros::Publisher Pose_Machines_Pub = n.advertise&amp;lt;deplacement_msg::Landmarks&amp;gt;(&amp;quot;/machines&amp;quot;, 1000);&lt;br /&gt;
    ROS_INFO(&amp;quot;Ready to send poses machines&amp;quot;);&lt;br /&gt;
    int xA,yA;&lt;br /&gt;
    ros::Rate loop_rate(1);&lt;br /&gt;
    while(ros::ok())&lt;br /&gt;
    {&lt;br /&gt;
       deplacement_msg::Landmarks machines_msgs;&lt;br /&gt;
       geometry_msgs::Pose2D tab;&lt;br /&gt;
       tab.x=-2;&lt;br /&gt;
       tab.y=2;&lt;br /&gt;
       tab.theta=0;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       tab.x=5;&lt;br /&gt;
       tab.y=4;&lt;br /&gt;
       tab.theta=2.5;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       Pose_Machines_Pub.publish(machines_msgs);&lt;br /&gt;
       ros::spinOnce();&lt;br /&gt;
       loop_rate.sleep();&lt;br /&gt;
    }&lt;br /&gt;
    return 0;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On visualise le résultat grâce au logiciel RVIZ qui peut lire les topics publiés et donc le topic /map :&lt;br /&gt;
&lt;br /&gt;
===Semaine 9===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
l'objectif de cette semaine sera de coder toutes les fonctions nécessaires à l'implémentation finale du [http://fr.wikipedia.org/wiki/Filtre_de_Kalman#Filtre_de_Kalman_.C3.A9tendu filtre de Kalman étendu] :&lt;br /&gt;
&lt;br /&gt;
*initialisations des différents éléments&lt;br /&gt;
*étape de prédiction&lt;br /&gt;
*étape de mise à jour&lt;br /&gt;
*publication des positions machines et du robot dans le repère global via un topic ROS&lt;br /&gt;
&lt;br /&gt;
Le schéma ci-dessous nous montre les deux étapes du filtre de Kalman :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Kalman.png | center]]&lt;br /&gt;
&lt;br /&gt;
le code pour la partie ''prédiction'' :&lt;br /&gt;
&lt;br /&gt;
 //on ressort la position du robot pour l'état n+1&lt;br /&gt;
 //les paramètres sont le vecteurs où on a la position du robot à l'état n, la matrice P, les commandes en vitesses et le temps à l'état n&lt;br /&gt;
 Vector3d prediction(VectorXd xMean, MatrixXd &amp;amp;P, geometry_msgs::Pose2D cmdVel, ros::Time &amp;amp;temps){&lt;br /&gt;
   ros::Duration duree = ros::Time::now() - temps;&lt;br /&gt;
   double periode = duree.toSec();&amp;lt;br&amp;gt;&lt;br /&gt;
   Vector3d cmdVelVect = Pose2DToVector(cmdVel);&lt;br /&gt;
   //le xMean.topLeftCorner(3,1) correspond à la position du robot&lt;br /&gt;
   Vector3d xPredicted = xMean.topLeftCorner(3,1) + periode*cmdVelVect;&amp;lt;br&amp;gt;&lt;br /&gt;
   MatrixXd Fx;&lt;br /&gt;
   Fx = MatrixXd::Identity(P.rows(), P.cols());&lt;br /&gt;
   Fx(0,0) = xPredicted(0);&lt;br /&gt;
   Fx(1,1) = xPredicted(1);&lt;br /&gt;
   Fx(2,2) = xPredicted(2);&amp;lt;br&amp;gt;&lt;br /&gt;
   //mise à jour de P&lt;br /&gt;
   P = Fx*P*(Fx.transpose());&amp;lt;br&amp;gt;&lt;br /&gt;
   //mise à jour du temps&lt;br /&gt;
   temps = ros::Time::now();&amp;lt;br&amp;gt;&lt;br /&gt;
   return xPredicted;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
le code pour la partie ''correction'' :&lt;br /&gt;
&lt;br /&gt;
 void correction(VectorXd &amp;amp;xMean, MatrixXd &amp;amp;P, Vector3d xPredicted, geometry_msgs::Pose2D m){&lt;br /&gt;
   int taille = P.rows();&lt;br /&gt;
   //on vérifie si la machine est présente ou pas dans le vecteur d'état&lt;br /&gt;
   int i = checkStateVector(xMean, m);&amp;lt;br&amp;gt;&lt;br /&gt;
   if (i != 0){&lt;br /&gt;
     //calcul de H&lt;br /&gt;
     MatrixXd H(3, taille);&lt;br /&gt;
     H = buildH(taille, i);&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul de Pm&lt;br /&gt;
     MatrixXd Pm(taille, taille);&lt;br /&gt;
     Pm = buildPm(P, i);&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul de Z&lt;br /&gt;
     MatrixXd Z(taille, taille);&lt;br /&gt;
     Z = H*Pm*(H.transpose());	&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul du gain de Kalman&lt;br /&gt;
     MatrixXd K(taille, taille);&lt;br /&gt;
     K = P*(H.transpose())*(Z.inverse());&amp;lt;br&amp;gt;&lt;br /&gt;
     //mise à jour du vecteur xMean&lt;br /&gt;
     xMean = xMean + K*(xMean.block(xMean.rows()-3,0,3,1) - xPredicted);&amp;lt;br&amp;gt;&lt;br /&gt;
     //mise à jour de la matrice P&lt;br /&gt;
     P = P - K*Z*(K.transpose());&lt;br /&gt;
   }&lt;br /&gt;
   else {&lt;br /&gt;
     addMachine(m, xMean, P);&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Pour notre cas, on doit ajouter des nouvelles machines, alors que pour un EKF classique on observe juste des machines déjà répertoriées. Il faut donc une fonction qui permet d'ajouter une machine dans le vecteur d'état. La voilà :&lt;br /&gt;
&lt;br /&gt;
 void addMachine(geometry_msgs::Pose2D machine, VectorXd &amp;amp;xMean, MatrixXd &amp;amp;P){&lt;br /&gt;
   //on redimensionne xMean et P pour accueillir la nouvelle machines&lt;br /&gt;
   xMean.conservativeResize(xMean.rows() + 3);&lt;br /&gt;
   P.conservativeResize(P.rows()+3,P.cols()+3);&amp;lt;br&amp;gt;&lt;br /&gt;
   //on remplit avec les coordonnées de la nouvelle machine&lt;br /&gt;
   xMean(xMean.rows()-3) = machine.x;&lt;br /&gt;
   xMean(xMean.rows()-2) = machine.y;&lt;br /&gt;
   xMean(xMean.rows()-1) = machine.theta;&amp;lt;br&amp;gt;&lt;br /&gt;
   //calcul de tous les PLi&lt;br /&gt;
   //initialisation des PLi à 0&lt;br /&gt;
   P.block(P.rows() - 3, 0, 3, P.cols()).setZero();&lt;br /&gt;
   P.block(0, P.cols() - 3, P.rows(), 3).setZero();&amp;lt;br&amp;gt;&lt;br /&gt;
   for (int j = 0; j &amp;lt; xMean.rows(); j = j + 3){&lt;br /&gt;
     //position de la nouvelle machines par rapport au robot et à toutes les autres&lt;br /&gt;
     double x 	 = xMean(xMean.rows()-3) - xMean(j  );&lt;br /&gt;
     double y 	 = xMean(xMean.rows()-2) - xMean(j+1);&lt;br /&gt;
     double theta = xMean(xMean.rows()-1) - xMean(j+2);&amp;lt;br&amp;gt;&lt;br /&gt;
     P(P.rows()-3, j  ) = x;&lt;br /&gt;
     P(P.rows()-2, j+1) = y;&lt;br /&gt;
     P(P.rows()-1, j+2) = theta;&amp;lt;br&amp;gt;&lt;br /&gt;
     P(j  , P.rows()-3) = x;&lt;br /&gt;
     P(j+1, P.rows()-2) = y;&lt;br /&gt;
     P(j+2, P.rows()-1) = theta;&amp;lt;br&amp;gt;&lt;br /&gt;
     P(j  , j  ) = xMean(j  ) - xMean(0);&lt;br /&gt;
     P(j+1, j+1) = xMean(j+1) - xMean(1);&lt;br /&gt;
     P(j+2, j+2) = xMean(j+2) - xMean(2);&amp;lt;br&amp;gt;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 10===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
La partie '''prédiction''' du filtre marche parfaitement, quelques corrections ont dues être faites au niveau de la commande vitesse. En effet, Nous avions oublié de la transposer dans le repère global. Pour la partie '''correction''', nous rencontrons un problème de divergence du filtre, qui est probablement due à une mauvaise initialisation. En effet, nous utilisons des enregistrements faits sur notre piste (1/4 de la vraie) avec des initialisations correspondant à la piste originale. Le filtre ne peut donc pas converger car la position de départ est fausse.&lt;br /&gt;
&lt;br /&gt;
===Semaine 11===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
Des corrections sont en cours de validation. Nous essayons de définir une initialisation avec les paramètres de notre piste, ce qui n'est pas évident. Les programmes permettant d'extraire les positions machines du filtres ont été réalisé, ainsi qu'un launch pour pouvoir lancer tous les noeuds de la localisation.&lt;br /&gt;
&lt;br /&gt;
===Semaine 12===&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - mise en place====&lt;br /&gt;
&lt;br /&gt;
Pendant les deux jours de mise en place, nous avons continué à travailler sur la localisation, qui est une partie critique et nécessaire à notre participation. Le filtre en lui même est fonctionnel et permet de corriger la position du robot, ainsi que celle des machines. Cependant, et ce n'est pas un petit &amp;quot;cependant&amp;quot;... Le fait que l'on ajoute des machines en cours de jeu perturbe fortement notre algorithme.&lt;br /&gt;
&lt;br /&gt;
En effet, le filtre de Kalman est optimal si la position des repères est connu, or, un ajout de machine crée un recalage forcé, et si l'on voit plusieurs machines... C'est la '''catastrophe'''. L'ajout de machines est une partie sensible qui nécessite des tests sur la position mesurée, avec un changement de repère à partir de la position du robot, si celle ci dérive, tout dérive. Chaque machine initialisée à la mauvaise position, ou chaque élément détecté comme machine mais n'en étant pas une (faux positif) perturbe le recalage.&lt;br /&gt;
&lt;br /&gt;
De nombreux tests ayant été fait sur la piste officiel avec différentes configurations nous ont permis de vérifier que l'odométrie mesurée ne dérivait que très peu. Il a donc été décidé de n'utiliser que l'odométrie et le scan laser pour la partie '''exploration'''. En effet, chaque machine mesurée est envoyée à un noeud ROS qui va créer une carte et la compléter au fur et à mesure de la partie. Le robot est donc repéré rien qu'avec son odométrie. Le fait que la phase d'exploration (découverte du terrain) ne dure que '''4 minutes''' nous a convaincu pour n'utiliser que cette mesure.&lt;br /&gt;
&lt;br /&gt;
De plus, la carte créée sera utilisée pour la phase suivante, la phase de '''production'''. Cette phase consiste, au niveau de la localisation, à se repérer sur la piste et atteindre la machine demandée par l'exécuteur de tâches. Pour cette phase qui dure '''15 minutes''', l'utilisation du filtre est nécessaire. Donc, avec les coordonnées des machines mesurées pendant la première phase, on peut créer le vecteur d'état et la matrice faisant le lien entre les machines. De là, la taille de ces deux éléments ne variant plus, on peut corriger uniquement la position du robot et le filtre sera efficace.&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - 1er jour====&lt;br /&gt;
&lt;br /&gt;
Durant ce premier jour, nous avons commencé à ''merger'' nos branches respectives pour pouvoir faire tourner tous nos programmes. Cette phase est laborieuse et nous a pris du temps. De toute façon, toutes les équipes ne sont pas prêtes, les organisateurs non plus. La '''Referee Box''' n'est pas fonctionnel pour la phase de production, ce qui veut dire que nous nous concentrons actuellement sur l'exploration. Les matchs joués aujourd'hui ne nous rapporte donc pas de points. Les tests nous ont permis de valider individuellement chacun des algos, il ne reste &amp;quot;plus qu'à&amp;quot; rejoindre le tout.&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - 2eme jour====&lt;br /&gt;
&lt;br /&gt;
Niveau '''localisation''', la navigation à l'odométrie et la détection de machine sont fonctionnelles. Cependant, le moyennage fait sur les positions machines (on moyenne toutes les positions trouvées appartenant à une même machine pour n'avoir qu'un seul point) fait que le point correspondant peut être perturbé par des mesures aberrantes. C'est le cas lorsque le robot se déplace à vitesse élevée.&lt;br /&gt;
&lt;br /&gt;
La détection de machine a été améliorée afin de ne rajouter QUE les machines, et pas les murs de la même taille. Nous allons donc retester le '''filtre de Kalman Etendu''' avec cette amélioration. Cependant, ce ne sera fait qu'après la compétition, puisque d'autres problèmes ont nécessité la présence de l'équipe sur certaines parties sensibles du déplacement.&lt;br /&gt;
&lt;br /&gt;
Sur la piste nous avons fait des mesures, qui nous donnent la carte suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:PisteSamediSoir.PNG | center]]&lt;br /&gt;
&lt;br /&gt;
La visualisation du trajet pour découvrir ces machines est le suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DetectionSamediSoir.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Et les positions machines, ainsi que leur orientation sont les suivantes :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:MachinesBagtestSamediSoir.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - 3eme et dernier jour====&lt;br /&gt;
&lt;br /&gt;
L'architecture choisie pour la localisation est la suivante :&lt;br /&gt;
*Navigation à l'odométrie&lt;br /&gt;
*Détection de machines et moyennage&lt;br /&gt;
*Quand on a vu toutes nos machines, on utilise la symétrie pour compléter les machines restantes&lt;br /&gt;
*Navigation et Localisation avec l'EKF (correction des positions machines et du robot)&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
Après de longs tests et des corrections importantes au niveau de l'ajout des machines dans le filtre, ce qui était la partie critique... Le meilleur résultat que l'on ait pu avoir avec l'EKF est celui ci dessous. Les machines étant en &amp;lt;span style=&amp;quot;color:#9966CC&amp;quot;&amp;gt;violet&amp;lt;/span&amp;gt;, la trajectoire calculée par l'EKF en &amp;lt;span style=&amp;quot;color:#00FF00&amp;quot;&amp;gt;vert&amp;lt;/span&amp;gt; et la trajectoire mesurée par les codeurs en &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;rouge&amp;lt;/span&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:BestResultWithEKF.PNG | center]]&lt;br /&gt;
&lt;br /&gt;
Nous rappelons que tous nos codes sont disponibles sur notre [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM GIT].&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=Fichier:BestResultWithEKF.PNG&amp;diff=20537</id>
		<title>Fichier:BestResultWithEKF.PNG</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=Fichier:BestResultWithEKF.PNG&amp;diff=20537"/>
				<updated>2015-04-30T12:55:01Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=20536</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=20536"/>
				<updated>2015-04-30T12:54:17Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Localisation - Extended Kalman Filter */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - vidéo====&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les résultats de la détection des machines nous avons utiliser l'interface graphique disponible avec ROS, RVIZ. Nous visualisons alors le scan laser (points blancs), le résultat de la détection de segments (en rouge) et les positions des machines trouvées (en vert). Un premier test a été fait sur le scan originel, celui sur lequel nous avons travaillé depuis le début.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=XSn4s1y-XT0 Visualisation des machines]&lt;br /&gt;
&lt;br /&gt;
On rencontre un problème quand le robot est exactement parallèle ou perpendiculaire à un mur. Après vérification dans le programme, il s'avère que la détection ne fonctionne pas pour ces cas. Ce bug est maintenant corrigé :&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=rKeqewpuLoQ Correction du bug]&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
La première étape consiste juste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;br /&gt;
&lt;br /&gt;
la matrice correspondant au changement (laser -&amp;gt; robot) est la suivante : &lt;br /&gt;
&lt;br /&gt;
 0   -1    0&lt;br /&gt;
 1    0  0.2&lt;br /&gt;
 0    0    1&lt;br /&gt;
&lt;br /&gt;
la matrice 2x2 en haut à gauche correspond à la rotation de 90°, et le vecteur (0, 0.2) correspond à la translation.&lt;br /&gt;
&lt;br /&gt;
Celle du changement (robot -&amp;gt; global) avec alpha angle mesuré par le gyroscope depuis la position initiale (angle 0) :&lt;br /&gt;
&lt;br /&gt;
 cos(alpha)   -sin(alpha)    posInit.x&lt;br /&gt;
 sin(alpha)    cos(alpha)    posInit.y&lt;br /&gt;
          0             0            1&lt;br /&gt;
&lt;br /&gt;
l'étape suivante est de vérifier si les machines vues par le laser sont bien des machines, c'est-à-dire si les positions mesurées à partir des données lasers correspond aux zones occupées par des machines envoyées par la Referee Box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Grid Map====&lt;br /&gt;
&lt;br /&gt;
L'autre objectif de cette semaine a été de coder le noeud qui génère la map. La map est générée sous forme d'OccupancyGrid. Ce type est constitué d'un seul vecteur dont la première case correspond à la case en bas à gauche de la map. D'autres paramètres sont réglable comme l'origine et la taille.&lt;br /&gt;
&lt;br /&gt;
Pour la taille on choisit de diviser la map en case de 10 cm et l'origine choisie est le x du centre de la map et en y l'abscisse du premier mur (voir la map ci-dessous). Afin d'expliquer comment est constituée cette map, prenons le code et analysons les différentes fonctions ainsi que le main :&lt;br /&gt;
&lt;br /&gt;
Ce vecteur de Pose2D (x, y et theta (angle de la machine)) va permettre d'enregistrer la position des machines, c'est une variable global qui sera mise à jour avec le Callback :&lt;br /&gt;
&lt;br /&gt;
 std::vector&amp;lt;geometry_msgs::Pose2D&amp;gt; tab;&lt;br /&gt;
&lt;br /&gt;
*Récupération des machines envoyées par le noeud du SLAM (sur le topic /landmarks):&lt;br /&gt;
&lt;br /&gt;
 void Poses_Machine_Callback(const deplacement_msg::LandmarksConstPtr &amp;amp;machines)&lt;br /&gt;
 {&lt;br /&gt;
          tab=machines-&amp;gt;landmarks;&lt;br /&gt;
          for (int i=0; i&amp;lt;tab.size(); i++)&lt;br /&gt;
          {&lt;br /&gt;
     	     tab[i].x = tab[i].x*1000;&lt;br /&gt;
     	     tab[i].y = tab[i].y*1000;&lt;br /&gt;
 	  }&lt;br /&gt;
    &lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
*Création d'une map vide de taille 14m sur 8m. Chaque case est initialisée à une valeur nulle, on remplit également les autres paramètres de OccupancyGrid:&lt;br /&gt;
(On rappelle que la technique utilisée est un vecteur qui représente chaque case auxquelles il associe une probabilité 100 c'est un point interdit et 0 quand c'est un point sans danger pour le passage du robot)&lt;br /&gt;
&lt;br /&gt;
 void Create_Empty_Map(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      Map.info.origin.position.x=-7000;&lt;br /&gt;
      Map.info.origin.position.y=-1000;&lt;br /&gt;
      Map.info.origin.position.z=0;&lt;br /&gt;
      Map.info.origin.orientation.x=0;&lt;br /&gt;
      Map.info.origin.orientation.y=0;&lt;br /&gt;
      Map.info.origin.orientation.z=0;&lt;br /&gt;
      Map.info.origin.orientation.w=1;&lt;br /&gt;
      Map.info.map_load_time=ros::Time::now();&lt;br /&gt;
      Map.info.resolution=100;&lt;br /&gt;
      Map.info.width=140;&lt;br /&gt;
      Map.info.height=80;&lt;br /&gt;
      Map.data.assign(Map.info.width*Map.info.height, 0);                   //map vide&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
*Construction des points fixes de la map donc les murs (probabilité 100) et les zones à risques (probabilité 50):&lt;br /&gt;
&lt;br /&gt;
 void Set_Wall(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
    for (int i=0;i&amp;lt;80;i++)&lt;br /&gt;
    {&lt;br /&gt;
       for (int j=0;j&amp;lt;140;j++)&lt;br /&gt;
       {&lt;br /&gt;
          if ((i&amp;lt;13)||(i&amp;gt;67))) Map.data[j+i*140]=100;&lt;br /&gt;
          if ((j&amp;lt;13)||(j&amp;gt;127)) Map.data[j+i*140]=100;&lt;br /&gt;
       }&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Nous ne mettons pas tout le code de cette fonction étant donné qu'il est long et répétitif puisque c'est le remplissage des données connues, donc en &amp;quot;dur&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Calcul des positions machines: &lt;br /&gt;
&lt;br /&gt;
Lorsqu'on reçoit une position machine, c'est en fait son centre et son orientation par rapport à x que l'on reçoit. Etant donné que les machines doivent être des rectangles de 110cm sur 75cm (réellement 70 x 35 mais on compte la moitié du robot en plus par sécurité), on décide d'abord de déterminer un des coins du rectangle et plus précisément le coin en bas à droite de ce dernier:&lt;br /&gt;
&lt;br /&gt;
 void Get_One_Point_Of_The_Rectangle(float x, float &amp;amp;xA, float y, float &amp;amp;yA, float theta, float largeur, float longueur)&lt;br /&gt;
 {&lt;br /&gt;
      float x1,y1;&lt;br /&gt;
      x1 = x - cos(theta)*longueur;&lt;br /&gt;
      y1 = y - sin(theta)*longueur; &lt;br /&gt;
      xA = x1 + sin(M_PI_2-theta)*largeur;&lt;br /&gt;
      yA = y1 - cos(M_PI_2-theta)*largeur;&lt;br /&gt;
  &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
*Remplissage des positions sur la map :&lt;br /&gt;
&lt;br /&gt;
On met alors tous les points de ce rectangle à une probabilité 100 dans le vecteur Map. Pour les calculs on différencie le cas ou l'angle de la machine est entre 0 et pi/2 et le cas où il est entre pi/2 et pi. L'algorithme est le suivant : &lt;br /&gt;
&lt;br /&gt;
 A partir du coin, on incrémente x et y de sorte à longer le grand coté et de remplir chaque case (incrémentation de 5 cm).&lt;br /&gt;
 Une fois arrivé au bout, on incrémente x et y de 5cm sur la largeur à partir du coin et on recommence l'opération précédente.&lt;br /&gt;
 Ceci jusqu'à remplir le complètement le rectangle.&lt;br /&gt;
&lt;br /&gt;
Afin d'établir les probabilités correspondantes aux cases de ce rectangle, nous utilisons la fonctions floor() pour &amp;quot;convertir&amp;quot; nos flottants en entier et accéder à la case correspondante. On notera aussi que la case 1470 correspond à l'origine de notre map.&lt;br /&gt;
&lt;br /&gt;
 void Set_Machines_In_Map(float rank, float theta, float xA, float yA, nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      float x=xA;&lt;br /&gt;
      float y=yA;&lt;br /&gt;
      if (theta&amp;lt;=M_PI_2)&lt;br /&gt;
      {&lt;br /&gt;
            for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
            {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++) &lt;br /&gt;
                  {&lt;br /&gt;
                      Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                      x = x + cos(theta)*50;&lt;br /&gt;
                      y = y + sin(theta)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(M_PI_2-theta)*50;&lt;br /&gt;
                  y = yA + j*sin(M_PI_2-theta)*50;&lt;br /&gt;
            }	&lt;br /&gt;
       }&lt;br /&gt;
       if (theta&amp;gt;M_PI_2)&lt;br /&gt;
       {&lt;br /&gt;
             for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
             {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++)&lt;br /&gt;
                  {&lt;br /&gt;
                        Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                        x = x - sin(theta-M_PI_2)*50;&lt;br /&gt;
                        y = y + cos(theta-M_PI_2)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(theta-M_PI_2)*50;&lt;br /&gt;
                  y = yA - j*sin(theta-M_PI_2)*50;&lt;br /&gt;
              }	&lt;br /&gt;
        }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Ci dessous on a les mains, avec les différentes fonctions appelées et la syntaxe particulière à ROS. &lt;br /&gt;
&lt;br /&gt;
*Noeud général pour le traitement et le remplissage de la map :   &lt;br /&gt;
                 &lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
     ros::init(argc, argv, &amp;quot;server&amp;quot;);&lt;br /&gt;
     ros::NodeHandle n;&lt;br /&gt;
     ros::Subscriber sub_poses_machine    = n.subscribe(&amp;quot;/machines&amp;quot;, 1000, Poses_Machine_Callback);   // Récupération des machines&lt;br /&gt;
     ros::Publisher Map_Pub = n.advertise&amp;lt;nav_msgs::OccupancyGrid&amp;gt;(&amp;quot;/map&amp;quot;, 1000);                     // Préparation de la publication de la map&lt;br /&gt;
     ROS_INFO(&amp;quot;Ready to Generate the Map&amp;quot;);&lt;br /&gt;
     float xA,yA;&lt;br /&gt;
     ros::Rate loop_rate(1);&lt;br /&gt;
     while(ros::ok())&lt;br /&gt;
     {&lt;br /&gt;
        nav_msgs::OccupancyGrid Map;&lt;br /&gt;
        Create_Empty_Map(Map);&lt;br /&gt;
        Set_Wall(Map);&lt;br /&gt;
        for (int z=0;z&amp;lt;tab.size();z++)&lt;br /&gt;
        {&lt;br /&gt;
           Get_One_Point_Of_The_Rectangle(tab[z].x, xA, tab[z].y, yA, tab[z].theta, 275, 450);&lt;br /&gt;
 	   Set_Machines_In_Map(100, tab[z].theta, xA, yA, Map);&lt;br /&gt;
        }&lt;br /&gt;
        Map_Pub.publish(Map);                                                                   // publication de la map&lt;br /&gt;
        ros::spinOnce();&lt;br /&gt;
        loop_rate.sleep();&lt;br /&gt;
     }&lt;br /&gt;
     return 0;&lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Noeud test qui publie 2 positions de machines : &lt;br /&gt;
&lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
    ros::init(argc, argv, &amp;quot;test&amp;quot;);&lt;br /&gt;
    ros::NodeHandle n;&lt;br /&gt;
    ros::Publisher Pose_Machines_Pub = n.advertise&amp;lt;deplacement_msg::Landmarks&amp;gt;(&amp;quot;/machines&amp;quot;, 1000);&lt;br /&gt;
    ROS_INFO(&amp;quot;Ready to send poses machines&amp;quot;);&lt;br /&gt;
    int xA,yA;&lt;br /&gt;
    ros::Rate loop_rate(1);&lt;br /&gt;
    while(ros::ok())&lt;br /&gt;
    {&lt;br /&gt;
       deplacement_msg::Landmarks machines_msgs;&lt;br /&gt;
       geometry_msgs::Pose2D tab;&lt;br /&gt;
       tab.x=-2;&lt;br /&gt;
       tab.y=2;&lt;br /&gt;
       tab.theta=0;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       tab.x=5;&lt;br /&gt;
       tab.y=4;&lt;br /&gt;
       tab.theta=2.5;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       Pose_Machines_Pub.publish(machines_msgs);&lt;br /&gt;
       ros::spinOnce();&lt;br /&gt;
       loop_rate.sleep();&lt;br /&gt;
    }&lt;br /&gt;
    return 0;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On visualise le résultat grâce au logiciel RVIZ qui peut lire les topics publiés et donc le topic /map :&lt;br /&gt;
&lt;br /&gt;
===Semaine 9===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
l'objectif de cette semaine sera de coder toutes les fonctions nécessaires à l'implémentation finale du [http://fr.wikipedia.org/wiki/Filtre_de_Kalman#Filtre_de_Kalman_.C3.A9tendu filtre de Kalman étendu] :&lt;br /&gt;
&lt;br /&gt;
*initialisations des différents éléments&lt;br /&gt;
*étape de prédiction&lt;br /&gt;
*étape de mise à jour&lt;br /&gt;
*publication des positions machines et du robot dans le repère global via un topic ROS&lt;br /&gt;
&lt;br /&gt;
Le schéma ci-dessous nous montre les deux étapes du filtre de Kalman :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Kalman.png | center]]&lt;br /&gt;
&lt;br /&gt;
le code pour la partie ''prédiction'' :&lt;br /&gt;
&lt;br /&gt;
 //on ressort la position du robot pour l'état n+1&lt;br /&gt;
 //les paramètres sont le vecteurs où on a la position du robot à l'état n, la matrice P, les commandes en vitesses et le temps à l'état n&lt;br /&gt;
 Vector3d prediction(VectorXd xMean, MatrixXd &amp;amp;P, geometry_msgs::Pose2D cmdVel, ros::Time &amp;amp;temps){&lt;br /&gt;
   ros::Duration duree = ros::Time::now() - temps;&lt;br /&gt;
   double periode = duree.toSec();&amp;lt;br&amp;gt;&lt;br /&gt;
   Vector3d cmdVelVect = Pose2DToVector(cmdVel);&lt;br /&gt;
   //le xMean.topLeftCorner(3,1) correspond à la position du robot&lt;br /&gt;
   Vector3d xPredicted = xMean.topLeftCorner(3,1) + periode*cmdVelVect;&amp;lt;br&amp;gt;&lt;br /&gt;
   MatrixXd Fx;&lt;br /&gt;
   Fx = MatrixXd::Identity(P.rows(), P.cols());&lt;br /&gt;
   Fx(0,0) = xPredicted(0);&lt;br /&gt;
   Fx(1,1) = xPredicted(1);&lt;br /&gt;
   Fx(2,2) = xPredicted(2);&amp;lt;br&amp;gt;&lt;br /&gt;
   //mise à jour de P&lt;br /&gt;
   P = Fx*P*(Fx.transpose());&amp;lt;br&amp;gt;&lt;br /&gt;
   //mise à jour du temps&lt;br /&gt;
   temps = ros::Time::now();&amp;lt;br&amp;gt;&lt;br /&gt;
   return xPredicted;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
le code pour la partie ''correction'' :&lt;br /&gt;
&lt;br /&gt;
 void correction(VectorXd &amp;amp;xMean, MatrixXd &amp;amp;P, Vector3d xPredicted, geometry_msgs::Pose2D m){&lt;br /&gt;
   int taille = P.rows();&lt;br /&gt;
   //on vérifie si la machine est présente ou pas dans le vecteur d'état&lt;br /&gt;
   int i = checkStateVector(xMean, m);&amp;lt;br&amp;gt;&lt;br /&gt;
   if (i != 0){&lt;br /&gt;
     //calcul de H&lt;br /&gt;
     MatrixXd H(3, taille);&lt;br /&gt;
     H = buildH(taille, i);&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul de Pm&lt;br /&gt;
     MatrixXd Pm(taille, taille);&lt;br /&gt;
     Pm = buildPm(P, i);&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul de Z&lt;br /&gt;
     MatrixXd Z(taille, taille);&lt;br /&gt;
     Z = H*Pm*(H.transpose());	&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul du gain de Kalman&lt;br /&gt;
     MatrixXd K(taille, taille);&lt;br /&gt;
     K = P*(H.transpose())*(Z.inverse());&amp;lt;br&amp;gt;&lt;br /&gt;
     //mise à jour du vecteur xMean&lt;br /&gt;
     xMean = xMean + K*(xMean.block(xMean.rows()-3,0,3,1) - xPredicted);&amp;lt;br&amp;gt;&lt;br /&gt;
     //mise à jour de la matrice P&lt;br /&gt;
     P = P - K*Z*(K.transpose());&lt;br /&gt;
   }&lt;br /&gt;
   else {&lt;br /&gt;
     addMachine(m, xMean, P);&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Pour notre cas, on doit ajouter des nouvelles machines, alors que pour un EKF classique on observe juste des machines déjà répertoriées. Il faut donc une fonction qui permet d'ajouter une machine dans le vecteur d'état. La voilà :&lt;br /&gt;
&lt;br /&gt;
 void addMachine(geometry_msgs::Pose2D machine, VectorXd &amp;amp;xMean, MatrixXd &amp;amp;P){&lt;br /&gt;
   //on redimensionne xMean et P pour accueillir la nouvelle machines&lt;br /&gt;
   xMean.conservativeResize(xMean.rows() + 3);&lt;br /&gt;
   P.conservativeResize(P.rows()+3,P.cols()+3);&amp;lt;br&amp;gt;&lt;br /&gt;
   //on remplit avec les coordonnées de la nouvelle machine&lt;br /&gt;
   xMean(xMean.rows()-3) = machine.x;&lt;br /&gt;
   xMean(xMean.rows()-2) = machine.y;&lt;br /&gt;
   xMean(xMean.rows()-1) = machine.theta;&amp;lt;br&amp;gt;&lt;br /&gt;
   //calcul de tous les PLi&lt;br /&gt;
   //initialisation des PLi à 0&lt;br /&gt;
   P.block(P.rows() - 3, 0, 3, P.cols()).setZero();&lt;br /&gt;
   P.block(0, P.cols() - 3, P.rows(), 3).setZero();&amp;lt;br&amp;gt;&lt;br /&gt;
   for (int j = 0; j &amp;lt; xMean.rows(); j = j + 3){&lt;br /&gt;
     //position de la nouvelle machines par rapport au robot et à toutes les autres&lt;br /&gt;
     double x 	 = xMean(xMean.rows()-3) - xMean(j  );&lt;br /&gt;
     double y 	 = xMean(xMean.rows()-2) - xMean(j+1);&lt;br /&gt;
     double theta = xMean(xMean.rows()-1) - xMean(j+2);&amp;lt;br&amp;gt;&lt;br /&gt;
     P(P.rows()-3, j  ) = x;&lt;br /&gt;
     P(P.rows()-2, j+1) = y;&lt;br /&gt;
     P(P.rows()-1, j+2) = theta;&amp;lt;br&amp;gt;&lt;br /&gt;
     P(j  , P.rows()-3) = x;&lt;br /&gt;
     P(j+1, P.rows()-2) = y;&lt;br /&gt;
     P(j+2, P.rows()-1) = theta;&amp;lt;br&amp;gt;&lt;br /&gt;
     P(j  , j  ) = xMean(j  ) - xMean(0);&lt;br /&gt;
     P(j+1, j+1) = xMean(j+1) - xMean(1);&lt;br /&gt;
     P(j+2, j+2) = xMean(j+2) - xMean(2);&amp;lt;br&amp;gt;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 10===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
La partie '''prédiction''' du filtre marche parfaitement, quelques corrections ont dues être faites au niveau de la commande vitesse. En effet, Nous avions oublié de la transposer dans le repère global. Pour la partie '''correction''', nous rencontrons un problème de divergence du filtre, qui est probablement due à une mauvaise initialisation. En effet, nous utilisons des enregistrements faits sur notre piste (1/4 de la vraie) avec des initialisations correspondant à la piste originale. Le filtre ne peut donc pas converger car la position de départ est fausse.&lt;br /&gt;
&lt;br /&gt;
===Semaine 11===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
Des corrections sont en cours de validation. Nous essayons de définir une initialisation avec les paramètres de notre piste, ce qui n'est pas évident. Les programmes permettant d'extraire les positions machines du filtres ont été réalisé, ainsi qu'un launch pour pouvoir lancer tous les noeuds de la localisation.&lt;br /&gt;
&lt;br /&gt;
===Semaine 12===&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - mise en place====&lt;br /&gt;
&lt;br /&gt;
Pendant les deux jours de mise en place, nous avons continué à travailler sur la localisation, qui est une partie critique et nécessaire à notre participation. Le filtre en lui même est fonctionnel et permet de corriger la position du robot, ainsi que celle des machines. Cependant, et ce n'est pas un petit &amp;quot;cependant&amp;quot;... Le fait que l'on ajoute des machines en cours de jeu perturbe fortement notre algorithme.&lt;br /&gt;
&lt;br /&gt;
En effet, le filtre de Kalman est optimal si la position des repères est connu, or, un ajout de machine crée un recalage forcé, et si l'on voit plusieurs machines... C'est la '''catastrophe'''. L'ajout de machines est une partie sensible qui nécessite des tests sur la position mesurée, avec un changement de repère à partir de la position du robot, si celle ci dérive, tout dérive. Chaque machine initialisée à la mauvaise position, ou chaque élément détecté comme machine mais n'en étant pas une (faux positif) perturbe le recalage.&lt;br /&gt;
&lt;br /&gt;
De nombreux tests ayant été fait sur la piste officiel avec différentes configurations nous ont permis de vérifier que l'odométrie mesurée ne dérivait que très peu. Il a donc été décidé de n'utiliser que l'odométrie et le scan laser pour la partie '''exploration'''. En effet, chaque machine mesurée est envoyée à un noeud ROS qui va créer une carte et la compléter au fur et à mesure de la partie. Le robot est donc repéré rien qu'avec son odométrie. Le fait que la phase d'exploration (découverte du terrain) ne dure que '''4 minutes''' nous a convaincu pour n'utiliser que cette mesure.&lt;br /&gt;
&lt;br /&gt;
De plus, la carte créée sera utilisée pour la phase suivante, la phase de '''production'''. Cette phase consiste, au niveau de la localisation, à se repérer sur la piste et atteindre la machine demandée par l'exécuteur de tâches. Pour cette phase qui dure '''15 minutes''', l'utilisation du filtre est nécessaire. Donc, avec les coordonnées des machines mesurées pendant la première phase, on peut créer le vecteur d'état et la matrice faisant le lien entre les machines. De là, la taille de ces deux éléments ne variant plus, on peut corriger uniquement la position du robot et le filtre sera efficace.&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - 1er jour====&lt;br /&gt;
&lt;br /&gt;
Durant ce premier jour, nous avons commencé à ''merger'' nos branches respectives pour pouvoir faire tourner tous nos programmes. Cette phase est laborieuse et nous a pris du temps. De toute façon, toutes les équipes ne sont pas prêtes, les organisateurs non plus. La '''Referee Box''' n'est pas fonctionnel pour la phase de production, ce qui veut dire que nous nous concentrons actuellement sur l'exploration. Les matchs joués aujourd'hui ne nous rapporte donc pas de points. Les tests nous ont permis de valider individuellement chacun des algos, il ne reste &amp;quot;plus qu'à&amp;quot; rejoindre le tout.&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - 2eme jour====&lt;br /&gt;
&lt;br /&gt;
Niveau '''localisation''', la navigation à l'odométrie et la détection de machine sont fonctionnelles. Cependant, le moyennage fait sur les positions machines (on moyenne toutes les positions trouvées appartenant à une même machine pour n'avoir qu'un seul point) fait que le point correspondant peut être perturbé par des mesures aberrantes. C'est le cas lorsque le robot se déplace à vitesse élevée.&lt;br /&gt;
&lt;br /&gt;
La détection de machine a été améliorée afin de ne rajouter QUE les machines, et pas les murs de la même taille. Nous allons donc retester le '''filtre de Kalman Etendu''' avec cette amélioration. Cependant, ce ne sera fait qu'après la compétition, puisque d'autres problèmes ont nécessité la présence de l'équipe sur certaines parties sensibles du déplacement.&lt;br /&gt;
&lt;br /&gt;
Sur la piste nous avons fait des mesures, qui nous donnent la carte suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:PisteSamediSoir.PNG | center]]&lt;br /&gt;
&lt;br /&gt;
La visualisation du trajet pour découvrir ces machines est le suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DetectionSamediSoir.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Et les positions machines, ainsi que leur orientation sont les suivantes :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:MachinesBagtestSamediSoir.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - 3eme et dernier jour====&lt;br /&gt;
&lt;br /&gt;
L'architecture choisie pour la localisation est la suivante :&lt;br /&gt;
*Navigation à l'odométrie&lt;br /&gt;
*Détection de machines et moyennage&lt;br /&gt;
*Quand on a vu toutes nos machines, on utilise la symétrie pour compléter les machines restantes&lt;br /&gt;
*Navigation et Localisation avec l'EKF (correction des positions machines et du robot)&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
Après de longs tests et des corrections importantes au niveau de l'ajout des machines dans le filtre, ce qui était la partie critique... Le meilleur résultat que l'on ait pu avoir avec l'EKF est celui ci dessous. Les machines étant en &amp;lt;span style=&amp;quot;color:#9966CC&amp;quot;&amp;gt;violet&amp;lt;/span&amp;gt;, la trajectoire calculée par l'EKF en &amp;lt;span style=&amp;quot;color:#00FF00&amp;quot;&amp;gt;vert&amp;lt;/span&amp;gt; et la trajectoire mesurée par les codeurs en &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;rouge&amp;lt;/span&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:BestResultWithEKF.PNG | center]]&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=20535</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=20535"/>
				<updated>2015-04-30T12:54:04Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Compétition Open German - 3eme et dernier jour */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - vidéo====&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les résultats de la détection des machines nous avons utiliser l'interface graphique disponible avec ROS, RVIZ. Nous visualisons alors le scan laser (points blancs), le résultat de la détection de segments (en rouge) et les positions des machines trouvées (en vert). Un premier test a été fait sur le scan originel, celui sur lequel nous avons travaillé depuis le début.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=XSn4s1y-XT0 Visualisation des machines]&lt;br /&gt;
&lt;br /&gt;
On rencontre un problème quand le robot est exactement parallèle ou perpendiculaire à un mur. Après vérification dans le programme, il s'avère que la détection ne fonctionne pas pour ces cas. Ce bug est maintenant corrigé :&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=rKeqewpuLoQ Correction du bug]&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
La première étape consiste juste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;br /&gt;
&lt;br /&gt;
la matrice correspondant au changement (laser -&amp;gt; robot) est la suivante : &lt;br /&gt;
&lt;br /&gt;
 0   -1    0&lt;br /&gt;
 1    0  0.2&lt;br /&gt;
 0    0    1&lt;br /&gt;
&lt;br /&gt;
la matrice 2x2 en haut à gauche correspond à la rotation de 90°, et le vecteur (0, 0.2) correspond à la translation.&lt;br /&gt;
&lt;br /&gt;
Celle du changement (robot -&amp;gt; global) avec alpha angle mesuré par le gyroscope depuis la position initiale (angle 0) :&lt;br /&gt;
&lt;br /&gt;
 cos(alpha)   -sin(alpha)    posInit.x&lt;br /&gt;
 sin(alpha)    cos(alpha)    posInit.y&lt;br /&gt;
          0             0            1&lt;br /&gt;
&lt;br /&gt;
l'étape suivante est de vérifier si les machines vues par le laser sont bien des machines, c'est-à-dire si les positions mesurées à partir des données lasers correspond aux zones occupées par des machines envoyées par la Referee Box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Grid Map====&lt;br /&gt;
&lt;br /&gt;
L'autre objectif de cette semaine a été de coder le noeud qui génère la map. La map est générée sous forme d'OccupancyGrid. Ce type est constitué d'un seul vecteur dont la première case correspond à la case en bas à gauche de la map. D'autres paramètres sont réglable comme l'origine et la taille.&lt;br /&gt;
&lt;br /&gt;
Pour la taille on choisit de diviser la map en case de 10 cm et l'origine choisie est le x du centre de la map et en y l'abscisse du premier mur (voir la map ci-dessous). Afin d'expliquer comment est constituée cette map, prenons le code et analysons les différentes fonctions ainsi que le main :&lt;br /&gt;
&lt;br /&gt;
Ce vecteur de Pose2D (x, y et theta (angle de la machine)) va permettre d'enregistrer la position des machines, c'est une variable global qui sera mise à jour avec le Callback :&lt;br /&gt;
&lt;br /&gt;
 std::vector&amp;lt;geometry_msgs::Pose2D&amp;gt; tab;&lt;br /&gt;
&lt;br /&gt;
*Récupération des machines envoyées par le noeud du SLAM (sur le topic /landmarks):&lt;br /&gt;
&lt;br /&gt;
 void Poses_Machine_Callback(const deplacement_msg::LandmarksConstPtr &amp;amp;machines)&lt;br /&gt;
 {&lt;br /&gt;
          tab=machines-&amp;gt;landmarks;&lt;br /&gt;
          for (int i=0; i&amp;lt;tab.size(); i++)&lt;br /&gt;
          {&lt;br /&gt;
     	     tab[i].x = tab[i].x*1000;&lt;br /&gt;
     	     tab[i].y = tab[i].y*1000;&lt;br /&gt;
 	  }&lt;br /&gt;
    &lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
*Création d'une map vide de taille 14m sur 8m. Chaque case est initialisée à une valeur nulle, on remplit également les autres paramètres de OccupancyGrid:&lt;br /&gt;
(On rappelle que la technique utilisée est un vecteur qui représente chaque case auxquelles il associe une probabilité 100 c'est un point interdit et 0 quand c'est un point sans danger pour le passage du robot)&lt;br /&gt;
&lt;br /&gt;
 void Create_Empty_Map(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      Map.info.origin.position.x=-7000;&lt;br /&gt;
      Map.info.origin.position.y=-1000;&lt;br /&gt;
      Map.info.origin.position.z=0;&lt;br /&gt;
      Map.info.origin.orientation.x=0;&lt;br /&gt;
      Map.info.origin.orientation.y=0;&lt;br /&gt;
      Map.info.origin.orientation.z=0;&lt;br /&gt;
      Map.info.origin.orientation.w=1;&lt;br /&gt;
      Map.info.map_load_time=ros::Time::now();&lt;br /&gt;
      Map.info.resolution=100;&lt;br /&gt;
      Map.info.width=140;&lt;br /&gt;
      Map.info.height=80;&lt;br /&gt;
      Map.data.assign(Map.info.width*Map.info.height, 0);                   //map vide&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
*Construction des points fixes de la map donc les murs (probabilité 100) et les zones à risques (probabilité 50):&lt;br /&gt;
&lt;br /&gt;
 void Set_Wall(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
    for (int i=0;i&amp;lt;80;i++)&lt;br /&gt;
    {&lt;br /&gt;
       for (int j=0;j&amp;lt;140;j++)&lt;br /&gt;
       {&lt;br /&gt;
          if ((i&amp;lt;13)||(i&amp;gt;67))) Map.data[j+i*140]=100;&lt;br /&gt;
          if ((j&amp;lt;13)||(j&amp;gt;127)) Map.data[j+i*140]=100;&lt;br /&gt;
       }&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Nous ne mettons pas tout le code de cette fonction étant donné qu'il est long et répétitif puisque c'est le remplissage des données connues, donc en &amp;quot;dur&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Calcul des positions machines: &lt;br /&gt;
&lt;br /&gt;
Lorsqu'on reçoit une position machine, c'est en fait son centre et son orientation par rapport à x que l'on reçoit. Etant donné que les machines doivent être des rectangles de 110cm sur 75cm (réellement 70 x 35 mais on compte la moitié du robot en plus par sécurité), on décide d'abord de déterminer un des coins du rectangle et plus précisément le coin en bas à droite de ce dernier:&lt;br /&gt;
&lt;br /&gt;
 void Get_One_Point_Of_The_Rectangle(float x, float &amp;amp;xA, float y, float &amp;amp;yA, float theta, float largeur, float longueur)&lt;br /&gt;
 {&lt;br /&gt;
      float x1,y1;&lt;br /&gt;
      x1 = x - cos(theta)*longueur;&lt;br /&gt;
      y1 = y - sin(theta)*longueur; &lt;br /&gt;
      xA = x1 + sin(M_PI_2-theta)*largeur;&lt;br /&gt;
      yA = y1 - cos(M_PI_2-theta)*largeur;&lt;br /&gt;
  &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
*Remplissage des positions sur la map :&lt;br /&gt;
&lt;br /&gt;
On met alors tous les points de ce rectangle à une probabilité 100 dans le vecteur Map. Pour les calculs on différencie le cas ou l'angle de la machine est entre 0 et pi/2 et le cas où il est entre pi/2 et pi. L'algorithme est le suivant : &lt;br /&gt;
&lt;br /&gt;
 A partir du coin, on incrémente x et y de sorte à longer le grand coté et de remplir chaque case (incrémentation de 5 cm).&lt;br /&gt;
 Une fois arrivé au bout, on incrémente x et y de 5cm sur la largeur à partir du coin et on recommence l'opération précédente.&lt;br /&gt;
 Ceci jusqu'à remplir le complètement le rectangle.&lt;br /&gt;
&lt;br /&gt;
Afin d'établir les probabilités correspondantes aux cases de ce rectangle, nous utilisons la fonctions floor() pour &amp;quot;convertir&amp;quot; nos flottants en entier et accéder à la case correspondante. On notera aussi que la case 1470 correspond à l'origine de notre map.&lt;br /&gt;
&lt;br /&gt;
 void Set_Machines_In_Map(float rank, float theta, float xA, float yA, nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      float x=xA;&lt;br /&gt;
      float y=yA;&lt;br /&gt;
      if (theta&amp;lt;=M_PI_2)&lt;br /&gt;
      {&lt;br /&gt;
            for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
            {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++) &lt;br /&gt;
                  {&lt;br /&gt;
                      Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                      x = x + cos(theta)*50;&lt;br /&gt;
                      y = y + sin(theta)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(M_PI_2-theta)*50;&lt;br /&gt;
                  y = yA + j*sin(M_PI_2-theta)*50;&lt;br /&gt;
            }	&lt;br /&gt;
       }&lt;br /&gt;
       if (theta&amp;gt;M_PI_2)&lt;br /&gt;
       {&lt;br /&gt;
             for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
             {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++)&lt;br /&gt;
                  {&lt;br /&gt;
                        Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                        x = x - sin(theta-M_PI_2)*50;&lt;br /&gt;
                        y = y + cos(theta-M_PI_2)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(theta-M_PI_2)*50;&lt;br /&gt;
                  y = yA - j*sin(theta-M_PI_2)*50;&lt;br /&gt;
              }	&lt;br /&gt;
        }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Ci dessous on a les mains, avec les différentes fonctions appelées et la syntaxe particulière à ROS. &lt;br /&gt;
&lt;br /&gt;
*Noeud général pour le traitement et le remplissage de la map :   &lt;br /&gt;
                 &lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
     ros::init(argc, argv, &amp;quot;server&amp;quot;);&lt;br /&gt;
     ros::NodeHandle n;&lt;br /&gt;
     ros::Subscriber sub_poses_machine    = n.subscribe(&amp;quot;/machines&amp;quot;, 1000, Poses_Machine_Callback);   // Récupération des machines&lt;br /&gt;
     ros::Publisher Map_Pub = n.advertise&amp;lt;nav_msgs::OccupancyGrid&amp;gt;(&amp;quot;/map&amp;quot;, 1000);                     // Préparation de la publication de la map&lt;br /&gt;
     ROS_INFO(&amp;quot;Ready to Generate the Map&amp;quot;);&lt;br /&gt;
     float xA,yA;&lt;br /&gt;
     ros::Rate loop_rate(1);&lt;br /&gt;
     while(ros::ok())&lt;br /&gt;
     {&lt;br /&gt;
        nav_msgs::OccupancyGrid Map;&lt;br /&gt;
        Create_Empty_Map(Map);&lt;br /&gt;
        Set_Wall(Map);&lt;br /&gt;
        for (int z=0;z&amp;lt;tab.size();z++)&lt;br /&gt;
        {&lt;br /&gt;
           Get_One_Point_Of_The_Rectangle(tab[z].x, xA, tab[z].y, yA, tab[z].theta, 275, 450);&lt;br /&gt;
 	   Set_Machines_In_Map(100, tab[z].theta, xA, yA, Map);&lt;br /&gt;
        }&lt;br /&gt;
        Map_Pub.publish(Map);                                                                   // publication de la map&lt;br /&gt;
        ros::spinOnce();&lt;br /&gt;
        loop_rate.sleep();&lt;br /&gt;
     }&lt;br /&gt;
     return 0;&lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Noeud test qui publie 2 positions de machines : &lt;br /&gt;
&lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
    ros::init(argc, argv, &amp;quot;test&amp;quot;);&lt;br /&gt;
    ros::NodeHandle n;&lt;br /&gt;
    ros::Publisher Pose_Machines_Pub = n.advertise&amp;lt;deplacement_msg::Landmarks&amp;gt;(&amp;quot;/machines&amp;quot;, 1000);&lt;br /&gt;
    ROS_INFO(&amp;quot;Ready to send poses machines&amp;quot;);&lt;br /&gt;
    int xA,yA;&lt;br /&gt;
    ros::Rate loop_rate(1);&lt;br /&gt;
    while(ros::ok())&lt;br /&gt;
    {&lt;br /&gt;
       deplacement_msg::Landmarks machines_msgs;&lt;br /&gt;
       geometry_msgs::Pose2D tab;&lt;br /&gt;
       tab.x=-2;&lt;br /&gt;
       tab.y=2;&lt;br /&gt;
       tab.theta=0;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       tab.x=5;&lt;br /&gt;
       tab.y=4;&lt;br /&gt;
       tab.theta=2.5;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       Pose_Machines_Pub.publish(machines_msgs);&lt;br /&gt;
       ros::spinOnce();&lt;br /&gt;
       loop_rate.sleep();&lt;br /&gt;
    }&lt;br /&gt;
    return 0;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On visualise le résultat grâce au logiciel RVIZ qui peut lire les topics publiés et donc le topic /map :&lt;br /&gt;
&lt;br /&gt;
===Semaine 9===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
l'objectif de cette semaine sera de coder toutes les fonctions nécessaires à l'implémentation finale du [http://fr.wikipedia.org/wiki/Filtre_de_Kalman#Filtre_de_Kalman_.C3.A9tendu filtre de Kalman étendu] :&lt;br /&gt;
&lt;br /&gt;
*initialisations des différents éléments&lt;br /&gt;
*étape de prédiction&lt;br /&gt;
*étape de mise à jour&lt;br /&gt;
*publication des positions machines et du robot dans le repère global via un topic ROS&lt;br /&gt;
&lt;br /&gt;
Le schéma ci-dessous nous montre les deux étapes du filtre de Kalman :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Kalman.png | center]]&lt;br /&gt;
&lt;br /&gt;
le code pour la partie ''prédiction'' :&lt;br /&gt;
&lt;br /&gt;
 //on ressort la position du robot pour l'état n+1&lt;br /&gt;
 //les paramètres sont le vecteurs où on a la position du robot à l'état n, la matrice P, les commandes en vitesses et le temps à l'état n&lt;br /&gt;
 Vector3d prediction(VectorXd xMean, MatrixXd &amp;amp;P, geometry_msgs::Pose2D cmdVel, ros::Time &amp;amp;temps){&lt;br /&gt;
   ros::Duration duree = ros::Time::now() - temps;&lt;br /&gt;
   double periode = duree.toSec();&amp;lt;br&amp;gt;&lt;br /&gt;
   Vector3d cmdVelVect = Pose2DToVector(cmdVel);&lt;br /&gt;
   //le xMean.topLeftCorner(3,1) correspond à la position du robot&lt;br /&gt;
   Vector3d xPredicted = xMean.topLeftCorner(3,1) + periode*cmdVelVect;&amp;lt;br&amp;gt;&lt;br /&gt;
   MatrixXd Fx;&lt;br /&gt;
   Fx = MatrixXd::Identity(P.rows(), P.cols());&lt;br /&gt;
   Fx(0,0) = xPredicted(0);&lt;br /&gt;
   Fx(1,1) = xPredicted(1);&lt;br /&gt;
   Fx(2,2) = xPredicted(2);&amp;lt;br&amp;gt;&lt;br /&gt;
   //mise à jour de P&lt;br /&gt;
   P = Fx*P*(Fx.transpose());&amp;lt;br&amp;gt;&lt;br /&gt;
   //mise à jour du temps&lt;br /&gt;
   temps = ros::Time::now();&amp;lt;br&amp;gt;&lt;br /&gt;
   return xPredicted;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
le code pour la partie ''correction'' :&lt;br /&gt;
&lt;br /&gt;
 void correction(VectorXd &amp;amp;xMean, MatrixXd &amp;amp;P, Vector3d xPredicted, geometry_msgs::Pose2D m){&lt;br /&gt;
   int taille = P.rows();&lt;br /&gt;
   //on vérifie si la machine est présente ou pas dans le vecteur d'état&lt;br /&gt;
   int i = checkStateVector(xMean, m);&amp;lt;br&amp;gt;&lt;br /&gt;
   if (i != 0){&lt;br /&gt;
     //calcul de H&lt;br /&gt;
     MatrixXd H(3, taille);&lt;br /&gt;
     H = buildH(taille, i);&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul de Pm&lt;br /&gt;
     MatrixXd Pm(taille, taille);&lt;br /&gt;
     Pm = buildPm(P, i);&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul de Z&lt;br /&gt;
     MatrixXd Z(taille, taille);&lt;br /&gt;
     Z = H*Pm*(H.transpose());	&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul du gain de Kalman&lt;br /&gt;
     MatrixXd K(taille, taille);&lt;br /&gt;
     K = P*(H.transpose())*(Z.inverse());&amp;lt;br&amp;gt;&lt;br /&gt;
     //mise à jour du vecteur xMean&lt;br /&gt;
     xMean = xMean + K*(xMean.block(xMean.rows()-3,0,3,1) - xPredicted);&amp;lt;br&amp;gt;&lt;br /&gt;
     //mise à jour de la matrice P&lt;br /&gt;
     P = P - K*Z*(K.transpose());&lt;br /&gt;
   }&lt;br /&gt;
   else {&lt;br /&gt;
     addMachine(m, xMean, P);&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Pour notre cas, on doit ajouter des nouvelles machines, alors que pour un EKF classique on observe juste des machines déjà répertoriées. Il faut donc une fonction qui permet d'ajouter une machine dans le vecteur d'état. La voilà :&lt;br /&gt;
&lt;br /&gt;
 void addMachine(geometry_msgs::Pose2D machine, VectorXd &amp;amp;xMean, MatrixXd &amp;amp;P){&lt;br /&gt;
   //on redimensionne xMean et P pour accueillir la nouvelle machines&lt;br /&gt;
   xMean.conservativeResize(xMean.rows() + 3);&lt;br /&gt;
   P.conservativeResize(P.rows()+3,P.cols()+3);&amp;lt;br&amp;gt;&lt;br /&gt;
   //on remplit avec les coordonnées de la nouvelle machine&lt;br /&gt;
   xMean(xMean.rows()-3) = machine.x;&lt;br /&gt;
   xMean(xMean.rows()-2) = machine.y;&lt;br /&gt;
   xMean(xMean.rows()-1) = machine.theta;&amp;lt;br&amp;gt;&lt;br /&gt;
   //calcul de tous les PLi&lt;br /&gt;
   //initialisation des PLi à 0&lt;br /&gt;
   P.block(P.rows() - 3, 0, 3, P.cols()).setZero();&lt;br /&gt;
   P.block(0, P.cols() - 3, P.rows(), 3).setZero();&amp;lt;br&amp;gt;&lt;br /&gt;
   for (int j = 0; j &amp;lt; xMean.rows(); j = j + 3){&lt;br /&gt;
     //position de la nouvelle machines par rapport au robot et à toutes les autres&lt;br /&gt;
     double x 	 = xMean(xMean.rows()-3) - xMean(j  );&lt;br /&gt;
     double y 	 = xMean(xMean.rows()-2) - xMean(j+1);&lt;br /&gt;
     double theta = xMean(xMean.rows()-1) - xMean(j+2);&amp;lt;br&amp;gt;&lt;br /&gt;
     P(P.rows()-3, j  ) = x;&lt;br /&gt;
     P(P.rows()-2, j+1) = y;&lt;br /&gt;
     P(P.rows()-1, j+2) = theta;&amp;lt;br&amp;gt;&lt;br /&gt;
     P(j  , P.rows()-3) = x;&lt;br /&gt;
     P(j+1, P.rows()-2) = y;&lt;br /&gt;
     P(j+2, P.rows()-1) = theta;&amp;lt;br&amp;gt;&lt;br /&gt;
     P(j  , j  ) = xMean(j  ) - xMean(0);&lt;br /&gt;
     P(j+1, j+1) = xMean(j+1) - xMean(1);&lt;br /&gt;
     P(j+2, j+2) = xMean(j+2) - xMean(2);&amp;lt;br&amp;gt;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 10===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
La partie '''prédiction''' du filtre marche parfaitement, quelques corrections ont dues être faites au niveau de la commande vitesse. En effet, Nous avions oublié de la transposer dans le repère global. Pour la partie '''correction''', nous rencontrons un problème de divergence du filtre, qui est probablement due à une mauvaise initialisation. En effet, nous utilisons des enregistrements faits sur notre piste (1/4 de la vraie) avec des initialisations correspondant à la piste originale. Le filtre ne peut donc pas converger car la position de départ est fausse.&lt;br /&gt;
&lt;br /&gt;
===Semaine 11===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
Des corrections sont en cours de validation. Nous essayons de définir une initialisation avec les paramètres de notre piste, ce qui n'est pas évident. Les programmes permettant d'extraire les positions machines du filtres ont été réalisé, ainsi qu'un launch pour pouvoir lancer tous les noeuds de la localisation.&lt;br /&gt;
&lt;br /&gt;
===Semaine 12===&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - mise en place====&lt;br /&gt;
&lt;br /&gt;
Pendant les deux jours de mise en place, nous avons continué à travailler sur la localisation, qui est une partie critique et nécessaire à notre participation. Le filtre en lui même est fonctionnel et permet de corriger la position du robot, ainsi que celle des machines. Cependant, et ce n'est pas un petit &amp;quot;cependant&amp;quot;... Le fait que l'on ajoute des machines en cours de jeu perturbe fortement notre algorithme.&lt;br /&gt;
&lt;br /&gt;
En effet, le filtre de Kalman est optimal si la position des repères est connu, or, un ajout de machine crée un recalage forcé, et si l'on voit plusieurs machines... C'est la '''catastrophe'''. L'ajout de machines est une partie sensible qui nécessite des tests sur la position mesurée, avec un changement de repère à partir de la position du robot, si celle ci dérive, tout dérive. Chaque machine initialisée à la mauvaise position, ou chaque élément détecté comme machine mais n'en étant pas une (faux positif) perturbe le recalage.&lt;br /&gt;
&lt;br /&gt;
De nombreux tests ayant été fait sur la piste officiel avec différentes configurations nous ont permis de vérifier que l'odométrie mesurée ne dérivait que très peu. Il a donc été décidé de n'utiliser que l'odométrie et le scan laser pour la partie '''exploration'''. En effet, chaque machine mesurée est envoyée à un noeud ROS qui va créer une carte et la compléter au fur et à mesure de la partie. Le robot est donc repéré rien qu'avec son odométrie. Le fait que la phase d'exploration (découverte du terrain) ne dure que '''4 minutes''' nous a convaincu pour n'utiliser que cette mesure.&lt;br /&gt;
&lt;br /&gt;
De plus, la carte créée sera utilisée pour la phase suivante, la phase de '''production'''. Cette phase consiste, au niveau de la localisation, à se repérer sur la piste et atteindre la machine demandée par l'exécuteur de tâches. Pour cette phase qui dure '''15 minutes''', l'utilisation du filtre est nécessaire. Donc, avec les coordonnées des machines mesurées pendant la première phase, on peut créer le vecteur d'état et la matrice faisant le lien entre les machines. De là, la taille de ces deux éléments ne variant plus, on peut corriger uniquement la position du robot et le filtre sera efficace.&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - 1er jour====&lt;br /&gt;
&lt;br /&gt;
Durant ce premier jour, nous avons commencé à ''merger'' nos branches respectives pour pouvoir faire tourner tous nos programmes. Cette phase est laborieuse et nous a pris du temps. De toute façon, toutes les équipes ne sont pas prêtes, les organisateurs non plus. La '''Referee Box''' n'est pas fonctionnel pour la phase de production, ce qui veut dire que nous nous concentrons actuellement sur l'exploration. Les matchs joués aujourd'hui ne nous rapporte donc pas de points. Les tests nous ont permis de valider individuellement chacun des algos, il ne reste &amp;quot;plus qu'à&amp;quot; rejoindre le tout.&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - 2eme jour====&lt;br /&gt;
&lt;br /&gt;
Niveau '''localisation''', la navigation à l'odométrie et la détection de machine sont fonctionnelles. Cependant, le moyennage fait sur les positions machines (on moyenne toutes les positions trouvées appartenant à une même machine pour n'avoir qu'un seul point) fait que le point correspondant peut être perturbé par des mesures aberrantes. C'est le cas lorsque le robot se déplace à vitesse élevée.&lt;br /&gt;
&lt;br /&gt;
La détection de machine a été améliorée afin de ne rajouter QUE les machines, et pas les murs de la même taille. Nous allons donc retester le '''filtre de Kalman Etendu''' avec cette amélioration. Cependant, ce ne sera fait qu'après la compétition, puisque d'autres problèmes ont nécessité la présence de l'équipe sur certaines parties sensibles du déplacement.&lt;br /&gt;
&lt;br /&gt;
Sur la piste nous avons fait des mesures, qui nous donnent la carte suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:PisteSamediSoir.PNG | center]]&lt;br /&gt;
&lt;br /&gt;
La visualisation du trajet pour découvrir ces machines est le suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DetectionSamediSoir.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Et les positions machines, ainsi que leur orientation sont les suivantes :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:MachinesBagtestSamediSoir.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - 3eme et dernier jour====&lt;br /&gt;
&lt;br /&gt;
L'architecture choisie pour la localisation est la suivante :&lt;br /&gt;
*Navigation à l'odométrie&lt;br /&gt;
*Détection de machines et moyennage&lt;br /&gt;
*Quand on a vu toutes nos machines, on utilise la symétrie pour compléter les machines restantes&lt;br /&gt;
*Navigation et Localisation avec l'EKF (correction des positions machines et du robot)&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
Après de longs tests et des corrections importantes au niveau de l'ajout des machines dans le filtre, ce qui était la partie critique... Le meilleur résultat que l'on ait pu avoir avec l'EKF est celui ci dessous. Les machines étant en &amp;lt;span style=&amp;quot;color:#9966CC&amp;quot;&amp;gt;violet&amp;lt;/span&amp;gt;, la trajectoire calculée par l'EKF en &amp;lt;span style=&amp;quot;color:#00FF00&amp;quot;&amp;gt;vert&amp;lt;/span&amp;gt; et la trajectoire mesurée par les codeurs en &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;rouge&amp;lt;/span&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:BestResultWithEKF.PNG]]&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=20502</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=20502"/>
				<updated>2015-04-28T13:05:10Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Compétition Open German - 2eme jour */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - vidéo====&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les résultats de la détection des machines nous avons utiliser l'interface graphique disponible avec ROS, RVIZ. Nous visualisons alors le scan laser (points blancs), le résultat de la détection de segments (en rouge) et les positions des machines trouvées (en vert). Un premier test a été fait sur le scan originel, celui sur lequel nous avons travaillé depuis le début.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=XSn4s1y-XT0 Visualisation des machines]&lt;br /&gt;
&lt;br /&gt;
On rencontre un problème quand le robot est exactement parallèle ou perpendiculaire à un mur. Après vérification dans le programme, il s'avère que la détection ne fonctionne pas pour ces cas. Ce bug est maintenant corrigé :&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=rKeqewpuLoQ Correction du bug]&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
La première étape consiste juste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;br /&gt;
&lt;br /&gt;
la matrice correspondant au changement (laser -&amp;gt; robot) est la suivante : &lt;br /&gt;
&lt;br /&gt;
 0   -1    0&lt;br /&gt;
 1    0  0.2&lt;br /&gt;
 0    0    1&lt;br /&gt;
&lt;br /&gt;
la matrice 2x2 en haut à gauche correspond à la rotation de 90°, et le vecteur (0, 0.2) correspond à la translation.&lt;br /&gt;
&lt;br /&gt;
Celle du changement (robot -&amp;gt; global) avec alpha angle mesuré par le gyroscope depuis la position initiale (angle 0) :&lt;br /&gt;
&lt;br /&gt;
 cos(alpha)   -sin(alpha)    posInit.x&lt;br /&gt;
 sin(alpha)    cos(alpha)    posInit.y&lt;br /&gt;
          0             0            1&lt;br /&gt;
&lt;br /&gt;
l'étape suivante est de vérifier si les machines vues par le laser sont bien des machines, c'est-à-dire si les positions mesurées à partir des données lasers correspond aux zones occupées par des machines envoyées par la Referee Box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Grid Map====&lt;br /&gt;
&lt;br /&gt;
L'autre objectif de cette semaine a été de coder le noeud qui génère la map. La map est générée sous forme d'OccupancyGrid. Ce type est constitué d'un seul vecteur dont la première case correspond à la case en bas à gauche de la map. D'autres paramètres sont réglable comme l'origine et la taille.&lt;br /&gt;
&lt;br /&gt;
Pour la taille on choisit de diviser la map en case de 10 cm et l'origine choisie est le x du centre de la map et en y l'abscisse du premier mur (voir la map ci-dessous). Afin d'expliquer comment est constituée cette map, prenons le code et analysons les différentes fonctions ainsi que le main :&lt;br /&gt;
&lt;br /&gt;
Ce vecteur de Pose2D (x, y et theta (angle de la machine)) va permettre d'enregistrer la position des machines, c'est une variable global qui sera mise à jour avec le Callback :&lt;br /&gt;
&lt;br /&gt;
 std::vector&amp;lt;geometry_msgs::Pose2D&amp;gt; tab;&lt;br /&gt;
&lt;br /&gt;
*Récupération des machines envoyées par le noeud du SLAM (sur le topic /landmarks):&lt;br /&gt;
&lt;br /&gt;
 void Poses_Machine_Callback(const deplacement_msg::LandmarksConstPtr &amp;amp;machines)&lt;br /&gt;
 {&lt;br /&gt;
          tab=machines-&amp;gt;landmarks;&lt;br /&gt;
          for (int i=0; i&amp;lt;tab.size(); i++)&lt;br /&gt;
          {&lt;br /&gt;
     	     tab[i].x = tab[i].x*1000;&lt;br /&gt;
     	     tab[i].y = tab[i].y*1000;&lt;br /&gt;
 	  }&lt;br /&gt;
    &lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
*Création d'une map vide de taille 14m sur 8m. Chaque case est initialisée à une valeur nulle, on remplit également les autres paramètres de OccupancyGrid:&lt;br /&gt;
(On rappelle que la technique utilisée est un vecteur qui représente chaque case auxquelles il associe une probabilité 100 c'est un point interdit et 0 quand c'est un point sans danger pour le passage du robot)&lt;br /&gt;
&lt;br /&gt;
 void Create_Empty_Map(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      Map.info.origin.position.x=-7000;&lt;br /&gt;
      Map.info.origin.position.y=-1000;&lt;br /&gt;
      Map.info.origin.position.z=0;&lt;br /&gt;
      Map.info.origin.orientation.x=0;&lt;br /&gt;
      Map.info.origin.orientation.y=0;&lt;br /&gt;
      Map.info.origin.orientation.z=0;&lt;br /&gt;
      Map.info.origin.orientation.w=1;&lt;br /&gt;
      Map.info.map_load_time=ros::Time::now();&lt;br /&gt;
      Map.info.resolution=100;&lt;br /&gt;
      Map.info.width=140;&lt;br /&gt;
      Map.info.height=80;&lt;br /&gt;
      Map.data.assign(Map.info.width*Map.info.height, 0);                   //map vide&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
*Construction des points fixes de la map donc les murs (probabilité 100) et les zones à risques (probabilité 50):&lt;br /&gt;
&lt;br /&gt;
 void Set_Wall(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
    for (int i=0;i&amp;lt;80;i++)&lt;br /&gt;
    {&lt;br /&gt;
       for (int j=0;j&amp;lt;140;j++)&lt;br /&gt;
       {&lt;br /&gt;
          if ((i&amp;lt;13)||(i&amp;gt;67))) Map.data[j+i*140]=100;&lt;br /&gt;
          if ((j&amp;lt;13)||(j&amp;gt;127)) Map.data[j+i*140]=100;&lt;br /&gt;
       }&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Nous ne mettons pas tout le code de cette fonction étant donné qu'il est long et répétitif puisque c'est le remplissage des données connues, donc en &amp;quot;dur&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Calcul des positions machines: &lt;br /&gt;
&lt;br /&gt;
Lorsqu'on reçoit une position machine, c'est en fait son centre et son orientation par rapport à x que l'on reçoit. Etant donné que les machines doivent être des rectangles de 110cm sur 75cm (réellement 70 x 35 mais on compte la moitié du robot en plus par sécurité), on décide d'abord de déterminer un des coins du rectangle et plus précisément le coin en bas à droite de ce dernier:&lt;br /&gt;
&lt;br /&gt;
 void Get_One_Point_Of_The_Rectangle(float x, float &amp;amp;xA, float y, float &amp;amp;yA, float theta, float largeur, float longueur)&lt;br /&gt;
 {&lt;br /&gt;
      float x1,y1;&lt;br /&gt;
      x1 = x - cos(theta)*longueur;&lt;br /&gt;
      y1 = y - sin(theta)*longueur; &lt;br /&gt;
      xA = x1 + sin(M_PI_2-theta)*largeur;&lt;br /&gt;
      yA = y1 - cos(M_PI_2-theta)*largeur;&lt;br /&gt;
  &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
*Remplissage des positions sur la map :&lt;br /&gt;
&lt;br /&gt;
On met alors tous les points de ce rectangle à une probabilité 100 dans le vecteur Map. Pour les calculs on différencie le cas ou l'angle de la machine est entre 0 et pi/2 et le cas où il est entre pi/2 et pi. L'algorithme est le suivant : &lt;br /&gt;
&lt;br /&gt;
 A partir du coin, on incrémente x et y de sorte à longer le grand coté et de remplir chaque case (incrémentation de 5 cm).&lt;br /&gt;
 Une fois arrivé au bout, on incrémente x et y de 5cm sur la largeur à partir du coin et on recommence l'opération précédente.&lt;br /&gt;
 Ceci jusqu'à remplir le complètement le rectangle.&lt;br /&gt;
&lt;br /&gt;
Afin d'établir les probabilités correspondantes aux cases de ce rectangle, nous utilisons la fonctions floor() pour &amp;quot;convertir&amp;quot; nos flottants en entier et accéder à la case correspondante. On notera aussi que la case 1470 correspond à l'origine de notre map.&lt;br /&gt;
&lt;br /&gt;
 void Set_Machines_In_Map(float rank, float theta, float xA, float yA, nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      float x=xA;&lt;br /&gt;
      float y=yA;&lt;br /&gt;
      if (theta&amp;lt;=M_PI_2)&lt;br /&gt;
      {&lt;br /&gt;
            for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
            {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++) &lt;br /&gt;
                  {&lt;br /&gt;
                      Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                      x = x + cos(theta)*50;&lt;br /&gt;
                      y = y + sin(theta)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(M_PI_2-theta)*50;&lt;br /&gt;
                  y = yA + j*sin(M_PI_2-theta)*50;&lt;br /&gt;
            }	&lt;br /&gt;
       }&lt;br /&gt;
       if (theta&amp;gt;M_PI_2)&lt;br /&gt;
       {&lt;br /&gt;
             for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
             {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++)&lt;br /&gt;
                  {&lt;br /&gt;
                        Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                        x = x - sin(theta-M_PI_2)*50;&lt;br /&gt;
                        y = y + cos(theta-M_PI_2)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(theta-M_PI_2)*50;&lt;br /&gt;
                  y = yA - j*sin(theta-M_PI_2)*50;&lt;br /&gt;
              }	&lt;br /&gt;
        }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Ci dessous on a les mains, avec les différentes fonctions appelées et la syntaxe particulière à ROS. &lt;br /&gt;
&lt;br /&gt;
*Noeud général pour le traitement et le remplissage de la map :   &lt;br /&gt;
                 &lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
     ros::init(argc, argv, &amp;quot;server&amp;quot;);&lt;br /&gt;
     ros::NodeHandle n;&lt;br /&gt;
     ros::Subscriber sub_poses_machine    = n.subscribe(&amp;quot;/machines&amp;quot;, 1000, Poses_Machine_Callback);   // Récupération des machines&lt;br /&gt;
     ros::Publisher Map_Pub = n.advertise&amp;lt;nav_msgs::OccupancyGrid&amp;gt;(&amp;quot;/map&amp;quot;, 1000);                     // Préparation de la publication de la map&lt;br /&gt;
     ROS_INFO(&amp;quot;Ready to Generate the Map&amp;quot;);&lt;br /&gt;
     float xA,yA;&lt;br /&gt;
     ros::Rate loop_rate(1);&lt;br /&gt;
     while(ros::ok())&lt;br /&gt;
     {&lt;br /&gt;
        nav_msgs::OccupancyGrid Map;&lt;br /&gt;
        Create_Empty_Map(Map);&lt;br /&gt;
        Set_Wall(Map);&lt;br /&gt;
        for (int z=0;z&amp;lt;tab.size();z++)&lt;br /&gt;
        {&lt;br /&gt;
           Get_One_Point_Of_The_Rectangle(tab[z].x, xA, tab[z].y, yA, tab[z].theta, 275, 450);&lt;br /&gt;
 	   Set_Machines_In_Map(100, tab[z].theta, xA, yA, Map);&lt;br /&gt;
        }&lt;br /&gt;
        Map_Pub.publish(Map);                                                                   // publication de la map&lt;br /&gt;
        ros::spinOnce();&lt;br /&gt;
        loop_rate.sleep();&lt;br /&gt;
     }&lt;br /&gt;
     return 0;&lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Noeud test qui publie 2 positions de machines : &lt;br /&gt;
&lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
    ros::init(argc, argv, &amp;quot;test&amp;quot;);&lt;br /&gt;
    ros::NodeHandle n;&lt;br /&gt;
    ros::Publisher Pose_Machines_Pub = n.advertise&amp;lt;deplacement_msg::Landmarks&amp;gt;(&amp;quot;/machines&amp;quot;, 1000);&lt;br /&gt;
    ROS_INFO(&amp;quot;Ready to send poses machines&amp;quot;);&lt;br /&gt;
    int xA,yA;&lt;br /&gt;
    ros::Rate loop_rate(1);&lt;br /&gt;
    while(ros::ok())&lt;br /&gt;
    {&lt;br /&gt;
       deplacement_msg::Landmarks machines_msgs;&lt;br /&gt;
       geometry_msgs::Pose2D tab;&lt;br /&gt;
       tab.x=-2;&lt;br /&gt;
       tab.y=2;&lt;br /&gt;
       tab.theta=0;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       tab.x=5;&lt;br /&gt;
       tab.y=4;&lt;br /&gt;
       tab.theta=2.5;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       Pose_Machines_Pub.publish(machines_msgs);&lt;br /&gt;
       ros::spinOnce();&lt;br /&gt;
       loop_rate.sleep();&lt;br /&gt;
    }&lt;br /&gt;
    return 0;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On visualise le résultat grâce au logiciel RVIZ qui peut lire les topics publiés et donc le topic /map :&lt;br /&gt;
&lt;br /&gt;
===Semaine 9===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
l'objectif de cette semaine sera de coder toutes les fonctions nécessaires à l'implémentation finale du [http://fr.wikipedia.org/wiki/Filtre_de_Kalman#Filtre_de_Kalman_.C3.A9tendu filtre de Kalman étendu] :&lt;br /&gt;
&lt;br /&gt;
*initialisations des différents éléments&lt;br /&gt;
*étape de prédiction&lt;br /&gt;
*étape de mise à jour&lt;br /&gt;
*publication des positions machines et du robot dans le repère global via un topic ROS&lt;br /&gt;
&lt;br /&gt;
Le schéma ci-dessous nous montre les deux étapes du filtre de Kalman :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Kalman.png | center]]&lt;br /&gt;
&lt;br /&gt;
le code pour la partie ''prédiction'' :&lt;br /&gt;
&lt;br /&gt;
 //on ressort la position du robot pour l'état n+1&lt;br /&gt;
 //les paramètres sont le vecteurs où on a la position du robot à l'état n, la matrice P, les commandes en vitesses et le temps à l'état n&lt;br /&gt;
 Vector3d prediction(VectorXd xMean, MatrixXd &amp;amp;P, geometry_msgs::Pose2D cmdVel, ros::Time &amp;amp;temps){&lt;br /&gt;
   ros::Duration duree = ros::Time::now() - temps;&lt;br /&gt;
   double periode = duree.toSec();&amp;lt;br&amp;gt;&lt;br /&gt;
   Vector3d cmdVelVect = Pose2DToVector(cmdVel);&lt;br /&gt;
   //le xMean.topLeftCorner(3,1) correspond à la position du robot&lt;br /&gt;
   Vector3d xPredicted = xMean.topLeftCorner(3,1) + periode*cmdVelVect;&amp;lt;br&amp;gt;&lt;br /&gt;
   MatrixXd Fx;&lt;br /&gt;
   Fx = MatrixXd::Identity(P.rows(), P.cols());&lt;br /&gt;
   Fx(0,0) = xPredicted(0);&lt;br /&gt;
   Fx(1,1) = xPredicted(1);&lt;br /&gt;
   Fx(2,2) = xPredicted(2);&amp;lt;br&amp;gt;&lt;br /&gt;
   //mise à jour de P&lt;br /&gt;
   P = Fx*P*(Fx.transpose());&amp;lt;br&amp;gt;&lt;br /&gt;
   //mise à jour du temps&lt;br /&gt;
   temps = ros::Time::now();&amp;lt;br&amp;gt;&lt;br /&gt;
   return xPredicted;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
le code pour la partie ''correction'' :&lt;br /&gt;
&lt;br /&gt;
 void correction(VectorXd &amp;amp;xMean, MatrixXd &amp;amp;P, Vector3d xPredicted, geometry_msgs::Pose2D m){&lt;br /&gt;
   int taille = P.rows();&lt;br /&gt;
   //on vérifie si la machine est présente ou pas dans le vecteur d'état&lt;br /&gt;
   int i = checkStateVector(xMean, m);&amp;lt;br&amp;gt;&lt;br /&gt;
   if (i != 0){&lt;br /&gt;
     //calcul de H&lt;br /&gt;
     MatrixXd H(3, taille);&lt;br /&gt;
     H = buildH(taille, i);&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul de Pm&lt;br /&gt;
     MatrixXd Pm(taille, taille);&lt;br /&gt;
     Pm = buildPm(P, i);&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul de Z&lt;br /&gt;
     MatrixXd Z(taille, taille);&lt;br /&gt;
     Z = H*Pm*(H.transpose());	&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul du gain de Kalman&lt;br /&gt;
     MatrixXd K(taille, taille);&lt;br /&gt;
     K = P*(H.transpose())*(Z.inverse());&amp;lt;br&amp;gt;&lt;br /&gt;
     //mise à jour du vecteur xMean&lt;br /&gt;
     xMean = xMean + K*(xMean.block(xMean.rows()-3,0,3,1) - xPredicted);&amp;lt;br&amp;gt;&lt;br /&gt;
     //mise à jour de la matrice P&lt;br /&gt;
     P = P - K*Z*(K.transpose());&lt;br /&gt;
   }&lt;br /&gt;
   else {&lt;br /&gt;
     addMachine(m, xMean, P);&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Pour notre cas, on doit ajouter des nouvelles machines, alors que pour un EKF classique on observe juste des machines déjà répertoriées. Il faut donc une fonction qui permet d'ajouter une machine dans le vecteur d'état. La voilà :&lt;br /&gt;
&lt;br /&gt;
 void addMachine(geometry_msgs::Pose2D machine, VectorXd &amp;amp;xMean, MatrixXd &amp;amp;P){&lt;br /&gt;
   //on redimensionne xMean et P pour accueillir la nouvelle machines&lt;br /&gt;
   xMean.conservativeResize(xMean.rows() + 3);&lt;br /&gt;
   P.conservativeResize(P.rows()+3,P.cols()+3);&amp;lt;br&amp;gt;&lt;br /&gt;
   //on remplit avec les coordonnées de la nouvelle machine&lt;br /&gt;
   xMean(xMean.rows()-3) = machine.x;&lt;br /&gt;
   xMean(xMean.rows()-2) = machine.y;&lt;br /&gt;
   xMean(xMean.rows()-1) = machine.theta;&amp;lt;br&amp;gt;&lt;br /&gt;
   //calcul de tous les PLi&lt;br /&gt;
   //initialisation des PLi à 0&lt;br /&gt;
   P.block(P.rows() - 3, 0, 3, P.cols()).setZero();&lt;br /&gt;
   P.block(0, P.cols() - 3, P.rows(), 3).setZero();&amp;lt;br&amp;gt;&lt;br /&gt;
   for (int j = 0; j &amp;lt; xMean.rows(); j = j + 3){&lt;br /&gt;
     //position de la nouvelle machines par rapport au robot et à toutes les autres&lt;br /&gt;
     double x 	 = xMean(xMean.rows()-3) - xMean(j  );&lt;br /&gt;
     double y 	 = xMean(xMean.rows()-2) - xMean(j+1);&lt;br /&gt;
     double theta = xMean(xMean.rows()-1) - xMean(j+2);&amp;lt;br&amp;gt;&lt;br /&gt;
     P(P.rows()-3, j  ) = x;&lt;br /&gt;
     P(P.rows()-2, j+1) = y;&lt;br /&gt;
     P(P.rows()-1, j+2) = theta;&amp;lt;br&amp;gt;&lt;br /&gt;
     P(j  , P.rows()-3) = x;&lt;br /&gt;
     P(j+1, P.rows()-2) = y;&lt;br /&gt;
     P(j+2, P.rows()-1) = theta;&amp;lt;br&amp;gt;&lt;br /&gt;
     P(j  , j  ) = xMean(j  ) - xMean(0);&lt;br /&gt;
     P(j+1, j+1) = xMean(j+1) - xMean(1);&lt;br /&gt;
     P(j+2, j+2) = xMean(j+2) - xMean(2);&amp;lt;br&amp;gt;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 10===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
La partie '''prédiction''' du filtre marche parfaitement, quelques corrections ont dues être faites au niveau de la commande vitesse. En effet, Nous avions oublié de la transposer dans le repère global. Pour la partie '''correction''', nous rencontrons un problème de divergence du filtre, qui est probablement due à une mauvaise initialisation. En effet, nous utilisons des enregistrements faits sur notre piste (1/4 de la vraie) avec des initialisations correspondant à la piste originale. Le filtre ne peut donc pas converger car la position de départ est fausse.&lt;br /&gt;
&lt;br /&gt;
===Semaine 11===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
Des corrections sont en cours de validation. Nous essayons de définir une initialisation avec les paramètres de notre piste, ce qui n'est pas évident. Les programmes permettant d'extraire les positions machines du filtres ont été réalisé, ainsi qu'un launch pour pouvoir lancer tous les noeuds de la localisation.&lt;br /&gt;
&lt;br /&gt;
===Semaine 12===&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - mise en place====&lt;br /&gt;
&lt;br /&gt;
Pendant les deux jours de mise en place, nous avons continué à travailler sur la localisation, qui est une partie critique et nécessaire à notre participation. Le filtre en lui même est fonctionnel et permet de corriger la position du robot, ainsi que celle des machines. Cependant, et ce n'est pas un petit &amp;quot;cependant&amp;quot;... Le fait que l'on ajoute des machines en cours de jeu perturbe fortement notre algorithme.&lt;br /&gt;
&lt;br /&gt;
En effet, le filtre de Kalman est optimal si la position des repères est connu, or, un ajout de machine crée un recalage forcé, et si l'on voit plusieurs machines... C'est la '''catastrophe'''. L'ajout de machines est une partie sensible qui nécessite des tests sur la position mesurée, avec un changement de repère à partir de la position du robot, si celle ci dérive, tout dérive. Chaque machine initialisée à la mauvaise position, ou chaque élément détecté comme machine mais n'en étant pas une (faux positif) perturbe le recalage.&lt;br /&gt;
&lt;br /&gt;
De nombreux tests ayant été fait sur la piste officiel avec différentes configurations nous ont permis de vérifier que l'odométrie mesurée ne dérivait que très peu. Il a donc été décidé de n'utiliser que l'odométrie et le scan laser pour la partie '''exploration'''. En effet, chaque machine mesurée est envoyée à un noeud ROS qui va créer une carte et la compléter au fur et à mesure de la partie. Le robot est donc repéré rien qu'avec son odométrie. Le fait que la phase d'exploration (découverte du terrain) ne dure que '''4 minutes''' nous a convaincu pour n'utiliser que cette mesure.&lt;br /&gt;
&lt;br /&gt;
De plus, la carte créée sera utilisée pour la phase suivante, la phase de '''production'''. Cette phase consiste, au niveau de la localisation, à se repérer sur la piste et atteindre la machine demandée par l'exécuteur de tâches. Pour cette phase qui dure '''15 minutes''', l'utilisation du filtre est nécessaire. Donc, avec les coordonnées des machines mesurées pendant la première phase, on peut créer le vecteur d'état et la matrice faisant le lien entre les machines. De là, la taille de ces deux éléments ne variant plus, on peut corriger uniquement la position du robot et le filtre sera efficace.&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - 1er jour====&lt;br /&gt;
&lt;br /&gt;
Durant ce premier jour, nous avons commencé à ''merger'' nos branches respectives pour pouvoir faire tourner tous nos programmes. Cette phase est laborieuse et nous a pris du temps. De toute façon, toutes les équipes ne sont pas prêtes, les organisateurs non plus. La '''Referee Box''' n'est pas fonctionnel pour la phase de production, ce qui veut dire que nous nous concentrons actuellement sur l'exploration. Les matchs joués aujourd'hui ne nous rapporte donc pas de points. Les tests nous ont permis de valider individuellement chacun des algos, il ne reste &amp;quot;plus qu'à&amp;quot; rejoindre le tout.&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - 2eme jour====&lt;br /&gt;
&lt;br /&gt;
Niveau '''localisation''', la navigation à l'odométrie et la détection de machine sont fonctionnelles. Cependant, le moyennage fait sur les positions machines (on moyenne toutes les positions trouvées appartenant à une même machine pour n'avoir qu'un seul point) fait que le point correspondant peut être perturbé par des mesures aberrantes. C'est le cas lorsque le robot se déplace à vitesse élevée.&lt;br /&gt;
&lt;br /&gt;
La détection de machine a été améliorée afin de ne rajouter QUE les machines, et pas les murs de la même taille. Nous allons donc retester le '''filtre de Kalman Etendu''' avec cette amélioration. Cependant, ce ne sera fait qu'après la compétition, puisque d'autres problèmes ont nécessité la présence de l'équipe sur certaines parties sensibles du déplacement.&lt;br /&gt;
&lt;br /&gt;
Sur la piste nous avons fait des mesures, qui nous donnent la carte suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:PisteSamediSoir.PNG | center]]&lt;br /&gt;
&lt;br /&gt;
La visualisation du trajet pour découvrir ces machines est le suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DetectionSamediSoir.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Et les positions machines, ainsi que leur orientation sont les suivantes :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:MachinesBagtestSamediSoir.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - 3eme et dernier jour====&lt;br /&gt;
&lt;br /&gt;
L'architecture choisie pour la localisation est la suivante :&lt;br /&gt;
*Navigation à l'odométrie&lt;br /&gt;
*Détection de machines et moyennage&lt;br /&gt;
*Quand on a vu toutes nos machines, on utilise la symétrie pour compléter les machines restantes&lt;br /&gt;
*Navigation et Localisation avec l'EKF (correction des positions machines et du robot)&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=Fichier:MachinesBagtestSamediSoir.PNG&amp;diff=20501</id>
		<title>Fichier:MachinesBagtestSamediSoir.PNG</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=Fichier:MachinesBagtestSamediSoir.PNG&amp;diff=20501"/>
				<updated>2015-04-28T13:04:06Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=Fichier:PisteSamediSoir.PNG&amp;diff=20500</id>
		<title>Fichier:PisteSamediSoir.PNG</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=Fichier:PisteSamediSoir.PNG&amp;diff=20500"/>
				<updated>2015-04-28T13:02:17Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=Fichier:DetectionSamediSoir.PNG&amp;diff=20499</id>
		<title>Fichier:DetectionSamediSoir.PNG</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=Fichier:DetectionSamediSoir.PNG&amp;diff=20499"/>
				<updated>2015-04-28T13:01:31Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=20498</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=20498"/>
				<updated>2015-04-28T13:00:54Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Compétition Open German - 2eme jour */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - vidéo====&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les résultats de la détection des machines nous avons utiliser l'interface graphique disponible avec ROS, RVIZ. Nous visualisons alors le scan laser (points blancs), le résultat de la détection de segments (en rouge) et les positions des machines trouvées (en vert). Un premier test a été fait sur le scan originel, celui sur lequel nous avons travaillé depuis le début.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=XSn4s1y-XT0 Visualisation des machines]&lt;br /&gt;
&lt;br /&gt;
On rencontre un problème quand le robot est exactement parallèle ou perpendiculaire à un mur. Après vérification dans le programme, il s'avère que la détection ne fonctionne pas pour ces cas. Ce bug est maintenant corrigé :&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=rKeqewpuLoQ Correction du bug]&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
La première étape consiste juste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;br /&gt;
&lt;br /&gt;
la matrice correspondant au changement (laser -&amp;gt; robot) est la suivante : &lt;br /&gt;
&lt;br /&gt;
 0   -1    0&lt;br /&gt;
 1    0  0.2&lt;br /&gt;
 0    0    1&lt;br /&gt;
&lt;br /&gt;
la matrice 2x2 en haut à gauche correspond à la rotation de 90°, et le vecteur (0, 0.2) correspond à la translation.&lt;br /&gt;
&lt;br /&gt;
Celle du changement (robot -&amp;gt; global) avec alpha angle mesuré par le gyroscope depuis la position initiale (angle 0) :&lt;br /&gt;
&lt;br /&gt;
 cos(alpha)   -sin(alpha)    posInit.x&lt;br /&gt;
 sin(alpha)    cos(alpha)    posInit.y&lt;br /&gt;
          0             0            1&lt;br /&gt;
&lt;br /&gt;
l'étape suivante est de vérifier si les machines vues par le laser sont bien des machines, c'est-à-dire si les positions mesurées à partir des données lasers correspond aux zones occupées par des machines envoyées par la Referee Box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Grid Map====&lt;br /&gt;
&lt;br /&gt;
L'autre objectif de cette semaine a été de coder le noeud qui génère la map. La map est générée sous forme d'OccupancyGrid. Ce type est constitué d'un seul vecteur dont la première case correspond à la case en bas à gauche de la map. D'autres paramètres sont réglable comme l'origine et la taille.&lt;br /&gt;
&lt;br /&gt;
Pour la taille on choisit de diviser la map en case de 10 cm et l'origine choisie est le x du centre de la map et en y l'abscisse du premier mur (voir la map ci-dessous). Afin d'expliquer comment est constituée cette map, prenons le code et analysons les différentes fonctions ainsi que le main :&lt;br /&gt;
&lt;br /&gt;
Ce vecteur de Pose2D (x, y et theta (angle de la machine)) va permettre d'enregistrer la position des machines, c'est une variable global qui sera mise à jour avec le Callback :&lt;br /&gt;
&lt;br /&gt;
 std::vector&amp;lt;geometry_msgs::Pose2D&amp;gt; tab;&lt;br /&gt;
&lt;br /&gt;
*Récupération des machines envoyées par le noeud du SLAM (sur le topic /landmarks):&lt;br /&gt;
&lt;br /&gt;
 void Poses_Machine_Callback(const deplacement_msg::LandmarksConstPtr &amp;amp;machines)&lt;br /&gt;
 {&lt;br /&gt;
          tab=machines-&amp;gt;landmarks;&lt;br /&gt;
          for (int i=0; i&amp;lt;tab.size(); i++)&lt;br /&gt;
          {&lt;br /&gt;
     	     tab[i].x = tab[i].x*1000;&lt;br /&gt;
     	     tab[i].y = tab[i].y*1000;&lt;br /&gt;
 	  }&lt;br /&gt;
    &lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
*Création d'une map vide de taille 14m sur 8m. Chaque case est initialisée à une valeur nulle, on remplit également les autres paramètres de OccupancyGrid:&lt;br /&gt;
(On rappelle que la technique utilisée est un vecteur qui représente chaque case auxquelles il associe une probabilité 100 c'est un point interdit et 0 quand c'est un point sans danger pour le passage du robot)&lt;br /&gt;
&lt;br /&gt;
 void Create_Empty_Map(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      Map.info.origin.position.x=-7000;&lt;br /&gt;
      Map.info.origin.position.y=-1000;&lt;br /&gt;
      Map.info.origin.position.z=0;&lt;br /&gt;
      Map.info.origin.orientation.x=0;&lt;br /&gt;
      Map.info.origin.orientation.y=0;&lt;br /&gt;
      Map.info.origin.orientation.z=0;&lt;br /&gt;
      Map.info.origin.orientation.w=1;&lt;br /&gt;
      Map.info.map_load_time=ros::Time::now();&lt;br /&gt;
      Map.info.resolution=100;&lt;br /&gt;
      Map.info.width=140;&lt;br /&gt;
      Map.info.height=80;&lt;br /&gt;
      Map.data.assign(Map.info.width*Map.info.height, 0);                   //map vide&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
*Construction des points fixes de la map donc les murs (probabilité 100) et les zones à risques (probabilité 50):&lt;br /&gt;
&lt;br /&gt;
 void Set_Wall(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
    for (int i=0;i&amp;lt;80;i++)&lt;br /&gt;
    {&lt;br /&gt;
       for (int j=0;j&amp;lt;140;j++)&lt;br /&gt;
       {&lt;br /&gt;
          if ((i&amp;lt;13)||(i&amp;gt;67))) Map.data[j+i*140]=100;&lt;br /&gt;
          if ((j&amp;lt;13)||(j&amp;gt;127)) Map.data[j+i*140]=100;&lt;br /&gt;
       }&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Nous ne mettons pas tout le code de cette fonction étant donné qu'il est long et répétitif puisque c'est le remplissage des données connues, donc en &amp;quot;dur&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Calcul des positions machines: &lt;br /&gt;
&lt;br /&gt;
Lorsqu'on reçoit une position machine, c'est en fait son centre et son orientation par rapport à x que l'on reçoit. Etant donné que les machines doivent être des rectangles de 110cm sur 75cm (réellement 70 x 35 mais on compte la moitié du robot en plus par sécurité), on décide d'abord de déterminer un des coins du rectangle et plus précisément le coin en bas à droite de ce dernier:&lt;br /&gt;
&lt;br /&gt;
 void Get_One_Point_Of_The_Rectangle(float x, float &amp;amp;xA, float y, float &amp;amp;yA, float theta, float largeur, float longueur)&lt;br /&gt;
 {&lt;br /&gt;
      float x1,y1;&lt;br /&gt;
      x1 = x - cos(theta)*longueur;&lt;br /&gt;
      y1 = y - sin(theta)*longueur; &lt;br /&gt;
      xA = x1 + sin(M_PI_2-theta)*largeur;&lt;br /&gt;
      yA = y1 - cos(M_PI_2-theta)*largeur;&lt;br /&gt;
  &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
*Remplissage des positions sur la map :&lt;br /&gt;
&lt;br /&gt;
On met alors tous les points de ce rectangle à une probabilité 100 dans le vecteur Map. Pour les calculs on différencie le cas ou l'angle de la machine est entre 0 et pi/2 et le cas où il est entre pi/2 et pi. L'algorithme est le suivant : &lt;br /&gt;
&lt;br /&gt;
 A partir du coin, on incrémente x et y de sorte à longer le grand coté et de remplir chaque case (incrémentation de 5 cm).&lt;br /&gt;
 Une fois arrivé au bout, on incrémente x et y de 5cm sur la largeur à partir du coin et on recommence l'opération précédente.&lt;br /&gt;
 Ceci jusqu'à remplir le complètement le rectangle.&lt;br /&gt;
&lt;br /&gt;
Afin d'établir les probabilités correspondantes aux cases de ce rectangle, nous utilisons la fonctions floor() pour &amp;quot;convertir&amp;quot; nos flottants en entier et accéder à la case correspondante. On notera aussi que la case 1470 correspond à l'origine de notre map.&lt;br /&gt;
&lt;br /&gt;
 void Set_Machines_In_Map(float rank, float theta, float xA, float yA, nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      float x=xA;&lt;br /&gt;
      float y=yA;&lt;br /&gt;
      if (theta&amp;lt;=M_PI_2)&lt;br /&gt;
      {&lt;br /&gt;
            for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
            {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++) &lt;br /&gt;
                  {&lt;br /&gt;
                      Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                      x = x + cos(theta)*50;&lt;br /&gt;
                      y = y + sin(theta)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(M_PI_2-theta)*50;&lt;br /&gt;
                  y = yA + j*sin(M_PI_2-theta)*50;&lt;br /&gt;
            }	&lt;br /&gt;
       }&lt;br /&gt;
       if (theta&amp;gt;M_PI_2)&lt;br /&gt;
       {&lt;br /&gt;
             for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
             {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++)&lt;br /&gt;
                  {&lt;br /&gt;
                        Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                        x = x - sin(theta-M_PI_2)*50;&lt;br /&gt;
                        y = y + cos(theta-M_PI_2)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(theta-M_PI_2)*50;&lt;br /&gt;
                  y = yA - j*sin(theta-M_PI_2)*50;&lt;br /&gt;
              }	&lt;br /&gt;
        }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Ci dessous on a les mains, avec les différentes fonctions appelées et la syntaxe particulière à ROS. &lt;br /&gt;
&lt;br /&gt;
*Noeud général pour le traitement et le remplissage de la map :   &lt;br /&gt;
                 &lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
     ros::init(argc, argv, &amp;quot;server&amp;quot;);&lt;br /&gt;
     ros::NodeHandle n;&lt;br /&gt;
     ros::Subscriber sub_poses_machine    = n.subscribe(&amp;quot;/machines&amp;quot;, 1000, Poses_Machine_Callback);   // Récupération des machines&lt;br /&gt;
     ros::Publisher Map_Pub = n.advertise&amp;lt;nav_msgs::OccupancyGrid&amp;gt;(&amp;quot;/map&amp;quot;, 1000);                     // Préparation de la publication de la map&lt;br /&gt;
     ROS_INFO(&amp;quot;Ready to Generate the Map&amp;quot;);&lt;br /&gt;
     float xA,yA;&lt;br /&gt;
     ros::Rate loop_rate(1);&lt;br /&gt;
     while(ros::ok())&lt;br /&gt;
     {&lt;br /&gt;
        nav_msgs::OccupancyGrid Map;&lt;br /&gt;
        Create_Empty_Map(Map);&lt;br /&gt;
        Set_Wall(Map);&lt;br /&gt;
        for (int z=0;z&amp;lt;tab.size();z++)&lt;br /&gt;
        {&lt;br /&gt;
           Get_One_Point_Of_The_Rectangle(tab[z].x, xA, tab[z].y, yA, tab[z].theta, 275, 450);&lt;br /&gt;
 	   Set_Machines_In_Map(100, tab[z].theta, xA, yA, Map);&lt;br /&gt;
        }&lt;br /&gt;
        Map_Pub.publish(Map);                                                                   // publication de la map&lt;br /&gt;
        ros::spinOnce();&lt;br /&gt;
        loop_rate.sleep();&lt;br /&gt;
     }&lt;br /&gt;
     return 0;&lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Noeud test qui publie 2 positions de machines : &lt;br /&gt;
&lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
    ros::init(argc, argv, &amp;quot;test&amp;quot;);&lt;br /&gt;
    ros::NodeHandle n;&lt;br /&gt;
    ros::Publisher Pose_Machines_Pub = n.advertise&amp;lt;deplacement_msg::Landmarks&amp;gt;(&amp;quot;/machines&amp;quot;, 1000);&lt;br /&gt;
    ROS_INFO(&amp;quot;Ready to send poses machines&amp;quot;);&lt;br /&gt;
    int xA,yA;&lt;br /&gt;
    ros::Rate loop_rate(1);&lt;br /&gt;
    while(ros::ok())&lt;br /&gt;
    {&lt;br /&gt;
       deplacement_msg::Landmarks machines_msgs;&lt;br /&gt;
       geometry_msgs::Pose2D tab;&lt;br /&gt;
       tab.x=-2;&lt;br /&gt;
       tab.y=2;&lt;br /&gt;
       tab.theta=0;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       tab.x=5;&lt;br /&gt;
       tab.y=4;&lt;br /&gt;
       tab.theta=2.5;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       Pose_Machines_Pub.publish(machines_msgs);&lt;br /&gt;
       ros::spinOnce();&lt;br /&gt;
       loop_rate.sleep();&lt;br /&gt;
    }&lt;br /&gt;
    return 0;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On visualise le résultat grâce au logiciel RVIZ qui peut lire les topics publiés et donc le topic /map :&lt;br /&gt;
&lt;br /&gt;
===Semaine 9===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
l'objectif de cette semaine sera de coder toutes les fonctions nécessaires à l'implémentation finale du [http://fr.wikipedia.org/wiki/Filtre_de_Kalman#Filtre_de_Kalman_.C3.A9tendu filtre de Kalman étendu] :&lt;br /&gt;
&lt;br /&gt;
*initialisations des différents éléments&lt;br /&gt;
*étape de prédiction&lt;br /&gt;
*étape de mise à jour&lt;br /&gt;
*publication des positions machines et du robot dans le repère global via un topic ROS&lt;br /&gt;
&lt;br /&gt;
Le schéma ci-dessous nous montre les deux étapes du filtre de Kalman :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Kalman.png | center]]&lt;br /&gt;
&lt;br /&gt;
le code pour la partie ''prédiction'' :&lt;br /&gt;
&lt;br /&gt;
 //on ressort la position du robot pour l'état n+1&lt;br /&gt;
 //les paramètres sont le vecteurs où on a la position du robot à l'état n, la matrice P, les commandes en vitesses et le temps à l'état n&lt;br /&gt;
 Vector3d prediction(VectorXd xMean, MatrixXd &amp;amp;P, geometry_msgs::Pose2D cmdVel, ros::Time &amp;amp;temps){&lt;br /&gt;
   ros::Duration duree = ros::Time::now() - temps;&lt;br /&gt;
   double periode = duree.toSec();&amp;lt;br&amp;gt;&lt;br /&gt;
   Vector3d cmdVelVect = Pose2DToVector(cmdVel);&lt;br /&gt;
   //le xMean.topLeftCorner(3,1) correspond à la position du robot&lt;br /&gt;
   Vector3d xPredicted = xMean.topLeftCorner(3,1) + periode*cmdVelVect;&amp;lt;br&amp;gt;&lt;br /&gt;
   MatrixXd Fx;&lt;br /&gt;
   Fx = MatrixXd::Identity(P.rows(), P.cols());&lt;br /&gt;
   Fx(0,0) = xPredicted(0);&lt;br /&gt;
   Fx(1,1) = xPredicted(1);&lt;br /&gt;
   Fx(2,2) = xPredicted(2);&amp;lt;br&amp;gt;&lt;br /&gt;
   //mise à jour de P&lt;br /&gt;
   P = Fx*P*(Fx.transpose());&amp;lt;br&amp;gt;&lt;br /&gt;
   //mise à jour du temps&lt;br /&gt;
   temps = ros::Time::now();&amp;lt;br&amp;gt;&lt;br /&gt;
   return xPredicted;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
le code pour la partie ''correction'' :&lt;br /&gt;
&lt;br /&gt;
 void correction(VectorXd &amp;amp;xMean, MatrixXd &amp;amp;P, Vector3d xPredicted, geometry_msgs::Pose2D m){&lt;br /&gt;
   int taille = P.rows();&lt;br /&gt;
   //on vérifie si la machine est présente ou pas dans le vecteur d'état&lt;br /&gt;
   int i = checkStateVector(xMean, m);&amp;lt;br&amp;gt;&lt;br /&gt;
   if (i != 0){&lt;br /&gt;
     //calcul de H&lt;br /&gt;
     MatrixXd H(3, taille);&lt;br /&gt;
     H = buildH(taille, i);&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul de Pm&lt;br /&gt;
     MatrixXd Pm(taille, taille);&lt;br /&gt;
     Pm = buildPm(P, i);&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul de Z&lt;br /&gt;
     MatrixXd Z(taille, taille);&lt;br /&gt;
     Z = H*Pm*(H.transpose());	&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul du gain de Kalman&lt;br /&gt;
     MatrixXd K(taille, taille);&lt;br /&gt;
     K = P*(H.transpose())*(Z.inverse());&amp;lt;br&amp;gt;&lt;br /&gt;
     //mise à jour du vecteur xMean&lt;br /&gt;
     xMean = xMean + K*(xMean.block(xMean.rows()-3,0,3,1) - xPredicted);&amp;lt;br&amp;gt;&lt;br /&gt;
     //mise à jour de la matrice P&lt;br /&gt;
     P = P - K*Z*(K.transpose());&lt;br /&gt;
   }&lt;br /&gt;
   else {&lt;br /&gt;
     addMachine(m, xMean, P);&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Pour notre cas, on doit ajouter des nouvelles machines, alors que pour un EKF classique on observe juste des machines déjà répertoriées. Il faut donc une fonction qui permet d'ajouter une machine dans le vecteur d'état. La voilà :&lt;br /&gt;
&lt;br /&gt;
 void addMachine(geometry_msgs::Pose2D machine, VectorXd &amp;amp;xMean, MatrixXd &amp;amp;P){&lt;br /&gt;
   //on redimensionne xMean et P pour accueillir la nouvelle machines&lt;br /&gt;
   xMean.conservativeResize(xMean.rows() + 3);&lt;br /&gt;
   P.conservativeResize(P.rows()+3,P.cols()+3);&amp;lt;br&amp;gt;&lt;br /&gt;
   //on remplit avec les coordonnées de la nouvelle machine&lt;br /&gt;
   xMean(xMean.rows()-3) = machine.x;&lt;br /&gt;
   xMean(xMean.rows()-2) = machine.y;&lt;br /&gt;
   xMean(xMean.rows()-1) = machine.theta;&amp;lt;br&amp;gt;&lt;br /&gt;
   //calcul de tous les PLi&lt;br /&gt;
   //initialisation des PLi à 0&lt;br /&gt;
   P.block(P.rows() - 3, 0, 3, P.cols()).setZero();&lt;br /&gt;
   P.block(0, P.cols() - 3, P.rows(), 3).setZero();&amp;lt;br&amp;gt;&lt;br /&gt;
   for (int j = 0; j &amp;lt; xMean.rows(); j = j + 3){&lt;br /&gt;
     //position de la nouvelle machines par rapport au robot et à toutes les autres&lt;br /&gt;
     double x 	 = xMean(xMean.rows()-3) - xMean(j  );&lt;br /&gt;
     double y 	 = xMean(xMean.rows()-2) - xMean(j+1);&lt;br /&gt;
     double theta = xMean(xMean.rows()-1) - xMean(j+2);&amp;lt;br&amp;gt;&lt;br /&gt;
     P(P.rows()-3, j  ) = x;&lt;br /&gt;
     P(P.rows()-2, j+1) = y;&lt;br /&gt;
     P(P.rows()-1, j+2) = theta;&amp;lt;br&amp;gt;&lt;br /&gt;
     P(j  , P.rows()-3) = x;&lt;br /&gt;
     P(j+1, P.rows()-2) = y;&lt;br /&gt;
     P(j+2, P.rows()-1) = theta;&amp;lt;br&amp;gt;&lt;br /&gt;
     P(j  , j  ) = xMean(j  ) - xMean(0);&lt;br /&gt;
     P(j+1, j+1) = xMean(j+1) - xMean(1);&lt;br /&gt;
     P(j+2, j+2) = xMean(j+2) - xMean(2);&amp;lt;br&amp;gt;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 10===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
La partie '''prédiction''' du filtre marche parfaitement, quelques corrections ont dues être faites au niveau de la commande vitesse. En effet, Nous avions oublié de la transposer dans le repère global. Pour la partie '''correction''', nous rencontrons un problème de divergence du filtre, qui est probablement due à une mauvaise initialisation. En effet, nous utilisons des enregistrements faits sur notre piste (1/4 de la vraie) avec des initialisations correspondant à la piste originale. Le filtre ne peut donc pas converger car la position de départ est fausse.&lt;br /&gt;
&lt;br /&gt;
===Semaine 11===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
Des corrections sont en cours de validation. Nous essayons de définir une initialisation avec les paramètres de notre piste, ce qui n'est pas évident. Les programmes permettant d'extraire les positions machines du filtres ont été réalisé, ainsi qu'un launch pour pouvoir lancer tous les noeuds de la localisation.&lt;br /&gt;
&lt;br /&gt;
===Semaine 12===&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - mise en place====&lt;br /&gt;
&lt;br /&gt;
Pendant les deux jours de mise en place, nous avons continué à travailler sur la localisation, qui est une partie critique et nécessaire à notre participation. Le filtre en lui même est fonctionnel et permet de corriger la position du robot, ainsi que celle des machines. Cependant, et ce n'est pas un petit &amp;quot;cependant&amp;quot;... Le fait que l'on ajoute des machines en cours de jeu perturbe fortement notre algorithme.&lt;br /&gt;
&lt;br /&gt;
En effet, le filtre de Kalman est optimal si la position des repères est connu, or, un ajout de machine crée un recalage forcé, et si l'on voit plusieurs machines... C'est la '''catastrophe'''. L'ajout de machines est une partie sensible qui nécessite des tests sur la position mesurée, avec un changement de repère à partir de la position du robot, si celle ci dérive, tout dérive. Chaque machine initialisée à la mauvaise position, ou chaque élément détecté comme machine mais n'en étant pas une (faux positif) perturbe le recalage.&lt;br /&gt;
&lt;br /&gt;
De nombreux tests ayant été fait sur la piste officiel avec différentes configurations nous ont permis de vérifier que l'odométrie mesurée ne dérivait que très peu. Il a donc été décidé de n'utiliser que l'odométrie et le scan laser pour la partie '''exploration'''. En effet, chaque machine mesurée est envoyée à un noeud ROS qui va créer une carte et la compléter au fur et à mesure de la partie. Le robot est donc repéré rien qu'avec son odométrie. Le fait que la phase d'exploration (découverte du terrain) ne dure que '''4 minutes''' nous a convaincu pour n'utiliser que cette mesure.&lt;br /&gt;
&lt;br /&gt;
De plus, la carte créée sera utilisée pour la phase suivante, la phase de '''production'''. Cette phase consiste, au niveau de la localisation, à se repérer sur la piste et atteindre la machine demandée par l'exécuteur de tâches. Pour cette phase qui dure '''15 minutes''', l'utilisation du filtre est nécessaire. Donc, avec les coordonnées des machines mesurées pendant la première phase, on peut créer le vecteur d'état et la matrice faisant le lien entre les machines. De là, la taille de ces deux éléments ne variant plus, on peut corriger uniquement la position du robot et le filtre sera efficace.&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - 1er jour====&lt;br /&gt;
&lt;br /&gt;
Durant ce premier jour, nous avons commencé à ''merger'' nos branches respectives pour pouvoir faire tourner tous nos programmes. Cette phase est laborieuse et nous a pris du temps. De toute façon, toutes les équipes ne sont pas prêtes, les organisateurs non plus. La '''Referee Box''' n'est pas fonctionnel pour la phase de production, ce qui veut dire que nous nous concentrons actuellement sur l'exploration. Les matchs joués aujourd'hui ne nous rapporte donc pas de points. Les tests nous ont permis de valider individuellement chacun des algos, il ne reste &amp;quot;plus qu'à&amp;quot; rejoindre le tout.&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - 2eme jour====&lt;br /&gt;
&lt;br /&gt;
Niveau '''localisation''', la navigation à l'odométrie et la détection de machine sont fonctionnelles. Cependant, le moyennage fait sur les positions machines (on moyenne toutes les positions trouvées appartenant à une même machine pour n'avoir qu'un seul point) fait que le point correspondant peut être perturbé par des mesures aberrantes. C'est le cas lorsque le robot se déplace à vitesse élevée.&lt;br /&gt;
&lt;br /&gt;
La détection de machine a été améliorée afin de ne rajouter QUE les machines, et pas les murs de la même taille. Nous allons donc retester le '''filtre de Kalman Etendu''' avec cette amélioration. Cependant, ce ne sera fait qu'après la compétition, puisque d'autres problèmes ont nécessité la présence de l'équipe sur certaines parties sensibles du déplacement.&lt;br /&gt;
&lt;br /&gt;
Sur la piste nous avons fait des mesures, qui nous donnent la carte suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:PisteSamediSoir.PNG]]&lt;br /&gt;
&lt;br /&gt;
La visualisation du trajet pour découvrir ces machines est le suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DetectionSamediSoir.PNG]]&lt;br /&gt;
&lt;br /&gt;
Et les positions machines, ainsi que leur orientation sont les suivantes :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:MachinesBagtestSamediSoir.PNG]]&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - 3eme et dernier jour====&lt;br /&gt;
&lt;br /&gt;
L'architecture choisie pour la localisation est la suivante :&lt;br /&gt;
*Navigation à l'odométrie&lt;br /&gt;
*Détection de machines et moyennage&lt;br /&gt;
*Quand on a vu toutes nos machines, on utilise la symétrie pour compléter les machines restantes&lt;br /&gt;
*Navigation et Localisation avec l'EKF (correction des positions machines et du robot)&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=20497</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=20497"/>
				<updated>2015-04-28T10:53:38Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Compétition Open German - 1er jour */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - vidéo====&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les résultats de la détection des machines nous avons utiliser l'interface graphique disponible avec ROS, RVIZ. Nous visualisons alors le scan laser (points blancs), le résultat de la détection de segments (en rouge) et les positions des machines trouvées (en vert). Un premier test a été fait sur le scan originel, celui sur lequel nous avons travaillé depuis le début.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=XSn4s1y-XT0 Visualisation des machines]&lt;br /&gt;
&lt;br /&gt;
On rencontre un problème quand le robot est exactement parallèle ou perpendiculaire à un mur. Après vérification dans le programme, il s'avère que la détection ne fonctionne pas pour ces cas. Ce bug est maintenant corrigé :&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=rKeqewpuLoQ Correction du bug]&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
La première étape consiste juste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;br /&gt;
&lt;br /&gt;
la matrice correspondant au changement (laser -&amp;gt; robot) est la suivante : &lt;br /&gt;
&lt;br /&gt;
 0   -1    0&lt;br /&gt;
 1    0  0.2&lt;br /&gt;
 0    0    1&lt;br /&gt;
&lt;br /&gt;
la matrice 2x2 en haut à gauche correspond à la rotation de 90°, et le vecteur (0, 0.2) correspond à la translation.&lt;br /&gt;
&lt;br /&gt;
Celle du changement (robot -&amp;gt; global) avec alpha angle mesuré par le gyroscope depuis la position initiale (angle 0) :&lt;br /&gt;
&lt;br /&gt;
 cos(alpha)   -sin(alpha)    posInit.x&lt;br /&gt;
 sin(alpha)    cos(alpha)    posInit.y&lt;br /&gt;
          0             0            1&lt;br /&gt;
&lt;br /&gt;
l'étape suivante est de vérifier si les machines vues par le laser sont bien des machines, c'est-à-dire si les positions mesurées à partir des données lasers correspond aux zones occupées par des machines envoyées par la Referee Box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Grid Map====&lt;br /&gt;
&lt;br /&gt;
L'autre objectif de cette semaine a été de coder le noeud qui génère la map. La map est générée sous forme d'OccupancyGrid. Ce type est constitué d'un seul vecteur dont la première case correspond à la case en bas à gauche de la map. D'autres paramètres sont réglable comme l'origine et la taille.&lt;br /&gt;
&lt;br /&gt;
Pour la taille on choisit de diviser la map en case de 10 cm et l'origine choisie est le x du centre de la map et en y l'abscisse du premier mur (voir la map ci-dessous). Afin d'expliquer comment est constituée cette map, prenons le code et analysons les différentes fonctions ainsi que le main :&lt;br /&gt;
&lt;br /&gt;
Ce vecteur de Pose2D (x, y et theta (angle de la machine)) va permettre d'enregistrer la position des machines, c'est une variable global qui sera mise à jour avec le Callback :&lt;br /&gt;
&lt;br /&gt;
 std::vector&amp;lt;geometry_msgs::Pose2D&amp;gt; tab;&lt;br /&gt;
&lt;br /&gt;
*Récupération des machines envoyées par le noeud du SLAM (sur le topic /landmarks):&lt;br /&gt;
&lt;br /&gt;
 void Poses_Machine_Callback(const deplacement_msg::LandmarksConstPtr &amp;amp;machines)&lt;br /&gt;
 {&lt;br /&gt;
          tab=machines-&amp;gt;landmarks;&lt;br /&gt;
          for (int i=0; i&amp;lt;tab.size(); i++)&lt;br /&gt;
          {&lt;br /&gt;
     	     tab[i].x = tab[i].x*1000;&lt;br /&gt;
     	     tab[i].y = tab[i].y*1000;&lt;br /&gt;
 	  }&lt;br /&gt;
    &lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
*Création d'une map vide de taille 14m sur 8m. Chaque case est initialisée à une valeur nulle, on remplit également les autres paramètres de OccupancyGrid:&lt;br /&gt;
(On rappelle que la technique utilisée est un vecteur qui représente chaque case auxquelles il associe une probabilité 100 c'est un point interdit et 0 quand c'est un point sans danger pour le passage du robot)&lt;br /&gt;
&lt;br /&gt;
 void Create_Empty_Map(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      Map.info.origin.position.x=-7000;&lt;br /&gt;
      Map.info.origin.position.y=-1000;&lt;br /&gt;
      Map.info.origin.position.z=0;&lt;br /&gt;
      Map.info.origin.orientation.x=0;&lt;br /&gt;
      Map.info.origin.orientation.y=0;&lt;br /&gt;
      Map.info.origin.orientation.z=0;&lt;br /&gt;
      Map.info.origin.orientation.w=1;&lt;br /&gt;
      Map.info.map_load_time=ros::Time::now();&lt;br /&gt;
      Map.info.resolution=100;&lt;br /&gt;
      Map.info.width=140;&lt;br /&gt;
      Map.info.height=80;&lt;br /&gt;
      Map.data.assign(Map.info.width*Map.info.height, 0);                   //map vide&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
*Construction des points fixes de la map donc les murs (probabilité 100) et les zones à risques (probabilité 50):&lt;br /&gt;
&lt;br /&gt;
 void Set_Wall(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
    for (int i=0;i&amp;lt;80;i++)&lt;br /&gt;
    {&lt;br /&gt;
       for (int j=0;j&amp;lt;140;j++)&lt;br /&gt;
       {&lt;br /&gt;
          if ((i&amp;lt;13)||(i&amp;gt;67))) Map.data[j+i*140]=100;&lt;br /&gt;
          if ((j&amp;lt;13)||(j&amp;gt;127)) Map.data[j+i*140]=100;&lt;br /&gt;
       }&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Nous ne mettons pas tout le code de cette fonction étant donné qu'il est long et répétitif puisque c'est le remplissage des données connues, donc en &amp;quot;dur&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Calcul des positions machines: &lt;br /&gt;
&lt;br /&gt;
Lorsqu'on reçoit une position machine, c'est en fait son centre et son orientation par rapport à x que l'on reçoit. Etant donné que les machines doivent être des rectangles de 110cm sur 75cm (réellement 70 x 35 mais on compte la moitié du robot en plus par sécurité), on décide d'abord de déterminer un des coins du rectangle et plus précisément le coin en bas à droite de ce dernier:&lt;br /&gt;
&lt;br /&gt;
 void Get_One_Point_Of_The_Rectangle(float x, float &amp;amp;xA, float y, float &amp;amp;yA, float theta, float largeur, float longueur)&lt;br /&gt;
 {&lt;br /&gt;
      float x1,y1;&lt;br /&gt;
      x1 = x - cos(theta)*longueur;&lt;br /&gt;
      y1 = y - sin(theta)*longueur; &lt;br /&gt;
      xA = x1 + sin(M_PI_2-theta)*largeur;&lt;br /&gt;
      yA = y1 - cos(M_PI_2-theta)*largeur;&lt;br /&gt;
  &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
*Remplissage des positions sur la map :&lt;br /&gt;
&lt;br /&gt;
On met alors tous les points de ce rectangle à une probabilité 100 dans le vecteur Map. Pour les calculs on différencie le cas ou l'angle de la machine est entre 0 et pi/2 et le cas où il est entre pi/2 et pi. L'algorithme est le suivant : &lt;br /&gt;
&lt;br /&gt;
 A partir du coin, on incrémente x et y de sorte à longer le grand coté et de remplir chaque case (incrémentation de 5 cm).&lt;br /&gt;
 Une fois arrivé au bout, on incrémente x et y de 5cm sur la largeur à partir du coin et on recommence l'opération précédente.&lt;br /&gt;
 Ceci jusqu'à remplir le complètement le rectangle.&lt;br /&gt;
&lt;br /&gt;
Afin d'établir les probabilités correspondantes aux cases de ce rectangle, nous utilisons la fonctions floor() pour &amp;quot;convertir&amp;quot; nos flottants en entier et accéder à la case correspondante. On notera aussi que la case 1470 correspond à l'origine de notre map.&lt;br /&gt;
&lt;br /&gt;
 void Set_Machines_In_Map(float rank, float theta, float xA, float yA, nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      float x=xA;&lt;br /&gt;
      float y=yA;&lt;br /&gt;
      if (theta&amp;lt;=M_PI_2)&lt;br /&gt;
      {&lt;br /&gt;
            for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
            {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++) &lt;br /&gt;
                  {&lt;br /&gt;
                      Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                      x = x + cos(theta)*50;&lt;br /&gt;
                      y = y + sin(theta)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(M_PI_2-theta)*50;&lt;br /&gt;
                  y = yA + j*sin(M_PI_2-theta)*50;&lt;br /&gt;
            }	&lt;br /&gt;
       }&lt;br /&gt;
       if (theta&amp;gt;M_PI_2)&lt;br /&gt;
       {&lt;br /&gt;
             for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
             {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++)&lt;br /&gt;
                  {&lt;br /&gt;
                        Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                        x = x - sin(theta-M_PI_2)*50;&lt;br /&gt;
                        y = y + cos(theta-M_PI_2)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(theta-M_PI_2)*50;&lt;br /&gt;
                  y = yA - j*sin(theta-M_PI_2)*50;&lt;br /&gt;
              }	&lt;br /&gt;
        }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Ci dessous on a les mains, avec les différentes fonctions appelées et la syntaxe particulière à ROS. &lt;br /&gt;
&lt;br /&gt;
*Noeud général pour le traitement et le remplissage de la map :   &lt;br /&gt;
                 &lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
     ros::init(argc, argv, &amp;quot;server&amp;quot;);&lt;br /&gt;
     ros::NodeHandle n;&lt;br /&gt;
     ros::Subscriber sub_poses_machine    = n.subscribe(&amp;quot;/machines&amp;quot;, 1000, Poses_Machine_Callback);   // Récupération des machines&lt;br /&gt;
     ros::Publisher Map_Pub = n.advertise&amp;lt;nav_msgs::OccupancyGrid&amp;gt;(&amp;quot;/map&amp;quot;, 1000);                     // Préparation de la publication de la map&lt;br /&gt;
     ROS_INFO(&amp;quot;Ready to Generate the Map&amp;quot;);&lt;br /&gt;
     float xA,yA;&lt;br /&gt;
     ros::Rate loop_rate(1);&lt;br /&gt;
     while(ros::ok())&lt;br /&gt;
     {&lt;br /&gt;
        nav_msgs::OccupancyGrid Map;&lt;br /&gt;
        Create_Empty_Map(Map);&lt;br /&gt;
        Set_Wall(Map);&lt;br /&gt;
        for (int z=0;z&amp;lt;tab.size();z++)&lt;br /&gt;
        {&lt;br /&gt;
           Get_One_Point_Of_The_Rectangle(tab[z].x, xA, tab[z].y, yA, tab[z].theta, 275, 450);&lt;br /&gt;
 	   Set_Machines_In_Map(100, tab[z].theta, xA, yA, Map);&lt;br /&gt;
        }&lt;br /&gt;
        Map_Pub.publish(Map);                                                                   // publication de la map&lt;br /&gt;
        ros::spinOnce();&lt;br /&gt;
        loop_rate.sleep();&lt;br /&gt;
     }&lt;br /&gt;
     return 0;&lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Noeud test qui publie 2 positions de machines : &lt;br /&gt;
&lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
    ros::init(argc, argv, &amp;quot;test&amp;quot;);&lt;br /&gt;
    ros::NodeHandle n;&lt;br /&gt;
    ros::Publisher Pose_Machines_Pub = n.advertise&amp;lt;deplacement_msg::Landmarks&amp;gt;(&amp;quot;/machines&amp;quot;, 1000);&lt;br /&gt;
    ROS_INFO(&amp;quot;Ready to send poses machines&amp;quot;);&lt;br /&gt;
    int xA,yA;&lt;br /&gt;
    ros::Rate loop_rate(1);&lt;br /&gt;
    while(ros::ok())&lt;br /&gt;
    {&lt;br /&gt;
       deplacement_msg::Landmarks machines_msgs;&lt;br /&gt;
       geometry_msgs::Pose2D tab;&lt;br /&gt;
       tab.x=-2;&lt;br /&gt;
       tab.y=2;&lt;br /&gt;
       tab.theta=0;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       tab.x=5;&lt;br /&gt;
       tab.y=4;&lt;br /&gt;
       tab.theta=2.5;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       Pose_Machines_Pub.publish(machines_msgs);&lt;br /&gt;
       ros::spinOnce();&lt;br /&gt;
       loop_rate.sleep();&lt;br /&gt;
    }&lt;br /&gt;
    return 0;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On visualise le résultat grâce au logiciel RVIZ qui peut lire les topics publiés et donc le topic /map :&lt;br /&gt;
&lt;br /&gt;
===Semaine 9===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
l'objectif de cette semaine sera de coder toutes les fonctions nécessaires à l'implémentation finale du [http://fr.wikipedia.org/wiki/Filtre_de_Kalman#Filtre_de_Kalman_.C3.A9tendu filtre de Kalman étendu] :&lt;br /&gt;
&lt;br /&gt;
*initialisations des différents éléments&lt;br /&gt;
*étape de prédiction&lt;br /&gt;
*étape de mise à jour&lt;br /&gt;
*publication des positions machines et du robot dans le repère global via un topic ROS&lt;br /&gt;
&lt;br /&gt;
Le schéma ci-dessous nous montre les deux étapes du filtre de Kalman :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Kalman.png | center]]&lt;br /&gt;
&lt;br /&gt;
le code pour la partie ''prédiction'' :&lt;br /&gt;
&lt;br /&gt;
 //on ressort la position du robot pour l'état n+1&lt;br /&gt;
 //les paramètres sont le vecteurs où on a la position du robot à l'état n, la matrice P, les commandes en vitesses et le temps à l'état n&lt;br /&gt;
 Vector3d prediction(VectorXd xMean, MatrixXd &amp;amp;P, geometry_msgs::Pose2D cmdVel, ros::Time &amp;amp;temps){&lt;br /&gt;
   ros::Duration duree = ros::Time::now() - temps;&lt;br /&gt;
   double periode = duree.toSec();&amp;lt;br&amp;gt;&lt;br /&gt;
   Vector3d cmdVelVect = Pose2DToVector(cmdVel);&lt;br /&gt;
   //le xMean.topLeftCorner(3,1) correspond à la position du robot&lt;br /&gt;
   Vector3d xPredicted = xMean.topLeftCorner(3,1) + periode*cmdVelVect;&amp;lt;br&amp;gt;&lt;br /&gt;
   MatrixXd Fx;&lt;br /&gt;
   Fx = MatrixXd::Identity(P.rows(), P.cols());&lt;br /&gt;
   Fx(0,0) = xPredicted(0);&lt;br /&gt;
   Fx(1,1) = xPredicted(1);&lt;br /&gt;
   Fx(2,2) = xPredicted(2);&amp;lt;br&amp;gt;&lt;br /&gt;
   //mise à jour de P&lt;br /&gt;
   P = Fx*P*(Fx.transpose());&amp;lt;br&amp;gt;&lt;br /&gt;
   //mise à jour du temps&lt;br /&gt;
   temps = ros::Time::now();&amp;lt;br&amp;gt;&lt;br /&gt;
   return xPredicted;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
le code pour la partie ''correction'' :&lt;br /&gt;
&lt;br /&gt;
 void correction(VectorXd &amp;amp;xMean, MatrixXd &amp;amp;P, Vector3d xPredicted, geometry_msgs::Pose2D m){&lt;br /&gt;
   int taille = P.rows();&lt;br /&gt;
   //on vérifie si la machine est présente ou pas dans le vecteur d'état&lt;br /&gt;
   int i = checkStateVector(xMean, m);&amp;lt;br&amp;gt;&lt;br /&gt;
   if (i != 0){&lt;br /&gt;
     //calcul de H&lt;br /&gt;
     MatrixXd H(3, taille);&lt;br /&gt;
     H = buildH(taille, i);&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul de Pm&lt;br /&gt;
     MatrixXd Pm(taille, taille);&lt;br /&gt;
     Pm = buildPm(P, i);&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul de Z&lt;br /&gt;
     MatrixXd Z(taille, taille);&lt;br /&gt;
     Z = H*Pm*(H.transpose());	&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul du gain de Kalman&lt;br /&gt;
     MatrixXd K(taille, taille);&lt;br /&gt;
     K = P*(H.transpose())*(Z.inverse());&amp;lt;br&amp;gt;&lt;br /&gt;
     //mise à jour du vecteur xMean&lt;br /&gt;
     xMean = xMean + K*(xMean.block(xMean.rows()-3,0,3,1) - xPredicted);&amp;lt;br&amp;gt;&lt;br /&gt;
     //mise à jour de la matrice P&lt;br /&gt;
     P = P - K*Z*(K.transpose());&lt;br /&gt;
   }&lt;br /&gt;
   else {&lt;br /&gt;
     addMachine(m, xMean, P);&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Pour notre cas, on doit ajouter des nouvelles machines, alors que pour un EKF classique on observe juste des machines déjà répertoriées. Il faut donc une fonction qui permet d'ajouter une machine dans le vecteur d'état. La voilà :&lt;br /&gt;
&lt;br /&gt;
 void addMachine(geometry_msgs::Pose2D machine, VectorXd &amp;amp;xMean, MatrixXd &amp;amp;P){&lt;br /&gt;
   //on redimensionne xMean et P pour accueillir la nouvelle machines&lt;br /&gt;
   xMean.conservativeResize(xMean.rows() + 3);&lt;br /&gt;
   P.conservativeResize(P.rows()+3,P.cols()+3);&amp;lt;br&amp;gt;&lt;br /&gt;
   //on remplit avec les coordonnées de la nouvelle machine&lt;br /&gt;
   xMean(xMean.rows()-3) = machine.x;&lt;br /&gt;
   xMean(xMean.rows()-2) = machine.y;&lt;br /&gt;
   xMean(xMean.rows()-1) = machine.theta;&amp;lt;br&amp;gt;&lt;br /&gt;
   //calcul de tous les PLi&lt;br /&gt;
   //initialisation des PLi à 0&lt;br /&gt;
   P.block(P.rows() - 3, 0, 3, P.cols()).setZero();&lt;br /&gt;
   P.block(0, P.cols() - 3, P.rows(), 3).setZero();&amp;lt;br&amp;gt;&lt;br /&gt;
   for (int j = 0; j &amp;lt; xMean.rows(); j = j + 3){&lt;br /&gt;
     //position de la nouvelle machines par rapport au robot et à toutes les autres&lt;br /&gt;
     double x 	 = xMean(xMean.rows()-3) - xMean(j  );&lt;br /&gt;
     double y 	 = xMean(xMean.rows()-2) - xMean(j+1);&lt;br /&gt;
     double theta = xMean(xMean.rows()-1) - xMean(j+2);&amp;lt;br&amp;gt;&lt;br /&gt;
     P(P.rows()-3, j  ) = x;&lt;br /&gt;
     P(P.rows()-2, j+1) = y;&lt;br /&gt;
     P(P.rows()-1, j+2) = theta;&amp;lt;br&amp;gt;&lt;br /&gt;
     P(j  , P.rows()-3) = x;&lt;br /&gt;
     P(j+1, P.rows()-2) = y;&lt;br /&gt;
     P(j+2, P.rows()-1) = theta;&amp;lt;br&amp;gt;&lt;br /&gt;
     P(j  , j  ) = xMean(j  ) - xMean(0);&lt;br /&gt;
     P(j+1, j+1) = xMean(j+1) - xMean(1);&lt;br /&gt;
     P(j+2, j+2) = xMean(j+2) - xMean(2);&amp;lt;br&amp;gt;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 10===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
La partie '''prédiction''' du filtre marche parfaitement, quelques corrections ont dues être faites au niveau de la commande vitesse. En effet, Nous avions oublié de la transposer dans le repère global. Pour la partie '''correction''', nous rencontrons un problème de divergence du filtre, qui est probablement due à une mauvaise initialisation. En effet, nous utilisons des enregistrements faits sur notre piste (1/4 de la vraie) avec des initialisations correspondant à la piste originale. Le filtre ne peut donc pas converger car la position de départ est fausse.&lt;br /&gt;
&lt;br /&gt;
===Semaine 11===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
Des corrections sont en cours de validation. Nous essayons de définir une initialisation avec les paramètres de notre piste, ce qui n'est pas évident. Les programmes permettant d'extraire les positions machines du filtres ont été réalisé, ainsi qu'un launch pour pouvoir lancer tous les noeuds de la localisation.&lt;br /&gt;
&lt;br /&gt;
===Semaine 12===&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - mise en place====&lt;br /&gt;
&lt;br /&gt;
Pendant les deux jours de mise en place, nous avons continué à travailler sur la localisation, qui est une partie critique et nécessaire à notre participation. Le filtre en lui même est fonctionnel et permet de corriger la position du robot, ainsi que celle des machines. Cependant, et ce n'est pas un petit &amp;quot;cependant&amp;quot;... Le fait que l'on ajoute des machines en cours de jeu perturbe fortement notre algorithme.&lt;br /&gt;
&lt;br /&gt;
En effet, le filtre de Kalman est optimal si la position des repères est connu, or, un ajout de machine crée un recalage forcé, et si l'on voit plusieurs machines... C'est la '''catastrophe'''. L'ajout de machines est une partie sensible qui nécessite des tests sur la position mesurée, avec un changement de repère à partir de la position du robot, si celle ci dérive, tout dérive. Chaque machine initialisée à la mauvaise position, ou chaque élément détecté comme machine mais n'en étant pas une (faux positif) perturbe le recalage.&lt;br /&gt;
&lt;br /&gt;
De nombreux tests ayant été fait sur la piste officiel avec différentes configurations nous ont permis de vérifier que l'odométrie mesurée ne dérivait que très peu. Il a donc été décidé de n'utiliser que l'odométrie et le scan laser pour la partie '''exploration'''. En effet, chaque machine mesurée est envoyée à un noeud ROS qui va créer une carte et la compléter au fur et à mesure de la partie. Le robot est donc repéré rien qu'avec son odométrie. Le fait que la phase d'exploration (découverte du terrain) ne dure que '''4 minutes''' nous a convaincu pour n'utiliser que cette mesure.&lt;br /&gt;
&lt;br /&gt;
De plus, la carte créée sera utilisée pour la phase suivante, la phase de '''production'''. Cette phase consiste, au niveau de la localisation, à se repérer sur la piste et atteindre la machine demandée par l'exécuteur de tâches. Pour cette phase qui dure '''15 minutes''', l'utilisation du filtre est nécessaire. Donc, avec les coordonnées des machines mesurées pendant la première phase, on peut créer le vecteur d'état et la matrice faisant le lien entre les machines. De là, la taille de ces deux éléments ne variant plus, on peut corriger uniquement la position du robot et le filtre sera efficace.&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - 1er jour====&lt;br /&gt;
&lt;br /&gt;
Durant ce premier jour, nous avons commencé à ''merger'' nos branches respectives pour pouvoir faire tourner tous nos programmes. Cette phase est laborieuse et nous a pris du temps. De toute façon, toutes les équipes ne sont pas prêtes, les organisateurs non plus. La '''Referee Box''' n'est pas fonctionnel pour la phase de production, ce qui veut dire que nous nous concentrons actuellement sur l'exploration. Les matchs joués aujourd'hui ne nous rapporte donc pas de points. Les tests nous ont permis de valider individuellement chacun des algos, il ne reste &amp;quot;plus qu'à&amp;quot; rejoindre le tout.&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - 2eme jour====&lt;br /&gt;
&lt;br /&gt;
Niveau '''localisation''', la navigation à l'odométrie et la détection de machine sont fonctionnelles. Cependant, le moyennage fait sur les positions machines (on moyenne toutes les positions trouvées appartenant à une même machine pour n'avoir qu'un seul point) fait que le point correspondant peut être perturbé par des mesures aberrantes. C'est le cas lorsque le robot se déplace à vitesse élevée.&lt;br /&gt;
&lt;br /&gt;
La détection de machine a été améliorée afin de ne rajouter QUE les machines, et pas les murs de la même taille. Nous allons donc retester le '''filtre de Kalman Etendu''' avec cette amélioration. Cependant, ce ne sera fait qu'après la compétition, puisque d'autres problèmes ont nécessité la présence de l'équipe sur certaines parties sensibles du déplacement.&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - 3eme et dernier jour====&lt;br /&gt;
&lt;br /&gt;
L'architecture choisie pour la localisation est la suivante :&lt;br /&gt;
*Navigation à l'odométrie&lt;br /&gt;
*Détection de machines et moyennage&lt;br /&gt;
*Quand on a vu toutes nos machines, on utilise la symétrie pour compléter les machines restantes&lt;br /&gt;
*Navigation et Localisation avec l'EKF (correction des positions machines et du robot)&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=20495</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=20495"/>
				<updated>2015-04-24T20:21:39Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Compétition Open German */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - vidéo====&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les résultats de la détection des machines nous avons utiliser l'interface graphique disponible avec ROS, RVIZ. Nous visualisons alors le scan laser (points blancs), le résultat de la détection de segments (en rouge) et les positions des machines trouvées (en vert). Un premier test a été fait sur le scan originel, celui sur lequel nous avons travaillé depuis le début.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=XSn4s1y-XT0 Visualisation des machines]&lt;br /&gt;
&lt;br /&gt;
On rencontre un problème quand le robot est exactement parallèle ou perpendiculaire à un mur. Après vérification dans le programme, il s'avère que la détection ne fonctionne pas pour ces cas. Ce bug est maintenant corrigé :&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=rKeqewpuLoQ Correction du bug]&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
La première étape consiste juste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;br /&gt;
&lt;br /&gt;
la matrice correspondant au changement (laser -&amp;gt; robot) est la suivante : &lt;br /&gt;
&lt;br /&gt;
 0   -1    0&lt;br /&gt;
 1    0  0.2&lt;br /&gt;
 0    0    1&lt;br /&gt;
&lt;br /&gt;
la matrice 2x2 en haut à gauche correspond à la rotation de 90°, et le vecteur (0, 0.2) correspond à la translation.&lt;br /&gt;
&lt;br /&gt;
Celle du changement (robot -&amp;gt; global) avec alpha angle mesuré par le gyroscope depuis la position initiale (angle 0) :&lt;br /&gt;
&lt;br /&gt;
 cos(alpha)   -sin(alpha)    posInit.x&lt;br /&gt;
 sin(alpha)    cos(alpha)    posInit.y&lt;br /&gt;
          0             0            1&lt;br /&gt;
&lt;br /&gt;
l'étape suivante est de vérifier si les machines vues par le laser sont bien des machines, c'est-à-dire si les positions mesurées à partir des données lasers correspond aux zones occupées par des machines envoyées par la Referee Box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Grid Map====&lt;br /&gt;
&lt;br /&gt;
L'autre objectif de cette semaine a été de coder le noeud qui génère la map. La map est générée sous forme d'OccupancyGrid. Ce type est constitué d'un seul vecteur dont la première case correspond à la case en bas à gauche de la map. D'autres paramètres sont réglable comme l'origine et la taille.&lt;br /&gt;
&lt;br /&gt;
Pour la taille on choisit de diviser la map en case de 10 cm et l'origine choisie est le x du centre de la map et en y l'abscisse du premier mur (voir la map ci-dessous). Afin d'expliquer comment est constituée cette map, prenons le code et analysons les différentes fonctions ainsi que le main :&lt;br /&gt;
&lt;br /&gt;
Ce vecteur de Pose2D (x, y et theta (angle de la machine)) va permettre d'enregistrer la position des machines, c'est une variable global qui sera mise à jour avec le Callback :&lt;br /&gt;
&lt;br /&gt;
 std::vector&amp;lt;geometry_msgs::Pose2D&amp;gt; tab;&lt;br /&gt;
&lt;br /&gt;
*Récupération des machines envoyées par le noeud du SLAM (sur le topic /landmarks):&lt;br /&gt;
&lt;br /&gt;
 void Poses_Machine_Callback(const deplacement_msg::LandmarksConstPtr &amp;amp;machines)&lt;br /&gt;
 {&lt;br /&gt;
          tab=machines-&amp;gt;landmarks;&lt;br /&gt;
          for (int i=0; i&amp;lt;tab.size(); i++)&lt;br /&gt;
          {&lt;br /&gt;
     	     tab[i].x = tab[i].x*1000;&lt;br /&gt;
     	     tab[i].y = tab[i].y*1000;&lt;br /&gt;
 	  }&lt;br /&gt;
    &lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
*Création d'une map vide de taille 14m sur 8m. Chaque case est initialisée à une valeur nulle, on remplit également les autres paramètres de OccupancyGrid:&lt;br /&gt;
(On rappelle que la technique utilisée est un vecteur qui représente chaque case auxquelles il associe une probabilité 100 c'est un point interdit et 0 quand c'est un point sans danger pour le passage du robot)&lt;br /&gt;
&lt;br /&gt;
 void Create_Empty_Map(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      Map.info.origin.position.x=-7000;&lt;br /&gt;
      Map.info.origin.position.y=-1000;&lt;br /&gt;
      Map.info.origin.position.z=0;&lt;br /&gt;
      Map.info.origin.orientation.x=0;&lt;br /&gt;
      Map.info.origin.orientation.y=0;&lt;br /&gt;
      Map.info.origin.orientation.z=0;&lt;br /&gt;
      Map.info.origin.orientation.w=1;&lt;br /&gt;
      Map.info.map_load_time=ros::Time::now();&lt;br /&gt;
      Map.info.resolution=100;&lt;br /&gt;
      Map.info.width=140;&lt;br /&gt;
      Map.info.height=80;&lt;br /&gt;
      Map.data.assign(Map.info.width*Map.info.height, 0);                   //map vide&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
*Construction des points fixes de la map donc les murs (probabilité 100) et les zones à risques (probabilité 50):&lt;br /&gt;
&lt;br /&gt;
 void Set_Wall(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
    for (int i=0;i&amp;lt;80;i++)&lt;br /&gt;
    {&lt;br /&gt;
       for (int j=0;j&amp;lt;140;j++)&lt;br /&gt;
       {&lt;br /&gt;
          if ((i&amp;lt;13)||(i&amp;gt;67))) Map.data[j+i*140]=100;&lt;br /&gt;
          if ((j&amp;lt;13)||(j&amp;gt;127)) Map.data[j+i*140]=100;&lt;br /&gt;
       }&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Nous ne mettons pas tout le code de cette fonction étant donné qu'il est long et répétitif puisque c'est le remplissage des données connues, donc en &amp;quot;dur&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Calcul des positions machines: &lt;br /&gt;
&lt;br /&gt;
Lorsqu'on reçoit une position machine, c'est en fait son centre et son orientation par rapport à x que l'on reçoit. Etant donné que les machines doivent être des rectangles de 110cm sur 75cm (réellement 70 x 35 mais on compte la moitié du robot en plus par sécurité), on décide d'abord de déterminer un des coins du rectangle et plus précisément le coin en bas à droite de ce dernier:&lt;br /&gt;
&lt;br /&gt;
 void Get_One_Point_Of_The_Rectangle(float x, float &amp;amp;xA, float y, float &amp;amp;yA, float theta, float largeur, float longueur)&lt;br /&gt;
 {&lt;br /&gt;
      float x1,y1;&lt;br /&gt;
      x1 = x - cos(theta)*longueur;&lt;br /&gt;
      y1 = y - sin(theta)*longueur; &lt;br /&gt;
      xA = x1 + sin(M_PI_2-theta)*largeur;&lt;br /&gt;
      yA = y1 - cos(M_PI_2-theta)*largeur;&lt;br /&gt;
  &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
*Remplissage des positions sur la map :&lt;br /&gt;
&lt;br /&gt;
On met alors tous les points de ce rectangle à une probabilité 100 dans le vecteur Map. Pour les calculs on différencie le cas ou l'angle de la machine est entre 0 et pi/2 et le cas où il est entre pi/2 et pi. L'algorithme est le suivant : &lt;br /&gt;
&lt;br /&gt;
 A partir du coin, on incrémente x et y de sorte à longer le grand coté et de remplir chaque case (incrémentation de 5 cm).&lt;br /&gt;
 Une fois arrivé au bout, on incrémente x et y de 5cm sur la largeur à partir du coin et on recommence l'opération précédente.&lt;br /&gt;
 Ceci jusqu'à remplir le complètement le rectangle.&lt;br /&gt;
&lt;br /&gt;
Afin d'établir les probabilités correspondantes aux cases de ce rectangle, nous utilisons la fonctions floor() pour &amp;quot;convertir&amp;quot; nos flottants en entier et accéder à la case correspondante. On notera aussi que la case 1470 correspond à l'origine de notre map.&lt;br /&gt;
&lt;br /&gt;
 void Set_Machines_In_Map(float rank, float theta, float xA, float yA, nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      float x=xA;&lt;br /&gt;
      float y=yA;&lt;br /&gt;
      if (theta&amp;lt;=M_PI_2)&lt;br /&gt;
      {&lt;br /&gt;
            for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
            {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++) &lt;br /&gt;
                  {&lt;br /&gt;
                      Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                      x = x + cos(theta)*50;&lt;br /&gt;
                      y = y + sin(theta)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(M_PI_2-theta)*50;&lt;br /&gt;
                  y = yA + j*sin(M_PI_2-theta)*50;&lt;br /&gt;
            }	&lt;br /&gt;
       }&lt;br /&gt;
       if (theta&amp;gt;M_PI_2)&lt;br /&gt;
       {&lt;br /&gt;
             for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
             {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++)&lt;br /&gt;
                  {&lt;br /&gt;
                        Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                        x = x - sin(theta-M_PI_2)*50;&lt;br /&gt;
                        y = y + cos(theta-M_PI_2)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(theta-M_PI_2)*50;&lt;br /&gt;
                  y = yA - j*sin(theta-M_PI_2)*50;&lt;br /&gt;
              }	&lt;br /&gt;
        }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Ci dessous on a les mains, avec les différentes fonctions appelées et la syntaxe particulière à ROS. &lt;br /&gt;
&lt;br /&gt;
*Noeud général pour le traitement et le remplissage de la map :   &lt;br /&gt;
                 &lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
     ros::init(argc, argv, &amp;quot;server&amp;quot;);&lt;br /&gt;
     ros::NodeHandle n;&lt;br /&gt;
     ros::Subscriber sub_poses_machine    = n.subscribe(&amp;quot;/machines&amp;quot;, 1000, Poses_Machine_Callback);   // Récupération des machines&lt;br /&gt;
     ros::Publisher Map_Pub = n.advertise&amp;lt;nav_msgs::OccupancyGrid&amp;gt;(&amp;quot;/map&amp;quot;, 1000);                     // Préparation de la publication de la map&lt;br /&gt;
     ROS_INFO(&amp;quot;Ready to Generate the Map&amp;quot;);&lt;br /&gt;
     float xA,yA;&lt;br /&gt;
     ros::Rate loop_rate(1);&lt;br /&gt;
     while(ros::ok())&lt;br /&gt;
     {&lt;br /&gt;
        nav_msgs::OccupancyGrid Map;&lt;br /&gt;
        Create_Empty_Map(Map);&lt;br /&gt;
        Set_Wall(Map);&lt;br /&gt;
        for (int z=0;z&amp;lt;tab.size();z++)&lt;br /&gt;
        {&lt;br /&gt;
           Get_One_Point_Of_The_Rectangle(tab[z].x, xA, tab[z].y, yA, tab[z].theta, 275, 450);&lt;br /&gt;
 	   Set_Machines_In_Map(100, tab[z].theta, xA, yA, Map);&lt;br /&gt;
        }&lt;br /&gt;
        Map_Pub.publish(Map);                                                                   // publication de la map&lt;br /&gt;
        ros::spinOnce();&lt;br /&gt;
        loop_rate.sleep();&lt;br /&gt;
     }&lt;br /&gt;
     return 0;&lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Noeud test qui publie 2 positions de machines : &lt;br /&gt;
&lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
    ros::init(argc, argv, &amp;quot;test&amp;quot;);&lt;br /&gt;
    ros::NodeHandle n;&lt;br /&gt;
    ros::Publisher Pose_Machines_Pub = n.advertise&amp;lt;deplacement_msg::Landmarks&amp;gt;(&amp;quot;/machines&amp;quot;, 1000);&lt;br /&gt;
    ROS_INFO(&amp;quot;Ready to send poses machines&amp;quot;);&lt;br /&gt;
    int xA,yA;&lt;br /&gt;
    ros::Rate loop_rate(1);&lt;br /&gt;
    while(ros::ok())&lt;br /&gt;
    {&lt;br /&gt;
       deplacement_msg::Landmarks machines_msgs;&lt;br /&gt;
       geometry_msgs::Pose2D tab;&lt;br /&gt;
       tab.x=-2;&lt;br /&gt;
       tab.y=2;&lt;br /&gt;
       tab.theta=0;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       tab.x=5;&lt;br /&gt;
       tab.y=4;&lt;br /&gt;
       tab.theta=2.5;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       Pose_Machines_Pub.publish(machines_msgs);&lt;br /&gt;
       ros::spinOnce();&lt;br /&gt;
       loop_rate.sleep();&lt;br /&gt;
    }&lt;br /&gt;
    return 0;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On visualise le résultat grâce au logiciel RVIZ qui peut lire les topics publiés et donc le topic /map :&lt;br /&gt;
&lt;br /&gt;
===Semaine 9===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
l'objectif de cette semaine sera de coder toutes les fonctions nécessaires à l'implémentation finale du [http://fr.wikipedia.org/wiki/Filtre_de_Kalman#Filtre_de_Kalman_.C3.A9tendu filtre de Kalman étendu] :&lt;br /&gt;
&lt;br /&gt;
*initialisations des différents éléments&lt;br /&gt;
*étape de prédiction&lt;br /&gt;
*étape de mise à jour&lt;br /&gt;
*publication des positions machines et du robot dans le repère global via un topic ROS&lt;br /&gt;
&lt;br /&gt;
Le schéma ci-dessous nous montre les deux étapes du filtre de Kalman :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Kalman.png | center]]&lt;br /&gt;
&lt;br /&gt;
le code pour la partie ''prédiction'' :&lt;br /&gt;
&lt;br /&gt;
 //on ressort la position du robot pour l'état n+1&lt;br /&gt;
 //les paramètres sont le vecteurs où on a la position du robot à l'état n, la matrice P, les commandes en vitesses et le temps à l'état n&lt;br /&gt;
 Vector3d prediction(VectorXd xMean, MatrixXd &amp;amp;P, geometry_msgs::Pose2D cmdVel, ros::Time &amp;amp;temps){&lt;br /&gt;
   ros::Duration duree = ros::Time::now() - temps;&lt;br /&gt;
   double periode = duree.toSec();&amp;lt;br&amp;gt;&lt;br /&gt;
   Vector3d cmdVelVect = Pose2DToVector(cmdVel);&lt;br /&gt;
   //le xMean.topLeftCorner(3,1) correspond à la position du robot&lt;br /&gt;
   Vector3d xPredicted = xMean.topLeftCorner(3,1) + periode*cmdVelVect;&amp;lt;br&amp;gt;&lt;br /&gt;
   MatrixXd Fx;&lt;br /&gt;
   Fx = MatrixXd::Identity(P.rows(), P.cols());&lt;br /&gt;
   Fx(0,0) = xPredicted(0);&lt;br /&gt;
   Fx(1,1) = xPredicted(1);&lt;br /&gt;
   Fx(2,2) = xPredicted(2);&amp;lt;br&amp;gt;&lt;br /&gt;
   //mise à jour de P&lt;br /&gt;
   P = Fx*P*(Fx.transpose());&amp;lt;br&amp;gt;&lt;br /&gt;
   //mise à jour du temps&lt;br /&gt;
   temps = ros::Time::now();&amp;lt;br&amp;gt;&lt;br /&gt;
   return xPredicted;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
le code pour la partie ''correction'' :&lt;br /&gt;
&lt;br /&gt;
 void correction(VectorXd &amp;amp;xMean, MatrixXd &amp;amp;P, Vector3d xPredicted, geometry_msgs::Pose2D m){&lt;br /&gt;
   int taille = P.rows();&lt;br /&gt;
   //on vérifie si la machine est présente ou pas dans le vecteur d'état&lt;br /&gt;
   int i = checkStateVector(xMean, m);&amp;lt;br&amp;gt;&lt;br /&gt;
   if (i != 0){&lt;br /&gt;
     //calcul de H&lt;br /&gt;
     MatrixXd H(3, taille);&lt;br /&gt;
     H = buildH(taille, i);&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul de Pm&lt;br /&gt;
     MatrixXd Pm(taille, taille);&lt;br /&gt;
     Pm = buildPm(P, i);&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul de Z&lt;br /&gt;
     MatrixXd Z(taille, taille);&lt;br /&gt;
     Z = H*Pm*(H.transpose());	&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul du gain de Kalman&lt;br /&gt;
     MatrixXd K(taille, taille);&lt;br /&gt;
     K = P*(H.transpose())*(Z.inverse());&amp;lt;br&amp;gt;&lt;br /&gt;
     //mise à jour du vecteur xMean&lt;br /&gt;
     xMean = xMean + K*(xMean.block(xMean.rows()-3,0,3,1) - xPredicted);&amp;lt;br&amp;gt;&lt;br /&gt;
     //mise à jour de la matrice P&lt;br /&gt;
     P = P - K*Z*(K.transpose());&lt;br /&gt;
   }&lt;br /&gt;
   else {&lt;br /&gt;
     addMachine(m, xMean, P);&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Pour notre cas, on doit ajouter des nouvelles machines, alors que pour un EKF classique on observe juste des machines déjà répertoriées. Il faut donc une fonction qui permet d'ajouter une machine dans le vecteur d'état. La voilà :&lt;br /&gt;
&lt;br /&gt;
 void addMachine(geometry_msgs::Pose2D machine, VectorXd &amp;amp;xMean, MatrixXd &amp;amp;P){&lt;br /&gt;
   //on redimensionne xMean et P pour accueillir la nouvelle machines&lt;br /&gt;
   xMean.conservativeResize(xMean.rows() + 3);&lt;br /&gt;
   P.conservativeResize(P.rows()+3,P.cols()+3);&amp;lt;br&amp;gt;&lt;br /&gt;
   //on remplit avec les coordonnées de la nouvelle machine&lt;br /&gt;
   xMean(xMean.rows()-3) = machine.x;&lt;br /&gt;
   xMean(xMean.rows()-2) = machine.y;&lt;br /&gt;
   xMean(xMean.rows()-1) = machine.theta;&amp;lt;br&amp;gt;&lt;br /&gt;
   //calcul de tous les PLi&lt;br /&gt;
   //initialisation des PLi à 0&lt;br /&gt;
   P.block(P.rows() - 3, 0, 3, P.cols()).setZero();&lt;br /&gt;
   P.block(0, P.cols() - 3, P.rows(), 3).setZero();&amp;lt;br&amp;gt;&lt;br /&gt;
   for (int j = 0; j &amp;lt; xMean.rows(); j = j + 3){&lt;br /&gt;
     //position de la nouvelle machines par rapport au robot et à toutes les autres&lt;br /&gt;
     double x 	 = xMean(xMean.rows()-3) - xMean(j  );&lt;br /&gt;
     double y 	 = xMean(xMean.rows()-2) - xMean(j+1);&lt;br /&gt;
     double theta = xMean(xMean.rows()-1) - xMean(j+2);&amp;lt;br&amp;gt;&lt;br /&gt;
     P(P.rows()-3, j  ) = x;&lt;br /&gt;
     P(P.rows()-2, j+1) = y;&lt;br /&gt;
     P(P.rows()-1, j+2) = theta;&amp;lt;br&amp;gt;&lt;br /&gt;
     P(j  , P.rows()-3) = x;&lt;br /&gt;
     P(j+1, P.rows()-2) = y;&lt;br /&gt;
     P(j+2, P.rows()-1) = theta;&amp;lt;br&amp;gt;&lt;br /&gt;
     P(j  , j  ) = xMean(j  ) - xMean(0);&lt;br /&gt;
     P(j+1, j+1) = xMean(j+1) - xMean(1);&lt;br /&gt;
     P(j+2, j+2) = xMean(j+2) - xMean(2);&amp;lt;br&amp;gt;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 10===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
La partie '''prédiction''' du filtre marche parfaitement, quelques corrections ont dues être faites au niveau de la commande vitesse. En effet, Nous avions oublié de la transposer dans le repère global. Pour la partie '''correction''', nous rencontrons un problème de divergence du filtre, qui est probablement due à une mauvaise initialisation. En effet, nous utilisons des enregistrements faits sur notre piste (1/4 de la vraie) avec des initialisations correspondant à la piste originale. Le filtre ne peut donc pas converger car la position de départ est fausse.&lt;br /&gt;
&lt;br /&gt;
===Semaine 11===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
Des corrections sont en cours de validation. Nous essayons de définir une initialisation avec les paramètres de notre piste, ce qui n'est pas évident. Les programmes permettant d'extraire les positions machines du filtres ont été réalisé, ainsi qu'un launch pour pouvoir lancer tous les noeuds de la localisation.&lt;br /&gt;
&lt;br /&gt;
===Semaine 12===&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - mise en place====&lt;br /&gt;
&lt;br /&gt;
Pendant les deux jours de mise en place, nous avons continué à travailler sur la localisation, qui est une partie critique et nécessaire à notre participation. Le filtre en lui même est fonctionnel et permet de corriger la position du robot, ainsi que celle des machines. Cependant, et ce n'est pas un petit &amp;quot;cependant&amp;quot;... Le fait que l'on ajoute des machines en cours de jeu perturbe fortement notre algorithme.&lt;br /&gt;
&lt;br /&gt;
En effet, le filtre de Kalman est optimal si la position des repères est connu, or, un ajout de machine crée un recalage forcé, et si l'on voit plusieurs machines... C'est la '''catastrophe'''. L'ajout de machines est une partie sensible qui nécessite des tests sur la position mesurée, avec un changement de repère à partir de la position du robot, si celle ci dérive, tout dérive. Chaque machine initialisée à la mauvaise position, ou chaque élément détecté comme machine mais n'en étant pas une (faux positif) perturbe le recalage.&lt;br /&gt;
&lt;br /&gt;
De nombreux tests ayant été fait sur la piste officiel avec différentes configurations nous ont permis de vérifier que l'odométrie mesurée ne dérivait que très peu. Il a donc été décidé de n'utiliser que l'odométrie et le scan laser pour la partie '''exploration'''. En effet, chaque machine mesurée est envoyée à un noeud ROS qui va créer une carte et la compléter au fur et à mesure de la partie. Le robot est donc repéré rien qu'avec son odométrie. Le fait que la phase d'exploration (découverte du terrain) ne dure que '''4 minutes''' nous a convaincu pour n'utiliser que cette mesure.&lt;br /&gt;
&lt;br /&gt;
De plus, la carte créée sera utilisée pour la phase suivante, la phase de '''production'''. Cette phase consiste, au niveau de la localisation, à se repérer sur la piste et atteindre la machine demandée par l'exécuteur de tâches. Pour cette phase qui dure '''15 minutes''', l'utilisation du filtre est nécessaire. Donc, avec les coordonnées des machines mesurées pendant la première phase, on peut créer le vecteur d'état et la matrice faisant le lien entre les machines. De là, la taille de ces deux éléments ne variant plus, on peut corriger uniquement la position du robot et le filtre sera efficace.&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German - 1er jour====&lt;br /&gt;
&lt;br /&gt;
Durant ce premier jour, nous avons commencé à ''merger'' nos branches respectives pour pouvoir faire tourner tous nos programmes. Cette phase est laborieuse et nous a pris du temps. De toute façon, toutes les équipes ne sont pas prêtes, les organisateurs non plus. La '''Referee Box''' n'est pas fonctionnel pour la phase de production, ce qui veut dire que nous nous concentrons actuellement sur l'exploration. Les matchs joués aujourd'hui ne nous rapporte donc pas de points. Les tests nous ont permis de valider individuellement chacun des algos, il ne reste &amp;quot;plus qu'à&amp;quot; rejoindre le tout.&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=20494</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=20494"/>
				<updated>2015-04-24T19:26:09Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Semaine 11 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - vidéo====&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les résultats de la détection des machines nous avons utiliser l'interface graphique disponible avec ROS, RVIZ. Nous visualisons alors le scan laser (points blancs), le résultat de la détection de segments (en rouge) et les positions des machines trouvées (en vert). Un premier test a été fait sur le scan originel, celui sur lequel nous avons travaillé depuis le début.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=XSn4s1y-XT0 Visualisation des machines]&lt;br /&gt;
&lt;br /&gt;
On rencontre un problème quand le robot est exactement parallèle ou perpendiculaire à un mur. Après vérification dans le programme, il s'avère que la détection ne fonctionne pas pour ces cas. Ce bug est maintenant corrigé :&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=rKeqewpuLoQ Correction du bug]&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
La première étape consiste juste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;br /&gt;
&lt;br /&gt;
la matrice correspondant au changement (laser -&amp;gt; robot) est la suivante : &lt;br /&gt;
&lt;br /&gt;
 0   -1    0&lt;br /&gt;
 1    0  0.2&lt;br /&gt;
 0    0    1&lt;br /&gt;
&lt;br /&gt;
la matrice 2x2 en haut à gauche correspond à la rotation de 90°, et le vecteur (0, 0.2) correspond à la translation.&lt;br /&gt;
&lt;br /&gt;
Celle du changement (robot -&amp;gt; global) avec alpha angle mesuré par le gyroscope depuis la position initiale (angle 0) :&lt;br /&gt;
&lt;br /&gt;
 cos(alpha)   -sin(alpha)    posInit.x&lt;br /&gt;
 sin(alpha)    cos(alpha)    posInit.y&lt;br /&gt;
          0             0            1&lt;br /&gt;
&lt;br /&gt;
l'étape suivante est de vérifier si les machines vues par le laser sont bien des machines, c'est-à-dire si les positions mesurées à partir des données lasers correspond aux zones occupées par des machines envoyées par la Referee Box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Grid Map====&lt;br /&gt;
&lt;br /&gt;
L'autre objectif de cette semaine a été de coder le noeud qui génère la map. La map est générée sous forme d'OccupancyGrid. Ce type est constitué d'un seul vecteur dont la première case correspond à la case en bas à gauche de la map. D'autres paramètres sont réglable comme l'origine et la taille.&lt;br /&gt;
&lt;br /&gt;
Pour la taille on choisit de diviser la map en case de 10 cm et l'origine choisie est le x du centre de la map et en y l'abscisse du premier mur (voir la map ci-dessous). Afin d'expliquer comment est constituée cette map, prenons le code et analysons les différentes fonctions ainsi que le main :&lt;br /&gt;
&lt;br /&gt;
Ce vecteur de Pose2D (x, y et theta (angle de la machine)) va permettre d'enregistrer la position des machines, c'est une variable global qui sera mise à jour avec le Callback :&lt;br /&gt;
&lt;br /&gt;
 std::vector&amp;lt;geometry_msgs::Pose2D&amp;gt; tab;&lt;br /&gt;
&lt;br /&gt;
*Récupération des machines envoyées par le noeud du SLAM (sur le topic /landmarks):&lt;br /&gt;
&lt;br /&gt;
 void Poses_Machine_Callback(const deplacement_msg::LandmarksConstPtr &amp;amp;machines)&lt;br /&gt;
 {&lt;br /&gt;
          tab=machines-&amp;gt;landmarks;&lt;br /&gt;
          for (int i=0; i&amp;lt;tab.size(); i++)&lt;br /&gt;
          {&lt;br /&gt;
     	     tab[i].x = tab[i].x*1000;&lt;br /&gt;
     	     tab[i].y = tab[i].y*1000;&lt;br /&gt;
 	  }&lt;br /&gt;
    &lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
*Création d'une map vide de taille 14m sur 8m. Chaque case est initialisée à une valeur nulle, on remplit également les autres paramètres de OccupancyGrid:&lt;br /&gt;
(On rappelle que la technique utilisée est un vecteur qui représente chaque case auxquelles il associe une probabilité 100 c'est un point interdit et 0 quand c'est un point sans danger pour le passage du robot)&lt;br /&gt;
&lt;br /&gt;
 void Create_Empty_Map(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      Map.info.origin.position.x=-7000;&lt;br /&gt;
      Map.info.origin.position.y=-1000;&lt;br /&gt;
      Map.info.origin.position.z=0;&lt;br /&gt;
      Map.info.origin.orientation.x=0;&lt;br /&gt;
      Map.info.origin.orientation.y=0;&lt;br /&gt;
      Map.info.origin.orientation.z=0;&lt;br /&gt;
      Map.info.origin.orientation.w=1;&lt;br /&gt;
      Map.info.map_load_time=ros::Time::now();&lt;br /&gt;
      Map.info.resolution=100;&lt;br /&gt;
      Map.info.width=140;&lt;br /&gt;
      Map.info.height=80;&lt;br /&gt;
      Map.data.assign(Map.info.width*Map.info.height, 0);                   //map vide&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
*Construction des points fixes de la map donc les murs (probabilité 100) et les zones à risques (probabilité 50):&lt;br /&gt;
&lt;br /&gt;
 void Set_Wall(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
    for (int i=0;i&amp;lt;80;i++)&lt;br /&gt;
    {&lt;br /&gt;
       for (int j=0;j&amp;lt;140;j++)&lt;br /&gt;
       {&lt;br /&gt;
          if ((i&amp;lt;13)||(i&amp;gt;67))) Map.data[j+i*140]=100;&lt;br /&gt;
          if ((j&amp;lt;13)||(j&amp;gt;127)) Map.data[j+i*140]=100;&lt;br /&gt;
       }&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Nous ne mettons pas tout le code de cette fonction étant donné qu'il est long et répétitif puisque c'est le remplissage des données connues, donc en &amp;quot;dur&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Calcul des positions machines: &lt;br /&gt;
&lt;br /&gt;
Lorsqu'on reçoit une position machine, c'est en fait son centre et son orientation par rapport à x que l'on reçoit. Etant donné que les machines doivent être des rectangles de 110cm sur 75cm (réellement 70 x 35 mais on compte la moitié du robot en plus par sécurité), on décide d'abord de déterminer un des coins du rectangle et plus précisément le coin en bas à droite de ce dernier:&lt;br /&gt;
&lt;br /&gt;
 void Get_One_Point_Of_The_Rectangle(float x, float &amp;amp;xA, float y, float &amp;amp;yA, float theta, float largeur, float longueur)&lt;br /&gt;
 {&lt;br /&gt;
      float x1,y1;&lt;br /&gt;
      x1 = x - cos(theta)*longueur;&lt;br /&gt;
      y1 = y - sin(theta)*longueur; &lt;br /&gt;
      xA = x1 + sin(M_PI_2-theta)*largeur;&lt;br /&gt;
      yA = y1 - cos(M_PI_2-theta)*largeur;&lt;br /&gt;
  &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
*Remplissage des positions sur la map :&lt;br /&gt;
&lt;br /&gt;
On met alors tous les points de ce rectangle à une probabilité 100 dans le vecteur Map. Pour les calculs on différencie le cas ou l'angle de la machine est entre 0 et pi/2 et le cas où il est entre pi/2 et pi. L'algorithme est le suivant : &lt;br /&gt;
&lt;br /&gt;
 A partir du coin, on incrémente x et y de sorte à longer le grand coté et de remplir chaque case (incrémentation de 5 cm).&lt;br /&gt;
 Une fois arrivé au bout, on incrémente x et y de 5cm sur la largeur à partir du coin et on recommence l'opération précédente.&lt;br /&gt;
 Ceci jusqu'à remplir le complètement le rectangle.&lt;br /&gt;
&lt;br /&gt;
Afin d'établir les probabilités correspondantes aux cases de ce rectangle, nous utilisons la fonctions floor() pour &amp;quot;convertir&amp;quot; nos flottants en entier et accéder à la case correspondante. On notera aussi que la case 1470 correspond à l'origine de notre map.&lt;br /&gt;
&lt;br /&gt;
 void Set_Machines_In_Map(float rank, float theta, float xA, float yA, nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      float x=xA;&lt;br /&gt;
      float y=yA;&lt;br /&gt;
      if (theta&amp;lt;=M_PI_2)&lt;br /&gt;
      {&lt;br /&gt;
            for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
            {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++) &lt;br /&gt;
                  {&lt;br /&gt;
                      Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                      x = x + cos(theta)*50;&lt;br /&gt;
                      y = y + sin(theta)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(M_PI_2-theta)*50;&lt;br /&gt;
                  y = yA + j*sin(M_PI_2-theta)*50;&lt;br /&gt;
            }	&lt;br /&gt;
       }&lt;br /&gt;
       if (theta&amp;gt;M_PI_2)&lt;br /&gt;
       {&lt;br /&gt;
             for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
             {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++)&lt;br /&gt;
                  {&lt;br /&gt;
                        Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                        x = x - sin(theta-M_PI_2)*50;&lt;br /&gt;
                        y = y + cos(theta-M_PI_2)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(theta-M_PI_2)*50;&lt;br /&gt;
                  y = yA - j*sin(theta-M_PI_2)*50;&lt;br /&gt;
              }	&lt;br /&gt;
        }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Ci dessous on a les mains, avec les différentes fonctions appelées et la syntaxe particulière à ROS. &lt;br /&gt;
&lt;br /&gt;
*Noeud général pour le traitement et le remplissage de la map :   &lt;br /&gt;
                 &lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
     ros::init(argc, argv, &amp;quot;server&amp;quot;);&lt;br /&gt;
     ros::NodeHandle n;&lt;br /&gt;
     ros::Subscriber sub_poses_machine    = n.subscribe(&amp;quot;/machines&amp;quot;, 1000, Poses_Machine_Callback);   // Récupération des machines&lt;br /&gt;
     ros::Publisher Map_Pub = n.advertise&amp;lt;nav_msgs::OccupancyGrid&amp;gt;(&amp;quot;/map&amp;quot;, 1000);                     // Préparation de la publication de la map&lt;br /&gt;
     ROS_INFO(&amp;quot;Ready to Generate the Map&amp;quot;);&lt;br /&gt;
     float xA,yA;&lt;br /&gt;
     ros::Rate loop_rate(1);&lt;br /&gt;
     while(ros::ok())&lt;br /&gt;
     {&lt;br /&gt;
        nav_msgs::OccupancyGrid Map;&lt;br /&gt;
        Create_Empty_Map(Map);&lt;br /&gt;
        Set_Wall(Map);&lt;br /&gt;
        for (int z=0;z&amp;lt;tab.size();z++)&lt;br /&gt;
        {&lt;br /&gt;
           Get_One_Point_Of_The_Rectangle(tab[z].x, xA, tab[z].y, yA, tab[z].theta, 275, 450);&lt;br /&gt;
 	   Set_Machines_In_Map(100, tab[z].theta, xA, yA, Map);&lt;br /&gt;
        }&lt;br /&gt;
        Map_Pub.publish(Map);                                                                   // publication de la map&lt;br /&gt;
        ros::spinOnce();&lt;br /&gt;
        loop_rate.sleep();&lt;br /&gt;
     }&lt;br /&gt;
     return 0;&lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Noeud test qui publie 2 positions de machines : &lt;br /&gt;
&lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
    ros::init(argc, argv, &amp;quot;test&amp;quot;);&lt;br /&gt;
    ros::NodeHandle n;&lt;br /&gt;
    ros::Publisher Pose_Machines_Pub = n.advertise&amp;lt;deplacement_msg::Landmarks&amp;gt;(&amp;quot;/machines&amp;quot;, 1000);&lt;br /&gt;
    ROS_INFO(&amp;quot;Ready to send poses machines&amp;quot;);&lt;br /&gt;
    int xA,yA;&lt;br /&gt;
    ros::Rate loop_rate(1);&lt;br /&gt;
    while(ros::ok())&lt;br /&gt;
    {&lt;br /&gt;
       deplacement_msg::Landmarks machines_msgs;&lt;br /&gt;
       geometry_msgs::Pose2D tab;&lt;br /&gt;
       tab.x=-2;&lt;br /&gt;
       tab.y=2;&lt;br /&gt;
       tab.theta=0;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       tab.x=5;&lt;br /&gt;
       tab.y=4;&lt;br /&gt;
       tab.theta=2.5;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       Pose_Machines_Pub.publish(machines_msgs);&lt;br /&gt;
       ros::spinOnce();&lt;br /&gt;
       loop_rate.sleep();&lt;br /&gt;
    }&lt;br /&gt;
    return 0;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On visualise le résultat grâce au logiciel RVIZ qui peut lire les topics publiés et donc le topic /map :&lt;br /&gt;
&lt;br /&gt;
===Semaine 9===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
l'objectif de cette semaine sera de coder toutes les fonctions nécessaires à l'implémentation finale du [http://fr.wikipedia.org/wiki/Filtre_de_Kalman#Filtre_de_Kalman_.C3.A9tendu filtre de Kalman étendu] :&lt;br /&gt;
&lt;br /&gt;
*initialisations des différents éléments&lt;br /&gt;
*étape de prédiction&lt;br /&gt;
*étape de mise à jour&lt;br /&gt;
*publication des positions machines et du robot dans le repère global via un topic ROS&lt;br /&gt;
&lt;br /&gt;
Le schéma ci-dessous nous montre les deux étapes du filtre de Kalman :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Kalman.png | center]]&lt;br /&gt;
&lt;br /&gt;
le code pour la partie ''prédiction'' :&lt;br /&gt;
&lt;br /&gt;
 //on ressort la position du robot pour l'état n+1&lt;br /&gt;
 //les paramètres sont le vecteurs où on a la position du robot à l'état n, la matrice P, les commandes en vitesses et le temps à l'état n&lt;br /&gt;
 Vector3d prediction(VectorXd xMean, MatrixXd &amp;amp;P, geometry_msgs::Pose2D cmdVel, ros::Time &amp;amp;temps){&lt;br /&gt;
   ros::Duration duree = ros::Time::now() - temps;&lt;br /&gt;
   double periode = duree.toSec();&amp;lt;br&amp;gt;&lt;br /&gt;
   Vector3d cmdVelVect = Pose2DToVector(cmdVel);&lt;br /&gt;
   //le xMean.topLeftCorner(3,1) correspond à la position du robot&lt;br /&gt;
   Vector3d xPredicted = xMean.topLeftCorner(3,1) + periode*cmdVelVect;&amp;lt;br&amp;gt;&lt;br /&gt;
   MatrixXd Fx;&lt;br /&gt;
   Fx = MatrixXd::Identity(P.rows(), P.cols());&lt;br /&gt;
   Fx(0,0) = xPredicted(0);&lt;br /&gt;
   Fx(1,1) = xPredicted(1);&lt;br /&gt;
   Fx(2,2) = xPredicted(2);&amp;lt;br&amp;gt;&lt;br /&gt;
   //mise à jour de P&lt;br /&gt;
   P = Fx*P*(Fx.transpose());&amp;lt;br&amp;gt;&lt;br /&gt;
   //mise à jour du temps&lt;br /&gt;
   temps = ros::Time::now();&amp;lt;br&amp;gt;&lt;br /&gt;
   return xPredicted;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
le code pour la partie ''correction'' :&lt;br /&gt;
&lt;br /&gt;
 void correction(VectorXd &amp;amp;xMean, MatrixXd &amp;amp;P, Vector3d xPredicted, geometry_msgs::Pose2D m){&lt;br /&gt;
   int taille = P.rows();&lt;br /&gt;
   //on vérifie si la machine est présente ou pas dans le vecteur d'état&lt;br /&gt;
   int i = checkStateVector(xMean, m);&amp;lt;br&amp;gt;&lt;br /&gt;
   if (i != 0){&lt;br /&gt;
     //calcul de H&lt;br /&gt;
     MatrixXd H(3, taille);&lt;br /&gt;
     H = buildH(taille, i);&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul de Pm&lt;br /&gt;
     MatrixXd Pm(taille, taille);&lt;br /&gt;
     Pm = buildPm(P, i);&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul de Z&lt;br /&gt;
     MatrixXd Z(taille, taille);&lt;br /&gt;
     Z = H*Pm*(H.transpose());	&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul du gain de Kalman&lt;br /&gt;
     MatrixXd K(taille, taille);&lt;br /&gt;
     K = P*(H.transpose())*(Z.inverse());&amp;lt;br&amp;gt;&lt;br /&gt;
     //mise à jour du vecteur xMean&lt;br /&gt;
     xMean = xMean + K*(xMean.block(xMean.rows()-3,0,3,1) - xPredicted);&amp;lt;br&amp;gt;&lt;br /&gt;
     //mise à jour de la matrice P&lt;br /&gt;
     P = P - K*Z*(K.transpose());&lt;br /&gt;
   }&lt;br /&gt;
   else {&lt;br /&gt;
     addMachine(m, xMean, P);&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Pour notre cas, on doit ajouter des nouvelles machines, alors que pour un EKF classique on observe juste des machines déjà répertoriées. Il faut donc une fonction qui permet d'ajouter une machine dans le vecteur d'état. La voilà :&lt;br /&gt;
&lt;br /&gt;
 void addMachine(geometry_msgs::Pose2D machine, VectorXd &amp;amp;xMean, MatrixXd &amp;amp;P){&lt;br /&gt;
   //on redimensionne xMean et P pour accueillir la nouvelle machines&lt;br /&gt;
   xMean.conservativeResize(xMean.rows() + 3);&lt;br /&gt;
   P.conservativeResize(P.rows()+3,P.cols()+3);&amp;lt;br&amp;gt;&lt;br /&gt;
   //on remplit avec les coordonnées de la nouvelle machine&lt;br /&gt;
   xMean(xMean.rows()-3) = machine.x;&lt;br /&gt;
   xMean(xMean.rows()-2) = machine.y;&lt;br /&gt;
   xMean(xMean.rows()-1) = machine.theta;&amp;lt;br&amp;gt;&lt;br /&gt;
   //calcul de tous les PLi&lt;br /&gt;
   //initialisation des PLi à 0&lt;br /&gt;
   P.block(P.rows() - 3, 0, 3, P.cols()).setZero();&lt;br /&gt;
   P.block(0, P.cols() - 3, P.rows(), 3).setZero();&amp;lt;br&amp;gt;&lt;br /&gt;
   for (int j = 0; j &amp;lt; xMean.rows(); j = j + 3){&lt;br /&gt;
     //position de la nouvelle machines par rapport au robot et à toutes les autres&lt;br /&gt;
     double x 	 = xMean(xMean.rows()-3) - xMean(j  );&lt;br /&gt;
     double y 	 = xMean(xMean.rows()-2) - xMean(j+1);&lt;br /&gt;
     double theta = xMean(xMean.rows()-1) - xMean(j+2);&amp;lt;br&amp;gt;&lt;br /&gt;
     P(P.rows()-3, j  ) = x;&lt;br /&gt;
     P(P.rows()-2, j+1) = y;&lt;br /&gt;
     P(P.rows()-1, j+2) = theta;&amp;lt;br&amp;gt;&lt;br /&gt;
     P(j  , P.rows()-3) = x;&lt;br /&gt;
     P(j+1, P.rows()-2) = y;&lt;br /&gt;
     P(j+2, P.rows()-1) = theta;&amp;lt;br&amp;gt;&lt;br /&gt;
     P(j  , j  ) = xMean(j  ) - xMean(0);&lt;br /&gt;
     P(j+1, j+1) = xMean(j+1) - xMean(1);&lt;br /&gt;
     P(j+2, j+2) = xMean(j+2) - xMean(2);&amp;lt;br&amp;gt;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 10===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
La partie '''prédiction''' du filtre marche parfaitement, quelques corrections ont dues être faites au niveau de la commande vitesse. En effet, Nous avions oublié de la transposer dans le repère global. Pour la partie '''correction''', nous rencontrons un problème de divergence du filtre, qui est probablement due à une mauvaise initialisation. En effet, nous utilisons des enregistrements faits sur notre piste (1/4 de la vraie) avec des initialisations correspondant à la piste originale. Le filtre ne peut donc pas converger car la position de départ est fausse.&lt;br /&gt;
&lt;br /&gt;
===Semaine 11===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
Des corrections sont en cours de validation. Nous essayons de définir une initialisation avec les paramètres de notre piste, ce qui n'est pas évident. Les programmes permettant d'extraire les positions machines du filtres ont été réalisé, ainsi qu'un launch pour pouvoir lancer tous les noeuds de la localisation.&lt;br /&gt;
&lt;br /&gt;
===Semaine 12===&lt;br /&gt;
&lt;br /&gt;
====Compétition Open German====&lt;br /&gt;
&lt;br /&gt;
Pendant les deux jours de mise en place, nous avons continué à travailler sur la localisation, qui est une partie critique et nécessaire à notre participation. Le filtre en lui même est fonctionnel et permet de corriger la position du robot, ainsi que celle des machines. Cependant, et ce n'est pas un petit &amp;quot;cependant&amp;quot;... Le fait que l'on ajoute des machines en cours de jeu perturbe fortement notre algorithme.&lt;br /&gt;
&lt;br /&gt;
En effet, le filtre de Kalman est optimal si la position des repères est connu, or, un ajout de machine crée un recalage forcé, et si l'on voit plusieurs machines... C'est la '''catastrophe'''. L'ajout de machines est une partie sensible qui nécessite des tests sur la position mesurée, avec un changement de repère à partir de la position du robot, si celle ci dérive, tout dérive. Chaque machine initialisée à la mauvaise position, ou chaque élément détecté comme machine mais n'en étant pas une (faux positif) perturbe le recalage.&lt;br /&gt;
&lt;br /&gt;
De nombreux tests ayant été fait sur la piste officiel avec différentes configurations nous ont permis de vérifier que l'odométrie mesurée ne dérivait que très peu. Il a donc été décidé de n'utiliser que l'odométrie et le scan laser pour la partie '''exploration'''. En effet, chaque machine mesurée est envoyée à un noeud ROS qui va créer une carte et la compléter au fur et à mesure de la partie. Le robot est donc repéré rien qu'avec son odométrie. Le fait que la phase d'exploration (découverte du terrain) ne dure que '''4 minutes''' nous a convaincu pour n'utiliser que cette mesure.&lt;br /&gt;
&lt;br /&gt;
De plus, la carte créée sera utilisée pour la phase suivante, la phase de '''production'''. Cette phase consiste, au niveau de la localisation, à se repérer sur la piste et atteindre la machine demandée par l'exécuteur de tâches. Pour cette phase qui dure '''15 minutes''', l'utilisation du filtre est nécessaire. Donc, avec les coordonnées des machines mesurées pendant la première phase, on peut créer le vecteur d'état et la matrice faisant le lien entre les machines. De là, la taille de ces deux éléments ne variant plus, on peut corriger uniquement la position du robot et le filtre sera efficace.&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=20082</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=20082"/>
				<updated>2015-04-16T13:07:49Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Semaine 9 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - vidéo====&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les résultats de la détection des machines nous avons utiliser l'interface graphique disponible avec ROS, RVIZ. Nous visualisons alors le scan laser (points blancs), le résultat de la détection de segments (en rouge) et les positions des machines trouvées (en vert). Un premier test a été fait sur le scan originel, celui sur lequel nous avons travaillé depuis le début.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=XSn4s1y-XT0 Visualisation des machines]&lt;br /&gt;
&lt;br /&gt;
On rencontre un problème quand le robot est exactement parallèle ou perpendiculaire à un mur. Après vérification dans le programme, il s'avère que la détection ne fonctionne pas pour ces cas. Ce bug est maintenant corrigé :&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=rKeqewpuLoQ Correction du bug]&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
La première étape consiste juste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;br /&gt;
&lt;br /&gt;
la matrice correspondant au changement (laser -&amp;gt; robot) est la suivante : &lt;br /&gt;
&lt;br /&gt;
 0   -1    0&lt;br /&gt;
 1    0  0.2&lt;br /&gt;
 0    0    1&lt;br /&gt;
&lt;br /&gt;
la matrice 2x2 en haut à gauche correspond à la rotation de 90°, et le vecteur (0, 0.2) correspond à la translation.&lt;br /&gt;
&lt;br /&gt;
Celle du changement (robot -&amp;gt; global) avec alpha angle mesuré par le gyroscope depuis la position initiale (angle 0) :&lt;br /&gt;
&lt;br /&gt;
 cos(alpha)   -sin(alpha)    posInit.x&lt;br /&gt;
 sin(alpha)    cos(alpha)    posInit.y&lt;br /&gt;
          0             0            1&lt;br /&gt;
&lt;br /&gt;
l'étape suivante est de vérifier si les machines vues par le laser sont bien des machines, c'est-à-dire si les positions mesurées à partir des données lasers correspond aux zones occupées par des machines envoyées par la Referee Box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Grid Map====&lt;br /&gt;
&lt;br /&gt;
L'autre objectif de cette semaine a été de coder le noeud qui génère la map. La map est générée sous forme d'OccupancyGrid. Ce type est constitué d'un seul vecteur dont la première case correspond à la case en bas à gauche de la map. D'autres paramètres sont réglable comme l'origine et la taille.&lt;br /&gt;
&lt;br /&gt;
Pour la taille on choisit de diviser la map en case de 10 cm et l'origine choisie est le x du centre de la map et en y l'abscisse du premier mur (voir la map ci-dessous). Afin d'expliquer comment est constituée cette map, prenons le code et analysons les différentes fonctions ainsi que le main :&lt;br /&gt;
&lt;br /&gt;
Ce vecteur de Pose2D (x, y et theta (angle de la machine)) va permettre d'enregistrer la position des machines, c'est une variable global qui sera mise à jour avec le Callback :&lt;br /&gt;
&lt;br /&gt;
 std::vector&amp;lt;geometry_msgs::Pose2D&amp;gt; tab;&lt;br /&gt;
&lt;br /&gt;
*Récupération des machines envoyées par le noeud du SLAM (sur le topic /landmarks):&lt;br /&gt;
&lt;br /&gt;
 void Poses_Machine_Callback(const deplacement_msg::LandmarksConstPtr &amp;amp;machines)&lt;br /&gt;
 {&lt;br /&gt;
          tab=machines-&amp;gt;landmarks;&lt;br /&gt;
          for (int i=0; i&amp;lt;tab.size(); i++)&lt;br /&gt;
          {&lt;br /&gt;
     	     tab[i].x = tab[i].x*1000;&lt;br /&gt;
     	     tab[i].y = tab[i].y*1000;&lt;br /&gt;
 	  }&lt;br /&gt;
    &lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
*Création d'une map vide de taille 14m sur 8m. Chaque case est initialisée à une valeur nulle, on remplit également les autres paramètres de OccupancyGrid:&lt;br /&gt;
(On rappelle que la technique utilisée est un vecteur qui représente chaque case auxquelles il associe une probabilité 100 c'est un point interdit et 0 quand c'est un point sans danger pour le passage du robot)&lt;br /&gt;
&lt;br /&gt;
 void Create_Empty_Map(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      Map.info.origin.position.x=-7000;&lt;br /&gt;
      Map.info.origin.position.y=-1000;&lt;br /&gt;
      Map.info.origin.position.z=0;&lt;br /&gt;
      Map.info.origin.orientation.x=0;&lt;br /&gt;
      Map.info.origin.orientation.y=0;&lt;br /&gt;
      Map.info.origin.orientation.z=0;&lt;br /&gt;
      Map.info.origin.orientation.w=1;&lt;br /&gt;
      Map.info.map_load_time=ros::Time::now();&lt;br /&gt;
      Map.info.resolution=100;&lt;br /&gt;
      Map.info.width=140;&lt;br /&gt;
      Map.info.height=80;&lt;br /&gt;
      Map.data.assign(Map.info.width*Map.info.height, 0);                   //map vide&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
*Construction des points fixes de la map donc les murs (probabilité 100) et les zones à risques (probabilité 50):&lt;br /&gt;
&lt;br /&gt;
 void Set_Wall(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
    for (int i=0;i&amp;lt;80;i++)&lt;br /&gt;
    {&lt;br /&gt;
       for (int j=0;j&amp;lt;140;j++)&lt;br /&gt;
       {&lt;br /&gt;
          if ((i&amp;lt;13)||(i&amp;gt;67))) Map.data[j+i*140]=100;&lt;br /&gt;
          if ((j&amp;lt;13)||(j&amp;gt;127)) Map.data[j+i*140]=100;&lt;br /&gt;
       }&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Nous ne mettons pas tout le code de cette fonction étant donné qu'il est long et répétitif puisque c'est le remplissage des données connues, donc en &amp;quot;dur&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Calcul des positions machines: &lt;br /&gt;
&lt;br /&gt;
Lorsqu'on reçoit une position machine, c'est en fait son centre et son orientation par rapport à x que l'on reçoit. Etant donné que les machines doivent être des rectangles de 110cm sur 75cm (réellement 70 x 35 mais on compte la moitié du robot en plus par sécurité), on décide d'abord de déterminer un des coins du rectangle et plus précisément le coin en bas à droite de ce dernier:&lt;br /&gt;
&lt;br /&gt;
 void Get_One_Point_Of_The_Rectangle(float x, float &amp;amp;xA, float y, float &amp;amp;yA, float theta, float largeur, float longueur)&lt;br /&gt;
 {&lt;br /&gt;
      float x1,y1;&lt;br /&gt;
      x1 = x - cos(theta)*longueur;&lt;br /&gt;
      y1 = y - sin(theta)*longueur; &lt;br /&gt;
      xA = x1 + sin(M_PI_2-theta)*largeur;&lt;br /&gt;
      yA = y1 - cos(M_PI_2-theta)*largeur;&lt;br /&gt;
  &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
*Remplissage des positions sur la map :&lt;br /&gt;
&lt;br /&gt;
On met alors tous les points de ce rectangle à une probabilité 100 dans le vecteur Map. Pour les calculs on différencie le cas ou l'angle de la machine est entre 0 et pi/2 et le cas où il est entre pi/2 et pi. L'algorithme est le suivant : &lt;br /&gt;
&lt;br /&gt;
 A partir du coin, on incrémente x et y de sorte à longer le grand coté et de remplir chaque case (incrémentation de 5 cm).&lt;br /&gt;
 Une fois arrivé au bout, on incrémente x et y de 5cm sur la largeur à partir du coin et on recommence l'opération précédente.&lt;br /&gt;
 Ceci jusqu'à remplir le complètement le rectangle.&lt;br /&gt;
&lt;br /&gt;
Afin d'établir les probabilités correspondantes aux cases de ce rectangle, nous utilisons la fonctions floor() pour &amp;quot;convertir&amp;quot; nos flottants en entier et accéder à la case correspondante. On notera aussi que la case 1470 correspond à l'origine de notre map.&lt;br /&gt;
&lt;br /&gt;
 void Set_Machines_In_Map(float rank, float theta, float xA, float yA, nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      float x=xA;&lt;br /&gt;
      float y=yA;&lt;br /&gt;
      if (theta&amp;lt;=M_PI_2)&lt;br /&gt;
      {&lt;br /&gt;
            for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
            {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++) &lt;br /&gt;
                  {&lt;br /&gt;
                      Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                      x = x + cos(theta)*50;&lt;br /&gt;
                      y = y + sin(theta)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(M_PI_2-theta)*50;&lt;br /&gt;
                  y = yA + j*sin(M_PI_2-theta)*50;&lt;br /&gt;
            }	&lt;br /&gt;
       }&lt;br /&gt;
       if (theta&amp;gt;M_PI_2)&lt;br /&gt;
       {&lt;br /&gt;
             for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
             {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++)&lt;br /&gt;
                  {&lt;br /&gt;
                        Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                        x = x - sin(theta-M_PI_2)*50;&lt;br /&gt;
                        y = y + cos(theta-M_PI_2)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(theta-M_PI_2)*50;&lt;br /&gt;
                  y = yA - j*sin(theta-M_PI_2)*50;&lt;br /&gt;
              }	&lt;br /&gt;
        }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Ci dessous on a les mains, avec les différentes fonctions appelées et la syntaxe particulière à ROS. &lt;br /&gt;
&lt;br /&gt;
*Noeud général pour le traitement et le remplissage de la map :   &lt;br /&gt;
                 &lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
     ros::init(argc, argv, &amp;quot;server&amp;quot;);&lt;br /&gt;
     ros::NodeHandle n;&lt;br /&gt;
     ros::Subscriber sub_poses_machine    = n.subscribe(&amp;quot;/machines&amp;quot;, 1000, Poses_Machine_Callback);   // Récupération des machines&lt;br /&gt;
     ros::Publisher Map_Pub = n.advertise&amp;lt;nav_msgs::OccupancyGrid&amp;gt;(&amp;quot;/map&amp;quot;, 1000);                     // Préparation de la publication de la map&lt;br /&gt;
     ROS_INFO(&amp;quot;Ready to Generate the Map&amp;quot;);&lt;br /&gt;
     float xA,yA;&lt;br /&gt;
     ros::Rate loop_rate(1);&lt;br /&gt;
     while(ros::ok())&lt;br /&gt;
     {&lt;br /&gt;
        nav_msgs::OccupancyGrid Map;&lt;br /&gt;
        Create_Empty_Map(Map);&lt;br /&gt;
        Set_Wall(Map);&lt;br /&gt;
        for (int z=0;z&amp;lt;tab.size();z++)&lt;br /&gt;
        {&lt;br /&gt;
           Get_One_Point_Of_The_Rectangle(tab[z].x, xA, tab[z].y, yA, tab[z].theta, 275, 450);&lt;br /&gt;
 	   Set_Machines_In_Map(100, tab[z].theta, xA, yA, Map);&lt;br /&gt;
        }&lt;br /&gt;
        Map_Pub.publish(Map);                                                                   // publication de la map&lt;br /&gt;
        ros::spinOnce();&lt;br /&gt;
        loop_rate.sleep();&lt;br /&gt;
     }&lt;br /&gt;
     return 0;&lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Noeud test qui publie 2 positions de machines : &lt;br /&gt;
&lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
    ros::init(argc, argv, &amp;quot;test&amp;quot;);&lt;br /&gt;
    ros::NodeHandle n;&lt;br /&gt;
    ros::Publisher Pose_Machines_Pub = n.advertise&amp;lt;deplacement_msg::Landmarks&amp;gt;(&amp;quot;/machines&amp;quot;, 1000);&lt;br /&gt;
    ROS_INFO(&amp;quot;Ready to send poses machines&amp;quot;);&lt;br /&gt;
    int xA,yA;&lt;br /&gt;
    ros::Rate loop_rate(1);&lt;br /&gt;
    while(ros::ok())&lt;br /&gt;
    {&lt;br /&gt;
       deplacement_msg::Landmarks machines_msgs;&lt;br /&gt;
       geometry_msgs::Pose2D tab;&lt;br /&gt;
       tab.x=-2;&lt;br /&gt;
       tab.y=2;&lt;br /&gt;
       tab.theta=0;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       tab.x=5;&lt;br /&gt;
       tab.y=4;&lt;br /&gt;
       tab.theta=2.5;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       Pose_Machines_Pub.publish(machines_msgs);&lt;br /&gt;
       ros::spinOnce();&lt;br /&gt;
       loop_rate.sleep();&lt;br /&gt;
    }&lt;br /&gt;
    return 0;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On visualise le résultat grâce au logiciel RVIZ qui peut lire les topics publiés et donc le topic /map :&lt;br /&gt;
&lt;br /&gt;
===Semaine 9===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
l'objectif de cette semaine sera de coder toutes les fonctions nécessaires à l'implémentation finale du [http://fr.wikipedia.org/wiki/Filtre_de_Kalman#Filtre_de_Kalman_.C3.A9tendu filtre de Kalman étendu] :&lt;br /&gt;
&lt;br /&gt;
*initialisations des différents éléments&lt;br /&gt;
*étape de prédiction&lt;br /&gt;
*étape de mise à jour&lt;br /&gt;
*publication des positions machines et du robot dans le repère global via un topic ROS&lt;br /&gt;
&lt;br /&gt;
Le schéma ci-dessous nous montre les deux étapes du filtre de Kalman :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Kalman.png | center]]&lt;br /&gt;
&lt;br /&gt;
le code pour la partie ''prédiction'' :&lt;br /&gt;
&lt;br /&gt;
 //on ressort la position du robot pour l'état n+1&lt;br /&gt;
 //les paramètres sont le vecteurs où on a la position du robot à l'état n, la matrice P, les commandes en vitesses et le temps à l'état n&lt;br /&gt;
 Vector3d prediction(VectorXd xMean, MatrixXd &amp;amp;P, geometry_msgs::Pose2D cmdVel, ros::Time &amp;amp;temps){&lt;br /&gt;
   ros::Duration duree = ros::Time::now() - temps;&lt;br /&gt;
   double periode = duree.toSec();&amp;lt;br&amp;gt;&lt;br /&gt;
   Vector3d cmdVelVect = Pose2DToVector(cmdVel);&lt;br /&gt;
   //le xMean.topLeftCorner(3,1) correspond à la position du robot&lt;br /&gt;
   Vector3d xPredicted = xMean.topLeftCorner(3,1) + periode*cmdVelVect;&amp;lt;br&amp;gt;&lt;br /&gt;
   MatrixXd Fx;&lt;br /&gt;
   Fx = MatrixXd::Identity(P.rows(), P.cols());&lt;br /&gt;
   Fx(0,0) = xPredicted(0);&lt;br /&gt;
   Fx(1,1) = xPredicted(1);&lt;br /&gt;
   Fx(2,2) = xPredicted(2);&amp;lt;br&amp;gt;&lt;br /&gt;
   //mise à jour de P&lt;br /&gt;
   P = Fx*P*(Fx.transpose());&amp;lt;br&amp;gt;&lt;br /&gt;
   //mise à jour du temps&lt;br /&gt;
   temps = ros::Time::now();&amp;lt;br&amp;gt;&lt;br /&gt;
   return xPredicted;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
le code pour la partie ''correction'' :&lt;br /&gt;
&lt;br /&gt;
 void correction(VectorXd &amp;amp;xMean, MatrixXd &amp;amp;P, Vector3d xPredicted, geometry_msgs::Pose2D m){&lt;br /&gt;
   int taille = P.rows();&lt;br /&gt;
   //on vérifie si la machine est présente ou pas dans le vecteur d'état&lt;br /&gt;
   int i = checkStateVector(xMean, m);&amp;lt;br&amp;gt;&lt;br /&gt;
   if (i != 0){&lt;br /&gt;
     //calcul de H&lt;br /&gt;
     MatrixXd H(3, taille);&lt;br /&gt;
     H = buildH(taille, i);&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul de Pm&lt;br /&gt;
     MatrixXd Pm(taille, taille);&lt;br /&gt;
     Pm = buildPm(P, i);&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul de Z&lt;br /&gt;
     MatrixXd Z(taille, taille);&lt;br /&gt;
     Z = H*Pm*(H.transpose());	&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul du gain de Kalman&lt;br /&gt;
     MatrixXd K(taille, taille);&lt;br /&gt;
     K = P*(H.transpose())*(Z.inverse());&amp;lt;br&amp;gt;&lt;br /&gt;
     //mise à jour du vecteur xMean&lt;br /&gt;
     xMean = xMean + K*(xMean.block(xMean.rows()-3,0,3,1) - xPredicted);&amp;lt;br&amp;gt;&lt;br /&gt;
     //mise à jour de la matrice P&lt;br /&gt;
     P = P - K*Z*(K.transpose());&lt;br /&gt;
   }&lt;br /&gt;
   else {&lt;br /&gt;
     addMachine(m, xMean, P);&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Pour notre cas, on doit ajouter des nouvelles machines, alors que pour un EKF classique on observe juste des machines déjà répertoriées. Il faut donc une fonction qui permet d'ajouter une machine dans le vecteur d'état. La voilà :&lt;br /&gt;
&lt;br /&gt;
 void addMachine(geometry_msgs::Pose2D machine, VectorXd &amp;amp;xMean, MatrixXd &amp;amp;P){&lt;br /&gt;
   //on redimensionne xMean et P pour accueillir la nouvelle machines&lt;br /&gt;
   xMean.conservativeResize(xMean.rows() + 3);&lt;br /&gt;
   P.conservativeResize(P.rows()+3,P.cols()+3);&amp;lt;br&amp;gt;&lt;br /&gt;
   //on remplit avec les coordonnées de la nouvelle machine&lt;br /&gt;
   xMean(xMean.rows()-3) = machine.x;&lt;br /&gt;
   xMean(xMean.rows()-2) = machine.y;&lt;br /&gt;
   xMean(xMean.rows()-1) = machine.theta;&amp;lt;br&amp;gt;&lt;br /&gt;
   //calcul de tous les PLi&lt;br /&gt;
   //initialisation des PLi à 0&lt;br /&gt;
   P.block(P.rows() - 3, 0, 3, P.cols()).setZero();&lt;br /&gt;
   P.block(0, P.cols() - 3, P.rows(), 3).setZero();&amp;lt;br&amp;gt;&lt;br /&gt;
   for (int j = 0; j &amp;lt; xMean.rows(); j = j + 3){&lt;br /&gt;
     //position de la nouvelle machines par rapport au robot et à toutes les autres&lt;br /&gt;
     double x 	 = xMean(xMean.rows()-3) - xMean(j  );&lt;br /&gt;
     double y 	 = xMean(xMean.rows()-2) - xMean(j+1);&lt;br /&gt;
     double theta = xMean(xMean.rows()-1) - xMean(j+2);&amp;lt;br&amp;gt;&lt;br /&gt;
     P(P.rows()-3, j  ) = x;&lt;br /&gt;
     P(P.rows()-2, j+1) = y;&lt;br /&gt;
     P(P.rows()-1, j+2) = theta;&amp;lt;br&amp;gt;&lt;br /&gt;
     P(j  , P.rows()-3) = x;&lt;br /&gt;
     P(j+1, P.rows()-2) = y;&lt;br /&gt;
     P(j+2, P.rows()-1) = theta;&amp;lt;br&amp;gt;&lt;br /&gt;
     P(j  , j  ) = xMean(j  ) - xMean(0);&lt;br /&gt;
     P(j+1, j+1) = xMean(j+1) - xMean(1);&lt;br /&gt;
     P(j+2, j+2) = xMean(j+2) - xMean(2);&amp;lt;br&amp;gt;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 10===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
La partie '''prédiction''' du filtre marche parfaitement, quelques corrections ont dues être faites au niveau de la commande vitesse. En effet, Nous avions oublié de la transposer dans le repère global. Pour la partie '''correction''', nous rencontrons un problème de divergence du filtre, qui est probablement due à une mauvaise initialisation. En effet, nous utilisons des enregistrements faits sur notre piste (1/4 de la vraie) avec des initialisations correspondant à la piste originale. Le filtre ne peut donc pas converger car la position de départ est fausse.&lt;br /&gt;
&lt;br /&gt;
===Semaine 11===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
Des corrections sont en cours de validation. Nous essayons de définir une initialisation avec les paramètres de notre piste, ce qui n'est pas évident. Les programmes permettant d'extraire les positions machines du filtres ont été réalisé, ainsi qu'un launch pour pouvoir lancer tous les noeuds de la localisation.&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19886</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19886"/>
				<updated>2015-04-12T10:19:17Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Localisation - Extended Kalman Filter */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - vidéo====&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les résultats de la détection des machines nous avons utiliser l'interface graphique disponible avec ROS, RVIZ. Nous visualisons alors le scan laser (points blancs), le résultat de la détection de segments (en rouge) et les positions des machines trouvées (en vert). Un premier test a été fait sur le scan originel, celui sur lequel nous avons travaillé depuis le début.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=XSn4s1y-XT0 Visualisation des machines]&lt;br /&gt;
&lt;br /&gt;
On rencontre un problème quand le robot est exactement parallèle ou perpendiculaire à un mur. Après vérification dans le programme, il s'avère que la détection ne fonctionne pas pour ces cas. Ce bug est maintenant corrigé :&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=rKeqewpuLoQ Correction du bug]&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
La première étape consiste juste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;br /&gt;
&lt;br /&gt;
la matrice correspondant au changement (laser -&amp;gt; robot) est la suivante : &lt;br /&gt;
&lt;br /&gt;
 0   -1    0&lt;br /&gt;
 1    0  0.2&lt;br /&gt;
 0    0    1&lt;br /&gt;
&lt;br /&gt;
la matrice 2x2 en haut à gauche correspond à la rotation de 90°, et le vecteur (0, 0.2) correspond à la translation.&lt;br /&gt;
&lt;br /&gt;
Celle du changement (robot -&amp;gt; global) avec alpha angle mesuré par le gyroscope depuis la position initiale (angle 0) :&lt;br /&gt;
&lt;br /&gt;
 cos(alpha)   -sin(alpha)    posInit.x&lt;br /&gt;
 sin(alpha)    cos(alpha)    posInit.y&lt;br /&gt;
          0             0            1&lt;br /&gt;
&lt;br /&gt;
l'étape suivante est de vérifier si les machines vues par le laser sont bien des machines, c'est-à-dire si les positions mesurées à partir des données lasers correspond aux zones occupées par des machines envoyées par la Referee Box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Grid Map====&lt;br /&gt;
&lt;br /&gt;
L'autre objectif de cette semaine a été de coder le noeud qui génère la map. La map est générée sous forme d'OccupancyGrid. Ce type est constitué d'un seul vecteur dont la première case correspond à la case en bas à gauche de la map. D'autres paramètres sont réglable comme l'origine et la taille.&lt;br /&gt;
&lt;br /&gt;
Pour la taille on choisit de diviser la map en case de 10 cm et l'origine choisie est le x du centre de la map et en y l'abscisse du premier mur (voir la map ci-dessous). Afin d'expliquer comment est constituée cette map, prenons le code et analysons les différentes fonctions ainsi que le main :&lt;br /&gt;
&lt;br /&gt;
Ce vecteur de Pose2D (x, y et theta (angle de la machine)) va permettre d'enregistrer la position des machines, c'est une variable global qui sera mise à jour avec le Callback :&lt;br /&gt;
&lt;br /&gt;
 std::vector&amp;lt;geometry_msgs::Pose2D&amp;gt; tab;&lt;br /&gt;
&lt;br /&gt;
*Récupération des machines envoyées par le noeud du SLAM (sur le topic /landmarks):&lt;br /&gt;
&lt;br /&gt;
 void Poses_Machine_Callback(const deplacement_msg::LandmarksConstPtr &amp;amp;machines)&lt;br /&gt;
 {&lt;br /&gt;
          tab=machines-&amp;gt;landmarks;&lt;br /&gt;
          for (int i=0; i&amp;lt;tab.size(); i++)&lt;br /&gt;
          {&lt;br /&gt;
     	     tab[i].x = tab[i].x*1000;&lt;br /&gt;
     	     tab[i].y = tab[i].y*1000;&lt;br /&gt;
 	  }&lt;br /&gt;
    &lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
*Création d'une map vide de taille 14m sur 8m. Chaque case est initialisée à une valeur nulle, on remplit également les autres paramètres de OccupancyGrid:&lt;br /&gt;
(On rappelle que la technique utilisée est un vecteur qui représente chaque case auxquelles il associe une probabilité 100 c'est un point interdit et 0 quand c'est un point sans danger pour le passage du robot)&lt;br /&gt;
&lt;br /&gt;
 void Create_Empty_Map(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      Map.info.origin.position.x=-7000;&lt;br /&gt;
      Map.info.origin.position.y=-1000;&lt;br /&gt;
      Map.info.origin.position.z=0;&lt;br /&gt;
      Map.info.origin.orientation.x=0;&lt;br /&gt;
      Map.info.origin.orientation.y=0;&lt;br /&gt;
      Map.info.origin.orientation.z=0;&lt;br /&gt;
      Map.info.origin.orientation.w=1;&lt;br /&gt;
      Map.info.map_load_time=ros::Time::now();&lt;br /&gt;
      Map.info.resolution=100;&lt;br /&gt;
      Map.info.width=140;&lt;br /&gt;
      Map.info.height=80;&lt;br /&gt;
      Map.data.assign(Map.info.width*Map.info.height, 0);                   //map vide&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
*Construction des points fixes de la map donc les murs (probabilité 100) et les zones à risques (probabilité 50):&lt;br /&gt;
&lt;br /&gt;
 void Set_Wall(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
    for (int i=0;i&amp;lt;80;i++)&lt;br /&gt;
    {&lt;br /&gt;
       for (int j=0;j&amp;lt;140;j++)&lt;br /&gt;
       {&lt;br /&gt;
          if ((i&amp;lt;13)||(i&amp;gt;67))) Map.data[j+i*140]=100;&lt;br /&gt;
          if ((j&amp;lt;13)||(j&amp;gt;127)) Map.data[j+i*140]=100;&lt;br /&gt;
       }&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Nous ne mettons pas tout le code de cette fonction étant donné qu'il est long et répétitif puisque c'est le remplissage des données connues, donc en &amp;quot;dur&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Calcul des positions machines: &lt;br /&gt;
&lt;br /&gt;
Lorsqu'on reçoit une position machine, c'est en fait son centre et son orientation par rapport à x que l'on reçoit. Etant donné que les machines doivent être des rectangles de 110cm sur 75cm (réellement 70 x 35 mais on compte la moitié du robot en plus par sécurité), on décide d'abord de déterminer un des coins du rectangle et plus précisément le coin en bas à droite de ce dernier:&lt;br /&gt;
&lt;br /&gt;
 void Get_One_Point_Of_The_Rectangle(float x, float &amp;amp;xA, float y, float &amp;amp;yA, float theta, float largeur, float longueur)&lt;br /&gt;
 {&lt;br /&gt;
      float x1,y1;&lt;br /&gt;
      x1 = x - cos(theta)*longueur;&lt;br /&gt;
      y1 = y - sin(theta)*longueur; &lt;br /&gt;
      xA = x1 + sin(M_PI_2-theta)*largeur;&lt;br /&gt;
      yA = y1 - cos(M_PI_2-theta)*largeur;&lt;br /&gt;
  &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
*Remplissage des positions sur la map :&lt;br /&gt;
&lt;br /&gt;
On met alors tous les points de ce rectangle à une probabilité 100 dans le vecteur Map. Pour les calculs on différencie le cas ou l'angle de la machine est entre 0 et pi/2 et le cas où il est entre pi/2 et pi. L'algorithme est le suivant : &lt;br /&gt;
&lt;br /&gt;
 A partir du coin, on incrémente x et y de sorte à longer le grand coté et de remplir chaque case (incrémentation de 5 cm).&lt;br /&gt;
 Une fois arrivé au bout, on incrémente x et y de 5cm sur la largeur à partir du coin et on recommence l'opération précédente.&lt;br /&gt;
 Ceci jusqu'à remplir le complètement le rectangle.&lt;br /&gt;
&lt;br /&gt;
Afin d'établir les probabilités correspondantes aux cases de ce rectangle, nous utilisons la fonctions floor() pour &amp;quot;convertir&amp;quot; nos flottants en entier et accéder à la case correspondante. On notera aussi que la case 1470 correspond à l'origine de notre map.&lt;br /&gt;
&lt;br /&gt;
 void Set_Machines_In_Map(float rank, float theta, float xA, float yA, nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      float x=xA;&lt;br /&gt;
      float y=yA;&lt;br /&gt;
      if (theta&amp;lt;=M_PI_2)&lt;br /&gt;
      {&lt;br /&gt;
            for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
            {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++) &lt;br /&gt;
                  {&lt;br /&gt;
                      Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                      x = x + cos(theta)*50;&lt;br /&gt;
                      y = y + sin(theta)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(M_PI_2-theta)*50;&lt;br /&gt;
                  y = yA + j*sin(M_PI_2-theta)*50;&lt;br /&gt;
            }	&lt;br /&gt;
       }&lt;br /&gt;
       if (theta&amp;gt;M_PI_2)&lt;br /&gt;
       {&lt;br /&gt;
             for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
             {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++)&lt;br /&gt;
                  {&lt;br /&gt;
                        Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                        x = x - sin(theta-M_PI_2)*50;&lt;br /&gt;
                        y = y + cos(theta-M_PI_2)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(theta-M_PI_2)*50;&lt;br /&gt;
                  y = yA - j*sin(theta-M_PI_2)*50;&lt;br /&gt;
              }	&lt;br /&gt;
        }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Ci dessous on a les mains, avec les différentes fonctions appelées et la syntaxe particulière à ROS. &lt;br /&gt;
&lt;br /&gt;
*Noeud général pour le traitement et le remplissage de la map :   &lt;br /&gt;
                 &lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
     ros::init(argc, argv, &amp;quot;server&amp;quot;);&lt;br /&gt;
     ros::NodeHandle n;&lt;br /&gt;
     ros::Subscriber sub_poses_machine    = n.subscribe(&amp;quot;/machines&amp;quot;, 1000, Poses_Machine_Callback);   // Récupération des machines&lt;br /&gt;
     ros::Publisher Map_Pub = n.advertise&amp;lt;nav_msgs::OccupancyGrid&amp;gt;(&amp;quot;/map&amp;quot;, 1000);                     // Préparation de la publication de la map&lt;br /&gt;
     ROS_INFO(&amp;quot;Ready to Generate the Map&amp;quot;);&lt;br /&gt;
     float xA,yA;&lt;br /&gt;
     ros::Rate loop_rate(1);&lt;br /&gt;
     while(ros::ok())&lt;br /&gt;
     {&lt;br /&gt;
        nav_msgs::OccupancyGrid Map;&lt;br /&gt;
        Create_Empty_Map(Map);&lt;br /&gt;
        Set_Wall(Map);&lt;br /&gt;
        for (int z=0;z&amp;lt;tab.size();z++)&lt;br /&gt;
        {&lt;br /&gt;
           Get_One_Point_Of_The_Rectangle(tab[z].x, xA, tab[z].y, yA, tab[z].theta, 275, 450);&lt;br /&gt;
 	   Set_Machines_In_Map(100, tab[z].theta, xA, yA, Map);&lt;br /&gt;
        }&lt;br /&gt;
        Map_Pub.publish(Map);                                                                   // publication de la map&lt;br /&gt;
        ros::spinOnce();&lt;br /&gt;
        loop_rate.sleep();&lt;br /&gt;
     }&lt;br /&gt;
     return 0;&lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Noeud test qui publie 2 positions de machines : &lt;br /&gt;
&lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
    ros::init(argc, argv, &amp;quot;test&amp;quot;);&lt;br /&gt;
    ros::NodeHandle n;&lt;br /&gt;
    ros::Publisher Pose_Machines_Pub = n.advertise&amp;lt;deplacement_msg::Landmarks&amp;gt;(&amp;quot;/machines&amp;quot;, 1000);&lt;br /&gt;
    ROS_INFO(&amp;quot;Ready to send poses machines&amp;quot;);&lt;br /&gt;
    int xA,yA;&lt;br /&gt;
    ros::Rate loop_rate(1);&lt;br /&gt;
    while(ros::ok())&lt;br /&gt;
    {&lt;br /&gt;
       deplacement_msg::Landmarks machines_msgs;&lt;br /&gt;
       geometry_msgs::Pose2D tab;&lt;br /&gt;
       tab.x=-2;&lt;br /&gt;
       tab.y=2;&lt;br /&gt;
       tab.theta=0;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       tab.x=5;&lt;br /&gt;
       tab.y=4;&lt;br /&gt;
       tab.theta=2.5;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       Pose_Machines_Pub.publish(machines_msgs);&lt;br /&gt;
       ros::spinOnce();&lt;br /&gt;
       loop_rate.sleep();&lt;br /&gt;
    }&lt;br /&gt;
    return 0;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On visualise le résultat grâce au logiciel RVIZ qui peut lire les topics publiés et donc le topic /map :&lt;br /&gt;
&lt;br /&gt;
===Semaine 9===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
l'objectif de cette semaine sera de coder toutes les fonctions nécessaires à l'implémentation finale du [http://fr.wikipedia.org/wiki/Filtre_de_Kalman#Filtre_de_Kalman_.C3.A9tendu filtre de Kalman étendu] :&lt;br /&gt;
&lt;br /&gt;
*initialisations des différents éléments&lt;br /&gt;
*étape de prédiction&lt;br /&gt;
*étape de mise à jour&lt;br /&gt;
*publication des positions machines et du robot dans le repère global via un topic ROS&lt;br /&gt;
&lt;br /&gt;
Le schéma ci-dessous nous montre les deux étapes du filtre de Kalman :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Kalman.png | center]]&lt;br /&gt;
&lt;br /&gt;
le code pour la partie ''prédiction'' :&lt;br /&gt;
&lt;br /&gt;
 //on ressort la position du robot pour l'état n+1&lt;br /&gt;
 //les paramètres sont le vecteurs où on a la position du robot à l'état n, la matrice P, les commandes en vitesses et le temps à l'état n&lt;br /&gt;
 Vector3d prediction(VectorXd xMean, MatrixXd &amp;amp;P, geometry_msgs::Pose2D cmdVel, ros::Time &amp;amp;temps){&lt;br /&gt;
   ros::Duration duree = ros::Time::now() - temps;&lt;br /&gt;
   double periode = duree.toSec();&amp;lt;br&amp;gt;&lt;br /&gt;
   Vector3d cmdVelVect = Pose2DToVector(cmdVel);&lt;br /&gt;
   //le xMean.topLeftCorner(3,1) correspond à la position du robot&lt;br /&gt;
   Vector3d xPredicted = xMean.topLeftCorner(3,1) + periode*cmdVelVect;&amp;lt;br&amp;gt;&lt;br /&gt;
   MatrixXd Fx;&lt;br /&gt;
   Fx = MatrixXd::Identity(P.rows(), P.cols());&lt;br /&gt;
   Fx(0,0) = xPredicted(0);&lt;br /&gt;
   Fx(1,1) = xPredicted(1);&lt;br /&gt;
   Fx(2,2) = xPredicted(2);&amp;lt;br&amp;gt;&lt;br /&gt;
   //mise à jour de P&lt;br /&gt;
   P = Fx*P*(Fx.transpose());&amp;lt;br&amp;gt;&lt;br /&gt;
   //mise à jour du temps&lt;br /&gt;
   temps = ros::Time::now();&amp;lt;br&amp;gt;&lt;br /&gt;
   return xPredicted;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
le code pour la partie ''correction'' :&lt;br /&gt;
&lt;br /&gt;
 void correction(VectorXd &amp;amp;xMean, MatrixXd &amp;amp;P, Vector3d xPredicted, geometry_msgs::Pose2D m){&lt;br /&gt;
   int taille = P.rows();&lt;br /&gt;
   //on vérifie si la machine est présente ou pas dans le vecteur d'état&lt;br /&gt;
   int i = checkStateVector(xMean, m);&amp;lt;br&amp;gt;&lt;br /&gt;
   if (i != 0){&lt;br /&gt;
     //calcul de H&lt;br /&gt;
     MatrixXd H(3, taille);&lt;br /&gt;
     H = buildH(taille, i);&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul de Pm&lt;br /&gt;
     MatrixXd Pm(taille, taille);&lt;br /&gt;
     Pm = buildPm(P, i);&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul de Z&lt;br /&gt;
     MatrixXd Z(taille, taille);&lt;br /&gt;
     Z = H*Pm*(H.transpose());	&amp;lt;br&amp;gt;&lt;br /&gt;
     //calcul du gain de Kalman&lt;br /&gt;
     MatrixXd K(taille, taille);&lt;br /&gt;
     K = P*(H.transpose())*(Z.inverse());&amp;lt;br&amp;gt;&lt;br /&gt;
     //mise à jour du vecteur xMean&lt;br /&gt;
     xMean = xMean + K*(xMean.block(xMean.rows()-3,0,3,1) - xPredicted);&amp;lt;br&amp;gt;&lt;br /&gt;
     //mise à jour de la matrice P&lt;br /&gt;
     P = P - K*Z*(K.transpose());&lt;br /&gt;
   }&lt;br /&gt;
   else {&lt;br /&gt;
     addMachine(m, xMean, P);&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Pour notre cas, on doit ajouter des nouvelles machines, alors que pour un EKF classique on observe juste des machines déjà répertoriées. Il faut donc une fonction qui permet d'ajouter une machine dans le vecteur d'état. La voilà :&lt;br /&gt;
&lt;br /&gt;
 void addMachine(geometry_msgs::Pose2D machine, VectorXd &amp;amp;xMean, MatrixXd &amp;amp;P){&lt;br /&gt;
   //on redimensionne xMean et P pour accueillir la nouvelle machines&lt;br /&gt;
   xMean.conservativeResize(xMean.rows() + 3);&lt;br /&gt;
   P.conservativeResize(P.rows()+3,P.cols()+3);&amp;lt;br&amp;gt;&lt;br /&gt;
   //on remplit avec les coordonnées de la nouvelle machine&lt;br /&gt;
   xMean(xMean.rows()-3) = machine.x;&lt;br /&gt;
   xMean(xMean.rows()-2) = machine.y;&lt;br /&gt;
   xMean(xMean.rows()-1) = machine.theta;&amp;lt;br&amp;gt;&lt;br /&gt;
   //calcul de tous les PLi&lt;br /&gt;
   //initialisation des PLi à 0&lt;br /&gt;
   P.block(P.rows() - 3, 0, 3, P.cols()).setZero();&lt;br /&gt;
   P.block(0, P.cols() - 3, P.rows(), 3).setZero();&amp;lt;br&amp;gt;&lt;br /&gt;
   for (int j = 0; j &amp;lt; xMean.rows(); j = j + 3){&lt;br /&gt;
     //position de la nouvelle machines par rapport au robot et à toutes les autres&lt;br /&gt;
     double x 	 = xMean(xMean.rows()-3) - xMean(j  );&lt;br /&gt;
     double y 	 = xMean(xMean.rows()-2) - xMean(j+1);&lt;br /&gt;
     double theta = xMean(xMean.rows()-1) - xMean(j+2);&amp;lt;br&amp;gt;&lt;br /&gt;
     P(P.rows()-3, j  ) = x;&lt;br /&gt;
     P(P.rows()-2, j+1) = y;&lt;br /&gt;
     P(P.rows()-1, j+2) = theta;&amp;lt;br&amp;gt;&lt;br /&gt;
     P(j  , P.rows()-3) = x;&lt;br /&gt;
     P(j+1, P.rows()-2) = y;&lt;br /&gt;
     P(j+2, P.rows()-1) = theta;&amp;lt;br&amp;gt;&lt;br /&gt;
     P(j  , j  ) = xMean(j  ) - xMean(0);&lt;br /&gt;
     P(j+1, j+1) = xMean(j+1) - xMean(1);&lt;br /&gt;
     P(j+2, j+2) = xMean(j+2) - xMean(2);&amp;lt;br&amp;gt;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19865</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19865"/>
				<updated>2015-04-11T16:11:56Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Localisation - Extended Kalman Filter */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - vidéo====&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les résultats de la détection des machines nous avons utiliser l'interface graphique disponible avec ROS, RVIZ. Nous visualisons alors le scan laser (points blancs), le résultat de la détection de segments (en rouge) et les positions des machines trouvées (en vert). Un premier test a été fait sur le scan originel, celui sur lequel nous avons travaillé depuis le début.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=XSn4s1y-XT0 Visualisation des machines]&lt;br /&gt;
&lt;br /&gt;
On rencontre un problème quand le robot est exactement parallèle ou perpendiculaire à un mur. Après vérification dans le programme, il s'avère que la détection ne fonctionne pas pour ces cas. Ce bug est maintenant corrigé :&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=rKeqewpuLoQ Correction du bug]&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
La première étape consiste juste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;br /&gt;
&lt;br /&gt;
la matrice correspondant au changement (laser -&amp;gt; robot) est la suivante : &lt;br /&gt;
&lt;br /&gt;
 0   -1    0&lt;br /&gt;
 1    0  0.2&lt;br /&gt;
 0    0    1&lt;br /&gt;
&lt;br /&gt;
la matrice 2x2 en haut à gauche correspond à la rotation de 90°, et le vecteur (0, 0.2) correspond à la translation.&lt;br /&gt;
&lt;br /&gt;
Celle du changement (robot -&amp;gt; global) avec alpha angle mesuré par le gyroscope depuis la position initiale (angle 0) :&lt;br /&gt;
&lt;br /&gt;
 cos(alpha)   -sin(alpha)    posInit.x&lt;br /&gt;
 sin(alpha)    cos(alpha)    posInit.y&lt;br /&gt;
          0             0            1&lt;br /&gt;
&lt;br /&gt;
l'étape suivante est de vérifier si les machines vues par le laser sont bien des machines, c'est-à-dire si les positions mesurées à partir des données lasers correspond aux zones occupées par des machines envoyées par la Referee Box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Grid Map====&lt;br /&gt;
&lt;br /&gt;
L'autre objectif de cette semaine a été de coder le noeud qui génère la map. La map est générée sous forme d'OccupancyGrid. Ce type est constitué d'un seul vecteur dont la première case correspond à la case en bas à gauche de la map. D'autres paramètres sont réglable comme l'origine et la taille.&lt;br /&gt;
&lt;br /&gt;
Pour la taille on choisit de diviser la map en case de 10 cm et l'origine choisie est le x du centre de la map et en y l'abscisse du premier mur (voir la map ci-dessous). Afin d'expliquer comment est constituée cette map, prenons le code et analysons les différentes fonctions ainsi que le main :&lt;br /&gt;
&lt;br /&gt;
Ce vecteur de Pose2D (x, y et theta (angle de la machine)) va permettre d'enregistrer la position des machines, c'est une variable global qui sera mise à jour avec le Callback :&lt;br /&gt;
&lt;br /&gt;
 std::vector&amp;lt;geometry_msgs::Pose2D&amp;gt; tab;&lt;br /&gt;
&lt;br /&gt;
*Récupération des machines envoyées par le noeud du SLAM (sur le topic /landmarks):&lt;br /&gt;
&lt;br /&gt;
 void Poses_Machine_Callback(const deplacement_msg::LandmarksConstPtr &amp;amp;machines)&lt;br /&gt;
 {&lt;br /&gt;
          tab=machines-&amp;gt;landmarks;&lt;br /&gt;
          for (int i=0; i&amp;lt;tab.size(); i++)&lt;br /&gt;
          {&lt;br /&gt;
     	     tab[i].x = tab[i].x*1000;&lt;br /&gt;
     	     tab[i].y = tab[i].y*1000;&lt;br /&gt;
 	  }&lt;br /&gt;
    &lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
*Création d'une map vide de taille 14m sur 8m. Chaque case est initialisée à une valeur nulle, on remplit également les autres paramètres de OccupancyGrid:&lt;br /&gt;
(On rappelle que la technique utilisée est un vecteur qui représente chaque case auxquelles il associe une probabilité 100 c'est un point interdit et 0 quand c'est un point sans danger pour le passage du robot)&lt;br /&gt;
&lt;br /&gt;
 void Create_Empty_Map(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      Map.info.origin.position.x=-7000;&lt;br /&gt;
      Map.info.origin.position.y=-1000;&lt;br /&gt;
      Map.info.origin.position.z=0;&lt;br /&gt;
      Map.info.origin.orientation.x=0;&lt;br /&gt;
      Map.info.origin.orientation.y=0;&lt;br /&gt;
      Map.info.origin.orientation.z=0;&lt;br /&gt;
      Map.info.origin.orientation.w=1;&lt;br /&gt;
      Map.info.map_load_time=ros::Time::now();&lt;br /&gt;
      Map.info.resolution=100;&lt;br /&gt;
      Map.info.width=140;&lt;br /&gt;
      Map.info.height=80;&lt;br /&gt;
      Map.data.assign(Map.info.width*Map.info.height, 0);                   //map vide&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
*Construction des points fixes de la map donc les murs (probabilité 100) et les zones à risques (probabilité 50):&lt;br /&gt;
&lt;br /&gt;
 void Set_Wall(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
    for (int i=0;i&amp;lt;80;i++)&lt;br /&gt;
    {&lt;br /&gt;
       for (int j=0;j&amp;lt;140;j++)&lt;br /&gt;
       {&lt;br /&gt;
          if ((i&amp;lt;13)||(i&amp;gt;67))) Map.data[j+i*140]=100;&lt;br /&gt;
          if ((j&amp;lt;13)||(j&amp;gt;127)) Map.data[j+i*140]=100;&lt;br /&gt;
       }&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Nous ne mettons pas tout le code de cette fonction étant donné qu'il est long et répétitif puisque c'est le remplissage des données connues, donc en &amp;quot;dur&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Calcul des positions machines: &lt;br /&gt;
&lt;br /&gt;
Lorsqu'on reçoit une position machine, c'est en fait son centre et son orientation par rapport à x que l'on reçoit. Etant donné que les machines doivent être des rectangles de 110cm sur 75cm (réellement 70 x 35 mais on compte la moitié du robot en plus par sécurité), on décide d'abord de déterminer un des coins du rectangle et plus précisément le coin en bas à droite de ce dernier:&lt;br /&gt;
&lt;br /&gt;
 void Get_One_Point_Of_The_Rectangle(float x, float &amp;amp;xA, float y, float &amp;amp;yA, float theta, float largeur, float longueur)&lt;br /&gt;
 {&lt;br /&gt;
      float x1,y1;&lt;br /&gt;
      x1 = x - cos(theta)*longueur;&lt;br /&gt;
      y1 = y - sin(theta)*longueur; &lt;br /&gt;
      xA = x1 + sin(M_PI_2-theta)*largeur;&lt;br /&gt;
      yA = y1 - cos(M_PI_2-theta)*largeur;&lt;br /&gt;
  &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
*Remplissage des positions sur la map :&lt;br /&gt;
&lt;br /&gt;
On met alors tous les points de ce rectangle à une probabilité 100 dans le vecteur Map. Pour les calculs on différencie le cas ou l'angle de la machine est entre 0 et pi/2 et le cas où il est entre pi/2 et pi. L'algorithme est le suivant : &lt;br /&gt;
&lt;br /&gt;
 A partir du coin, on incrémente x et y de sorte à longer le grand coté et de remplir chaque case (incrémentation de 5 cm).&lt;br /&gt;
 Une fois arrivé au bout, on incrémente x et y de 5cm sur la largeur à partir du coin et on recommence l'opération précédente.&lt;br /&gt;
 Ceci jusqu'à remplir le complètement le rectangle.&lt;br /&gt;
&lt;br /&gt;
Afin d'établir les probabilités correspondantes aux cases de ce rectangle, nous utilisons la fonctions floor() pour &amp;quot;convertir&amp;quot; nos flottants en entier et accéder à la case correspondante. On notera aussi que la case 1470 correspond à l'origine de notre map.&lt;br /&gt;
&lt;br /&gt;
 void Set_Machines_In_Map(float rank, float theta, float xA, float yA, nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      float x=xA;&lt;br /&gt;
      float y=yA;&lt;br /&gt;
      if (theta&amp;lt;=M_PI_2)&lt;br /&gt;
      {&lt;br /&gt;
            for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
            {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++) &lt;br /&gt;
                  {&lt;br /&gt;
                      Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                      x = x + cos(theta)*50;&lt;br /&gt;
                      y = y + sin(theta)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(M_PI_2-theta)*50;&lt;br /&gt;
                  y = yA + j*sin(M_PI_2-theta)*50;&lt;br /&gt;
            }	&lt;br /&gt;
       }&lt;br /&gt;
       if (theta&amp;gt;M_PI_2)&lt;br /&gt;
       {&lt;br /&gt;
             for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
             {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++)&lt;br /&gt;
                  {&lt;br /&gt;
                        Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                        x = x - sin(theta-M_PI_2)*50;&lt;br /&gt;
                        y = y + cos(theta-M_PI_2)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(theta-M_PI_2)*50;&lt;br /&gt;
                  y = yA - j*sin(theta-M_PI_2)*50;&lt;br /&gt;
              }	&lt;br /&gt;
        }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Ci dessous on a les mains, avec les différentes fonctions appelées et la syntaxe particulière à ROS. &lt;br /&gt;
&lt;br /&gt;
*Noeud général pour le traitement et le remplissage de la map :   &lt;br /&gt;
                 &lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
     ros::init(argc, argv, &amp;quot;server&amp;quot;);&lt;br /&gt;
     ros::NodeHandle n;&lt;br /&gt;
     ros::Subscriber sub_poses_machine    = n.subscribe(&amp;quot;/machines&amp;quot;, 1000, Poses_Machine_Callback);   // Récupération des machines&lt;br /&gt;
     ros::Publisher Map_Pub = n.advertise&amp;lt;nav_msgs::OccupancyGrid&amp;gt;(&amp;quot;/map&amp;quot;, 1000);                     // Préparation de la publication de la map&lt;br /&gt;
     ROS_INFO(&amp;quot;Ready to Generate the Map&amp;quot;);&lt;br /&gt;
     float xA,yA;&lt;br /&gt;
     ros::Rate loop_rate(1);&lt;br /&gt;
     while(ros::ok())&lt;br /&gt;
     {&lt;br /&gt;
        nav_msgs::OccupancyGrid Map;&lt;br /&gt;
        Create_Empty_Map(Map);&lt;br /&gt;
        Set_Wall(Map);&lt;br /&gt;
        for (int z=0;z&amp;lt;tab.size();z++)&lt;br /&gt;
        {&lt;br /&gt;
           Get_One_Point_Of_The_Rectangle(tab[z].x, xA, tab[z].y, yA, tab[z].theta, 275, 450);&lt;br /&gt;
 	   Set_Machines_In_Map(100, tab[z].theta, xA, yA, Map);&lt;br /&gt;
        }&lt;br /&gt;
        Map_Pub.publish(Map);                                                                   // publication de la map&lt;br /&gt;
        ros::spinOnce();&lt;br /&gt;
        loop_rate.sleep();&lt;br /&gt;
     }&lt;br /&gt;
     return 0;&lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Noeud test qui publie 2 positions de machines : &lt;br /&gt;
&lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
    ros::init(argc, argv, &amp;quot;test&amp;quot;);&lt;br /&gt;
    ros::NodeHandle n;&lt;br /&gt;
    ros::Publisher Pose_Machines_Pub = n.advertise&amp;lt;deplacement_msg::Landmarks&amp;gt;(&amp;quot;/machines&amp;quot;, 1000);&lt;br /&gt;
    ROS_INFO(&amp;quot;Ready to send poses machines&amp;quot;);&lt;br /&gt;
    int xA,yA;&lt;br /&gt;
    ros::Rate loop_rate(1);&lt;br /&gt;
    while(ros::ok())&lt;br /&gt;
    {&lt;br /&gt;
       deplacement_msg::Landmarks machines_msgs;&lt;br /&gt;
       geometry_msgs::Pose2D tab;&lt;br /&gt;
       tab.x=-2;&lt;br /&gt;
       tab.y=2;&lt;br /&gt;
       tab.theta=0;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       tab.x=5;&lt;br /&gt;
       tab.y=4;&lt;br /&gt;
       tab.theta=2.5;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       Pose_Machines_Pub.publish(machines_msgs);&lt;br /&gt;
       ros::spinOnce();&lt;br /&gt;
       loop_rate.sleep();&lt;br /&gt;
    }&lt;br /&gt;
    return 0;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On visualise le résultat grâce au logiciel RVIZ qui peut lire les topics publiés et donc le topic /map :&lt;br /&gt;
&lt;br /&gt;
===Semaine 9===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
l'objectif de cette semaine sera de coder toutes les fonctions nécessaires à l'implémentation finale du [http://fr.wikipedia.org/wiki/Filtre_de_Kalman#Filtre_de_Kalman_.C3.A9tendu filtre de Kalman étendu] :&lt;br /&gt;
&lt;br /&gt;
*initialisations des différents éléments&lt;br /&gt;
*étape de prédiction&lt;br /&gt;
*étape de mise à jour&lt;br /&gt;
*publication des positions machines et du robot dans le repère global via un topic ROS&lt;br /&gt;
&lt;br /&gt;
Le schéma ci-dessous nous montre les deux étapes du filtre de Kalman :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Kalman.png | center]]&lt;br /&gt;
&lt;br /&gt;
le code pour la partie ''prédiction'' :&lt;br /&gt;
&lt;br /&gt;
 //on ressort la position du robot pour l'état n+1&lt;br /&gt;
 //les paramètres sont le vecteurs où on a la position du robot à l'état n, la matrice P, les commandes en vitesses et le temps à l'état n&lt;br /&gt;
 Vector3d prediction(VectorXd xMean, MatrixXd &amp;amp;P, geometry_msgs::Pose2D cmdVel, ros::Time &amp;amp;temps){&lt;br /&gt;
   ros::Duration duree = ros::Time::now() - temps;&lt;br /&gt;
   double periode = duree.toSec();&amp;lt;br&amp;gt;&lt;br /&gt;
   Vector3d cmdVelVect = Pose2DToVector(cmdVel);&lt;br /&gt;
   //le xMean.topLeftCorner(3,1) correspond à la position du robot&lt;br /&gt;
   Vector3d xPredicted = xMean.topLeftCorner(3,1) + periode*cmdVelVect;&amp;lt;br&amp;gt;&lt;br /&gt;
   MatrixXd Fx;&lt;br /&gt;
   Fx = MatrixXd::Identity(P.rows(), P.cols());&lt;br /&gt;
   Fx(0,0) = xPredicted(0);&lt;br /&gt;
   Fx(1,1) = xPredicted(1);&lt;br /&gt;
   Fx(2,2) = xPredicted(2);&amp;lt;br&amp;gt;&lt;br /&gt;
   //mise à jour de P&lt;br /&gt;
   P = Fx*P*Fx;&amp;lt;br&amp;gt;&lt;br /&gt;
   //mise à jour du temps&lt;br /&gt;
   temps = ros::Time::now();&amp;lt;br&amp;gt;&lt;br /&gt;
   return xPredicted;&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19596</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19596"/>
				<updated>2015-04-02T08:23:40Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Génération du noeud Map */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - vidéo====&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les résultats de la détection des machines nous avons utiliser l'interface graphique disponible avec ROS, RVIZ. Nous visualisons alors le scan laser (points blancs), le résultat de la détection de segments (en rouge) et les positions des machines trouvées (en vert). Un premier test a été fait sur le scan originel, celui sur lequel nous avons travaillé depuis le début.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=XSn4s1y-XT0 Visualisation des machines]&lt;br /&gt;
&lt;br /&gt;
On rencontre un problème quand le robot est exactement parallèle ou perpendiculaire à un mur. Après vérification dans le programme, il s'avère que la détection ne fonctionne pas pour ces cas. Ce bug est maintenant corrigé :&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=rKeqewpuLoQ Correction du bug]&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
La première étape consiste juste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;br /&gt;
&lt;br /&gt;
la matrice correspondant au changement (laser -&amp;gt; robot) est la suivante : &lt;br /&gt;
&lt;br /&gt;
 0   -1    0&lt;br /&gt;
 1    0  0.2&lt;br /&gt;
 0    0    1&lt;br /&gt;
&lt;br /&gt;
la matrice 2x2 en haut à gauche correspond à la rotation de 90°, et le vecteur (0, 0.2) correspond à la translation.&lt;br /&gt;
&lt;br /&gt;
Celle du changement (robot -&amp;gt; global) avec alpha angle mesuré par le gyroscope depuis la position initiale (angle 0) :&lt;br /&gt;
&lt;br /&gt;
 cos(alpha)   -sin(alpha)    posInit.x&lt;br /&gt;
 sin(alpha)    cos(alpha)    posInit.y&lt;br /&gt;
          0             0            1&lt;br /&gt;
&lt;br /&gt;
l'étape suivante est de vérifier si les machines vues par le laser sont bien des machines, c'est-à-dire si les positions mesurées à partir des données lasers correspond aux zones occupées par des machines envoyées par la Referee Box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Grid Map====&lt;br /&gt;
&lt;br /&gt;
L'autre objectif de cette semaine a été de coder le noeud qui génère la map. La map est générée sous forme d'OccupancyGrid. Ce type est constitué d'un seul vecteur dont la première case correspond à la case en bas à gauche de la map. D'autres paramètres sont réglable comme l'origine et la taille.&lt;br /&gt;
&lt;br /&gt;
Pour la taille on choisit de diviser la map en case de 10 cm et l'origine choisie est le x du centre de la map et en y l'abscisse du premier mur (voir la map ci-dessous). Afin d'expliquer comment est constituée cette map, prenons le code et analysons les différentes fonctions ainsi que le main :&lt;br /&gt;
&lt;br /&gt;
Ce vecteur de Pose2D (x, y et theta (angle de la machine)) va permettre d'enregistrer la position des machines, c'est une variable global qui sera mise à jour avec le Callback :&lt;br /&gt;
&lt;br /&gt;
 std::vector&amp;lt;geometry_msgs::Pose2D&amp;gt; tab;&lt;br /&gt;
&lt;br /&gt;
*Récupération des machines envoyées par le noeud du SLAM (sur le topic /landmarks):&lt;br /&gt;
&lt;br /&gt;
 void Poses_Machine_Callback(const deplacement_msg::LandmarksConstPtr &amp;amp;machines)&lt;br /&gt;
 {&lt;br /&gt;
          tab=machines-&amp;gt;landmarks;&lt;br /&gt;
          for (int i=0; i&amp;lt;tab.size(); i++)&lt;br /&gt;
          {&lt;br /&gt;
     	     tab[i].x = tab[i].x*1000;&lt;br /&gt;
     	     tab[i].y = tab[i].y*1000;&lt;br /&gt;
 	  }&lt;br /&gt;
    &lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
*Création d'une map vide de taille 14m sur 8m. Chaque case est initialisée à une valeur nulle, on remplit également les autres paramètres de OccupancyGrid:&lt;br /&gt;
(On rappelle que la technique utilisée est un vecteur qui représente chaque case auxquelles il associe une probabilité 100 c'est un point interdit et 0 quand c'est un point sans danger pour le passage du robot)&lt;br /&gt;
&lt;br /&gt;
 void Create_Empty_Map(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      Map.info.origin.position.x=-7000;&lt;br /&gt;
      Map.info.origin.position.y=-1000;&lt;br /&gt;
      Map.info.origin.position.z=0;&lt;br /&gt;
      Map.info.origin.orientation.x=0;&lt;br /&gt;
      Map.info.origin.orientation.y=0;&lt;br /&gt;
      Map.info.origin.orientation.z=0;&lt;br /&gt;
      Map.info.origin.orientation.w=1;&lt;br /&gt;
      Map.info.map_load_time=ros::Time::now();&lt;br /&gt;
      Map.info.resolution=100;&lt;br /&gt;
      Map.info.width=140;&lt;br /&gt;
      Map.info.height=80;&lt;br /&gt;
      Map.data.assign(Map.info.width*Map.info.height, 0);                   //map vide&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
*Construction des points fixes de la map donc les murs (probabilité 100) et les zones à risques (probabilité 50):&lt;br /&gt;
&lt;br /&gt;
 void Set_Wall(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
    for (int i=0;i&amp;lt;80;i++)&lt;br /&gt;
    {&lt;br /&gt;
       for (int j=0;j&amp;lt;140;j++)&lt;br /&gt;
       {&lt;br /&gt;
          if ((i&amp;lt;13)||(i&amp;gt;67))) Map.data[j+i*140]=100;&lt;br /&gt;
          if ((j&amp;lt;13)||(j&amp;gt;127)) Map.data[j+i*140]=100;&lt;br /&gt;
       }&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Nous ne mettons pas tout le code de cette fonction étant donné qu'il est long et répétitif puisque c'est le remplissage des données connues, donc en &amp;quot;dur&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Calcul des positions machines: &lt;br /&gt;
&lt;br /&gt;
Lorsqu'on reçoit une position machine, c'est en fait son centre et son orientation par rapport à x que l'on reçoit. Etant donné que les machines doivent être des rectangles de 110cm sur 75cm (réellement 70 x 35 mais on compte la moitié du robot en plus par sécurité), on décide d'abord de déterminer un des coins du rectangle et plus précisément le coin en bas à droite de ce dernier:&lt;br /&gt;
&lt;br /&gt;
 void Get_One_Point_Of_The_Rectangle(float x, float &amp;amp;xA, float y, float &amp;amp;yA, float theta, float largeur, float longueur)&lt;br /&gt;
 {&lt;br /&gt;
      float x1,y1;&lt;br /&gt;
      x1 = x - cos(theta)*longueur;&lt;br /&gt;
      y1 = y - sin(theta)*longueur; &lt;br /&gt;
      xA = x1 + sin(M_PI_2-theta)*largeur;&lt;br /&gt;
      yA = y1 - cos(M_PI_2-theta)*largeur;&lt;br /&gt;
  &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
*Remplissage des positions sur la map :&lt;br /&gt;
&lt;br /&gt;
On met alors tous les points de ce rectangle à une probabilité 100 dans le vecteur Map. Pour les calculs on différencie le cas ou l'angle de la machine est entre 0 et pi/2 et le cas où il est entre pi/2 et pi. L'algorithme est le suivant : &lt;br /&gt;
&lt;br /&gt;
 A partir du coin, on incrémente x et y de sorte à longer le grand coté et de remplir chaque case (incrémentation de 5 cm).&lt;br /&gt;
 Une fois arrivé au bout, on incrémente x et y de 5cm sur la largeur à partir du coin et on recommence l'opération précédente.&lt;br /&gt;
 Ceci jusqu'à remplir le complètement le rectangle.&lt;br /&gt;
&lt;br /&gt;
Afin d'établir les probabilités correspondantes aux cases de ce rectangle, nous utilisons la fonctions floor() pour &amp;quot;convertir&amp;quot; nos flottants en entier et accéder à la case correspondante. On notera aussi que la case 1470 correspond à l'origine de notre map.&lt;br /&gt;
&lt;br /&gt;
 void Set_Machines_In_Map(float rank, float theta, float xA, float yA, nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      float x=xA;&lt;br /&gt;
      float y=yA;&lt;br /&gt;
      if (theta&amp;lt;=M_PI_2)&lt;br /&gt;
      {&lt;br /&gt;
            for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
            {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++) &lt;br /&gt;
                  {&lt;br /&gt;
                      Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                      x = x + cos(theta)*50;&lt;br /&gt;
                      y = y + sin(theta)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(M_PI_2-theta)*50;&lt;br /&gt;
                  y = yA + j*sin(M_PI_2-theta)*50;&lt;br /&gt;
            }	&lt;br /&gt;
       }&lt;br /&gt;
       if (theta&amp;gt;M_PI_2)&lt;br /&gt;
       {&lt;br /&gt;
             for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
             {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++)&lt;br /&gt;
                  {&lt;br /&gt;
                        Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                        x = x - sin(theta-M_PI_2)*50;&lt;br /&gt;
                        y = y + cos(theta-M_PI_2)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(theta-M_PI_2)*50;&lt;br /&gt;
                  y = yA - j*sin(theta-M_PI_2)*50;&lt;br /&gt;
              }	&lt;br /&gt;
        }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Ci dessous on a les mains, avec les différentes fonctions appelées et la syntaxe particulière à ROS. &lt;br /&gt;
&lt;br /&gt;
*Noeud général pour le traitement et le remplissage de la map :   &lt;br /&gt;
                 &lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
     ros::init(argc, argv, &amp;quot;server&amp;quot;);&lt;br /&gt;
     ros::NodeHandle n;&lt;br /&gt;
     ros::Subscriber sub_poses_machine    = n.subscribe(&amp;quot;/machines&amp;quot;, 1000, Poses_Machine_Callback);   // Récupération des machines&lt;br /&gt;
     ros::Publisher Map_Pub = n.advertise&amp;lt;nav_msgs::OccupancyGrid&amp;gt;(&amp;quot;/map&amp;quot;, 1000);                     // Préparation de la publication de la map&lt;br /&gt;
     ROS_INFO(&amp;quot;Ready to Generate the Map&amp;quot;);&lt;br /&gt;
     float xA,yA;&lt;br /&gt;
     ros::Rate loop_rate(1);&lt;br /&gt;
     while(ros::ok())&lt;br /&gt;
     {&lt;br /&gt;
        nav_msgs::OccupancyGrid Map;&lt;br /&gt;
        Create_Empty_Map(Map);&lt;br /&gt;
        Set_Wall(Map);&lt;br /&gt;
        for (int z=0;z&amp;lt;tab.size();z++)&lt;br /&gt;
        {&lt;br /&gt;
           Get_One_Point_Of_The_Rectangle(tab[z].x, xA, tab[z].y, yA, tab[z].theta, 275, 450);&lt;br /&gt;
 	   Set_Machines_In_Map(100, tab[z].theta, xA, yA, Map);&lt;br /&gt;
        }&lt;br /&gt;
        Map_Pub.publish(Map);                                                                   // publication de la map&lt;br /&gt;
        ros::spinOnce();&lt;br /&gt;
        loop_rate.sleep();&lt;br /&gt;
     }&lt;br /&gt;
     return 0;&lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Noeud test qui publie 2 positions de machines : &lt;br /&gt;
&lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
    ros::init(argc, argv, &amp;quot;test&amp;quot;);&lt;br /&gt;
    ros::NodeHandle n;&lt;br /&gt;
    ros::Publisher Pose_Machines_Pub = n.advertise&amp;lt;deplacement_msg::Landmarks&amp;gt;(&amp;quot;/machines&amp;quot;, 1000);&lt;br /&gt;
    ROS_INFO(&amp;quot;Ready to send poses machines&amp;quot;);&lt;br /&gt;
    int xA,yA;&lt;br /&gt;
    ros::Rate loop_rate(1);&lt;br /&gt;
    while(ros::ok())&lt;br /&gt;
    {&lt;br /&gt;
       deplacement_msg::Landmarks machines_msgs;&lt;br /&gt;
       geometry_msgs::Pose2D tab;&lt;br /&gt;
       tab.x=-2;&lt;br /&gt;
       tab.y=2;&lt;br /&gt;
       tab.theta=0;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       tab.x=5;&lt;br /&gt;
       tab.y=4;&lt;br /&gt;
       tab.theta=2.5;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       Pose_Machines_Pub.publish(machines_msgs);&lt;br /&gt;
       ros::spinOnce();&lt;br /&gt;
       loop_rate.sleep();&lt;br /&gt;
    }&lt;br /&gt;
    return 0;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On visualise le résultat grâce au logiciel RVIZ qui peut lire les topics publiés et donc le topic /map :&lt;br /&gt;
&lt;br /&gt;
===Semaine 9===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
l'objectif de cette semaine sera de coder toutes les fonctions nécessaires à l'implémentation finale du [http://fr.wikipedia.org/wiki/Filtre_de_Kalman#Filtre_de_Kalman_.C3.A9tendu filtre de Kalman étendu] :&lt;br /&gt;
&lt;br /&gt;
*initialisations des différents éléments&lt;br /&gt;
*étape de prédiction&lt;br /&gt;
*étape de mise à jour&lt;br /&gt;
*publication des positions machines et du robot dans le repère global via un topic ROS&lt;br /&gt;
&lt;br /&gt;
Le schéma ci-dessous nous montre les deux étapes du filtre de Kalman :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Kalman.png | center]]&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19587</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19587"/>
				<updated>2015-04-01T15:28:11Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Génération du noeud Map */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - vidéo====&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les résultats de la détection des machines nous avons utiliser l'interface graphique disponible avec ROS, RVIZ. Nous visualisons alors le scan laser (points blancs), le résultat de la détection de segments (en rouge) et les positions des machines trouvées (en vert). Un premier test a été fait sur le scan originel, celui sur lequel nous avons travaillé depuis le début.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=XSn4s1y-XT0 Visualisation des machines]&lt;br /&gt;
&lt;br /&gt;
On rencontre un problème quand le robot est exactement parallèle ou perpendiculaire à un mur. Après vérification dans le programme, il s'avère que la détection ne fonctionne pas pour ces cas. Ce bug est maintenant corrigé :&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=rKeqewpuLoQ Correction du bug]&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
La première étape consiste juste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;br /&gt;
&lt;br /&gt;
la matrice correspondant au changement (laser -&amp;gt; robot) est la suivante : &lt;br /&gt;
&lt;br /&gt;
 0   -1    0&lt;br /&gt;
 1    0  0.2&lt;br /&gt;
 0    0    1&lt;br /&gt;
&lt;br /&gt;
la matrice 2x2 en haut à gauche correspond à la rotation de 90°, et le vecteur (0, 0.2) correspond à la translation.&lt;br /&gt;
&lt;br /&gt;
Celle du changement (robot -&amp;gt; global) avec alpha angle mesuré par le gyroscope depuis la position initiale (angle 0) :&lt;br /&gt;
&lt;br /&gt;
 cos(alpha)   -sin(alpha)    posInit.x&lt;br /&gt;
 sin(alpha)    cos(alpha)    posInit.y&lt;br /&gt;
          0             0            1&lt;br /&gt;
&lt;br /&gt;
l'étape suivante est de vérifier si les machines vues par le laser sont bien des machines, c'est-à-dire si les positions mesurées à partir des données lasers correspond aux zones occupées par des machines envoyées par la Referee Box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Génération du noeud Map====&lt;br /&gt;
&lt;br /&gt;
L'autre objectif de cette semaine a été de coder le noeud qui génère la map. La map est générée sous forme d'OccupancyGrid. Ce type est constitué d'un seul vecteur dont la première case correspond à la case en bas à gauche de la map. D'autres paramètres sont réglable comme l'origine et la taille.&lt;br /&gt;
&lt;br /&gt;
Pour la taille on choisit de diviser la map en case de 10 cm et l'origine choisie est le x du centre de la map et en y l'abscisse du premier mur (voir la map ci-dessous). Afin d'expliquer comment est constituée cette map, prenons le code et analysons les différentes fonctions ainsi que le main :&lt;br /&gt;
&lt;br /&gt;
Ce vecteur de Pose2D (x, y et theta (angle de la machine)) va permettre d'enregistrer la position des machines, c'est une variable global qui sera mise à jour avec le Callback :&lt;br /&gt;
&lt;br /&gt;
 std::vector&amp;lt;geometry_msgs::Pose2D&amp;gt; tab;&lt;br /&gt;
&lt;br /&gt;
*Récupération des machines envoyées par le noeud du SLAM (sur le topic /landmarks):&lt;br /&gt;
&lt;br /&gt;
 void Poses_Machine_Callback(const deplacement_msg::LandmarksConstPtr &amp;amp;machines)&lt;br /&gt;
 {&lt;br /&gt;
          tab=machines-&amp;gt;landmarks;&lt;br /&gt;
          for (int i=0; i&amp;lt;tab.size(); i++)&lt;br /&gt;
          {&lt;br /&gt;
     	     tab[i].x = tab[i].x*1000;&lt;br /&gt;
     	     tab[i].y = tab[i].y*1000;&lt;br /&gt;
 	  }&lt;br /&gt;
    &lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
*Création d'une map vide de taille 14m sur 8m. Chaque case est initialisée à une valeur nulle, on remplit également les autres paramètres de OccupancyGrid:&lt;br /&gt;
(On rappelle que la technique utilisée est un vecteur qui représente chaque case auxquelles il associe une probabilité 100 c'est un point interdit et 0 quand c'est un point sans danger pour le passage du robot)&lt;br /&gt;
&lt;br /&gt;
 void Create_Empty_Map(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      Map.info.origin.position.x=-7000;&lt;br /&gt;
      Map.info.origin.position.y=-1000;&lt;br /&gt;
      Map.info.origin.position.z=0;&lt;br /&gt;
      Map.info.origin.orientation.x=0;&lt;br /&gt;
      Map.info.origin.orientation.y=0;&lt;br /&gt;
      Map.info.origin.orientation.z=0;&lt;br /&gt;
      Map.info.origin.orientation.w=1;&lt;br /&gt;
      Map.info.map_load_time=ros::Time::now();&lt;br /&gt;
      Map.info.resolution=100;&lt;br /&gt;
      Map.info.width=140;&lt;br /&gt;
      Map.info.height=80;&lt;br /&gt;
      Map.data.assign(Map.info.width*Map.info.height, 0);                   //map vide&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
*Construction des points fixes de la map donc les murs (probabilité 100) et les zones à risques (probabilité 50):&lt;br /&gt;
&lt;br /&gt;
 void Set_Wall(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
    for (int i=0;i&amp;lt;80;i++)&lt;br /&gt;
    {&lt;br /&gt;
       for (int j=0;j&amp;lt;140;j++)&lt;br /&gt;
       {&lt;br /&gt;
          if ((i&amp;lt;13)||(i&amp;gt;67))) Map.data[j+i*140]=100;&lt;br /&gt;
          if ((j&amp;lt;13)||(j&amp;gt;127)) Map.data[j+i*140]=100;&lt;br /&gt;
       }&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Nous ne mettons pas tout le code de cette fonction étant donné qu'il est long et répétitif puisque c'est le remplissage des données connues, donc en &amp;quot;dur&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*Calcul des positions machines: &lt;br /&gt;
&lt;br /&gt;
Lorsqu'on reçoit une position machine, c'est en fait son centre et son orientation par rapport à x que l'on reçoit. Etant donné que les machines doivent être des rectangles de 110cm sur 75cm (réellement 70 x 35 mais on compte la moitié du robot en plus par sécurité), on décide d'abord de déterminer un des coins du rectangle et plus précisément le coin en bas à droite de ce dernier:&lt;br /&gt;
&lt;br /&gt;
 void Get_One_Point_Of_The_Rectangle(float x, float &amp;amp;xA, float y, float &amp;amp;yA, float theta, float largeur, float longueur)&lt;br /&gt;
 {&lt;br /&gt;
      float x1,y1;&lt;br /&gt;
      x1 = x - cos(theta)*longueur;&lt;br /&gt;
      y1 = y - sin(theta)*longueur; &lt;br /&gt;
      xA = x1 + sin(M_PI_2-theta)*largeur;&lt;br /&gt;
      yA = y1 - cos(M_PI_2-theta)*largeur;&lt;br /&gt;
  &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
*Remplissage des positions sur la map :&lt;br /&gt;
&lt;br /&gt;
On met alors tous les points de ce rectangle à une probabilité 100 dans le vecteur Map. Pour les calculs on différencie le cas ou l'angle de la machine est entre 0 et pi/2 et le cas où il est entre pi/2 et pi. L'algorithme est le suivant : &lt;br /&gt;
&lt;br /&gt;
 A partir du coin, on incrémente x et y de sorte à longer le grand coté et de remplir chaque case (incrémentation de 5 cm).&lt;br /&gt;
 Une fois arrivé au bout, on incrémente x et y de 5cm sur la largeur à partir du coin et on recommence l'opération précédente.&lt;br /&gt;
 Ceci jusqu'à remplir le complètement le rectangle.&lt;br /&gt;
&lt;br /&gt;
Afin d'établir les probabilités correspondantes aux cases de ce rectangle, nous utilisons la fonctions floor() pour &amp;quot;convertir&amp;quot; nos flottants en entier et accéder à la case correspondante. On notera aussi que la case 1470 correspond à l'origine de notre map.&lt;br /&gt;
&lt;br /&gt;
 void Set_Machines_In_Map(float rank, float theta, float xA, float yA, nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      float x=xA;&lt;br /&gt;
      float y=yA;&lt;br /&gt;
      if (theta&amp;lt;=M_PI_2)&lt;br /&gt;
      {&lt;br /&gt;
            for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
            {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++) &lt;br /&gt;
                  {&lt;br /&gt;
                      Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                      x = x + cos(theta)*50;&lt;br /&gt;
                      y = y + sin(theta)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(M_PI_2-theta)*50;&lt;br /&gt;
                  y = yA + j*sin(M_PI_2-theta)*50;&lt;br /&gt;
            }	&lt;br /&gt;
       }&lt;br /&gt;
       if (theta&amp;gt;M_PI_2)&lt;br /&gt;
       {&lt;br /&gt;
             for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
             {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++)&lt;br /&gt;
                  {&lt;br /&gt;
                        Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                        x = x - sin(theta-M_PI_2)*50;&lt;br /&gt;
                        y = y + cos(theta-M_PI_2)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(theta-M_PI_2)*50;&lt;br /&gt;
                  y = yA - j*sin(theta-M_PI_2)*50;&lt;br /&gt;
              }	&lt;br /&gt;
        }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Ci dessous on a les mains, avec les différentes fonctions appelées et la syntaxe particulière à ROS. &lt;br /&gt;
&lt;br /&gt;
*Noeud général pour le traitement et le remplissage de la map :   &lt;br /&gt;
                 &lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
     ros::init(argc, argv, &amp;quot;server&amp;quot;);&lt;br /&gt;
     ros::NodeHandle n;&lt;br /&gt;
     ros::Subscriber sub_poses_machine    = n.subscribe(&amp;quot;/machines&amp;quot;, 1000, Poses_Machine_Callback);   // Récupération des machines&lt;br /&gt;
     ros::Publisher Map_Pub = n.advertise&amp;lt;nav_msgs::OccupancyGrid&amp;gt;(&amp;quot;/map&amp;quot;, 1000);                     // Préparation de la publication de la map&lt;br /&gt;
     ROS_INFO(&amp;quot;Ready to Generate the Map&amp;quot;);&lt;br /&gt;
     float xA,yA;&lt;br /&gt;
     ros::Rate loop_rate(1);&lt;br /&gt;
     while(ros::ok())&lt;br /&gt;
     {&lt;br /&gt;
        nav_msgs::OccupancyGrid Map;&lt;br /&gt;
        Create_Empty_Map(Map);&lt;br /&gt;
        Set_Wall(Map);&lt;br /&gt;
        for (int z=0;z&amp;lt;tab.size();z++)&lt;br /&gt;
        {&lt;br /&gt;
           Get_One_Point_Of_The_Rectangle(tab[z].x, xA, tab[z].y, yA, tab[z].theta, 275, 450);&lt;br /&gt;
 	   Set_Machines_In_Map(100, tab[z].theta, xA, yA, Map);&lt;br /&gt;
        }&lt;br /&gt;
        Map_Pub.publish(Map);                                                                   // publication de la map&lt;br /&gt;
        ros::spinOnce();&lt;br /&gt;
        loop_rate.sleep();&lt;br /&gt;
     }&lt;br /&gt;
     return 0;&lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Noeud test qui publie 2 positions de machines : &lt;br /&gt;
&lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
    ros::init(argc, argv, &amp;quot;test&amp;quot;);&lt;br /&gt;
    ros::NodeHandle n;&lt;br /&gt;
    ros::Publisher Pose_Machines_Pub = n.advertise&amp;lt;deplacement_msg::Landmarks&amp;gt;(&amp;quot;/machines&amp;quot;, 1000);&lt;br /&gt;
    ROS_INFO(&amp;quot;Ready to send poses machines&amp;quot;);&lt;br /&gt;
    int xA,yA;&lt;br /&gt;
    ros::Rate loop_rate(1);&lt;br /&gt;
    while(ros::ok())&lt;br /&gt;
    {&lt;br /&gt;
       deplacement_msg::Landmarks machines_msgs;&lt;br /&gt;
       geometry_msgs::Pose2D tab;&lt;br /&gt;
       tab.x=-2;&lt;br /&gt;
       tab.y=2;&lt;br /&gt;
       tab.theta=0;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       tab.x=5;&lt;br /&gt;
       tab.y=4;&lt;br /&gt;
       tab.theta=2.5;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       Pose_Machines_Pub.publish(machines_msgs);&lt;br /&gt;
       ros::spinOnce();&lt;br /&gt;
       loop_rate.sleep();&lt;br /&gt;
    }&lt;br /&gt;
    return 0;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On visualise le résultat grâce au logiciel RVIZ qui peut lire les topics publiés et donc le topic /map :&lt;br /&gt;
&lt;br /&gt;
===Semaine 9===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
l'objectif de cette semaine sera de coder toutes les fonctions nécessaires à l'implémentation finale du [http://fr.wikipedia.org/wiki/Filtre_de_Kalman#Filtre_de_Kalman_.C3.A9tendu filtre de Kalman étendu] :&lt;br /&gt;
&lt;br /&gt;
*initialisations des différents éléments&lt;br /&gt;
*étape de prédiction&lt;br /&gt;
*étape de mise à jour&lt;br /&gt;
*publication des positions machines et du robot dans le repère global via un topic ROS&lt;br /&gt;
&lt;br /&gt;
Le schéma ci-dessous nous montre les deux étapes du filtre de Kalman :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Kalman.png | center]]&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19586</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19586"/>
				<updated>2015-04-01T15:23:23Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Génération du noeud Map */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - vidéo====&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les résultats de la détection des machines nous avons utiliser l'interface graphique disponible avec ROS, RVIZ. Nous visualisons alors le scan laser (points blancs), le résultat de la détection de segments (en rouge) et les positions des machines trouvées (en vert). Un premier test a été fait sur le scan originel, celui sur lequel nous avons travaillé depuis le début.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=XSn4s1y-XT0 Visualisation des machines]&lt;br /&gt;
&lt;br /&gt;
On rencontre un problème quand le robot est exactement parallèle ou perpendiculaire à un mur. Après vérification dans le programme, il s'avère que la détection ne fonctionne pas pour ces cas. Ce bug est maintenant corrigé :&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=rKeqewpuLoQ Correction du bug]&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
La première étape consiste juste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;br /&gt;
&lt;br /&gt;
la matrice correspondant au changement (laser -&amp;gt; robot) est la suivante : &lt;br /&gt;
&lt;br /&gt;
 0   -1    0&lt;br /&gt;
 1    0  0.2&lt;br /&gt;
 0    0    1&lt;br /&gt;
&lt;br /&gt;
la matrice 2x2 en haut à gauche correspond à la rotation de 90°, et le vecteur (0, 0.2) correspond à la translation.&lt;br /&gt;
&lt;br /&gt;
Celle du changement (robot -&amp;gt; global) avec alpha angle mesuré par le gyroscope depuis la position initiale (angle 0) :&lt;br /&gt;
&lt;br /&gt;
 cos(alpha)   -sin(alpha)    posInit.x&lt;br /&gt;
 sin(alpha)    cos(alpha)    posInit.y&lt;br /&gt;
          0             0            1&lt;br /&gt;
&lt;br /&gt;
l'étape suivante est de vérifier si les machines vues par le laser sont bien des machines, c'est-à-dire si les positions mesurées à partir des données lasers correspond aux zones occupées par des machines envoyées par la Referee Box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Génération du noeud Map====&lt;br /&gt;
&lt;br /&gt;
L'autre objectif de cette semaine a été de coder le noeud qui génère la map. La map est générée sous forme d'OccupancyGrid. Ce type est constitué d'un seul vecteur dont la première case correspond à la case en bas à gauche de la map. D'autres paramètres sont réglable comme l'origine et la taille.&lt;br /&gt;
&lt;br /&gt;
Pour la taille on choisit de diviser la map en case de 10 cm et l'origine choisie est le x du centre de la map et en y l'abscisse du premier mur (voir la map ci-dessous). Afin d'expliquer comment est constituée cette map, prenons le code et analysons les différentes fonctions ainsi que le main :&lt;br /&gt;
&lt;br /&gt;
Ce vecteur de Pose2D (x, y et theta (angle de la machine)) va permettre d'enregistrer la position des machines, c'est une variable global qui sera mise à jour avec le Callback :&lt;br /&gt;
&lt;br /&gt;
 std::vector&amp;lt;geometry_msgs::Pose2D&amp;gt; tab;&lt;br /&gt;
&lt;br /&gt;
*Récupération des machines envoyées par le noeud du SLAM (sur le topic /landmarks):&lt;br /&gt;
&lt;br /&gt;
 void Poses_Machine_Callback(const deplacement_msg::LandmarksConstPtr &amp;amp;machines)&lt;br /&gt;
 {&lt;br /&gt;
          tab=machines-&amp;gt;landmarks;&lt;br /&gt;
          for (int i=0; i&amp;lt;tab.size(); i++)&lt;br /&gt;
          {&lt;br /&gt;
     	     tab[i].x = tab[i].x*1000;&lt;br /&gt;
     	     tab[i].y = tab[i].y*1000;&lt;br /&gt;
 	  }&lt;br /&gt;
    &lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
*Création d'une map vide de taille 14m sur 8m. Chaque case est initialisée à une valeur nulle, on remplit également les autres paramètres de OccupancyGrid:&lt;br /&gt;
(On rappelle que la technique utilisée est un vecteur qui représente chaque case auxquelles il associe une probabilité 100 c'est un point interdit et 0 quand c'est un point sans danger pour le passage du robot)&lt;br /&gt;
&lt;br /&gt;
 void Create_Empty_Map(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      Map.info.origin.position.x=-7000;&lt;br /&gt;
      Map.info.origin.position.y=-1000;&lt;br /&gt;
      Map.info.origin.position.z=0;&lt;br /&gt;
      Map.info.origin.orientation.x=0;&lt;br /&gt;
      Map.info.origin.orientation.y=0;&lt;br /&gt;
      Map.info.origin.orientation.z=0;&lt;br /&gt;
      Map.info.origin.orientation.w=1;&lt;br /&gt;
      Map.info.map_load_time=ros::Time::now();&lt;br /&gt;
      Map.info.resolution=100;&lt;br /&gt;
      Map.info.width=140;&lt;br /&gt;
      Map.info.height=80;&lt;br /&gt;
&lt;br /&gt;
      Map.data.assign(Map.info.width*Map.info.height, 0);                   //map vide&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
*Construction des points fixes de la map donc les murs (probabilité 100) et les zones à risques (probabilité 50):&lt;br /&gt;
&lt;br /&gt;
 void Set_Wall(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
    for (int i=0;i&amp;lt;80;i++)&lt;br /&gt;
    {&lt;br /&gt;
       for (int j=0;j&amp;lt;140;j++)&lt;br /&gt;
       {	&lt;br /&gt;
	  if ((i&amp;lt;13)||(i&amp;gt;67))) Map.data[j+i*140]=100;&lt;br /&gt;
          if ((j&amp;lt;13)||(j&amp;gt;127)) Map.data[j+i*140]=100;&lt;br /&gt;
       }&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Nous ne mettons pas tout le code de cette fonction étant donné qu'il est long et répétitif puisque c'est le remplissage des données connues, donc en &amp;quot;dur&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Maintenant, nous passons aux positions machines: &lt;br /&gt;
&lt;br /&gt;
Lorsqu'on reçoit une position machine, c'est en fait son centre et son orientation par rapport à x que l'on reçoit.&lt;br /&gt;
Etant donné que les machines doivent être des rectangles de 110cm sur 75cm (réellement 70 x 35 mais on compte la moitié du robot par sécurité), on décide d'abord de déterminer un des coins du rectangle et plus précisément le coin en bas à droite de ce dernier:&lt;br /&gt;
&lt;br /&gt;
 void Get_One_Point_Of_The_Rectangle(float x, float &amp;amp;xA, float y, float &amp;amp;yA, float theta, float largeur, float longueur)&lt;br /&gt;
 {&lt;br /&gt;
      float x1,y1;&lt;br /&gt;
      x1 = x - cos(theta)*longueur;&lt;br /&gt;
      y1 = y - sin(theta)*longueur; &lt;br /&gt;
      xA = x1 + sin(M_PI_2-theta)*largeur;&lt;br /&gt;
      yA = y1 - cos(M_PI_2-theta)*largeur;&lt;br /&gt;
  &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Il reste ensuite à mettre tout les points de se rectangles à une probabilité 100 dans le vecteur Map.&lt;br /&gt;
Pour les calculs on différencie le cas ou l'angle de la machine est entre 0 et pi/2 et le cas où il est entre pi/2 et pi.&lt;br /&gt;
L'algorithme est le suivant : &lt;br /&gt;
&lt;br /&gt;
A partir du coin, on incrémente x et y de sorte à longer le grand coté et de remplir chaque case (incrémentation de 5 cm).&lt;br /&gt;
Une fois arrivé au bout, on incrémente x et y de 5cm sur la largeur à partir du coin et on recommence l'opération précédente.&lt;br /&gt;
Ceci jusqu'à remplir le complètement le rectangle.&lt;br /&gt;
&lt;br /&gt;
Afin d'établir les probabilités de ce rectangle, nous utilisons la fonctions floor pour convertir nos flottants en entier et accéder à la case correspondante. On notera aussi que la case 1470 correspond à l'origine de notre map.&lt;br /&gt;
&lt;br /&gt;
 void Set_Machines_In_Map(float rank, float theta, float xA, float yA, nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      float x=xA;&lt;br /&gt;
      float y=yA;&lt;br /&gt;
      if (theta&amp;lt;=M_PI_2)&lt;br /&gt;
      {&lt;br /&gt;
            for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
            {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++) &lt;br /&gt;
                  {&lt;br /&gt;
                      Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                      x = x + cos(theta)*50;&lt;br /&gt;
                      y = y + sin(theta)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(M_PI_2-theta)*50;&lt;br /&gt;
                  y = yA + j*sin(M_PI_2-theta)*50;&lt;br /&gt;
            }	&lt;br /&gt;
       }&lt;br /&gt;
       if (theta&amp;gt;M_PI_2)&lt;br /&gt;
       {&lt;br /&gt;
             for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
             {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++)&lt;br /&gt;
                  {&lt;br /&gt;
                        Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                        x = x - sin(theta-M_PI_2)*50;&lt;br /&gt;
                        y = y + cos(theta-M_PI_2)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(theta-M_PI_2)*50;&lt;br /&gt;
                  y = yA - j*sin(theta-M_PI_2)*50;&lt;br /&gt;
              }	&lt;br /&gt;
        }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Ci dessous on a les mains, avec les différentes fonctions et la syntaxe particulière à ROS. &lt;br /&gt;
&lt;br /&gt;
*Noeud général pour le traitement et le remplissage de la map :   &lt;br /&gt;
                 &lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
     ros::init(argc, argv, &amp;quot;server&amp;quot;);&lt;br /&gt;
     ros::NodeHandle n;&lt;br /&gt;
     ros::Subscriber sub_poses_machine    = n.subscribe(&amp;quot;/machines&amp;quot;, 1000, Poses_Machine_Callback);   // Récupération des machines&lt;br /&gt;
     ros::Publisher Map_Pub = n.advertise&amp;lt;nav_msgs::OccupancyGrid&amp;gt;(&amp;quot;/map&amp;quot;, 1000);                     // Préparation de la publication de la map&lt;br /&gt;
     ROS_INFO(&amp;quot;Ready to Generate the Map&amp;quot;);&lt;br /&gt;
     float xA,yA;&lt;br /&gt;
     ros::Rate loop_rate(1);&lt;br /&gt;
     while(ros::ok())&lt;br /&gt;
     {&lt;br /&gt;
        nav_msgs::OccupancyGrid Map;&lt;br /&gt;
        Create_Empty_Map(Map);&lt;br /&gt;
        Set_Wall(Map);&lt;br /&gt;
        for (int z=0;z&amp;lt;tab.size();z++)&lt;br /&gt;
        {&lt;br /&gt;
           Get_One_Point_Of_The_Rectangle(tab[z].x, xA, tab[z].y, yA, tab[z].theta, 275, 450);&lt;br /&gt;
 	   Set_Machines_In_Map(100, tab[z].theta, xA, yA, Map);&lt;br /&gt;
        }&lt;br /&gt;
        Map_Pub.publish(Map);                                                                   // publication de la map&lt;br /&gt;
        ros::spinOnce();&lt;br /&gt;
        loop_rate.sleep();&lt;br /&gt;
     }&lt;br /&gt;
     return 0;&lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Noeud test qui publie 2 positions de machines : &lt;br /&gt;
&lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
    ros::init(argc, argv, &amp;quot;test&amp;quot;);&lt;br /&gt;
    ros::NodeHandle n;&lt;br /&gt;
    ros::Publisher Pose_Machines_Pub = n.advertise&amp;lt;deplacement_msg::Landmarks&amp;gt;(&amp;quot;/machines&amp;quot;, 1000);&lt;br /&gt;
    ROS_INFO(&amp;quot;Ready to send poses machines&amp;quot;);&lt;br /&gt;
    int xA,yA;&lt;br /&gt;
    ros::Rate loop_rate(1);&lt;br /&gt;
    while(ros::ok())&lt;br /&gt;
    {&lt;br /&gt;
       deplacement_msg::Landmarks machines_msgs;&lt;br /&gt;
       geometry_msgs::Pose2D tab;&lt;br /&gt;
       tab.x=-2;&lt;br /&gt;
       tab.y=2;&lt;br /&gt;
       tab.theta=0;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       tab.x=5;&lt;br /&gt;
       tab.y=4;&lt;br /&gt;
       tab.theta=2.5;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       Pose_Machines_Pub.publish(machines_msgs);&lt;br /&gt;
       ros::spinOnce();&lt;br /&gt;
       loop_rate.sleep();&lt;br /&gt;
    }&lt;br /&gt;
    return 0;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On visualise le résultat grâce au logiciel RVIZ qui peut lire les topics publiés et donc le topic /map :&lt;br /&gt;
&lt;br /&gt;
===Semaine 9===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
l'objectif de cette semaine sera de coder toutes les fonctions nécessaires à l'implémentation finale du [http://fr.wikipedia.org/wiki/Filtre_de_Kalman#Filtre_de_Kalman_.C3.A9tendu filtre de Kalman étendu] :&lt;br /&gt;
&lt;br /&gt;
*initialisations des différents éléments&lt;br /&gt;
*étape de prédiction&lt;br /&gt;
*étape de mise à jour&lt;br /&gt;
*publication des positions machines et du robot dans le repère global via un topic ROS&lt;br /&gt;
&lt;br /&gt;
Le schéma ci-dessous nous montre les deux étapes du filtre de Kalman :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Kalman.png | center]]&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19585</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19585"/>
				<updated>2015-04-01T15:20:38Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Génération du noeud Map */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - vidéo====&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les résultats de la détection des machines nous avons utiliser l'interface graphique disponible avec ROS, RVIZ. Nous visualisons alors le scan laser (points blancs), le résultat de la détection de segments (en rouge) et les positions des machines trouvées (en vert). Un premier test a été fait sur le scan originel, celui sur lequel nous avons travaillé depuis le début.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=XSn4s1y-XT0 Visualisation des machines]&lt;br /&gt;
&lt;br /&gt;
On rencontre un problème quand le robot est exactement parallèle ou perpendiculaire à un mur. Après vérification dans le programme, il s'avère que la détection ne fonctionne pas pour ces cas. Ce bug est maintenant corrigé :&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=rKeqewpuLoQ Correction du bug]&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
La première étape consiste juste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;br /&gt;
&lt;br /&gt;
la matrice correspondant au changement (laser -&amp;gt; robot) est la suivante : &lt;br /&gt;
&lt;br /&gt;
 0   -1    0&lt;br /&gt;
 1    0  0.2&lt;br /&gt;
 0    0    1&lt;br /&gt;
&lt;br /&gt;
la matrice 2x2 en haut à gauche correspond à la rotation de 90°, et le vecteur (0, 0.2) correspond à la translation.&lt;br /&gt;
&lt;br /&gt;
Celle du changement (robot -&amp;gt; global) avec alpha angle mesuré par le gyroscope depuis la position initiale (angle 0) :&lt;br /&gt;
&lt;br /&gt;
 cos(alpha)   -sin(alpha)    posInit.x&lt;br /&gt;
 sin(alpha)    cos(alpha)    posInit.y&lt;br /&gt;
          0             0            1&lt;br /&gt;
&lt;br /&gt;
l'étape suivante est de vérifier si les machines vues par le laser sont bien des machines, c'est-à-dire si les positions mesurées à partir des données lasers correspond aux zones occupées par des machines envoyées par la Referee Box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Génération du noeud Map====&lt;br /&gt;
&lt;br /&gt;
L'autre objectif de cette semaine a été de coder le noeud qui génère la map. La map est générée sous forme d'OccupancyGrid. Ce type est constitué d'un seul vecteur dont la première case correspond à la case en bas à gauche de la map. D'autres paramètres sont réglable comme l'origine et la taille.&lt;br /&gt;
&lt;br /&gt;
Pour la taille on choisit de diviser la map en case de 10 cm et l'origine choisie est le x du centre de la map et en y l'abscisse du premier mur (voir la map ci-dessous). Afin d'expliquer comment est constituée cette map, prenons le code et analysons les différentes fonctions ainsi que le main :&lt;br /&gt;
&lt;br /&gt;
Ce vecteur de Pose2D (x, y et theta (angle de la machine) va permettre d'enregistrer la position des machines, c'est une variable global qui sera mise à jour avec le Callback :&lt;br /&gt;
&lt;br /&gt;
 std::vector&amp;lt;geometry_msgs::Pose2D&amp;gt; tab;&lt;br /&gt;
&lt;br /&gt;
*Récupération des machines envoyées par le noeud du SLAM (sur le topic /landmarks):&lt;br /&gt;
&lt;br /&gt;
 void Poses_Machine_Callback(const deplacement_msg::LandmarksConstPtr &amp;amp;machines)&lt;br /&gt;
 {&lt;br /&gt;
          tab=machines-&amp;gt;landmarks;&lt;br /&gt;
          for (int i=0; i&amp;lt;tab.size(); i++)&lt;br /&gt;
          {&lt;br /&gt;
     	     tab[i].x = tab[i].x*1000;&lt;br /&gt;
     	     tab[i].y = tab[i].y*1000;&lt;br /&gt;
 	  }&lt;br /&gt;
    &lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
*Création d'une map vide de taille 14m sur 8m. Chaque case est initialisée à une valeur nulle, on remplit également les autres paramètres de OccupancyGrid:&lt;br /&gt;
(On rappelle que la technique utilisée est un vecteur qui représente chaque case auxquelles il associe une probabilité 100 c'est un point interdit et 0 quand c'est un point sans danger pour le passage du robot)&lt;br /&gt;
&lt;br /&gt;
 void Create_Empty_Map(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      Map.info.origin.position.x=-7000;&lt;br /&gt;
      Map.info.origin.position.y=-1000;&lt;br /&gt;
      Map.info.origin.position.z=0;&lt;br /&gt;
      Map.info.origin.orientation.x=0;&lt;br /&gt;
      Map.info.origin.orientation.y=0;&lt;br /&gt;
      Map.info.origin.orientation.z=0;&lt;br /&gt;
      Map.info.origin.orientation.w=1;&lt;br /&gt;
      Map.info.map_load_time=ros::Time::now();&lt;br /&gt;
      Map.info.resolution=100;&lt;br /&gt;
      Map.info.width=140;&lt;br /&gt;
      Map.info.height=80;&lt;br /&gt;
&lt;br /&gt;
      Map.data.assign(Map.info.width*Map.info.height, 0);                   //map vide&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
*Construction des points fixes de la map donc les murs (probabilité 100) et les zones à risques (probabilité 50):&lt;br /&gt;
&lt;br /&gt;
 void Set_Wall(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      for (int i=0;i&amp;lt;80;i++)&lt;br /&gt;
         {&lt;br /&gt;
           for (int j=0;j&amp;lt;140;j++)&lt;br /&gt;
		 {	&lt;br /&gt;
		 	 if ((i&amp;lt;13)||(i&amp;gt;67)) Map.data[j+i*140]=100;&lt;br /&gt;
                         if ((j&amp;lt;13)||(j&amp;gt;127)) Map.data[j+i*140]=100;&lt;br /&gt;
                 }&lt;br /&gt;
         }&lt;br /&gt;
     ...&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Nous ne mettons pas tout le code de cette fonction étant donné qu'il est long et répétitif puisque c'est le remplissage des données connues, donc en &amp;quot;dur&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Maintenant, nous passons aux positions machines: &lt;br /&gt;
&lt;br /&gt;
Lorsqu'on reçoit une position machine, c'est en fait son centre et son orientation par rapport à x que l'on reçoit.&lt;br /&gt;
Etant donné que les machines doivent être des rectangles de 110cm sur 75cm (réellement 70 x 35 mais on compte la moitié du robot par sécurité), on décide d'abord de déterminer un des coins du rectangle et plus précisément le coin en bas à droite de ce dernier:&lt;br /&gt;
&lt;br /&gt;
 void Get_One_Point_Of_The_Rectangle(float x, float &amp;amp;xA, float y, float &amp;amp;yA, float theta, float largeur, float longueur)&lt;br /&gt;
 {&lt;br /&gt;
      float x1,y1;&lt;br /&gt;
      x1 = x - cos(theta)*longueur;&lt;br /&gt;
      y1 = y - sin(theta)*longueur; &lt;br /&gt;
      xA = x1 + sin(M_PI_2-theta)*largeur;&lt;br /&gt;
      yA = y1 - cos(M_PI_2-theta)*largeur;&lt;br /&gt;
  &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Il reste ensuite à mettre tout les points de se rectangles à une probabilité 100 dans le vecteur Map.&lt;br /&gt;
Pour les calculs on différencie le cas ou l'angle de la machine est entre 0 et pi/2 et le cas où il est entre pi/2 et pi.&lt;br /&gt;
L'algorithme est le suivant : &lt;br /&gt;
&lt;br /&gt;
A partir du coin, on incrémente x et y de sorte à longer le grand coté et de remplir chaque case (incrémentation de 5 cm).&lt;br /&gt;
Une fois arrivé au bout, on incrémente x et y de 5cm sur la largeur à partir du coin et on recommence l'opération précédente.&lt;br /&gt;
Ceci jusqu'à remplir le complètement le rectangle.&lt;br /&gt;
&lt;br /&gt;
Afin d'établir les probabilités de ce rectangle, nous utilisons la fonctions floor pour convertir nos flottants en entier et accéder à la case correspondante. On notera aussi que la case 1470 correspond à l'origine de notre map.&lt;br /&gt;
&lt;br /&gt;
 void Set_Machines_In_Map(float rank, float theta, float xA, float yA, nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      float x=xA;&lt;br /&gt;
      float y=yA;&lt;br /&gt;
      if (theta&amp;lt;=M_PI_2)&lt;br /&gt;
      {&lt;br /&gt;
            for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
            {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++) &lt;br /&gt;
                  {&lt;br /&gt;
                      Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                      x = x + cos(theta)*50;&lt;br /&gt;
                      y = y + sin(theta)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(M_PI_2-theta)*50;&lt;br /&gt;
                  y = yA + j*sin(M_PI_2-theta)*50;&lt;br /&gt;
            }	&lt;br /&gt;
       }&lt;br /&gt;
       if (theta&amp;gt;M_PI_2)&lt;br /&gt;
       {&lt;br /&gt;
             for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
             {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++)&lt;br /&gt;
                  {&lt;br /&gt;
                        Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                        x = x - sin(theta-M_PI_2)*50;&lt;br /&gt;
                        y = y + cos(theta-M_PI_2)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(theta-M_PI_2)*50;&lt;br /&gt;
                  y = yA - j*sin(theta-M_PI_2)*50;&lt;br /&gt;
              }	&lt;br /&gt;
        }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Ci dessous on a les mains, avec les différentes fonctions et la syntaxe particulière à ROS. &lt;br /&gt;
&lt;br /&gt;
*Noeud général pour le traitement et le remplissage de la map :   &lt;br /&gt;
                 &lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
     ros::init(argc, argv, &amp;quot;server&amp;quot;);&lt;br /&gt;
     ros::NodeHandle n;&lt;br /&gt;
     ros::Subscriber sub_poses_machine    = n.subscribe(&amp;quot;/machines&amp;quot;, 1000, Poses_Machine_Callback);   // Récupération des machines&lt;br /&gt;
     ros::Publisher Map_Pub = n.advertise&amp;lt;nav_msgs::OccupancyGrid&amp;gt;(&amp;quot;/map&amp;quot;, 1000);                     // Préparation de la publication de la map&lt;br /&gt;
     ROS_INFO(&amp;quot;Ready to Generate the Map&amp;quot;);&lt;br /&gt;
     float xA,yA;&lt;br /&gt;
     ros::Rate loop_rate(1);&lt;br /&gt;
     while(ros::ok())&lt;br /&gt;
     {&lt;br /&gt;
        nav_msgs::OccupancyGrid Map;&lt;br /&gt;
        Create_Empty_Map(Map);&lt;br /&gt;
        Set_Wall(Map);&lt;br /&gt;
        for (int z=0;z&amp;lt;tab.size();z++)&lt;br /&gt;
        {&lt;br /&gt;
           Get_One_Point_Of_The_Rectangle(tab[z].x, xA, tab[z].y, yA, tab[z].theta, 275, 450);&lt;br /&gt;
 	   Set_Machines_In_Map(100, tab[z].theta, xA, yA, Map);&lt;br /&gt;
        }&lt;br /&gt;
        Map_Pub.publish(Map);                                                                   // publication de la map&lt;br /&gt;
        ros::spinOnce();&lt;br /&gt;
        loop_rate.sleep();&lt;br /&gt;
     }&lt;br /&gt;
     return 0;&lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Noeud test qui publie 2 positions de machines : &lt;br /&gt;
&lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
    ros::init(argc, argv, &amp;quot;test&amp;quot;);&lt;br /&gt;
    ros::NodeHandle n;&lt;br /&gt;
    ros::Publisher Pose_Machines_Pub = n.advertise&amp;lt;deplacement_msg::Landmarks&amp;gt;(&amp;quot;/machines&amp;quot;, 1000);&lt;br /&gt;
    ROS_INFO(&amp;quot;Ready to send poses machines&amp;quot;);&lt;br /&gt;
    int xA,yA;&lt;br /&gt;
    ros::Rate loop_rate(1);&lt;br /&gt;
    while(ros::ok())&lt;br /&gt;
    {&lt;br /&gt;
       deplacement_msg::Landmarks machines_msgs;&lt;br /&gt;
       geometry_msgs::Pose2D tab;&lt;br /&gt;
       tab.x=-2;&lt;br /&gt;
       tab.y=2;&lt;br /&gt;
       tab.theta=0;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       tab.x=5;&lt;br /&gt;
       tab.y=4;&lt;br /&gt;
       tab.theta=2.5;&lt;br /&gt;
       machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
       Pose_Machines_Pub.publish(machines_msgs);&lt;br /&gt;
       ros::spinOnce();&lt;br /&gt;
       loop_rate.sleep();&lt;br /&gt;
    }&lt;br /&gt;
    return 0;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On visualise le résultat grâce au logiciel RVIZ qui peut lire les topics publiés et donc le topic /map :&lt;br /&gt;
&lt;br /&gt;
===Semaine 9===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
l'objectif de cette semaine sera de coder toutes les fonctions nécessaires à l'implémentation finale du [http://fr.wikipedia.org/wiki/Filtre_de_Kalman#Filtre_de_Kalman_.C3.A9tendu filtre de Kalman étendu] :&lt;br /&gt;
&lt;br /&gt;
*initialisations des différents éléments&lt;br /&gt;
*étape de prédiction&lt;br /&gt;
*étape de mise à jour&lt;br /&gt;
*publication des positions machines et du robot dans le repère global via un topic ROS&lt;br /&gt;
&lt;br /&gt;
Le schéma ci-dessous nous montre les deux étapes du filtre de Kalman :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Kalman.png | center]]&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19584</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19584"/>
				<updated>2015-04-01T14:37:20Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Génération du noeud Map */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - vidéo====&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les résultats de la détection des machines nous avons utiliser l'interface graphique disponible avec ROS, RVIZ. Nous visualisons alors le scan laser (points blancs), le résultat de la détection de segments (en rouge) et les positions des machines trouvées (en vert). Un premier test a été fait sur le scan originel, celui sur lequel nous avons travaillé depuis le début.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=XSn4s1y-XT0 Visualisation des machines]&lt;br /&gt;
&lt;br /&gt;
On rencontre un problème quand le robot est exactement parallèle ou perpendiculaire à un mur. Après vérification dans le programme, il s'avère que la détection ne fonctionne pas pour ces cas. Ce bug est maintenant corrigé :&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=rKeqewpuLoQ Correction du bug]&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
La première étape consiste juste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;br /&gt;
&lt;br /&gt;
la matrice correspondant au changement (laser -&amp;gt; robot) est la suivante : &lt;br /&gt;
&lt;br /&gt;
 0   -1    0&lt;br /&gt;
 1    0  0.2&lt;br /&gt;
 0    0    1&lt;br /&gt;
&lt;br /&gt;
la matrice 2x2 en haut à gauche correspond à la rotation de 90°, et le vecteur (0, 0.2) correspond à la translation.&lt;br /&gt;
&lt;br /&gt;
Celle du changement (robot -&amp;gt; global) avec alpha angle mesuré par le gyroscope depuis la position initiale (angle 0) :&lt;br /&gt;
&lt;br /&gt;
 cos(alpha)   -sin(alpha)    posInit.x&lt;br /&gt;
 sin(alpha)    cos(alpha)    posInit.y&lt;br /&gt;
          0             0            1&lt;br /&gt;
&lt;br /&gt;
l'étape suivante est de vérifier si les machines vues par le laser sont bien des machines, c'est-à-dire si les positions mesurées à partir des données lasers correspond aux zones occupées par des machines envoyées par la Referee Box.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Génération du noeud Map====&lt;br /&gt;
&lt;br /&gt;
L'autre objectif de cette semaine a été de coder le noeud qui génère la map. La map est générée sous forme d'OccupancyGrid. Ce type est constitué d'un seul vecteur dont la première case correspond à la case en bas à gauche de la map. D'autres paramètres sont réglable comme l'origine, la taille etc.&lt;br /&gt;
&lt;br /&gt;
Pour la taille on choisi de diviser la map en case de 10 cm (100 mm) et l'origine choisi est le centre de la mep en x et en y le premier mur (voir la map ci-dessous)&lt;br /&gt;
&lt;br /&gt;
Afin d'expliquer comment est constituée cette map, prenons le code et analysons les différentes fonctions:&lt;br /&gt;
&lt;br /&gt;
 #include &amp;quot;Map.hpp&amp;quot;&lt;br /&gt;
&lt;br /&gt;
ce vecteur de Pose2D (x et y) va permettre d'enregistrer le vecteur qui contient la position des machines :&lt;br /&gt;
&lt;br /&gt;
 std::vector&amp;lt;geometry_msgs::Pose2D&amp;gt; tab;    &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                 &lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
     ros::init(argc, argv, &amp;quot;server&amp;quot;);&lt;br /&gt;
     ros::NodeHandle n;&lt;br /&gt;
     ros::Subscriber sub_poses_machine    = n.subscribe(&amp;quot;/machines&amp;quot;, 1000, Poses_Machine_Callback);   // Récupération des machines&lt;br /&gt;
     ros::Publisher Map_Pub = n.advertise&amp;lt;nav_msgs::OccupancyGrid&amp;gt;(&amp;quot;/map&amp;quot;, 1000);                     // Préparation de la publication de la map&lt;br /&gt;
     ROS_INFO(&amp;quot;Ready to Generate the Map&amp;quot;);&lt;br /&gt;
     float xA,yA;&lt;br /&gt;
     ros::Rate loop_rate(1);&lt;br /&gt;
     while(ros::ok())&lt;br /&gt;
     {&lt;br /&gt;
     nav_msgs::OccupancyGrid Map;&lt;br /&gt;
     Create_Empty_Map(Map);&lt;br /&gt;
     Set_Wall(Map);&lt;br /&gt;
     for (int z=0;z&amp;lt;tab.size();z++)&lt;br /&gt;
         {&lt;br /&gt;
 		Get_One_Point_Of_The_Rectangle(tab[z].x, xA, tab[z].y, yA, tab[z].theta, 275, 450);&lt;br /&gt;
 		Set_Machines_In_Map(100, tab[z].theta, xA, yA, Map);&lt;br /&gt;
   	}&lt;br /&gt;
  	Map_Pub.publish(Map);                                                                   // publication de la map&lt;br /&gt;
  	ros::spinOnce();&lt;br /&gt;
 	loop_rate.sleep();&lt;br /&gt;
  	}&lt;br /&gt;
     return 0;&lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Cette fonction va récupérer les machines envoyées par le noeud du slam (sur le message landmarks):&lt;br /&gt;
&lt;br /&gt;
 void Poses_Machine_Callback(const deplacement_msg::LandmarksConstPtr &amp;amp;machines)&lt;br /&gt;
 {&lt;br /&gt;
          tab=machines-&amp;gt;landmarks;&lt;br /&gt;
          for (int i=0; i&amp;lt;tab.size(); i++)&lt;br /&gt;
          {&lt;br /&gt;
     	     tab[i].x = tab[i].x*1000;&lt;br /&gt;
     	     tab[i].y = tab[i].y*1000;&lt;br /&gt;
 	  }&lt;br /&gt;
    &lt;br /&gt;
  }  &lt;br /&gt;
&lt;br /&gt;
Cette fonction va créer une map vide de taille 14m sur 8m. Chaque case à une valeur nulle, il remplit aussi les autres paramètres de OccupancyGrid:&lt;br /&gt;
(On rappelle que la technique utilisée est un vecteur qui représente chaque case auxquelles il associe une probabilité 100 étant un point interdit et 0 un point sans danger de passage pour le robot)&lt;br /&gt;
&lt;br /&gt;
 void Create_Empty_Map(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      Map.info.origin.position.x=-7000;&lt;br /&gt;
      Map.info.origin.position.y=-1000;&lt;br /&gt;
      Map.info.origin.position.z=0;&lt;br /&gt;
      Map.info.origin.orientation.x=0;&lt;br /&gt;
      Map.info.origin.orientation.y=0;&lt;br /&gt;
      Map.info.origin.orientation.z=0;&lt;br /&gt;
      Map.info.origin.orientation.w=1;&lt;br /&gt;
      Map.info.map_load_time=ros::Time::now();&lt;br /&gt;
      Map.info.resolution=100;&lt;br /&gt;
      Map.info.width=140;&lt;br /&gt;
      Map.info.height=80;&lt;br /&gt;
      Map.data.assign(Map.info.width*Map.info.height, 0);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Ce noeud va construire les points fixes de la map donc les murs (probabilité 100) et les zones à risques (probabilité 50):&lt;br /&gt;
&lt;br /&gt;
 void Set_Wall(nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      for (int i=0;i&amp;lt;80;i++)&lt;br /&gt;
         {&lt;br /&gt;
           for (int j=0;j&amp;lt;140;j++)&lt;br /&gt;
		 {	&lt;br /&gt;
		 	 if ((i&amp;lt;13)||(i&amp;gt;67)) Map.data[j+i*140]=100;&lt;br /&gt;
                         if ((j&amp;lt;13)||(j&amp;gt;127)) Map.data[j+i*140]=100;&lt;br /&gt;
                 }&lt;br /&gt;
         }&lt;br /&gt;
      for (int i=0;i&amp;lt;80;i++)&lt;br /&gt;
         {&lt;br /&gt;
           for (int j=0;j&amp;lt;140;j++)&lt;br /&gt;
                {&lt;br /&gt;
                         if ((i&amp;lt;10)||(i&amp;gt;70)) Map.data[j+i*140]=50;&lt;br /&gt;
                         if ((j&amp;lt;10)||(j&amp;gt;130)) Map.data[j+i*140]=50;&lt;br /&gt;
                }  &lt;br /&gt;
&lt;br /&gt;
Nous ne mettons pas tout le code de cette fonction étant donné qu'il est long et répétitif afin de tout remplir&lt;br /&gt;
	&lt;br /&gt;
&lt;br /&gt;
Maintenant, nous passons aux positions machines: &lt;br /&gt;
&lt;br /&gt;
Lorsqu'on reçoit une position machine, c'est en fait son centre et son orientation par rapport à x que l'on reçoit.&lt;br /&gt;
Etant donné que les machines doivent être des rectangles de 90cm sur 55cm, on décide d'abord de déterminer un des coins du rectangle et plus précisément le coin en bas à droite de ce dernier:&lt;br /&gt;
&lt;br /&gt;
 void Get_One_Point_Of_The_Rectangle(float x, float &amp;amp;xA, float y, float &amp;amp;yA, float theta, float largeur, float longueur)&lt;br /&gt;
 {&lt;br /&gt;
      float x1,y1;&lt;br /&gt;
      x1 = x - cos(theta)*longueur;&lt;br /&gt;
      y1 = y - sin(theta)*longueur; &lt;br /&gt;
      xA = x1 + sin(M_PI_2-theta)*largeur;&lt;br /&gt;
      yA = y1 - cos(M_PI_2-theta)*largeur;&lt;br /&gt;
  &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Il reste ensuite à mettre tout les points de se rectangles à une probabilité 100 dans le vecteur Map.&lt;br /&gt;
Pour les calculs on différencie le cas ou l'angle de la machine est entre 0 et pi/2 et le cas où il est entre pi/2 et pi.&lt;br /&gt;
L'algorithme est le suivant : &lt;br /&gt;
&lt;br /&gt;
A partir du coin, on incrémente x et y de sorte à longer le grand coté et de remplir chaque case (incrémentation de 5 cm).&lt;br /&gt;
Une fois arrivé au bout, on incrémente x et y de 5cm sur la largeur à partir du coin et on recommence l'opération précédente.&lt;br /&gt;
Ceci jusqu'à remplir le complètement le rectangle.&lt;br /&gt;
&lt;br /&gt;
Afin d'établir les probabilités de ce rectangle, nous utilisons la fonctions floor pour convertir nos flottants en entier et accéder à la case correspondante.&lt;br /&gt;
On notera aussi que la case 1470 correspond à l'origine de notre map.&lt;br /&gt;
&lt;br /&gt;
 void Set_Machines_In_Map(float rank, float theta, float xA, float yA, nav_msgs::OccupancyGrid &amp;amp;Map)&lt;br /&gt;
 {&lt;br /&gt;
      float x=xA;&lt;br /&gt;
      float y=yA;&lt;br /&gt;
      if (theta&amp;lt;=M_PI_2)&lt;br /&gt;
      {&lt;br /&gt;
            for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
            {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++) &lt;br /&gt;
                  {&lt;br /&gt;
                      Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                      x = x + cos(theta)*50;&lt;br /&gt;
                      y = y + sin(theta)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(M_PI_2-theta)*50;&lt;br /&gt;
                  y = yA + j*sin(M_PI_2-theta)*50;&lt;br /&gt;
            }	&lt;br /&gt;
       }&lt;br /&gt;
       if (theta&amp;gt;M_PI_2)&lt;br /&gt;
       {&lt;br /&gt;
             for (int j=0;j&amp;lt;10;j++)&lt;br /&gt;
             {&lt;br /&gt;
                  for (int i=0;i&amp;lt;18;i++)&lt;br /&gt;
                  {&lt;br /&gt;
                        Map.data[1470+floor(x/rank)+floor(y/rank)*140]=100;&lt;br /&gt;
                        x = x - sin(theta-M_PI_2)*50;&lt;br /&gt;
                        y = y + cos(theta-M_PI_2)*50;&lt;br /&gt;
                  }&lt;br /&gt;
                  x = xA - j*cos(theta-M_PI_2)*50;&lt;br /&gt;
                  y = yA - j*sin(theta-M_PI_2)*50;&lt;br /&gt;
              }	&lt;br /&gt;
        }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On crée un noeud test qui publie 2 positions de machines : &lt;br /&gt;
 #include &amp;quot;Test.hpp&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 /*==========  Main  ==========*/&lt;br /&gt;
 int main(int argc, char **argv)&lt;br /&gt;
 {&lt;br /&gt;
    ros::init(argc, argv, &amp;quot;test&amp;quot;);&lt;br /&gt;
    ros::NodeHandle n;&lt;br /&gt;
    ros::Publisher Pose_Machines_Pub = n.advertise&amp;lt;deplacement_msg::Landmarks&amp;gt;(&amp;quot;/machines&amp;quot;, 1000);&lt;br /&gt;
    ROS_INFO(&amp;quot;Ready to send poses machines&amp;quot;);&lt;br /&gt;
    int xA,yA;&lt;br /&gt;
    ros::Rate loop_rate(1);&lt;br /&gt;
    while(ros::ok())&lt;br /&gt;
    {&lt;br /&gt;
    deplacement_msg::Landmarks machines_msgs;&lt;br /&gt;
    geometry_msgs::Pose2D tab;&lt;br /&gt;
    tab.x=-2;&lt;br /&gt;
    tab.y=2;&lt;br /&gt;
    tab.theta=0;&lt;br /&gt;
    machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
    tab.x=5;&lt;br /&gt;
    tab.y=4;&lt;br /&gt;
    tab.theta=2.5;&lt;br /&gt;
    machines_msgs.landmarks.push_back(tab);&lt;br /&gt;
 	Pose_Machines_Pub.publish(machines_msgs);&lt;br /&gt;
 	ros::spinOnce();&lt;br /&gt;
        loop_rate.sleep();&lt;br /&gt;
 	}&lt;br /&gt;
    return 0;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On visualise le résultat grâce au logiciel RVIZ qui peut lire les topics publiés et donc le topic /map !:&lt;br /&gt;
&lt;br /&gt;
===Semaine 9===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
l'objectif de cette semaine sera de coder toutes les fonctions nécessaires à l'implémentation finale du [http://fr.wikipedia.org/wiki/Filtre_de_Kalman#Filtre_de_Kalman_.C3.A9tendu filtre de Kalman étendu] :&lt;br /&gt;
&lt;br /&gt;
*initialisations des différents éléments&lt;br /&gt;
*étape de prédiction&lt;br /&gt;
*étape de mise à jour&lt;br /&gt;
*publication des positions machines et du robot dans le repère global via un topic ROS&lt;br /&gt;
&lt;br /&gt;
Le schéma ci-dessous nous montre les deux étapes du filtre de Kalman :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Kalman.png | center]]&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19461</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19461"/>
				<updated>2015-03-29T16:14:32Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Localisation - Extended Kalman Filter */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - vidéo====&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les résultats de la détection des machines nous avons utiliser l'interface graphique disponible avec ROS, RVIZ. Nous visualisons alors le scan laser (points blancs), le résultat de la détection de segments (en rouge) et les positions des machines trouvées (en vert). Un premier test a été fait sur le scan originel, celui sur lequel nous avons travaillé depuis le début.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=XSn4s1y-XT0 Visualisation des machines]&lt;br /&gt;
&lt;br /&gt;
On rencontre un problème quand le robot est exactement parallèle ou perpendiculaire à un mur. Après vérification dans le programme, il s'avère que la détection ne fonctionne pas pour ces cas. Ce bug est maintenant corrigé :&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=rKeqewpuLoQ Correction du bug]&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
La première étape consiste juste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;br /&gt;
&lt;br /&gt;
la matrice correspondant au changement (laser -&amp;gt; robot) est la suivante : &lt;br /&gt;
&lt;br /&gt;
 0   -1    0&lt;br /&gt;
 1    0  0.2&lt;br /&gt;
 0    0    1&lt;br /&gt;
&lt;br /&gt;
la matrice 2x2 en haut à gauche correspond à la rotation de 90°, et le vecteur (0, 0.2) correspond à la translation.&lt;br /&gt;
&lt;br /&gt;
Celle du changement (robot -&amp;gt; global) avec alpha angle mesuré par le gyroscope depuis la position initiale (angle 0) :&lt;br /&gt;
&lt;br /&gt;
 cos(alpha)   -sin(alpha)    posInit.x&lt;br /&gt;
 sin(alpha)    cos(alpha)    posInit.y&lt;br /&gt;
          0             0            1&lt;br /&gt;
&lt;br /&gt;
l'étape suivante est de vérifier si les machines vues par le laser sont bien des machines, c'est-à-dire si les positions mesurées à partir des données lasers correspond aux zones occupées par des machines envoyées par la Referee Box.&lt;br /&gt;
&lt;br /&gt;
===Semaine 9===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
l'objectif de cette semaine sera de coder toutes les fonctions nécessaires à l'implémentation finale du [http://fr.wikipedia.org/wiki/Filtre_de_Kalman#Filtre_de_Kalman_.C3.A9tendu filtre de Kalman étendu] :&lt;br /&gt;
&lt;br /&gt;
*initialisations des différents éléments&lt;br /&gt;
*étape de prédiction&lt;br /&gt;
*étape de mise à jour&lt;br /&gt;
*publication des positions machines et du robot dans le repère global via un topic ROS&lt;br /&gt;
&lt;br /&gt;
Le schéma ci-dessous nous montre les deux étapes du filtre de Kalman :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Kalman.png | center]]&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19460</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19460"/>
				<updated>2015-03-29T16:13:49Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Localisation - Extended Kalman Filter */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - vidéo====&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les résultats de la détection des machines nous avons utiliser l'interface graphique disponible avec ROS, RVIZ. Nous visualisons alors le scan laser (points blancs), le résultat de la détection de segments (en rouge) et les positions des machines trouvées (en vert). Un premier test a été fait sur le scan originel, celui sur lequel nous avons travaillé depuis le début.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=XSn4s1y-XT0 Visualisation des machines]&lt;br /&gt;
&lt;br /&gt;
On rencontre un problème quand le robot est exactement parallèle ou perpendiculaire à un mur. Après vérification dans le programme, il s'avère que la détection ne fonctionne pas pour ces cas. Ce bug est maintenant corrigé :&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=rKeqewpuLoQ Correction du bug]&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
La première étape consiste juste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;br /&gt;
&lt;br /&gt;
la matrice correspondant au changement (laser -&amp;gt; robot) est la suivante : &lt;br /&gt;
&lt;br /&gt;
 0   -1    0&lt;br /&gt;
 1    0  0.2&lt;br /&gt;
 0    0    1&lt;br /&gt;
&lt;br /&gt;
la matrice 2x2 en haut à gauche correspond à la rotation de 90°, et le vecteur (0, 0.2) correspond à la translation.&lt;br /&gt;
&lt;br /&gt;
Celle du changement (robot -&amp;gt; global) avec alpha angle mesuré par le gyroscope depuis la position initiale (angle 0) :&lt;br /&gt;
&lt;br /&gt;
 cos(alpha)   -sin(alpha)    posInit.x&lt;br /&gt;
 sin(alpha)    cos(alpha)    posInit.y&lt;br /&gt;
          0             0            1&lt;br /&gt;
&lt;br /&gt;
l'étape suivante est de vérifier si les machines vues par le laser sont bien des machines, c'est-à-dire si les positions mesurées à partir des données lasers correspond aux zones occupées par des machines envoyées par la Referee Box.&lt;br /&gt;
&lt;br /&gt;
===Semaine 9===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
l'objectif de cette semaine sera de coder toutes les fonctions nécessaires à l'implémentation finale du [http://fr.wikipedia.org/wiki/Filtre_de_Kalman#Filtre_de_Kalman_.C3.A9tendu filtre de Kalman étendu] :&lt;br /&gt;
&lt;br /&gt;
*initialisations des différents éléments&lt;br /&gt;
*étape de prédiction&lt;br /&gt;
*étape de mise à jour&lt;br /&gt;
*publication des positions machines et du robot dans le repère global via un topic ROS&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Kalman.png | center]]&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=Fichier:Kalman.png&amp;diff=19459</id>
		<title>Fichier:Kalman.png</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=Fichier:Kalman.png&amp;diff=19459"/>
				<updated>2015-03-29T16:13:10Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : a téléversé une nouvelle version de « Fichier:Kalman.png »&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=Fichier:Kalman.png&amp;diff=19458</id>
		<title>Fichier:Kalman.png</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=Fichier:Kalman.png&amp;diff=19458"/>
				<updated>2015-03-29T16:10:56Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19457</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19457"/>
				<updated>2015-03-29T16:09:52Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Localisation - Extended Kalman Filter */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - vidéo====&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les résultats de la détection des machines nous avons utiliser l'interface graphique disponible avec ROS, RVIZ. Nous visualisons alors le scan laser (points blancs), le résultat de la détection de segments (en rouge) et les positions des machines trouvées (en vert). Un premier test a été fait sur le scan originel, celui sur lequel nous avons travaillé depuis le début.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=XSn4s1y-XT0 Visualisation des machines]&lt;br /&gt;
&lt;br /&gt;
On rencontre un problème quand le robot est exactement parallèle ou perpendiculaire à un mur. Après vérification dans le programme, il s'avère que la détection ne fonctionne pas pour ces cas. Ce bug est maintenant corrigé :&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=rKeqewpuLoQ Correction du bug]&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
La première étape consiste juste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;br /&gt;
&lt;br /&gt;
la matrice correspondant au changement (laser -&amp;gt; robot) est la suivante : &lt;br /&gt;
&lt;br /&gt;
 0   -1    0&lt;br /&gt;
 1    0  0.2&lt;br /&gt;
 0    0    1&lt;br /&gt;
&lt;br /&gt;
la matrice 2x2 en haut à gauche correspond à la rotation de 90°, et le vecteur (0, 0.2) correspond à la translation.&lt;br /&gt;
&lt;br /&gt;
Celle du changement (robot -&amp;gt; global) avec alpha angle mesuré par le gyroscope depuis la position initiale (angle 0) :&lt;br /&gt;
&lt;br /&gt;
 cos(alpha)   -sin(alpha)    posInit.x&lt;br /&gt;
 sin(alpha)    cos(alpha)    posInit.y&lt;br /&gt;
          0             0            1&lt;br /&gt;
&lt;br /&gt;
l'étape suivante est de vérifier si les machines vues par le laser sont bien des machines, c'est-à-dire si les positions mesurées à partir des données lasers correspond aux zones occupées par des machines envoyées par la Referee Box.&lt;br /&gt;
&lt;br /&gt;
===Semaine 9===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
l'objectif de cette semaine sera de coder toutes les fonctions nécessaires à l'implémentation finale du [http://fr.wikipedia.org/wiki/Filtre_de_Kalman#Filtre_de_Kalman_.C3.A9tendu filtre de Kalman étendu] :&lt;br /&gt;
&lt;br /&gt;
*initialisations des différents éléments&lt;br /&gt;
*étape de prédiction&lt;br /&gt;
*étape de mise à jour&lt;br /&gt;
*publication des positions machines et du robot dans le repère global via un topic ROS&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Kalman.png]]&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19456</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19456"/>
				<updated>2015-03-29T15:41:27Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Localisation - Extended Kalman Filter */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - vidéo====&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les résultats de la détection des machines nous avons utiliser l'interface graphique disponible avec ROS, RVIZ. Nous visualisons alors le scan laser (points blancs), le résultat de la détection de segments (en rouge) et les positions des machines trouvées (en vert). Un premier test a été fait sur le scan originel, celui sur lequel nous avons travaillé depuis le début.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=XSn4s1y-XT0 Visualisation des machines]&lt;br /&gt;
&lt;br /&gt;
On rencontre un problème quand le robot est exactement parallèle ou perpendiculaire à un mur. Après vérification dans le programme, il s'avère que la détection ne fonctionne pas pour ces cas. Ce bug est maintenant corrigé :&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=rKeqewpuLoQ Correction du bug]&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
La première étape consiste juste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;br /&gt;
&lt;br /&gt;
la matrice correspondant au changement (laser -&amp;gt; robot) est la suivante : &lt;br /&gt;
&lt;br /&gt;
 0   -1    0&lt;br /&gt;
 1    0  0.2&lt;br /&gt;
 0    0    1&lt;br /&gt;
&lt;br /&gt;
la matrice 2x2 en haut à gauche correspond à la rotation de 90°, et le vecteur (0, 0.2) correspond à la translation.&lt;br /&gt;
&lt;br /&gt;
Celle du changement (robot -&amp;gt; global) avec alpha angle mesuré par le gyroscope depuis la position initiale (angle 0) :&lt;br /&gt;
&lt;br /&gt;
 cos(alpha)   -sin(alpha)    posInit.x&lt;br /&gt;
 sin(alpha)    cos(alpha)    posInit.y&lt;br /&gt;
          0             0            1&lt;br /&gt;
&lt;br /&gt;
l'étape suivante est de vérifier si les machines vues par le laser sont bien des machines, c'est-à-dire si les positions mesurées à partir des données lasers correspond aux zones occupées par des machines envoyées par la Referee Box.&lt;br /&gt;
&lt;br /&gt;
===Semaine 9===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
l'objectif de cette semaine sera de coder toutes les fonctions nécessaires à l'implémentation finale du [http://fr.wikipedia.org/wiki/Filtre_de_Kalman#Filtre_de_Kalman_.C3.A9tendu filtre de Kalman étendu] :&lt;br /&gt;
&lt;br /&gt;
*initialisations des différents éléments&lt;br /&gt;
*étape de prédiction&lt;br /&gt;
*étape de mise à jour&lt;br /&gt;
*publication des positions machines et du robot dans le repère global via un topic ROS&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19455</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19455"/>
				<updated>2015-03-29T15:03:02Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Semaine 8 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - vidéo====&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les résultats de la détection des machines nous avons utiliser l'interface graphique disponible avec ROS, RVIZ. Nous visualisons alors le scan laser (points blancs), le résultat de la détection de segments (en rouge) et les positions des machines trouvées (en vert). Un premier test a été fait sur le scan originel, celui sur lequel nous avons travaillé depuis le début.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=XSn4s1y-XT0 Visualisation des machines]&lt;br /&gt;
&lt;br /&gt;
On rencontre un problème quand le robot est exactement parallèle ou perpendiculaire à un mur. Après vérification dans le programme, il s'avère que la détection ne fonctionne pas pour ces cas. Ce bug est maintenant corrigé :&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=rKeqewpuLoQ Correction du bug]&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
La première étape consiste juste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;br /&gt;
&lt;br /&gt;
la matrice correspondant au changement (laser -&amp;gt; robot) est la suivante : &lt;br /&gt;
&lt;br /&gt;
 0   -1    0&lt;br /&gt;
 1    0  0.2&lt;br /&gt;
 0    0    1&lt;br /&gt;
&lt;br /&gt;
la matrice 2x2 en haut à gauche correspond à la rotation de 90°, et le vecteur (0, 0.2) correspond à la translation.&lt;br /&gt;
&lt;br /&gt;
Celle du changement (robot -&amp;gt; global) avec alpha angle mesuré par le gyroscope depuis la position initiale (angle 0) :&lt;br /&gt;
&lt;br /&gt;
 cos(alpha)   -sin(alpha)    posInit.x&lt;br /&gt;
 sin(alpha)    cos(alpha)    posInit.y&lt;br /&gt;
          0             0            1&lt;br /&gt;
&lt;br /&gt;
l'étape suivante est de vérifier si les machines vues par le laser sont bien des machines, c'est-à-dire si les positions mesurées à partir des données lasers correspond aux zones occupées par des machines envoyées par la Referee Box.&lt;br /&gt;
&lt;br /&gt;
===Semaine 9===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Extended Kalman Filter====&lt;br /&gt;
&lt;br /&gt;
l'objectif de cette semaine sera de coder toutes les fonctions nécessaires à l'implémentation finale du [http://fr.wikipedia.org/wiki/Filtre_de_Kalman filtre de Kalman] étendu :&lt;br /&gt;
&lt;br /&gt;
*initialisations des différents éléments&lt;br /&gt;
*étape de prédiction&lt;br /&gt;
*étape de mise à jour&lt;br /&gt;
*publication des positions machines et du robot dans le repère global via un topic ROS&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19447</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19447"/>
				<updated>2015-03-29T14:27:39Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Localisation - Data Association */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
Cette étape consiste juste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;br /&gt;
&lt;br /&gt;
la matrice correspondant au changement (laser -&amp;gt; robot) est la suivante : &lt;br /&gt;
&lt;br /&gt;
 0   -1    0&lt;br /&gt;
 1    0  0.2&lt;br /&gt;
 0    0    1&lt;br /&gt;
&lt;br /&gt;
la matrice 2x2 en haut à gauche correspond à la rotation de 90°, et le vecteur (0, 0.2) correspond à la translation.&lt;br /&gt;
&lt;br /&gt;
Celle du changement (robot -&amp;gt; global) avec alpha angle mesuré par le gyroscope depuis la position initiale (angle 0) :&lt;br /&gt;
&lt;br /&gt;
 cos(alpha)   -sin(alpha)    posInit.x&lt;br /&gt;
 sin(alpha)    cos(alpha)    posInit.y&lt;br /&gt;
          0             0            1&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - vidéo====&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les résultats de la détection des machines nous avons utiliser l'interface graphique disponible avec ROS, RVIZ. Nous visualisons alors le scan laser (points blancs), le résultat de la détection de segments (en rouge) et les positions des machines trouvées (en vert). Un premier test a été fait sur le scan originel, celui sur lequel nous avons travaillé depuis le début.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=XSn4s1y-XT0 Visualisation des machines]&lt;br /&gt;
&lt;br /&gt;
On rencontre un problème quand le robot est exactement parallèle ou perpendiculaire à un mur. Après vérification dans le programme, il s'avère que la détection ne fonctionne pas pour ces cas. Ce bug est maintenant corrigé :&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=rKeqewpuLoQ Correction du bug]&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19446</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19446"/>
				<updated>2015-03-29T11:22:15Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Localisation - Landmarks Extraction - vidéo */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
La première étape consiste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Nous allons créer une matrice de taille dynamique qui sera la matrice principale de l'algorithme du ''Filtre de Kalman Etendu''.&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - vidéo====&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les résultats de la détection des machines nous avons utiliser l'interface graphique disponible avec ROS, RVIZ. Nous visualisons alors le scan laser (points blancs), le résultat de la détection de segments (en rouge) et les positions des machines trouvées (en vert). Un premier test a été fait sur le scan originel, celui sur lequel nous avons travaillé depuis le début.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=XSn4s1y-XT0 Visualisation des machines]&lt;br /&gt;
&lt;br /&gt;
On rencontre un problème quand le robot est exactement parallèle ou perpendiculaire à un mur. Après vérification dans le programme, il s'avère que la détection ne fonctionne pas pour ces cas. Ce bug est maintenant corrigé :&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=rKeqewpuLoQ Correction du bug]&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19444</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19444"/>
				<updated>2015-03-27T21:33:56Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Localisation - Landmarks Extraction - vidéo */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
La première étape consiste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Nous allons créer une matrice de taille dynamique qui sera la matrice principale de l'algorithme du ''Filtre de Kalman Etendu''.&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - vidéo====&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les résultats de la détection des machines nous avons utiliser l'interface graphique disponible avec ROS, RVIZ. Nous visualisons alors le scan laser (points blancs), le résultat de la détection de segments (en rouge) et les positions des machines trouvées (en vert). Un premier test a été fait sur le scan originel, celui sur lequel nous avons travaillé depuis le début.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=XSn4s1y-XT0 Visualisation des machines]&lt;br /&gt;
&lt;br /&gt;
On rencontre un problème quand le robot est exactement parallèle ou perpendiculaire à un mur. Après vérification dans le programme, il s'avère que la détection ne fonctionne pas pour ces cas. Ce bug est maintenant corrigéet la vidéo sera prochainement disponible.&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19443</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19443"/>
				<updated>2015-03-27T21:33:22Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Localisation - Landmarks Extraction - vidéo */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
La première étape consiste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Nous allons créer une matrice de taille dynamique qui sera la matrice principale de l'algorithme du ''Filtre de Kalman Etendu''.&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - vidéo====&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les résultats de la détection des machines nous avons utiliser l'interface graphique disponible avec ROS, RVIZ. Nous visualisons alors le scan laser (points blancs), le résultat de la détection de segments (en rouge) et les positions des machines trouvées (en vert). Un premier test a été fait sur le scan originel, celui sur lequel nous avons travaillé depuis le début.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=XSn4s1y-XT0 Visualisation des machines]&lt;br /&gt;
&lt;br /&gt;
On rencontre un problème quand le robot est exactement parallèle ou perpendiculaire à un mur. Après vérification dans le programme, il s'avère que la détection ne fonctionne pas pour ces cas. Le problème sera traité après la réalisation de l'EKF puisque c'est la partie la plus importante du projet en ce qui concerne la localisation. Ce bug est maintenant et la vidéo sera prochainement disponible.&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19385</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19385"/>
				<updated>2015-03-26T10:22:38Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Localisation - Data Association */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
La première étape consiste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Nous allons créer une matrice de taille dynamique qui sera la matrice principale de l'algorithme du ''Filtre de Kalman Etendu''.&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - vidéo====&lt;br /&gt;
&lt;br /&gt;
Pour visualiser les résultats de la détection des machines nous avons utiliser l'interface graphique disponible avec ROS, RVIZ. Nous visualisons alors le scan laser (points blancs), le résultat de la détection de segments (en rouge) et les positions des machines trouvées (en vert). Un premier test a été fait sur le scan originel, celui sur lequel nous avons travaillé depuis le début.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=XSn4s1y-XT0 Visualisation des machines]&lt;br /&gt;
&lt;br /&gt;
On rencontre un problème quand le robot est exactement parallèle ou perpendiculaire à un mur. Après vérification dans le programme, il s'avère que la détection ne fonctionne pas pour ces cas. Le problème sera traité après la réalisation de l'EKF puisque c'est la partie la plus importante du projet en ce qui concerne la localisation.&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19383</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19383"/>
				<updated>2015-03-26T10:09:35Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Semaine 7 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Semaine 8===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
La première étape consiste à faire un changement de repère, d'abord du repère laser vers le repère robot, puisque le laser sera placé en avant du robot, puis du repère robot au repère global, comme ci dessous :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Chgt_Repère.png |center | thumb]]&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=Fichier:Chgt_Rep%C3%A8re.png&amp;diff=19382</id>
		<title>Fichier:Chgt Repère.png</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=Fichier:Chgt_Rep%C3%A8re.png&amp;diff=19382"/>
				<updated>2015-03-26T10:08:28Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19078</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19078"/>
				<updated>2015-03-20T14:21:29Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Localisation - Data Association */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;br /&gt;
&lt;br /&gt;
Il a été décidé de faire une association de données avant la détection de machines, pour distinguer les pans de murs directement afin de stocker ces informations directement à la source. On pourra éventuellement détecter les coins intérieurs de la piste pour plus de précision dans le recalage. Pour le reste, rien ne change.&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19035</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=19035"/>
				<updated>2015-03-19T16:58:38Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Localisation - Data Association */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7°/s sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=18974</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=18974"/>
				<updated>2015-03-18T16:55:10Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Localisation - Data Association */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le nœud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le nœud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un nœud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du nœud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7° sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les nœuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de nœud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les intégrer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=18973</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=18973"/>
				<updated>2015-03-18T16:54:16Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Localisation - Data Association */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le noeud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le noeud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un noeud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du noeud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
La correction d'odométrie a fait apparaître une erreur de mesure d'environ 1,7° sur la vitesse angulaire, à faible vitesse. Pour de la Localisation et Cartographie Simultanée, c'est assez important. Ça justifie donc la nécessité de faire cet ajustement.&lt;br /&gt;
&lt;br /&gt;
Pour la suite, il a été décidé de fusionner les noeuds '''Data Association''' et '''Extended Kalman Filter''' puisque l'association de données n'étant au final qu'un changement de repère, la structure de noeud ROS n'est pas adaptée.&lt;br /&gt;
&lt;br /&gt;
Nous avons trouvé un [https://github.com/yangyimeng/machine-learning/blob/master/slam/EKF/SLAM%20course.pdf PDF] expliquant l'algorithme de SLAM. Grâce à celui ci nous avons déterminer les éléments à rentrer dans le noeud, ainsi que les différentes opérations incluses dans ce filtre. Pour les calculs matriciels, nous allons probablement utiliser la librairie EIGEN pour travailler sur des [http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html matrices] de façon optimisée. La prochaine étape sera de &amp;quot;typer&amp;quot; nos informations (position robot + machine + murs) pour pouvoir les insérer facilement au filtre. Nous avons aussi décidé d'inclure les murs comme ''landmark'' dans la matrice de covariance du vecteur d'état.&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=18823</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=18823"/>
				<updated>2015-03-16T15:48:44Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Localisation - Data Association */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser.&lt;br /&gt;
&lt;br /&gt;
Il faudra aussi corriger l'odométrie donné par le noeud ''robotino_odometry_node'', qui donne l'odométrie (mesure de la position et de la vitesse du robot). Le problème est que nous utilisons un gyroscope externe, car le gyroscope de base est de très basse qualité. Or, si le noeud corrige parfaitement la position, il ne corrige pas du tout la vitesse angulaire ! Nous devons donc réaliser un noeud qui le fera pour nous.&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du noeud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center]]&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=18812</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=18812"/>
				<updated>2015-03-15T22:17:03Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Localisation - Data Association */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
L'objectif principal de cette semaine est de coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du noeud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center]]&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	<entry>
		<id>https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=18811</id>
		<title>RoboCup 2015 - Pyro Team</title>
		<link rel="alternate" type="text/html" href="https://wiki-ima.plil.fr/mediawiki//index.php?title=RoboCup_2015_-_Pyro_Team&amp;diff=18811"/>
				<updated>2015-03-15T22:15:48Z</updated>
		
		<summary type="html">&lt;p&gt;Tdanel : /* Localisation - Landmarks Extraction - reconnaissance de machines */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot;/&amp;gt;&lt;br /&gt;
==Cahier des charges==&lt;br /&gt;
&lt;br /&gt;
[[Fichier:logoPyro_icone.png|center]]&lt;br /&gt;
&lt;br /&gt;
===Présentation générale du projet=== &lt;br /&gt;
&lt;br /&gt;
Avec plusieurs IMAs, nous avons créer une équipe pour participer à la [http://www.robocup-logistics.org/ Logistic League] de la RoboCup. Lors de la compétition de l'Open German, version européenne de la RoboCup, il faudra mettre en place un système autonome de production à l'aide de Robotinos (robots mobiles de Festo ayant un système d'exploitation Linux) afin de réaliser des produits en fonction des demandes de l'arbitre du jeu : la Referee Box. Nous traiterons dans ce projet de l'aspect navigation des robots, composé d'une partie localisation et d'une partie déplacement.&lt;br /&gt;
&lt;br /&gt;
====Contexte====&lt;br /&gt;
&lt;br /&gt;
La compétition de l'Open German se déroule en quatre phases spécifiques : phase de début-de-jeu, phase d'exploration, phase de production, phase de fin-de-jeu. La navigation sera utilisée dans la phase d'exploration afin de réaliser une carte de la zone de jeu permettant de définir des zones de passage entre les machines. Dans la phase de production, la navigation permettra de se déplacer à partir de la carte créée au préalable (avec les obstacles fixes) et des robots (obstacles mobiles) se déplaçant en même temps.&lt;br /&gt;
&lt;br /&gt;
====Objectif du projet====&lt;br /&gt;
&lt;br /&gt;
Fournir aux Robotinos un système capable de se localiser et de parcourir des trajectoires calculées à partir de coordonnées envoyées par le [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]. &lt;br /&gt;
&lt;br /&gt;
====Description du projet====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ProjetS8.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
*Localiser correctement le robot (à 5 cm près)&lt;br /&gt;
*Localiser les éléments fixes :&lt;br /&gt;
**Murs&lt;br /&gt;
**Machines&lt;br /&gt;
*Générer une trajectoire selon :&lt;br /&gt;
**les demandes du &amp;quot;[http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&amp;quot;&lt;br /&gt;
**la détection d'obstacles dynamiques (robots)&lt;br /&gt;
*Assurer le suivi de la trajectoire&lt;br /&gt;
&lt;br /&gt;
====Choix techniques : matériel et logiciel====&lt;br /&gt;
&lt;br /&gt;
*Utilisation de 3 Robotinos équipés chacun de :&lt;br /&gt;
**1 détecteur laser pouvant réaliser des mesures à 240°&lt;br /&gt;
**1 gyroscope&lt;br /&gt;
**9 capteurs SHARP (télémètres infrarouges)&lt;br /&gt;
**3 codeurs incrémentaux présents en sortie de chaque moteur du Robotino&lt;br /&gt;
*Utilisation de [http://wiki.ros.org/hydro ROS Hydro]&lt;br /&gt;
*Utilisation de différents langages : C++ ou Python&lt;br /&gt;
*Utilisation de Linux Ubuntu 12.04&lt;br /&gt;
&lt;br /&gt;
===Etapes du projet===&lt;br /&gt;
&lt;br /&gt;
*Conception du schéma global des différentes parties :&lt;br /&gt;
**Localisation avec le SLAM&lt;br /&gt;
**Création de la carte avec le SLAM&lt;br /&gt;
**Génération de trajectoire avec A-Star&lt;br /&gt;
**Execution de trajectoire avec le noeud ROS pour Robotino robotino_local_move&lt;br /&gt;
&lt;br /&gt;
*Codage des différents noeuds ROS&lt;br /&gt;
&lt;br /&gt;
*Tests de précision et de robustesse sur robot&lt;br /&gt;
&lt;br /&gt;
*Validation du modèle&lt;br /&gt;
&lt;br /&gt;
*Améliorations possibles :&lt;br /&gt;
**Fusionner les maps des 3 robots&lt;br /&gt;
**D-Star Lite au lieu de A-Star&lt;br /&gt;
**Filtrage des données laser&lt;br /&gt;
&lt;br /&gt;
====Vocabulaire====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nos comptes rendus peuvent contenir des expressions que nous employons régulièrement mais qui ne sont parfois pas évidentes. Nous proposons alors cette partie vocabulaire afin d'aider le lecteur à comprendre ces expressions.&lt;br /&gt;
&lt;br /&gt;
* '''Noeud :''' C'est un programme qui tourne de manière indépendante et qui réalise une tâche spécifique.&lt;br /&gt;
&lt;br /&gt;
* '''Type :''' C'est un format spécifique de message. Il définit les valeurs que peut prendre une donnée, ainsi que les opérateurs qui peuvent lui être appliqués.&lt;br /&gt;
&lt;br /&gt;
* '''Odométrie :''' L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Cette mesure de bas niveau est présente sur quasiment tous les robots mobiles, grâce à des capteurs embarqués permettant de mesurer le déplacement du robot (de ses roues).&lt;br /&gt;
&lt;br /&gt;
==Avancement du Projet==&lt;br /&gt;
===Semaine 1===&lt;br /&gt;
&lt;br /&gt;
*Participation aux Finales Nationales des Olympiades des Métiers en robotique mobile (4ème)&lt;br /&gt;
&lt;br /&gt;
===Semaine 2===&lt;br /&gt;
&lt;br /&gt;
====Etablissement du cahier des charges====&lt;br /&gt;
&lt;br /&gt;
*Prise de connaissance des contraintes d'environnement&lt;br /&gt;
*Dialogue avec l'équipe responsable de la partie [http://projets-imasc.plil.net/mediawiki/index.php?title=RoboCup_2015 Manager]&lt;br /&gt;
Familiarisation avec l'environnement logiciel ROS&lt;br /&gt;
Recherches de solutions pour la localisation (SLAM) et la génération de trajectoire (algorithme A-star)&lt;br /&gt;
&lt;br /&gt;
====Recherche d'un algorithme de recherche de chemin====&lt;br /&gt;
&lt;br /&gt;
Nous avons fait nos recherches en nous orientant sur le déplacement du Robotino afin de trouver un algorithme de recherche de chemin, capable de trouver le chemin le plus court, puisqu'un des buts de la compétition étant la rapidité.&amp;lt;br&amp;gt;&lt;br /&gt;
Plusieurs algorithmes sont donc ressortis :&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme Dijkstra (On part du point de départ et on cherche le chemin le plus court vers le point d'arrivée en cherchant dans TOUTES les directions)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme A-Star (Basé sur Dijkstra, cet algo s'oriente directement vers le point d'arrivée en minimisant la distance avec celui-ci)&amp;lt;br&amp;gt;&lt;br /&gt;
*L'algorithme D-Star Lite (Amélioration du A-Star avec bufferisation des précédents calculs pour éviter les calculs inutiles en cas d'arrivée d'un obstacle mobile sur la trajectoire)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nous avons visualisé les différents algorithmes sur [http://qiao.github.io/PathFinding.js/visual/ PathFinding]&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de l'algorithme A-Star :&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Tout d'abord, on calcule la distance qui sépare le robot du point d'arrivée, et on définit les points interdits par les obstacles. (la zone bleue correspond&lt;br /&gt;
à l'obstacle et la zone verte est une zone ou le robot touche l'obstacle. Ces deux zones constituent la zone interdite).&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_1.PNG | 400px | center]][[Image:Projet_S8_A_STAR_2.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Ensuite le Robot trouve un premier noeud sur la grille qu'on lui a attribué. Si le noeud n'est pas dans une zone interdite, il sauvegarde ce noeud.&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_3.PNG | 400px | center]][[Image:Projet_S8_A_STAR_4.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Il répète l'opération jusqu'à trouver le chemin qui le mènera à l'arrivée&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:Projet_S8_A_STAR_5.PNG | 400px | center]]&lt;br /&gt;
&lt;br /&gt;
*Attention : c'est seulement lorsqu'il aura trouvé le chemin complet que le robot va se déplacer !&lt;br /&gt;
&lt;br /&gt;
====Recherche d'une solution pour la localisation====&lt;br /&gt;
&lt;br /&gt;
Pour la localisation nous allons utilisé un '''''Algorithme de Localisation et Cartographie Simultanée''''' (SLAM en anglais):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SLAM.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Explicitation des différentes parties :&lt;br /&gt;
&lt;br /&gt;
*Odometry change     : changement de position&lt;br /&gt;
*Odometry update     : mise à jour de l'odométrie&lt;br /&gt;
*Re-observation      : vérification des changements à partir de toutes les données disponibles&lt;br /&gt;
*New observations    : mise à jours de la matrice d'état&lt;br /&gt;
&lt;br /&gt;
*Laser scan          : scan laser brut&lt;br /&gt;
*Landmark Extraction : extraction des objets caractéristiques&lt;br /&gt;
*Data Association    : association entre objets scannés et objets en mémoire&lt;br /&gt;
&lt;br /&gt;
Ce schéma sera explicité à la séance prochaine.&lt;br /&gt;
&lt;br /&gt;
===Semaine 3===&lt;br /&gt;
&lt;br /&gt;
====Découpage du travail à effectuer====&lt;br /&gt;
&lt;br /&gt;
Nous avons découper le travail de génération de map et de la correction de position de la manière suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SchémaProjetS8-1.png | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
( Nous recommandons au lecteur de se référer à la partie vocabulaire pour comprendre les termes techniques )&lt;br /&gt;
&lt;br /&gt;
Chaque case du diagramme précédent correspond à un noeud ROS.&lt;br /&gt;
&lt;br /&gt;
Décrivons précisément le rôle de chaque noeud :&lt;br /&gt;
*'''Laser''' récupère les données brutes du laser.&lt;br /&gt;
*'''Filtrage''' permet, comme son nom l'indique, d'enlever les éventuels bruits qui affectent les données du laser.&lt;br /&gt;
*'''Reconnaissance des droites''' traite les données laser filtrées pour détecter les droites présentes (Transformée de Hough ou Ransac)&lt;br /&gt;
*'''Reconnaissance des formes''' extrapole les objets (machines) à partir des droites.&lt;br /&gt;
*'''Corrélation emplacements machines''' lie la position des machines détectées au laser et les positions envoyées par RefBoxCom pour éviter les incohérences.&lt;br /&gt;
*'''Odométrie''' récupère la position du robot par rapport au point de départ. Il renvoie une position corrigée grâce au gyroscope(Pose) et une position non corrigée par le gyroscope (Twist) &lt;br /&gt;
*'''Traitement de position''' corrige l'erreur sur le Twist avec les données du gyroscope (par dérivation).&lt;br /&gt;
*'''Fusion de Kalman''' est un algorithme qui va coupler les données de position et les données du laser afin de fournir un modèle et une position précise. C'est le noeud central du SLAM.&lt;br /&gt;
*'''Stockage machines + robot''' transforme les positions des machines et du robot en grille. Il sera couplé aux détections d'obstacles.&lt;br /&gt;
*'''Grid Map''' renvoit une map utilisée ensuite pour les déplacements et les calculs de trajectoires (A_Star)&lt;br /&gt;
*'''RefBoxCom''' stocke et renvoie la position des machines.&lt;br /&gt;
*'''Position robot''' renvoie la position exacte du robot sur la grille.&lt;br /&gt;
*'''Manager''' Noeud qui envoie la position à atteindre.&lt;br /&gt;
*'''Pathfinder''' recherche le chemin demandé par le Manager sur une grille&lt;br /&gt;
*'''Parcoureur''' exécute le chemin trouvé en fournissant les vitesses au noeud Déplacement.&lt;br /&gt;
*'''Déplacement''' (noeud robotino_local_move_server), qui donne les commandes aux moteurs à partir de la vitesse linéaire et angulaire envoyée par le Parcoureur.&lt;br /&gt;
&lt;br /&gt;
====Recherche de documentation sur ROS et l'API du Robotino====&lt;br /&gt;
&lt;br /&gt;
Nous avons cherchés toutes les documentations techniques nécessaires pour la programmation de chaque noeud : [http://wiki.ros.org/fr Wiki_ROS] et [http://wiki.ros.org/robotino API_Robotino], nous permettant de mettre à jour le schéma global, notamment au niveau des types.&lt;br /&gt;
&lt;br /&gt;
====Etude de l'algorithme A-star précédent====&lt;br /&gt;
&lt;br /&gt;
Nous nous sommes ensuite concentrés sur le noeud GridMap qui contient ''Map.cpp'' :&lt;br /&gt;
&lt;br /&gt;
Dans le code de l'an dernier, ce noeud générait une grille en dur. Cependant, cette solution n'est pas possible cette année car nous ne connaissons pas toutes les informations sur la piste (on connaît à peu près la position mais pas l'orientation). Il va donc falloir générer une grille en fonction du noeud précédent qui nous renverra un type ''OccupancyGrid''. &lt;br /&gt;
&lt;br /&gt;
Etant donné que ce noeud tournera en permanence, si des informations changent pendant que le robot est sur la piste (détection des nouvelles machines par exemple), le noeud ''Map.cpp'' modifiera la grille en temps réel.&lt;br /&gt;
&lt;br /&gt;
La grille est décomposée en case pour le A-Star :&lt;br /&gt;
&lt;br /&gt;
Si c'est une case interdite (obstacle) ont associe a la case la valeur 1, si elle est autorisée, on associe la valeur 0. On illustre le principe précédent par un exemple :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
Cependant, le noeud &amp;quot;Grid Map&amp;quot; va nous délivrer un vecteur et non une matrice par le biais de ''OccupancyGrid.Data''.Dans notre exemple précédent, on récupère le vecteur suivant : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet_S8_Creation_Map_2.PNG | 800px | center]]&lt;br /&gt;
&lt;br /&gt;
On choisit donc de transformer ce vecteur en matrice, car l'algorithme A-Star fonctionne sur un graphe, pas un vecteur. On connait la largeur (en case) de la grille grâce au type ''OccupancyGrid.info.width''.&lt;br /&gt;
&lt;br /&gt;
Le pseudo-code pour générer la matrice à partir de ce vecteur sera le suivant :&lt;br /&gt;
&lt;br /&gt;
 fonction create_grid (OccupancyGrid.Data vecteur[size]) : matrice[height].[width]&lt;br /&gt;
 {&lt;br /&gt;
   matrice[height].[width] ;		&lt;br /&gt;
      int t &amp;lt;- size;&lt;br /&gt;
          Pour (i de 0 à height)&lt;br /&gt;
          faire:&lt;br /&gt;
                {&lt;br /&gt;
                    Pour (j de 0 à width)&lt;br /&gt;
                    faire :&lt;br /&gt;
                            {&lt;br /&gt;
                               matrice[i].[j] &amp;lt;- vecteur[t] ;&lt;br /&gt;
                               t++;&lt;br /&gt;
                            }&lt;br /&gt;
                }&lt;br /&gt;
   return matrice;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Semaine 4===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction====&lt;br /&gt;
&lt;br /&gt;
Nous nous concentrons essentiellement sur la première partie, qui est la partie : &amp;quot;Landmarks Extraction&amp;quot; (extraction des points de repères). On travaille ici dans le repère du laser, qui est différent de celui du robot, et du global. La transposition dans le repère global se fera dans la partie &amp;quot;Data Association&amp;quot;. On doit ainsi, dans l'ordre :&lt;br /&gt;
&lt;br /&gt;
☑ récupérer des données lasers via le topic /scan&amp;lt;br&amp;gt;&lt;br /&gt;
☑ convertir les coordonnées polaires en coordonnées cartésiennes en filtrant les données aberrantes (&amp;gt; range_max et &amp;lt; range_min)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ implémenter l'algorithme [http://fr.wikipedia.org/wiki/RANSAC RANSAC] (Random SAmple Consensus) de détection de droites :&amp;lt;br&amp;gt;&lt;br /&gt;
☑ détecter la &amp;quot;meilleure&amp;quot; droite à partir des points en sélectionnant aléatoirement des combinaisons de points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ stocker le meilleur modèle (angle + tableau de points)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ recommencer tant qu'il reste assez de points à traiter (5)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les segments à partir des modèles trouvés et des points&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extraire les points extrèmes&amp;lt;br&amp;gt;&lt;br /&gt;
☑ calculer la taille du segment&amp;lt;br&amp;gt;&lt;br /&gt;
☑ chercher des angles droits, des segments de 35 ou 70 cm (largeur et longueur d'une machine)&amp;lt;br&amp;gt;&lt;br /&gt;
☑ extrapoler les positions des machines dans le repère du laser&amp;lt;br&amp;gt;&lt;br /&gt;
☑ définir le barycentre de la machine ainsi que son angle&amp;lt;br&amp;gt;&lt;br /&gt;
☐ stocker ces positions&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pathfinder====&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi pris du temps avec '''Valentin VERGEZ''', qui a développé, l'an dernier, les codes pour le déplacement du Robotino et le calcul de trajectoire&lt;br /&gt;
&lt;br /&gt;
Nous avons éclairci quelques points sur cette partie du projet :&lt;br /&gt;
*Les commentaires sur l'utilité de chaque fonction ont été rajoutés.&lt;br /&gt;
*Le &amp;quot;code mort&amp;quot; a été nettoyé ainsi que les parties inutiles.&lt;br /&gt;
*Nous devons trouver un moyen de tester cette partie du code seule. (A priori graphiquement).&lt;br /&gt;
&lt;br /&gt;
Etant donné l'arrivée d'un nouvel ordinateur au sein de l'équipe, nous en avons profités pour installer les logiciels qui nous permettrons de faire tourner les noeuds codés sur les Robotino :&lt;br /&gt;
&lt;br /&gt;
*Installation d'Ubuntu 12.04 ( c'est cette version qui permet de faire tourner ROS Hydro)&lt;br /&gt;
&lt;br /&gt;
*Installation de ROS Hydro (ensemble d'outils informatiques open source permettant de développer des logiciels pour la robotique.)&lt;br /&gt;
&lt;br /&gt;
*Installation des paquets nécessaires (catkin, Desktop Install, ROS-Base, Individual Package)&lt;br /&gt;
&lt;br /&gt;
*Installation de GIT (outil de bas niveau permettant de gérer l'évolution du contenu d'une arborescence)&lt;br /&gt;
&lt;br /&gt;
*Vérification que toutes les fonctionnalités de ROS Hydro étaient présentes ( [http://wiki.ros.org/ROS/Tutorials Tutoriel])&lt;br /&gt;
&lt;br /&gt;
La récupération du code complet de l'année dernière et une solution a été trouvée afin de tester le code de génération de trajectoire A-star:&lt;br /&gt;
&lt;br /&gt;
*Pour visualiser une Map ainsi qu'un Path (chemin), on peut utiliser l'outils [http://wiki.ros.org/rviz RVIZ].&lt;br /&gt;
*Dans RVIZ, on peut ajouter un Path (topic /path), ainsi qu'ajouter une Map (/grid): Ceci correspond exactement à ce que nous souhaitons visualiser pour la partie calcul de trajectoire.&lt;br /&gt;
*Pour publier une Map fictive, on executera le script fakeGrid.sh&lt;br /&gt;
*Pour générer un chemin, on lancera le pathfinder (rosruns rbqt_pathfinder server : notre code) et on effectuera une requête avec le script pathReq.sh.&lt;br /&gt;
&lt;br /&gt;
Si tout se passe correctement, le chemin devrait s'afficher en &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; vert &amp;lt;/span&amp;gt; sur la map.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du communiquer notre avancement aux autres parties de l'équipe. Le schéma général ainsi qu'un outil permettant d'expliquer les différents algorithmes de recherche de trajectoire optimale nous ont aidé à leur communiquer nos objectifs et les processus choisis.&lt;br /&gt;
&lt;br /&gt;
L'algorithme A-Star que nous allons utiliser donne le résultat final suivant (utilisation du site [http://qiao.github.io/PathFinding.js/visual/ PathFinding] ):&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Projet S8 A STAR E.PNG | center | thumb ]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FFFF00;&amp;quot;&amp;gt; le chemin optimal calculé par A-Star &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt; le point de départ&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt; le point d'arrivée&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt; les points interdits (obstacle)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt; les points que l'algorithme a déjà calculé&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt; les points que l'algorithme aurait calculé à la prochaine itération&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - filtrage====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons commencé à définir une classe laserScan qui contient la fonction polarToCart, elle convertit les données laser (tableau de ranges) en liste de points (x,y) :&lt;br /&gt;
&lt;br /&gt;
 void laserScan::PolarToCart (){&lt;br /&gt;
  Point p;&lt;br /&gt;
  for (int i=0; i&amp;lt;m_ranges.size(); i++){&lt;br /&gt;
    if((m_ranges[i]&amp;gt;getRangeMin()) &amp;amp;&amp;amp; (m_ranges[i]&amp;lt;getRangeMax())){&lt;br /&gt;
      p.setX(m_ranges[i]*cos(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      p.setY(m_ranges[i]*sin(getAngleMin() + i*getAngleInc()));&lt;br /&gt;
      m_points.push_back(p);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Dans cette partie, nous avons déterminé quel algorithme nous allons utiliser : [http://fr.wikipedia.org/wiki/RANSAC#L.27algorithme RANSAC]. L'algorithme de RANSAC trouve la meilleure droite dans un nuage de points. On itère plusieurs fois cet algorithme afin de trouver l'ensemble de toutes les droites du scan laser. On a donc en sortie une liste des droites composants le nuage de points initial.&lt;br /&gt;
&lt;br /&gt;
 Entrée : listOfPoints    -&amp;gt; liste de points initiale &lt;br /&gt;
 Sortie : meilleur_modèle -&amp;gt; les paramètres de la droite qui correspondent le mieux aux points&lt;br /&gt;
                          -&amp;gt; tableau de points à partir desquels la droite a été estimée&lt;br /&gt;
                          -&amp;gt; erreur du modèle de droite par rapport aux points&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: #000080;&amp;quot;&amp;gt;&lt;br /&gt;
 tant que la liste contient assez de points&lt;br /&gt;
  itérateur := 0&lt;br /&gt;
  meilleur_modèle := aucun&lt;br /&gt;
  tant que itérateur &amp;lt; k (fixé par une loi de probabilité)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #008000;&amp;quot;&amp;gt;on choisit deux points au hasard dans la liste&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #00FFFF;&amp;quot;&amp;gt;on fabrique un modèle_possible à partir de ces deux points&amp;lt;/span&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;color: #FF0000;&amp;quot;&amp;gt;Pour chaque point de la liste qui ne sont pas dans le modele_possible&lt;br /&gt;
    si le point s'ajuste au modele_possible avec une erreur inférieure à t&lt;br /&gt;
     Ajouter ce point au modele&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #00FF00;&amp;quot;&amp;gt;si le nombre de points dans le modele est suffisant pour valider l'existence du modele&lt;br /&gt;
     erreur := coefficient de corrélation de la régression linéaire de ensemble_points&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;si erreur &amp;lt; erreur du meilleur_modele&lt;br /&gt;
     meilleur_modèle := modèle_possible&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  stocker meilleur_modèle dans liste de modèles&lt;br /&gt;
  retirer meilleur_ensemble_points de la liste des points initiale&lt;br /&gt;
  recommencer avec la liste modifiée&lt;br /&gt;
&lt;br /&gt;
===Semaine 5===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous avons adapté l'algorithme précédent afin de mieux correspondre aux structures que nous avons créées :&lt;br /&gt;
*Modele&lt;br /&gt;
**Liste de points&lt;br /&gt;
**Liste d'indices&lt;br /&gt;
**Corrélation&lt;br /&gt;
**Droite&lt;br /&gt;
***Point&lt;br /&gt;
***Angle&lt;br /&gt;
**Segment&lt;br /&gt;
***Point &amp;quot;min&amp;quot;&lt;br /&gt;
***Point &amp;quot;max&amp;quot;&lt;br /&gt;
***Angle&lt;br /&gt;
***Taille&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi codé toutes les fonctions nécessaires dans l'algorithme de Ransac, dont celle permettant la correction de l'approximation de droite par régression linéaire des points correspondants à un modèle trouvé (''linReg()'') qui nous a donné matière à réflexion. Aussi, notre première idée qui était de travailler avec des ''std::vector'' a du changer puisque l'aspect récursif de l'algorithme que nous allons utiliser nécessite de multiples suppressions sur les données à entrer dans l'algorithme de Ransac. On travaille donc maintenant avec des ''std::list''.&lt;br /&gt;
&lt;br /&gt;
Tous nos codes sont disponibles sur la branche [https://github.com/PyroTeam/robocup-pkg/tree/feature/navigation/SLAM/navigation/localisation/src feature/navigation/SLAM du GIT de l'équipe PyroTeam].&lt;br /&gt;
&lt;br /&gt;
===Semaine de vacances de février===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de droite====&lt;br /&gt;
&lt;br /&gt;
Nous devons réaliser un noeud permettant de valider notre algorithme, c'est-à-dire implémenter sous ROS notre code C++ afin de tester, soit directement sur le robot, soit avec des [http://wiki.ros.org/Bags bagfiles]. Cette étape est très importante pour pouvoir passer à la suite : extrapoler les droites trouvées en segments puis en objets.&lt;br /&gt;
&lt;br /&gt;
Notre programme consistant à reconnaître les droites à partir du scan laser est fonctionnel et a été testé à partir du scan laser suivant :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:ScanLaser.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Processus de validation :&lt;br /&gt;
&lt;br /&gt;
*Lancer le programme ''rosrun localisation test_polar_to_cart''&lt;br /&gt;
&lt;br /&gt;
résultat : on trouve 5 droites&lt;br /&gt;
&lt;br /&gt;
 m = -0.0229637 p = -0.24079&lt;br /&gt;
 nb de points dans la droite : 246&lt;br /&gt;
 coeff de correlation : 0.812376&lt;br /&gt;
&lt;br /&gt;
 m = -0.0315132 p = 3.7506&lt;br /&gt;
 nb de points dans la droite : 102&lt;br /&gt;
 coeff de correlation : 0.928089&lt;br /&gt;
&lt;br /&gt;
 m = 32.9243 p = -139.943&lt;br /&gt;
 nb de points dans la droite : 77&lt;br /&gt;
 coeff de correlation : 0.914475&lt;br /&gt;
&lt;br /&gt;
 m = 7.04634 p = -15.42&lt;br /&gt;
 nb de points dans la droite : 32&lt;br /&gt;
 coeff de correlation : 0.970724&lt;br /&gt;
&lt;br /&gt;
 m = 0.253029 p = 1.32235&lt;br /&gt;
 nb de points dans la droite : 28&lt;br /&gt;
 coeff de correlation : 0.979578&lt;br /&gt;
&lt;br /&gt;
ce qui correspond à l'image suivante :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
On voit que la recherche de droite marche bien, mais peut être améliorée en ajoutant des conditions de proximité des points correspondants à une seule droite, pour éviter le phénomène que l'on voit au milieu. Le résultat après avoir ajouté cette condition et en ayant affiné au maximum les paramètres, au dépend d'un temps de calcul beaucoup plus élevé (9,416 secondes au lieu de 0,536 s)  :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:DroitesTrouvées2.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Les impératifs de la compétition nous imposant une certaine rapidité pour se localiser et détecter les machines, nous retiendrons la solution la plus rapide et nous séparerons les droites en segment après leur détection.&lt;br /&gt;
&lt;br /&gt;
Pour valider l'algorithme de régression linéaire nous avons :&lt;br /&gt;
*Récupéré tous les points correspondants à chaque droite&lt;br /&gt;
*Rentré ces points sur Excel&lt;br /&gt;
*Fait une courbe de tendance&lt;br /&gt;
*Affiché l'équation de droite et le coefficient de corrélation&lt;br /&gt;
*Comparé avec ce qu'a trouvé notre programme&lt;br /&gt;
*Conclu que notre programme était bon&lt;br /&gt;
&lt;br /&gt;
===Semaine 6===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Landmarks Extraction - reconnaissance de machines====&lt;br /&gt;
&lt;br /&gt;
Les objectifs de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*à partir de la liste de droites, extraire les segments&lt;br /&gt;
*extrapoler les positions machines à partir d'un segment complet (35 ou 70 cm)&lt;br /&gt;
*réaliser une interface graphique pour visualiser les segments trouvés en temps réel&lt;br /&gt;
*regarder ce qu'on doit rentrer dans l' '''Extended Kalman Filter''' au niveau du format des positions machines et de l'odométrie pour pouvoir réaliser le '''Data Association''' de façon cohérente avec la suite.&lt;br /&gt;
&lt;br /&gt;
L'extraction de segment à partir des 5 droite précédemment trouvées nous donne 7 segments:&lt;br /&gt;
&lt;br /&gt;
 Segment 1&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.04033e-08, -0.238)&lt;br /&gt;
 Max(4.24699, -0.26092)&lt;br /&gt;
 taille : 4.24705&lt;br /&gt;
 angle  : -0.309205&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 2&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(-1.64267e-07, 3.758)&lt;br /&gt;
 Max(3.4172, 3.63358)&lt;br /&gt;
 taille : 3.41946&lt;br /&gt;
 angle  : -2.08521&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 3&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(4.24452, -0.234635)&lt;br /&gt;
 Max(4.33124, 2.18017)&lt;br /&gt;
 taille : 2.41636&lt;br /&gt;
 angle  : 87.9432&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 4&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.30055, 0.871242)&lt;br /&gt;
 Max(2.32511, 0.736592)&lt;br /&gt;
 taille : 0.136872&lt;br /&gt;
 angle  : -79.6622&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 5&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.50359, 2.18655)&lt;br /&gt;
 Max(2.53413, 2.56542)&lt;br /&gt;
 taille : 0.380104&lt;br /&gt;
 angle  : 85.3914&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 6&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(2.73122, 2.05171)&lt;br /&gt;
 Max(3.049, 2.03728)&lt;br /&gt;
 taille : 0.318107&lt;br /&gt;
 angle  : -2.5999&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 Segment 7&amp;lt;br&amp;gt;&lt;br /&gt;
 Min(1.14156, 1.64221)&lt;br /&gt;
 Max(1.39648, 1.61891)&lt;br /&gt;
 taille : 0.255984&lt;br /&gt;
 angle  : -5.22068&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SegmentsTrouvés.png | center | thumb]]&lt;br /&gt;
&lt;br /&gt;
Tout cela en 0,540s !&lt;br /&gt;
&lt;br /&gt;
A partir de la liste de segments précédente, on extrait une liste de machine à partir des segments de 35 ou 70 cm, qui sont les tailles des machines. Comme le scan que nous utilisons pour le moment n'est pas un scan avec une vraie machine, mais disposant quand même de 2 segments d'à peu près 35 cm, nous utilisons ces deux segments comme ''petit côté'' de la machine. On trouve ainsi deux machines :&lt;br /&gt;
&lt;br /&gt;
 Machine 1&lt;br /&gt;
   centre en (2.53292, 2.20155)&lt;br /&gt;
   orientation : 175.391°&lt;br /&gt;
&lt;br /&gt;
 Machine 2&lt;br /&gt;
   centre en (3.06493, 2.05243)&lt;br /&gt;
   orientation : 87.4001°&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Une amélioration de l'algorithme a été faite pour la détection de machine. En effet, dans le cas où on détectait un petit et un grand côté de machine, on trouvait deux machines avec des centres à peu près au même endroit. Maintenant, on fusionne ces données en créant un point milieu entre les deux données, et on prend l'orientation du grand côté.&lt;br /&gt;
&lt;br /&gt;
On a commencé à faire des tests sur ROS directement avec un noeud factice qui publie un scan laser à une fréquence de 10Hz, ce qui est la fréquence réelle du laser Hokuyo. La détection se fait assez rapidement et de façon précise. Des tests sur le robot sont prévus en début de semaine 7 avec les vraies machines.&lt;br /&gt;
&lt;br /&gt;
===Semaine 7===&lt;br /&gt;
&lt;br /&gt;
====Localisation - Data Association====&lt;br /&gt;
&lt;br /&gt;
Les objectif de cette semaine :&lt;br /&gt;
&lt;br /&gt;
*coder le noeud '''Data Association''' qui liera la position donnée par l'odométrie (mesure relative de la position par rapport à un point de départ à peu près connu) avec les machines trouvées dans le champ du laser&lt;br /&gt;
&lt;br /&gt;
D'après la dernière version du sujet 2015, l'aire de jeu de 6 x 12 m est séparée en zones de 1,5 x 2 m de large, dans lesquelles se situent une seule machine. Chaque équipe a 6 machines dont la zone est connue, donnée par la Referee Box. Le but du noeud ROS de ''Data Association'' sera de transposer les positions machines dans le repère global de la piste, ainsi le Manager pour savoir devant quelle machine le robot est, et connaître sa position et son orientation.&lt;br /&gt;
&lt;br /&gt;
La piste sera donc comme cela :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Piste.PNG | center]]&lt;/div&gt;</summary>
		<author><name>Tdanel</name></author>	</entry>

	</feed>