Études et réalisations conception d'un robot mobile iut de toulon
TRANSCRIPT
Études et Réalisations
Conception d'un Robot Mobile
Etudiant : LE GLOUANEC Maéva
MARTINEZ Laura
CORDIER Camille
COSCOLLA Arthur
RAVAZZOLA Arnaud
BOTOU Florian
IUT de Toulon - Département GEII
Université de Toulon
IUT de Toulon - Département GEII
IUT de Toulon - Département GEII
Sommaire
1. Présentation du robot et prise en main de l'environnement de développement……….V
a. Présentation du robot
b. Prise en main de l'environnement de développement
2. Les timers……………………………………………………………………………VII
3. Les convertisseurs analogique-numérique…………………………………………….X
4. Le pilotage des moteurs……………………………………………………………...XII
5. Robot mobile autonome……………………………………………………………XVII
6. Télémètre laser rotatif................................................................................................XXI
a. Documentation du télémètre laser
b. Récupération et analyse des données
c. Filtrage des données
d. Calcul de la meilleure trajectoire à suivre 7. Le module réception balise......................................................................................................4
a.Principe de la balise..................................................................................................4
b. Le codeur de position (QEI)..................................................... ......................4
c.Triangulation de la position du robot..................................................................6
8. L'analyse du signal...................................................................................................................7
a. Le module Input Capture.....................................................................................7
b. Gestion des fréquences reçues............................................................................11
9. La carte Balise.......................................................................................................................13
a. Choix du filtre sous FilterLab............................................................................13
b. Shématique sous Orcad.....................................................................................14
c. Le Routage........................................................................................................16
10.Asservissement moteur ..............................................................................................
a) Mécanique …................................
b) Informatique ….............................
c) Odométrie ….................................
11. Liaison SPI ….....................................
IUT de Toulon - Département GEII
Introduction
Participer à la coupe de France robotique des IUT est un défi extrêmement motivant.
C’est pour cela que notre équipe a choisi de le relever. Notre groupe se compose de 10
membres avec la volonté de mettre en commun les connaissances acquises.
Ce concours est un défi vis-à-vis de la pluridisciplinarité qu’il demande. En effet, seul un kit
comprenant les moteurs, les roues, un châssis et les engrenages sont fournis, donc un travail
électronique est exigé. Mais pas seulement, nous nous devons d’optimiser un maximum
l’architecture du robot, inventer une approche la plus efficace possible puis la programmer.
Tout notre travail se doit de respecter les nombreuses règles qu’impose ce concours.
Certaines s’appliquent aux Robots qui vont concourir et d’autres sur l’organisation du
tournois. Ce dossier présente donc l'état du robot tel qu'il est en cette fin du mois de Mars
2014.
Nous détaillons dans ce rapport les solutions apportés pour répondre au règlement de la
coupe.
IUT de Toulon - Département GEII
1. Présentation du robot et prise en main de l'environnement de
développement
a. Présentation du robot
i. Architecture
Le robot possède une forme ronde, car c'est la forme la plus stratégique pour ne pas
entrer en collision avec l'objet détecté juste en tournant sur lui-même. Sachant que le diamètre
minimum nous a été imposé par le châssis métallique obligatoire pour la participation au
concours. Mise à part les "carénages" à réaliser nous n'avons aucune tâche mécanique.
ii. Equipements
En ce qui concerne la partie électronique du robot, nous avons à cette heure-ci une
carte mère, une carte fille et une carte de puissance. La carte mère a le rôle de superviser la
carte fille et la carte de puissance permet d'établir des courants stables et de les distribuer par
la suite afin de protéger les cartes clientes de celle-ci.
Nous avons installé 3 capteurs infrarouges qui ont pour but de détecter les obstacles
afin de les éviter avant l'accident. Ces 3 capteurs réunis forment un angle de 120° de vision
devant, avec une distance de fonctionnement entre 10 et 80cm. La distance maximum de
détection est amplement suffisante pour éviter l'obstacle avec la vitesse à laquelle tourne le
robot.
b. Prise en main de l'environnement de développement
L'environnement de développement se compose de 2 logiciels couplés :
MPLAB X : Ce logiciel permet de gérer des projets utilisant des
microcontrôleurs PIC ou dsPIC. Il comprend un éditeur de code, un
compilateur de code assembleur en code machine, et un module
permettant d'envoyer le programme compilé au PIC via une interface
(ici on utilisera l'interface MPLAB ICD 3). XC16 : Permet de générer du code assembleur destiné au PIC 16 Bits à
partir d'un code en C.
Ces deux logiciels permettant donc de programmer un PIC à l'aide d'un code en C.
IUT de Toulon - Département GEII
i. Installation de MPLAB
Nous suivons le protocole d'installation de MPLAB afin de pouvoir programmer les cartes du
robot mobile. L'ICD 3 est correctement reconnu par Windows.
ii. Premier programme
Pour les tests, on utilisera une carte conçue pour ce projet. Elle intègre un
dsPIC33FJ128MC804, programmable à l'aide de l'ICD 3, ainsi que de nombreux capteurs
et périphériques de communication permettant d'effectuer des tests sans avoir à réaliser de
montage électrique.
Le dsPIC33FJ128MC804 utilisé est décrit en détail sur le site internet de chez Microchip
(Voir ce lien :
http://www.microchip.com/wwwproducts/Devices.aspx?dDocName=en532303).
IUT de Toulon - Département GEII
1. Création d'un Projet
Nous créons tout d'abord un premier projet de type MicrochipEmbedded → StandaloneProjet
via MPLAB X.
On spécifie alors le projet :
La famille de composant : 16-bit Dscs ( dsPIC33)
Le composant utilisé : dsPIC33FJ128MC804 L'outil de programmation : ICD 3 Le compilateur : XC16 Le nom et le chemin du projet
Maintenant que le projet est créé, nous pouvons commencer à programmer.
2. Ecriture du programme
Nous créons pour commencer un programme appelé main.c qui sera codé en C#.
Dans ce premier programme, nous définissons FCY (Frequency Instruction Cycle) soit la vitesse d'exécution du Microchip à 16MHz.
On configure aussi le Quartz sans PPL ainsi que l'Horloge.
On appelle aussi la fonction InitIO, or nous ne l'avons pas créée. Pour éviter ce problème,
il nous faut ajouter un fichier IO.c ainsi que la fonction InitIO.
Pour cela, nous créons un fichier IO.c dans lequel nous codons la fonction InitIO appelé
dans le main, ainsi que son Header associé IO.h.
Le Header contient les prototypes des fonctions, les définitions des pins, la déclaration de
variable externe. C'est ce fichier qu'on appelle pour utiliser les fonctions créées dans le
fichier source.
RA4 → sortie 34 du microcontrôleur
RA7 → sortie 13 du microcontrôleur
RA10 → sortie 12 du microcontrôleur
Après avoir relié correctement les pins de sorties du microcontrôleur aux pins des DELS
on constate que les 3 DELS s'allume.
IUT de Toulon - Département GEII
3. Débuggeur
Nous allons nous intéresser à présent aux points d'arrêt. Pour en placer il suffit d'un
double clic sur le numéro de la ligne à laquelle on veut insérer le point d'arrêt. Lorsque le
programme atteint un point d'arrêt, il se fige et attend qu'on lui donne l'ordre de continuer.
C'est uniquement lorsque le programme est figé que l'on peut regarder l'état de n'importe
quelle variable crée dans ce dernier. Pour cela on utilise la fenêtre Watch, on peut dans ce
cas-là visualiser le port A en l'ajoutant en faisant un double clic sur <Entry new watch>.
C'est donc une technique de debug qu'on devra utiliser lorsque le programme se compile
mais ne fonctionne pas correctement.
2. Les timers
Le timer est un compteur de cycles d'instructions. Il suffit de lire régulièrement ce compteur
pour évaluer le temps qui s'écoule. Il est également possible d'initialiser ce compteur avec le
nombre de notre choix. Il faut aussi noter que ce compteur doit être configuré pour
fonctionner.
Le timer est constitué de :
le TMR0. C'est un registre, qui compte les fronts montant du signal qu'on lui fournit.
Arrivé à son maximum il repasse à 0.
le prescaler. Il divise la fréquence du signal qu'on lui fournit par une constante qu'il est nécessaire de programmer. Ex : un signal de période 1us divisé par 32 do nnera un signal de période 32µs.
les bits de configuration (RTE, RTS …). Ils permettent de définir les différentes fonctions.
la synchro. Retarde le début du fonctionnement de 2 cycles d'instruction lorsqu'un bit
relatif au timer est modifié. Cette fonction est due à l'architecture du timer et ne peut
être contournée.
Le dsPIC33FJ128MC804 utilisé possède 5 timers 16 bits pouvant former jusqu'à 2 timers 32
bits qui peuvent être ajustés de manière différente. L'intérêt d'un timer est de permettre la
génération d’événements périodiques tels que le clignotement d'une diode ou la génération
d'un signal PWM.
Un timer peut générer des interruptions s’il est configuré comme tel, c’est ce que nous allons
programmer pour gérer le clignotement d’une DEL toute les secondes.
IUT de Toulon - Département GEII
Pour configurer un timer nous devons changer la valeur des bits prédéfinis pour le timer
expliqués dans la datasheet du pic.
Tout d'abord, nous allons couplés les timers 2 et 3 afin de gérer le clignotement de la DEL 3
avec ce regroupement et le clignotement de la DEL 1 à l'aide du timer 1. Les timers nous
seront utiles pour de multiples tâches tel que la modification de la rampe d'accélération pour
que le signal de commande soit plus ou moins rapide pour atteindre le signal de consigne etc.
On constate à l'oscilloscope les deux fréquences attendues, à l'œil nu on peut observer le
changement d'état de la DEL 1 car le timer change toute les secondes.
Dans le futur, on utilisera les DELs dans le but de vérifier le bon fonctionnement du timer
dont elle décrira la fréquence.
Si on change la valeur des prescalers et/ou des périodes des timers on peut observer une
variation de la fréquence des DELS c'est à dire qu'on a changé la fréquence des interruptions
des timers en changeant un ou les deux paramètres. Exemple de configuration dans le fichier
timer.c en annexe.
IUT de Toulon - Département GEII
3- Le convertisseur analogique-numérique
Cette partie utilise la carte moteur du robot. C’est donc cette carte qu’il faudra programmer !
Dans, cette partie, nous allons utiliser le convertisseur analogique numérique du dsPIC. Il sera
utilisé pour récupérer les distances vues par des télémètres infrarouges situés sur le robot.
Le convertisseur analogique-numérique du dsPIC est un convertisseur à approximation
successive (SAR ADC). Les entrées sorties utilisables ont un certain nombre de restrictions,
indiquées sur le schéma suivant :
IUT de Toulon - Département GEII
Dans ce projet, nous utiliserons le convertisseur analogique-numérique dans une version
simplifiée : les conversions se feront uniquement sur le channel 0, et séquentiellement. Le
mode DMA (Direct Memory Access permettant de faire des acquisitions simultanées sur
plusieurs canaux ne sera pas utilisé.
On utilise ce convertisseur pour convertir le signal renvoyé par les télémètres lasers :
if(ADCIsConversionFinished() != 0)
{
ADCClearConversionFinishedFlag(); unsigned int *result = ADCGetResult();
float volts = ((float)result[1])*3.3/4096;
valeurTelemetreMilieu = 15/volts;
volts = ((float)result[3])*3.3/4096;
valeurTelemetreDroit = 15/volts;
volts = ((float)result[2])*3.3/4096;
valeurTelemetreGauche = 15/volts;
}
Dans ce code, on récupère la valeur retournée par le convertisseur, et avec l’équation écrite
tirée de la datasheet du télémètre laser monté sur le robot, on obtient dans les variables
valeurTelemetre*** la distance en centimètres entre celui-ci et l’obstacle prochain. Sachant
que notre télémètre est fiable entre 10 et 80 centimètres.
4- Le pilotage des moteurs
On se consacre dorénavant à la partie motrice du robot mobile. Cette partie a pour
objectif de contrôler les déplacements du robot selon les informations qu'elle recevra.
Le pilotage des moteurs (Deux moteurs identiques fournis par la coupe des IUT) est
assuré par une carte motrice conçue à l'IUT.
Celle-ci est contrôlé par un DSPIC33FJ128MC804 dont les sorties sont câblées
comme indiqué sur la figure ci-dessous.
Schéma du DSPIC33FJ128MC804 de la carte moteur
IUT de Toulon - Département GEII
IUT de Toulon - Département GEII
Cette carte moteur dispose de sorties permettant de brancher 4 moteurs à courant
continu simultanément, pilotés chacun par une Pulse Width Modulation (PWM) et dont le
courant transmis est régulé par 4 hacheurs
Cette dernière est également équipée de 3 diodes électroluminescentes qui serviront à
tester les différents codes et instruments utilisés.
Carte moteur : détails des fonctions
Des broches serviront à alimenter la carte moteur ainsi qu’à la programmer.
1) Mise en œuvre d'une Pulse Width Modulation (PWM)
La PWM permet de piloté un moteur et de contrôler la puissance transmise et donc la
vitesse à laquelle tourne les moteurs. On peut donc diminuer ou bien augmenter la vitesse du
robot à l'aide de la PWM.
IUT de Toulon - Département GEII Page 1414
Unsigned char command = PWMSpeedCurrentCommand[pwmNumber - 1];
switch (pwmNumber)
{
case 1:
PWM1CON1bits.PEN1H = 0;
MOTOR1_IN1 = 1;
PWM1CON1bits.PEN1L = 1;
P1DC1 = (100 - command)*20;
break;
case 2:
PWM1CON1bits.PEN2H = 0;
MOTOR2_IN1 = 1;
PWM1CON1bits.PEN2L = 1;
P1DC2 = (100 - command) *20;
break;
}
Cette première partie de code permet de faire tourner les 2 moteurs du robot,
cependant on ne peut les faire tourner que dans un seul sens. On rajoute donc ce code qui
servira à faire tourner les moteurs dans l’autre sens à fin que le robot puisse reculer en cas de
nécessité.
Unsigned char command = -PWMSpeedCurrentCommand[pwmNumber - 1];
Switch (pwmNumber)
{
Case 1: PWM1CON1bits.PEN1H
= 1; MOTOR1_IN1 = 0;
PWM1CON1bits.PEN1L = 1;
P1DC1 = (100 - command)*20;
Break;
Case 2: PWM1CON1bits.PEN2H
= 1; MOTOR2_IN1 = 0;
PWM1CON1bits.PEN2L = 1;
P1DC2 = (100 - command) *20;
Break;
}
Avec ce code, on ne peut uniquement faire tourner les moteurs dans les deux sens mais
on ne peut contrôler la puissance transmise. Il nous faut donc utiliser des hacheurs afin de
réguler celle-ci et donc de contrôler la vitesse des moteurs.
IUT de Toulon - Département GEII Page 1515
2) Mise en œuvre du hacheur
On s'intéresse alors au hacheur de puissance. Celui permet de modifier la valeur de la tension
transmise aux moteurs
Les chronogrammes de fonctionnement de ce hacheur en rotation
directe et inverse sont les suivants :
3) Commande en rampe de vitesse
Nous pouvons désormais régler la vitesse des moteurs à l'aide des hacheurs.
Cependant, à chaque changement de consigne et donc de vitesse, nous remarquons que le
robot se met à glisser. Cela est dû au changement trop brutal de vitesse, il nous faut donc
remédier à ce problème.
Pour cela, nous implantons une rampe de vitesse afin d'avoir un changement de vitesse
linéaire et donc éviter les glissements et la perte de l'adhérence.
La vitesse suivra la pente d'une rampe définie par une variable accélération de type
unsigned char initialisé à 5.
IUT de Toulon - Département GEII Page 1616
Lors d'un changement de consigne de vitesse, la valeur de la commande de la PWM
attendra la vitesse de consigne en suivant la rampe alors codée.
Les modifications de consigne de vitesse seront faites lors des interruptions du
Timer23 alors que les modifications de commande se feront sur les interruptions du Timer1.
Nous commençons donc à coder la rampe de vitesse de la PWM :
void PWMUpdateSpeed(unsigned char pwmNumber)
{
//Cette fonction est appelée sur timer et permet de respecter une rampe d'accélération
//L'appel se fait à 10Hz
if (PWMSpeedCurrentCommand[pwmNumber - 1] < PWMSpeedConsigne[pwmNumber - 1])
{
PWMSpeedCurrentCommand[pwmNumber - 1] += acceleration;
if (PWMSpeedCurrentCommand[pwmNumber - 1] > PWMSpeedConsigne[pwmNumber - 1])
{
PWMSpeedCurrentCommand[pwmNumber - 1] = PWMSpeedConsigne[pwmNumber - 1];
}
}
else if (PWMSpeedCurrentCommand[pwmNumber - 1] > PWMSpeedConsigne[pwmNumber - 1])
{
PWMSpeedCurrentCommand[pwmNumber - 1] -= acceleration;
if (PWMSpeedCurrentCommand[pwmNumber - 1] < PWMSpeedConsigne[pwmNumber - 1])
PWMSpeedCurrentCommand[pwmNumber - 1] = PWMSpeedConsigne[pwmNumber - 1];
}
//Ce code est suivi par la PWM codée précédemment
L’utilisation de l’oscilloscope nous permet de vérifier le bon fonctionnement de la
rampe de vitesse.
Après plusieurs tests, nous décidons de modifier la variable accélération en la passant
de 5 à 7 ainsi qu'en augmentant le timer1 à 20Hz. Ces modifications permettent au robot
d’atteindre la vitesse de consigne plus rapidement sans perte d’adhérence. Ces valeurs
pourront être changées dans le futur afin d’avoir de meilleures performances.
IUT de Toulon - Département GEII Page XVII
5- Robot mobile autonome
Dans cette partie, nous allons mettre en œuvre les différentes fonctions vues dans les
parties précédentes. L'objectif est de réaliser un robot capable de se déplacer de manière
autonome en évitant les obstacles qui se trouve sur son parcours.
Afin de programmer notre robot mobile autonome, nous allons utiliser uen machine à
états. Le programme pourra donc changer d'état à chaque fois qu'un évènement (Comme
l'apparition d'un obstacle ou d'un autre robot) se produit.
On utilise donc la fonction switch-case afin de créer une machine à états. Celle-ci sera
appelée dans la boucle infinie du programme principale (main.c). Le changement d'état se fera
dès que le robot le pourra, cependant, si le code reste bloqué dans une interruption, a lors le
changement tardera à venir et un choc pourrait avoir lieu. Il est donc préférable de le mettre ce
changement d'état dans l'interruption d'un timer, on choisit le timer T4 que l'on initialise a
1000Hz. Le changement d'état est donc quasiment instantané ce qui permettra d'éviter les
chocs à cause de trop long temps d'attente.
1) Réglage optimal des timers
Pour commencer, on modifie la structure des timers afin de pouvoir modifier
facilement leur fréquence.
On ajoute alors ce code pour les 3 timers ut ilisés :
void SetFreqTimerX(float freq)
{
T1CONbits.TCKPS=0b00; //00=1:1 prescaler value
if (FCY/freq > 65535)
{
T1CONbits.TCKPS=0b01; //01=1:8 prescaler value
if (FCY/freq/8 > 65535)
{
T1CONbits.TCKPS=0b10; //10=1:64 prescaler value
if (FCY/freq/64 > 65535)
{
T1CONbits.TCKPS=0b11; //11=1:256 prescaler value
IUT de Toulon - Département GEII
PR1=(int)(FCY/freq/256);
}
else
PR1=(int)(FCY/freq/64);
}
else
PR1=(int)(FCY/freq/8);
}
else
PR1=(int)(FCY/freq);
}
Dorénavant, il nous suffit d’utiliser la fonction SetFreqTimerX(fréquence souhaitée)
pour modifier la fréquence d’un timer.
2) Horodatage : génération du temps courant
Nous souhaitons tout simplement créer une variable qui sera incrémenté toutes les
millisecondes. Cette variable sera donc incrémentée à chaque interruption du Timer4 initialisé
à 1KHz. Nous pourrons, à l’aide de cette variable, créer une temporisation avant de lancer le
robot afin de le placer convenablement ainsi que connaître la durée depuis le démarrage du
robot.
extern unsigned long timestamp ;
3) Machine à état de gestion du robot
Nous débutons donc la fonction (OperatingSystemLoop) qui contrôlera le robot selon
les données transmises par les capteurs infrarouges. Il s’agit donc d’une machine à états qui
sera décrite après le code ci-dessous :
void OperatingSystemLoop (void)
{
switch(stateRobot)
{
case STATE_ATTENTE:
if(timestamp>2500)
stateRobot=STATE_AVANCE;
break;
IUT de Toulon - Département GEII
case STATE_AVANCE:
consigneVitesseMoteurDroit=-58;
consigneVitesseMoteurGauche=60;
PWMSetSpeed(consigneVitesseMoteurDroit, 1);
PWMSetSpeed(consigneVitesseMoteurGauche, 2);
stateRobot=STATE_AVANCE_EN_COURS;
break;
case STATE_AVANCE_EN_COURS:
if((valeurTelemetreDroit<35)&&(valeurTelemetreMilieu>35)&&(valeurTelemetreGauche>3
5))
{
consigneVitesseMoteurDroit=-25;
consigneVitesseMoteurGauche=15;
PWMSetSpeed(consigneVitesseMoteurDroit, 1);
PWMSetSpeed(consigneVitesseMoteurGauche, 2);
}
else
if((valeurTelemetreDroit>35)&&(valeurTelemetreMilieu>35)&&(valeurTelemetreGauche<3
5))
{
consigneVitesseMoteurDroit=-15;
consigneVitesseMoteurGauche=25;
PWMSetSpeed(consigneVitesseMoteurDroit, 1);
PWMSetSpeed(consigneVitesseMoteurGauche, 2);
}
else if(valeurTelemetreMilieu<35)
{
consigneVitesseMoteurDroit=15;
consigneVitesseMoteurGauche=15;
PWMSetSpeed(consigneVitesseMoteurDroit, 1);
PWMSetSpeed(consigneVitesseMoteurGauche, 2);
}
else if((valeurTelemetreDroit>40)&&(valeurTelemetreMilieu
>40)&&(valeurTelemetreGauche>40))
{
consigneVitesseMoteurDroit=-58;
consigneVitesseMoteurGauche=60;
PWMSetSpeed(consigneVitesseMoteurDroit, 1);
PWMSetSpeed(consigneVitesseMoteurGauche, 2);
}
break;
IUT de Toulon - Département GEII
}
Le switchcase alors codé fonctionne comme ceci :
Si les capteurs ne captent aucun obstacle alors le robot avance.
Si le capteur droit détecte un objet, le robot tournera sur la gauche en diminuant la vitesse du moteur gauche. Si c’est le capteur gauche qui détecte un objet, ce sera le moteur droit qui ralentira afin que le robot tourne sur la droite. Dès que le capteur ne décèle plus d’objet, le robot se remet en marche avant.
Si le capteur du milieu capte un objet, le robot fait alors demi-tour en modifiant le sens de rotation du moteur droit.
Ce code très simpliste permet au robot d’avancer sur un terrain inconnu en évitant les
obstacles. On procède à quelques modifications des valeurs pour augmenter les
performances.
IUT de Toulon - Département GEII
6- Télémètre laser rotatif
Introduction
Nous avons commencé le projet avec des télémètres infrarouges, mais nous étions limités sur
la portée. On choisissait de changer de direction lorsqu’on avait un obstacle à environ 50
centimètres devant soi. Pour un souci d’efficacité, nous avons décidé d’opter pour les télémètres laser car leur portée est beaucoup plus grande. Ensuite il nous fallait un
télémètre rotatif afin de cartographier le
terrain. Le fait de cartographier le terrain est
intéressant, en effet si on répertorie tous les
obstacles visibles par le robot, on pourra
analyser les chemins les plus astucieux afin de
rejoindre le coin opposé à celui du départ.
Documentation du télémètre laser
Nous allons donc utiliser le RPLIDAR 360 degré 2D Laser Scanner de la marque RoboPeak, un télémètre laser infra-rouge permettant de scanner à 360°. Celui-ci est vendu avec une carte permettant d’analyser les données envoyées par le télémètre laser. Cette carte est muni d’un port USB, ce qui nous permettra de transférer les données de la carte vers un ordinateur afin de créer un programme en C# (Sous Visual-Studio) qui nous permettra d’analyser nos futurs programmes embarqués.
IUT de Toulon - Département GEII
Le RPLIDAR scanne 360 points par tour, à une fréquence normal de 5.5Hz (Soit, 5.5 tours par minutes). Cette vitesse de rotation peut être régulée, via le Pin MOTOCTL, jusqu’à 10Hz. Cependant, une augmentation trop importante de la fréquence implique une perte de certaines valeurs étant donné que la fréquence maximale d’échantillonnage est de 2010Hz. Nous garderons donc une fréquence de 5.5Hz.
Le télémètre laser est muni de 7 Pins :
Le pin MOTOCTL, permettant de réguler la vitesse du télémètre laser, sera simplement mis sous tension afin d’avoir une fréquence de 5.5Hz et donc un échantillonnage optimal. Le pin RX nous permettra de contrôler le télémètre laser afin de le démarrer lors de l’initialisation du robot ou bien de l’arrêter si nécessaire. Le pin TX, quant à lui, permet de transmettre les données brutes du télémètre laser vers la carte moteur qui seront alors analysées. Les autres pins permettent d’alimenter le télémètre laser ainsi que le moteur lui permettant de tourner.
IUT de Toulon - Département GEII
Récupération et analyse des données
Tout d’abord nous devons réaliser un second
UART pour échanger avec le télémètre, que ce
soit transmission ou réception. Nous avons repris
les buffers réalisés pour la communication entre
la carte moteur et carte mère. Mais sur ces
nouveaux UART nous avons établi un baudrate
de 115200 qui est la vitesse maximale de
transmission.
Nous avons également modifié la taille du buffer
d’envoi à la carte mère dans le but d’envoyer un
seul paquet pour chaque tour complété par le
télémètre, la nouvelle taille est de 1024.
Afin de récupérer les données, nous devons chercher dans la documentation du télémètre les trames qu’on doit lui passer pour lui faire débuter la cartographie :
Pour la gestion de l’ensemble de ces requêtes nous créons les fonctions associées, on peut voir
que chaque requête doit débuter par la valeur hexadécimale A5 ensuite par exemple pour
lancer un scan la deuxième valeur envoyé doit être 20 en hexadécimal.
Catalogue des requêtes rédigées en C :
unsigned char buffer[2];
void StopIR()
{
buffer[0] = 0xA5; buffer[1] =
0x25;
Uart2SendMessage(buffer, 2); }
void StartIR()
{
buffer[0] = 0xA5;
IUT de Toulon - Département GEII
buffer[1] = 0x20;
Uart2SendMessage(buffer, 2);
}
void GetHealthIR()
{
buffer[0] = 0xA5; buffer[1] =
0x52;
Uart2SendMessage(buffer, 2);
}
void GetInfoIR()
{ buffer[0] = 0xA5; buffer[1] = 0x50;
Uart2SendMessage(buffer, 2);
}
Nous devons une fois lancer le scan, analyser les trames que le télémètre envoie pour les utiliser par la suite.
Fonction qui analyse les données brutes envoyées par le télémètre IR :
void AutoDetectIrFrames(char c)
{
int i=0;
Une dataresponse de type mesure de distance est composée de 5 octets, le premier étant terminé par !S-S, S valant un si on commence un nouveau tour.
Le second est est terminé par 1 quoiqu'il arrive. switch (frameIndex)
{
case 0:
{
Si on est censé être sur le premier octet d'une dataresponse mesure distance on vérifie que les deux bits de poids faible sont bien opposés
rawMeasure[0] = rawMeasure[1] = rawMeasure[2] = rawMeasure[3] = rawMeasure[4] = 0;
angle_T1 = angle;
IUT de Toulon - Département GEII
if ((c & 0x01) != ((c >> 1) & 0x01))
{
Le test est valide if ((c & 0x01) == 0x01)
{
On a un tour qui vient de s'achever Event qui envoi le tableau des distances du télémètreIR On recopie les données dans le tableau de sortie, en bourrant les valeurs nulles (et il y en
a beaucoup) distanceList2[0] = 0; for (i = 0; i < ANGLE_MAX - ANGLE_MIN; i++)
{
//On recopie dans le tableau de sortie
if (distanceList[i] != 0)
distanceList2[i] = distanceList[i];
else if(i>0)
distanceList2[i] = distanceList2[i-1];
}
//Set ANGLE_USE case a partir d'angle min de approachlimitlisyt
//memset(approachLimitList+ANGLE_MIN,255,ANGLE_USE);
DetectApproachLimit(30);
PonderateByPyramid(approachList,ponderationTable,220);
On initialise le tableau de stockage des distances à 0 for (i = 0; i < ANGLE_MAX - ANGLE_MIN; i++)
{
distanceList[i]=0;
}
sysEvents.TelemetreIrCaptureFinishedEvent = 1;
countIrPoints = 0;
//sysEvents.TelemetreIrEvent = 1;
}
quality = c >> 2;
rawMeasure[0] = c;
frameIndex += 1;
}
else
frameIndex = 0; break;
}
case 1:
{
si on est censé être sur le second octet d'une dataresponse mesure distance
on doit vérifier que le bit de poids faible vaut bien 1 if ((c & 0x01) == 0x01) {
Le test est valide angle = (((int) c) >> 1)&0x007F; En plus du décalage on fait un masque afin d’assurer le
fait de ne plus avoir de bit de poids fort rawMeasure[1] = c;
frameIndex += 1;
}
else
frameIndex = 0;
break;
}
IUT de Toulon - Département GEII
case 2:
{
rawMeasure[2] = c;
angle += (((int) c)&0x00FF) << 7;
angle = (angle >> 6) & 0x03FF; //On divise par 64
frameIndex += 1; break;
}
case 3:
{
rawMeasure[3] = c; distance = ((int) c) & 0x00FF; frameIndex += 1;
break;
}
case 4:
{
rawMeasure[4] = c;
distance += ((int) c) << 8;
distance = (distance >> 2) & 0x3FFF;
//Console.WriteLine("angle :" + angle.ToString("N2") + " distance : " + distance.ToString("N2") + "
quality : " + quality.ToString()); if (quality == 0)
distance = 0;
//mesureList.Add(new IrMeasure(distance, angle, quality, (byte[])rawMeasure.Clone()));
if ((angle >= ANGLE_MIN) && (angle <= ANGLE_MAX))
{
if (distance >= 2550)
distanceList[angle - ANGLE_MIN] = 255;
else
distanceList[angle - ANGLE_MIN] = (unsigned char) (distance / 10);
countIrPoints++;
} //On ramène à 0 l'index frameIndex = 0; break;
}
default:
{
frameIndex = 0;
break;
}
}
}
IUT de Toulon - Département GEII
Filtrage des données
Maintenant que nous avons récupéré et analysé les trames envoyées par le RPLIDAR, nous allons filtrer ses données
Le filtre appliqué permet de retenir la distance maximale que peut parcourir le robot dans chaque direction avant de butter sur un obstacle, en prenant en compte sa largeur.
Le schéma ci-dessous montre l’utilité du filtrage qui est appliqué aux données recueillies.
ROBOT
ROBOT
ROBOT
ROBOT
ROBOT
Sur le schéma ci-dessus, le robot est représenté par le cercle rouge alors que les obstacles qui doivent être évités.
La zone bleue symbolise les zones où le robot peut se déplacer. On peut remarquer que le filtre prend en compte la dimension du robot (en vert sur le
schéma), pour déterminer les passages envisageable en dehors de l’obstacle.
IUT de Toulon - Département GEII
Nous réalisons tout d’abord le code sous Visual Studio en C# afin de filtrer les
données reçu sur l’ordinateur.
List<double> DetectApproachLimit(List<double> distanceList, double largeurPassage)
{
//Renvoie la distance maximum que peut parcourir le robot dans chaque direction avant de toucher un
obstacle, en supposant que le robot fait largeurPassage centimètre de large
List<double> approachLimitList = new List<double>(); approachLimitList.AddRange(Enumerable.Repeat((double)250, distanceList.Count));
int countIterations = 0;
for (int i = 0; i < distanceList.Count; i++)
{
if (distanceList[i] > 0)
{
// On néglige l’Arctan (voir commentaire ci-dessous)
//double angleRobot = Math.Atan(largeurPassage /
distanceList[i]) / Math.PI * 90;
double angleRobot = largeurPassage / distanceList[i] / Math.PI * 90; int angleMin = (int)Math.Max(0, i - angleRobot / 2); int angleMax = (int)Math.Min(distanceList.Count, i + angleRobot / 2);
for (int j = angleMin; j < angleMax; j++)
{
approachLimitList[j] = Math.Min(distanceList[i], approachLimitList[j]);
countIterations += 1;
}
}
}
Console.WriteLine(countIterations);
return approachLimitList;
}
Tout d’abord, ce programme crée une liste, nommée approachLimitList, dont la
distance est de 250cm (Distance maximale prise en compte) pour toutes les directions. On modifie alors cette liste en fonction des données précédemment recueillies, en
prenant compte de la largeur du robot.
Ce filtrage est nécessaire afin que le robot ne percute aucun obstacle, mais celui-ci doit
être assez précis afin de ne pas manquer une direction envisageable.
Nous avons alors transposé cette fonction en embarqué :
unsigned char * DetectApproachLimit(unsigned char largeurPassage)
{
LEDOrange = 1;
int i=0;
//int j, max=0,min=0;
//Renvoie la distance maximum que peut parcourir le robot dans chaque direction avant de toucher un
obstacle, en supposant que le robot fait largeurPassage millimètre de large
//unsigned char approachList[ANGLE_MAX-ANGLE_MIN] = {0xFF};
for (i = 0; i < ANGLE_MAX-ANGLE_MIN; i++)
{
approachList[i] = 0xFF;
}
for (i = 0; i < ANGLE_MAX-ANGLE_MIN; i++)
IUT de Toulon - Département GEII
{
if(distanceList2[i] > 0)
{
currentDist = distanceList2[i];
//double angleRobot = Math.Atan(largeurPassage / distanceList[i]) / Math.PI * 90;
unsigned char angleRobot = (unsigned char)((int)largeurPassage *
CONST_RADIAN_TO_DEGREE_DIV_2 / currentDist);
int angleMin = 0;
if(i - angleRobot > angleMin)
{
angleMin = i - angleRobot;
}
int angleMax = ANGLE_MAX-ANGLE_MIN;
if(i + angleRobot < angleMax)
{
angleMax = i + angleRobot;
}
int j;
for (j = angleMin; j < angleMax; j++)
{ if(distanceList2[i] < approachList[j])
approachList[j] = distanceList2[i];
}
}
}
Cette fonction nécessite d’importantes ressources, c’est pourquoi, en embarqué, nous ne traitons que 180 données .
IUT de Toulon - Département GEII
Calcul de la meilleure trajectoire à suivre
Nous avons réalisé l’algorithme permettant de choisir la direction que doit prendre le robot de
manière à rejoindre la balise le plus efficacement possible. On a fixé l’angle de la balise parce
que nous n’avons pas de balise opérationnelle pour le moment.
Tout d’abord nous avons testé l’algorithme en C#, la logique est de créer en premier lieu un tableau qui décrit une droite affine, qui sera multiplié aux données des distances.
La fonction en C# pour la fonction qui génère le tableau :
List<double> GeneratePonderationTable(int width)
{ ponderationTable.Clear(); for (i = 0; i < width; i++)
{ if(i<width/2)
ponderationTable.Add(((double)i)/(width/2));
else ponderationTable.Add((double)(width-i)/(width/2));
} return ponderationTable;
}
La même fonction retranscrit en C : float * GeneratePonderationTable(int width)
{ for (i = 0; i < width; i++)
{ if(i<width/2)
ponderationTable[i]=(((float)i)/((float)width/2));
else ponderationTable[i]=((float)(width-i)/((float)width/2));
}
return ponderationTable;
}
Nous utilisons donc cette table en sachant l’angle où est situé la balise
Fonction en C# :
//Cette fonction permet de relever la trajectoire optimale selon la position de la balise
List<double> PonderateByPyramid(List<double> distanceList, List<double> ponderationTable, int angleBalise)
{
List<double> ponderatedDistanceList = new List<double>();
double constantPonderationValue = 0.2;
int lowlimit = angleBalise-180-ponderationTable.Count/2;
if(lowlimit<0)
lowlimit = 0;
int highlimit = angleBalise-180+ponderationTable.Count/2;
if(highlimit>distanceList.Count)
highlimit = distanceList.Count; for (int i = 0; i < distanceList.Count; i++)
{
if (i >= lowlimit && i < highlimit)
{
ponderatedDistanceList.Add(distanceList[i] * (ponderationTable[i -
lowlimit]+constantPonderationValue));
IUT de Toulon - Département GEII
}
else
{
ponderatedDistanceList.Add(distanceList[i] * constantPonderationValue);
}
}
return ponderatedDistanceList;
}
Transcription de PonderateByPyramid en C :
unsigned char * PonderateByPyramid(unsigned char
distanceListPonderate[ANGLE_USE],float ponderationTable[ANGLE_USE], int
angleBalise) {
float constantPonderationValue = 0.2;
int lowlimit = angleBalise-180-(ANGLE_USE+1)/2;
if(lowlimit<0)
lowlimit = 0;
int highlimit = angleBalise-180+(ANGLE_USE+1)/2;
if(highlimit>ANGLE_USE)
highlimit = ANGLE_USE;
for (i = 0; i < ANGLE_USE; i++)
{
if (i >= lowlimit && i < highlimit)
{
ponderatedDistanceList[i]=((float)distanceListPonderate[i] *
((float)ponderationTable[i- lowlimit]+constantPonderationValue)); } else
{
ponderatedDistanceList[i]=((float)distanceListPonderate[i] * constantPonderationValue);
}
}
return ponderatedDistanceList;
}
Résul
tat Le programme embarqué permet donc de
récupérer la meilleure trajectoire à suivre afin
d’arriver au plus vite à l’objectif. Nous
pourrons alors utiliser les codeurs placés sur
les moteurs afin de diriger, avec précision, le
robot dans la bonne direction.
IUT de Toulon - Département GEII
7.Le module réception balise
a. Principe de la balise
Le but des balises et d'envoyer des signaux de certaines fréquences afin de pouvoir déterminer la
position du robot en fonction des signaux reçus. Le robot est donc équipé d'un système de réception
composé d'un petit miroir et d'un tête qui tourne grâce au moteur et qui peut donc capter les rayons
infrarouges émis de part et d'autre du terrain.
b. Le codeur de position (QEI)
Le module Quadrature Encoder Interface est le module qui correspond aux capteurs incrémentaux
installés sur les moteurs. Ces codeurs permettent d'obtenir des informations concernant la position
et également le sens de rotation.
Afin de récupérer la position de la balise, il a fallu créer la fonction QEIGetPosition() ci-dessous
IUT de Toulon - Département GEII
Nous avons initialisé le timer 2 à une fréquence de 10Hz et créé un registre qui agit comme une
variable drapeau d'un unique bit permettant de déclencher une action de manière différée à
l'interruption. Lors d'une interruption, on récupère la valeur de la position du compteur et on envoie
cette valeur vers l'uart.
Voici la trame envoyée par le biais de l'uart. Les bits 6 et 7 affichés correspondent à la position
renvoyée par le compteur.
IUT de Toulon - Département GEII
c. Triangulation de la position du robot
Une fois le QEI mis en place, il faut maintenant programmer une fonction permettant de déterminer la
position exacte du robot d'après les informations données par la balise.
Cette fonction se sert des angles relatifs par rapport aux différents points d'émission afin de calculer les
"coordonnées" de la position du robot à un instant précis, à condition de connaître à l'avance la position
des balises émetrices.
Dans le schéma ci-dessus, le point R correspond au robot, B1, B2 et B3 sont les balises émettant les
signaux et α1, α2 et α3 sont les angles mesurés relatifs à l'orientation du robot θ.
En recherchant des solutions à notre problème, nous
avons trouvé un algorithme de triangulation qui nous
permet de calculer la position du robot.
IUT de Toulon - Département GEII
Source :
http://www2.ulg.ac.be/telecom/publi/publications/pierlot/Pierlot2011ANewThreeObject/index.html
IUT de Toulon - Département GEII
8 L'analyse du signal
a. Le module Input Capture
Ce module est présent sur le dsPIC33FJ128MC804 que nous utilisons. Il est utilisé pour
récupérer le temps écoulé entre deux évenement détéctés sur la broche d'entrée.
Il est très utile pour les applications qui nécéssite une mesure de fréquence ou d'impulsions. C'est
notre cas puisque nous souhaitons récupérer la fréquence du signal reçu par les balises pour les
identifier.
Nous avons simulé les balises à l'aide d'un GBF (un générateur de basse fréquences) et nous
avons tenté de récupérer la fréquence émise.
Dans un premier temps nous n'avions pas conaîssance du module d'Input Capture et nous avons
tenter de la récupérer à l'aide de Timer en comptant les periodes et en calculant la ffréquence reçu à
partir de ces résultats. Cependant, sans pouvoir expliquer pourquoi, nous avons observé un décalage
entre la fréquence émise et celle calculé par le pic d'environ 200Hz. On suppose que c'est dû à la
fréquence du timer qui apparaît trop élevée pour que la valeur soit précise au moment ou elle est
sauvegardé (un retard doit apparaître).
Pour éviter ce problème nous avons opté par la suite à utiliser une autre méthode :
L'utilisation du module input capture qui nous permet en quelque sorte de faire la même chose mais
en hardware plutôt qu'en soft.
Au départ nous avions initialisé le Timer 3 à une fréquence très élevée dans le but d'avoir une
précision maximale.
Cependant, l'input capture fonctionne en récupérant la valeur du timer au front montant du signal
reçu sans tenir compte du nombre de débordements effectués par le timer entre deux fronts
montants (voir illustration ci-dessous).
IUT de Toulon - Département GEII
La valeur récupérée par l'input capture est faussée et la fréquence calculée ne correspond pas à celle
émise par le générateur de basses fréquences.
Pour éviter ceci nous avons décidé de réduire la fréquence du timer.
En effet, le fonctionnement le l'input capture (voir illustration ci-dessous) nécessite une fréquence
de timer moins élevée que la fréquence à détecter.
IUT de Toulon - Département GEII
Nous avons choisi la fréquence suivante pour notre timer.
#define FREQ_T3 10000UL (timer.h)
Voici la fonction qui nous permet de récupérer la fréquence émise par le GBF :
IUT de Toulon - Département GEII
b. Gestion des fréquences reçues
Pour reconnaître une balise on regarde la fréquence reçue par notre detecteur de balise.
Nous avons supposé avoir 3 balises de fréquences respectives 10 000 Hz, 7 000 Hz et 5 000 Hz.
Voici la fonction qui nous permet de détecter une balise en fonction des fréquences récupérés :
Les 3 LEDs utilisés nous permettent de vérifier facilement le fonctionnement de détection.
IUT de Toulon - Département GEII
9 La carte Balise
a. Choix du filtre sous FilterLab
On cherche à réaliser le schéma d'un filtre passe-haut de bonne qualité [1k-7k] avec un gain
de 100. Pour cela nous nous sommes aidés du logiciel FilterLab qui nous a fournis le filtre que nous
cherchions avec les valeurs des composants qu'il comporte.
Interface FilterLab
Cela nous a conduit au schéma suivant, un filtre à quatre étages.
IUT de Toulon - Département GEII
b. Shématique sous Orcad
Pour implémenter ce filtre d'amplification analogique sur la carte nous avons décidé d'utiliser une
structure générique.
Voici un étages de la structure générique. De ce fait, les quatres étages seront identiques sur la carte
avant le placement des composants.
IUT de Toulon - Département GEII
Nous nous sommes également occupés de l'alimentation des Leds. Une carte possède quatres
rangées de 6 Leds placées en série. Voici la schématique d'une de ces rangées.
IUT de Toulon - Département GEII
c. Le Routage
Au niveau du routage nous nous sommes spécifiquement occupés de placer les Leds.
Elles ont des contraintes particulières parce qu'il est nécessaire qu'elles ballaient 180°.
Nous les avons donc toutes inclinés en les placant sur les bords de la carte.
Voici une première partie du routage de la carte Balise.
IUT de Toulon - Département GEII
10. Asservissement moteur
a) Mécanique
Afin de réaliser l'odométrie nous devons réaliser l'asservissement des moteurs. Pour
cela nous utilisons des codeurs excentrés car nous ne pouvons les fixer directement sur les
moteurs. Pour cela nous avons réalisé des pièces sur-mesure à l'imprimante 3D.
Malheureusement, il y avait un manque de précision trop important lors des modifications de ceux-
ci (reperçage de l'axe), ce qui entraînait un mauvais fonctionnement, nous avons acheté des
engrenages pour remplacer les précédents et donc améliorer le fonctionnement.
Mécanique pour l'encodeur vu de dessus
IUT de Toulon - Département GEII
b) Informatique
IUT de Toulon - Département GEII
IUT de Toulon - Département GEII
Dans le code ci-dessus nous actualisons les informations des moteurs a 50Hz, ce qui nous
permet d'avoir des informations fiables sans pour autant surchargé le dsPic.
Le QEIProcessing lance la capture des nouvelles données des codeurs, on sauvegarde l'ancienne
valeur de la position puis nous calculons la vitesse.
Ensuite la PWMUpdateSpeed nous permet de faire des rampes d'accélérations et donc de
moins abîmer les moteurs ainsi qu'éviter de perdre l'adhérence lorsque qu'il y a de fort
changement de consigne.
IUT de Toulon - Département GEII
La PWMAsserSpeed nous permet de faire rouler les moteurs à la même vitesse. En effet
cela est impossible sans asservissement à cause des frottements qui ne sont pas identiques sur
les 2 moteurs. De plus, si un moteur est ralenti par un raison quelconque, il fera son possible pour
continuer de rester sur la vitesse de consigne.
Le Speedcoeff correspond au rapport de réduction du aux engrenages.
Cet asservissement est réalisé à l'aide d'un correcteur PI (Proportionnel- intégrateur). Pour
éviter de faire sauter les hacheurs, nous avons fixé la limite Speed entre
-2000 et 2000.
c) Odométrie
L'odométrie permet d'estimer la position du robot, en mouvement grâce à des capteurs
positionnés sur les roues. C'est à dire elle détermine un déplacement. Elle repose sur la mesure
individuelle des déplacements des roues pour reconstituer le mouvement global du robot. Avec une
position initiale connue et en intégrant les déplacements mesurés, on peut calculer à chaque instant
la position du robot.
Les odomètres sont des capteurs embarqués qui mesurent une distance parcourue. Les plus
classique sont des ensembles électromagnétiques. Ils sont composé d'une roue en contact avec le sol
et d'une roue dentée ou une roue codeuse entraînée par la première roue. Une paire de faisceau
lumineux (ou infrarouge) sera coupé (ou non) en fonction de la roue codeuse. L'ordre dans lequel
les faisceaux sont coupés donne le sens de la rotation, le nombre de front donne le déplacement.
Ces capteurs mesurent la rotation d'un axe. On en déduit la distance parcourue à l'aide du rayon de
la roue en contact avec le sol. Les valeurs retournées par ces capteurs sont des distances de
déplacement d'un point. La détermination du mouvement (translation et rotation) d'un robot se
fait généralement grâce à 2 odomètres.
IUT de Toulon - Département GEII
11. Liaison SPI
La liaison SPI (Serial Peripheral Interface) est un bus de données série synchrone en mode
full-duplex. Les circuits communiquent selon un schéma maître-esclaves, où le maître s'occupe
totalement de la communication. Plusieurs esclaves peuvent coexister sur un même bus, dans ce
cas, la sélection du destinataire se fait par une ligne dédiée entre le maître et l'esclave appelée chip
select.
Le bus SPI utilise 4 signaux logiques :
– SCLK : Serial Clock, Horloge (généré par le maître)
– MOSI : Master Output, Slave Input (généré par le maître)
– MISO : - Master Input, Slave Output (généré par l'esclave)
– SS : Slave Select, Actif à l'état bas (généré par le maître)
Une transmission SPI typique est une communication simultanée entre un maître et un
esclave :
– Le maître génère l'horloge et sélectionne l'esclave avec qui il veut communiquer par
l'utilisation du signal SS
– L'esclave répond aux requêtes du maître
A chaque coup d'horloge le maître et l'esclave s'échangent un bit. Après huit coups
d'horloge, le maître a transmis un octet à l'esclave et vice versa. La vitesse de l'horloge est réglée
selon les caractéristiques propres aux périphériques.
Avantages :
– Communication full duplex
– Débit assez importante
– Flexibilité du nombre de bits à transmettre ainsi que du protocole en lui-même
– Simplicité de l'interface matérielle
– Partage d'un bus commun pour l'horloge, MISO et MOSI entre les périphériques.
Inconvénients :
– Monopolise plus de broche qu'une UART qui en utilise que 2
– Aucun adressage possible
– Le protocole n'a pas d'acquittement, le maître peut parler dans le vide sans le savoir
– Un seul maître par bus.
– Courte distance.
Afin de mettre en place cette liaison SPI, nous l'avons d'abord réaliser et tester avec un
gyroscope de type L3G4200D. En effet, on regardait les données sur l'interface graphique afin de
vérifier que la liaison SPI marchait.
IUT de Toulon - Département GEII
Nous avons du souder le gyroscope à l'aide de la machine à infrarouge afin d'avoir des
soudures parfaites.
IUT de Toulon - Département GEII
Conclusion
Au terme d'un long travail depuis le semestre 2 le robot est fonctionnel en classe.
Nous devons maintenant ajuster finement les paramètres de réglage en conditions réelles, sur
le site de la coupe.
En effet au semestre 3, le robot était déjà capable de se déplacer et d'éviter les obstacles
de manière autonome. A partir du semestre 4, chaque groupe s’est spécialisé sur une fonction
précise du robot (télémètre laser, SPI, asservissement moteur, balise) afin d’en améliorer les
performances.
Sur le plan technique la réalisation du robot mobile, nous avons pu apprendre à utiliser
deux logiciels de programmation : MPLAB (C) pour le PIC et Visual Studio (C#) pour
l'interface graphique. Nous avions également à disposition une machine à infrarouge pour
souder, des oscilloscopes performants (traduire les trames, …) et deux imprimantes 3D afin de
réaliser la mécanique du robot.
Sur le plan humain le projet tuteuré, concernant le robot mobile, nous a permis de
travailler en équipe et d'apprendre comment concevoir, fabriquer et développer un robot à partir
de zéro. C'est une expérience enrichissante et valorisante pour la gestion de projet et un travail
intense dans plusieurs domaines que la robotique requière.