Cours:MiniQ v2 : Différence entre versions

De troyesGEII
Aller à : navigation, rechercher
m (Travail à faire : exercice 3)
(Travail à faire : Exercice 1 (arduino))
 
(21 révisions intermédiaires par 2 utilisateurs non affichées)
Ligne 1 : Ligne 1 :
 
[[Cours:miniq_v2_Correctionprof|{{Vert|'''Corrections uniquement accessibles aux enseignants'''}}]]
 
[[Cours:miniq_v2_Correctionprof|{{Vert|'''Corrections uniquement accessibles aux enseignants'''}}]]
  
Le robot MiniQ est vendu maintenant en version 2. C'est cette nouvelle version qui va nous intéresser dans ce chapitre.
+
 
={{Bleu|Programmation avec arduino}}=
+
=Programmation avec arduino=
 
Le robot miniQ est architecturé autour d'un processeur ATMega32U4. C'est le processeur qui équipe les cartes Leonardo et il est d'ailleurs complètement compatible. Il faut donc changer de board qui est par défaut "Arduino UNO" qui est essentiellement utilisé pour les TPs.
 
Le robot miniQ est architecturé autour d'un processeur ATMega32U4. C'est le processeur qui équipe les cartes Leonardo et il est d'ailleurs complètement compatible. Il faut donc changer de board qui est par défaut "Arduino UNO" qui est essentiellement utilisé pour les TPs.
  
Le processeur 32U4 est capable de gérer une liaison série USB sans l'aide d'un circuit spécialisé (FTDI par exemple). L'inconvénient de ce processeur est que sa partie matérielle consacrée aux périphériques n'est pas complètement compatible avec celle du UNO (ATMega328). La bonne nouvelle c'est que l'environnement Arduino est capable de gommer ces différences.
+
Le processeur 32U4 est capable de gérer une liaison série USB sans l'aide d'un circuit spécialisé (FTDI par exemple).
  
 
Le schéma peut être trouvé sur [http://www.dfrobot.com/index.php?route=product/product&product_id=555#.VnvPFF64AW1 cette page commerciale] avec des exemples de code et des exercices en anglais.
 
Le schéma peut être trouvé sur [http://www.dfrobot.com/index.php?route=product/product&product_id=555#.VnvPFF64AW1 cette page commerciale] avec des exemples de code et des exercices en anglais.
Ligne 11 : Ligne 11 :
 
En résumé :
 
En résumé :
 
* La carte Arduino équivalente est la : Arduino Leonardo
 
* La carte Arduino équivalente est la : Arduino Leonardo
* Le programmateur d'origine est : AVR ISP  
+
* Le programmateur d'origine est : AVR ISP
* Le port série est en général /dev/ACMO sous Linux
+
 
 +
**********************************************
 +
**********************************************
 +
Attention : pour programmer aller dans le menu
 +
{{Rouge|Croquis : Téléverser avec un programmateur}}
 +
**********************************************
 +
**********************************************
 +
 
 +
=Utilisation de analogWrite() pour la MLI=
 +
==Commande d'un moteur==
 +
[https://zestedesavoir.com/tutoriels/686/arduino-premiers-pas-en-informatique-embarquee/747_le-mouvement-grace-aux-moteurs/3437_le-moteur-a-courant-continu/ Vous trouverez des détails sur le moteur à courant continu et sa commande sur cette page]
 +
 
 +
[https://electrotoile.eu/c-est-quoi-la-PWM-avec-arduino.php Vous pourrez consulter plus tard cette page pour comprendre le signal PWM/MLI]
 +
 
 +
 
 +
Pour faire varier la vitesse d'un moteur il suffit de faire varier sa tension de commande. En général ceci est réalisé avec un signal MLI ou PWM (signal à rapport cyclique variable), nous n'entrerons pas dans le détail dans ce TP.
  
={{Bleu|Utilisation de analogWrite() pour la MLI}}=
 
==Commande d'un moteur à l'aide d'un timer==
 
On rappelle que pour faire varier la vitesse d'un moteur il suffit de faire varier sa tension de commande. En général ceci est réalisé avec un signal MLI (signal à rapport cyclique variable). Le rapport cyclique varie entre 0 et 1, mais les registres de commandes sont sur 8 bits et donc permettent une correspondance :
 
* rapport cyclique = 0 alors commande = 0
 
* rapport cyclique = 0,5 alors commande = 128
 
* rapport cyclique = 1 alors commande = 255
 
 
Tout ceci se fait dans le monde Arduino avec une commande "analogWrite()"
 
Tout ceci se fait dans le monde Arduino avec une commande "analogWrite()"
 +
*analogWrite(broche,255); => tension moyenne de 5v sur la broche
 +
*analogWrite(broche,127); => tension moyenne de 2.5v sur la broche
 +
*analogWrite(broche,0); => tension moyenne de 0v sur la broche
  
La variable précédente permettra de commander le moteur gauche. Vous devez être capable à ce stade de le faire tourner plus ou moins vite avec l'incrémentation/décrémentation de la section précédente dans un sens fixé par vous même.
 
  
'''Indications''' :  
+
 
* Il y a deux sorties de commandes du moteur gauche (il faudra donc les positionner en sortie) :  
+
'''Commande d'un moteur :''' :  
** broche 5 Arduino (PC6) pour la commande rapport cyclique variable
+
*Il y a deux sorties de commandes du moteur gauche (il faudra donc les positionner en sortie) :  
** broche 12 Arduino (PD6) pour le sens de rotation
+
**broche 5 Arduino (PC6) pour la commande rapport cyclique variable : vitesse de rotation
* On vous donne le code source ci-dessous :
+
**broche 12 Arduino (PD6) pour le sens de rotation
**Le premier paramètre est ce qui ira dans la broche 12 : 0 pour marche en avant et 1 pour marche arrière
+
*On vous donne la fonction ci-dessous qu'il faudra utiliser pour changer la vitesse du moteur :
**Le deuxième le rapport cyclique qui ira sur la broche 5
+
*Le paramètre est une valeur entre -255 et 255 qui indique la valeur souhaitée pour la vitesse du moteur
 
<source lang=C>
 
<source lang=C>
void MotorG(unsigned char M1_DIR,unsigned char M1_EN)//control the motor
+
void MotorG(int vitesse)//control the motor
 
{
 
{
  //////////M1-->left motor////////////////////////
+
   if (vitesse<0)
   if(M1_DIR==0)//en avant
+
  {
    digitalWrite(12,0);
+
    vitesse=-vitesse;
 +
    digitalWrite(12,1);
 +
  }
 
   else
 
   else
    digitalWrite(12,1);
+
  {
   if(M1_EN==0)
+
    digitalWrite(12,0);
    analogWrite(5,LOW);
+
  }
else
+
   if (vitesse>255) vitesse=255;
    analogWrite(5,M1_EN);
+
  analogWrite(5,vitesse);
 
}
 
}
 
</source>
 
</source>
'''Indications''' : On complète la commande du moteur gauche par celle du moteur droit.
+
 
 +
Exemple d'utilisation
 +
<source lang=C>
 +
void setup()
 +
{
 +
  MoteurG(0);
 +
}
 +
</source>
 +
 
 +
 
 +
On complète la commande du moteur gauche par celle du moteur droit.
 
* Il y a deux sorties de commandes du moteur droit (il faudra donc les positionner en sortie) :  
 
* Il y a deux sorties de commandes du moteur droit (il faudra donc les positionner en sortie) :  
 
** broche 6 Arduino (PD7) pour la commande rapport cyclique variable
 
** broche 6 Arduino (PD7) pour la commande rapport cyclique variable
 
** broche 7 Arduino (PE6) pour le sens de rotation
 
** broche 7 Arduino (PE6) pour le sens de rotation
* On vous donne le code source ci-dessous :
+
*La fonction suivante permet de changer la vitesse du 2ème moteur
**Le premier paramètre est ce qui ira dans la broche 7 : 0 pour marche en avant et 1 pour marche arrière
 
**Le deuxième le rapport cyclique qui ira sur la broche 6
 
* La commande Mi_EN (pour i=1 et i=2) qui choisit le rapport cyclique ne doit pas dépasser 75 !
 
 
<source lang=C>
 
<source lang=C>
void MotorD(unsigned char M2_DIR,unsigned char M2_EN)//control the motor
+
void MotorD(int vitesse)//control the motor
 
{
 
{
  //////////M2-->right motor////////////////////////
+
   if (vitesse<0)
   if(M2_DIR==0)//en avant
+
  {
    digitalWrite(7,0);
+
    vitesse=-vitesse;
 +
    digitalWrite(7,1);
 +
  }
 
   else
 
   else
    digitalWrite(7,1);
+
  {
   if(M2_EN==0)
+
    digitalWrite(7,0);
    analogWrite(6,LOW);
+
  }
else
+
   if (vitesse>255) vitesse=255;
    analogWrite(6,M2_EN);
+
  analogWrite(6,vitesse);
 
}
 
}
 
</source>
 
</source>
===Travail à faire : Exercice 1 (arduino)===
+
 
 +
{{Question|Travail à faire}}
 
Vous devez réaliser une commande du robot pour qu'il réalise un huit (deux cercles connectés par un point). Vous choisirez le rayon de vos cercles en jouant sur les rapports cycliques. Puis vous jouerez sur les temporisations pour gérer tout cela. Bien entendu, le fait qu'il n'y ait pas d'information de retour sur l'endroit où vous êtes complique un peu la mise au point.
 
Vous devez réaliser une commande du robot pour qu'il réalise un huit (deux cercles connectés par un point). Vous choisirez le rayon de vos cercles en jouant sur les rapports cycliques. Puis vous jouerez sur les temporisations pour gérer tout cela. Bien entendu, le fait qu'il n'y ait pas d'information de retour sur l'endroit où vous êtes complique un peu la mise au point.
  
Ligne 73 : Ligne 96 :
  
 
==Suivre une source de lumière par Conversion Analogique Numérique==
 
==Suivre une source de lumière par Conversion Analogique Numérique==
Le travail demandé dans cette section utilise encore la conversion analogique numérique. La différence est que maintenant c'est la position d'une source de lumière qui va faire changer les valeurs analogiques.
+
Le travail demandé dans cette section utilise encore la conversion analogique numérique.
 +
 
 +
La différence est que maintenant c'est la position d'une source de lumière qui va faire changer les valeurs analogiques.
 +
 
 +
Le capteur est connecté sur la broche A5
 +
 
 
===Étalonnage des capteurs===
 
===Étalonnage des capteurs===
  
Ligne 80 : Ligne 108 :
 
Vous disposez de deux capteurs de lumière monté comme dans le schéma ci-contre. Utilisez une liaison série pour trouver les zones pour :
 
Vous disposez de deux capteurs de lumière monté comme dans le schéma ci-contre. Utilisez une liaison série pour trouver les zones pour :
 
* lumière au centre
 
* lumière au centre
* lumière légèrement à droite
+
* lumière à droite
* lumière très à droite
+
* lumière à gauche
* lumière légèrement à gauche
+
 
* lumière très à gauche
+
{{Question|Ecrire un programme qui permet d'orienter le robot face à la lumière en utilisant l'information droite/centre/gauche}}
 +
 
 +
===Correcteur proportionnel===
 +
 
 +
Pour le moment, nous n'utilisons que 3 valeurs différentes pour faire le suivi de lumière. Afin de faire un suivi plus performant, nous allons calculer la vitesse de rotation du robot en fonction de la position de la lumière par rapport au robot :
 +
 
 +
{{Question|Trouver une équation permettant de donner l'angle entre l'axe du robot et la source de lumière, en fonction de la valeur du CAN.}} On considérera qu'il s'agit d'une relation affine :
 +
*relever les valeurs de l'entrée analogique pour :
 +
**angle -45°
 +
**angle 0°
 +
**angle +45°
 +
*tracer la caractéristique angle en fonction de la valeur de l'entrée analogique
 +
*donner l'équation de la droite
 +
 
 +
 
 +
La vitesse du robot peut être décomposée en une translation et une rotation. On aura donc :
 +
*vt : vitesse de translation (ex 20)
 +
*wr : vitesse de rotation
 +
*vitMoteurD = vt + wr
 +
*vitMoteurG = vt - wr
 +
* wr = k * positionAngulaireLumiere
 +
 
 +
{{Question|Ecrire un programme permettant de faire le suivi de la lumière d'après ce principe.}}
 +
 
 +
=Utilisation de l'infra-rouge pour suivre une ligne=
 +
 
 +
On souhaite maintenant programmer un robot suiveur de ligne, qui sera de couleur noire.
 +
 
 +
==Principe==
  
===Travail à faire exercice 2 : Réalisation d'un suivi de lumière===
+
5 capteurs photoréflectifs sont disposés sur le robot tel que résumé dans le tableau ci-dessous.
On vous demande de réaliser un programme capable de suivre parfaitement rotation de la source de lumière qui a servi au calibrage. Pour cela le robot devra tourner sur place.
 
  
={{Bleu|Utilisation de l'infra-rouge pour détecter des obstacles}}=
+
{| class="wikitable"
Il y a plusieurs détecteurs infra-rouges dans le robot mini-Q. Nous allons commencer par étudier ceux qui sont sur l'avant du robot et qui sont donc destinés à détecter des obstacles.
+
|-
==Utiliser les détecteurs infra-rouge frontaux==
+
| Position du capteur || extrême gauche || gauche || centre || droite || extrême droite
Le robot dispose de cinq détecteurs infra-rouge pour le suivi de lignes. Ce n'est pas ces détecteurs que nous allons étudier mais un détecteur et deux émetteurs dirigés respectivement vers la droite et vers la gauche. Cela devrait nous permettre de détecter des obstacles. Le détecteur est relié à INT0/PB0 et peut donc être géré par une interruption.
+
|-
 +
| broche arduino || A0 || A1 || A2 || A3 || A4
 +
|-
 +
| entrée CAN || ADC7 || ADC6 || ADC5 || ADC4 || ADC1
 +
|}
  
L'idée générale est d'envoyer un train d'impulsions en émission et de compter ce que l'on reçoit.
+
On peut considérer dans un premier temps que la valeur lue sur le CAN est :
===Code d'émission===
+
*inférieure à 300 sur du noir
Vous pouvez utiliser le code suivant :
+
*supérieur à 300 pour le blanc
<source lang=C>
+
 
// train d'impulsion Gauche
+
On décomposera la vitesse du robot de la même façon que précédemment :
void L_Send40KHZ(void)//left ir transmitter sends 40kHZ pulse
+
*vt : vitesse de translation, constante par ex 30
{
+
*wr : vitesse de rotation, dépendra de la position du robot par rapport à la ligne
  int i;
+
*vitMoteurD = vt + wr
  for(i=0;i<24;i++)
+
*vitMoteurG = vt - wr
  {
 
    digitalWrite(L_IR,LOW);
 
    delayMicroseconds(8);
 
    digitalWrite(L_IR,HIGH);
 
    delayMicroseconds(8);
 
  }
 
}
 
//train d'impulsion Droit
 
void R_Send40KHZ(void)//right ir transmitter sends 40kHZ pulse
 
{
 
  int i;
 
  for(i=0;i<24;i++)
 
  {
 
    digitalWrite(R_IR,LOW);
 
    delayMicroseconds(8);
 
    digitalWrite(R_IR,HIGH);
 
    delayMicroseconds(8);
 
  }
 
}
 
</source>
 
Si vous regardez attentivement le schéma de principe vous déduisez facilement que l'émission se fait à l'aide d'un zéro.
 
Ce code nécessite les définitions suivantes
 
<source lang=c>
 
#define IR_IN  17//infrared receiver
 
#define L_IR 13//infrared transmitter in the left side
 
#define R_IR 8//infrared transmitter in the right side
 
</source>
 
  
===Réception par interruption===
+
=={{Bleu|Position de la ligne}}==
L'interruption est d'abord initialisée à l'aide du code :
 
<source lang=C>
 
void pcint0_init(void)
 
{
 
PCICR = 0X01;
 
PCMSK0 = 0X01;//Autorisation de l'interruption INT0
 
}
 
</source>
 
Le code de l'interruption est tout simple :
 
<source lang=C>
 
volatile unsigned int count=0;
 
ISR(PCINT0_vect)
 
{
 
count++;//on incrémente le compteur pour chaque impulsion reçue
 
}
 
</source>
 
  
===setup() associé===
+
Le plus important est de trouver la position du robot par rapport à la ligne, que l'on notera pos.
Les lignes de code associé à la détection infra-rouge à mettre dans la partie setup() du programme sont :
 
<source lang=c>
 
pinMode(L_IR,OUTPUT);//init the left transmitter pin
 
pinMode(R_IR,OUTPUT);//init the right transmitter pin
 
pinMode(IR_IN,INPUT);//init the ir receiver pin
 
digitalWrite(R_IR,HIGH);
 
digitalWrite(L_IR,HIGH);
 
pcint0_init();
 
sei(); 
 
</source>
 
  
===Un code pour éviter les obstacles===
+
Le principe est d'attribuer un poids à chaque capteur, d'autant plus grand que le capteur est excentré. Le signe donne le côté du capteur :
Tout ce qui précède peut être utilisé pour détecter et donc éviter les obstacles. L'idée générale est très simple :
 
* on initialise le compteur "count" à 0
 
* On émet à droite 24 impulsions plusieurs fois, on compte ensuite ce que l'on reçoit (cela est réalisé automatiquement à l'aide d'une interruption).
 
* si c'est supérieur à 20, on recule suffisamment on tourne du bon côté et on repart en marche avant.
 
* on initialise le compteur à 0
 
* On émet à gauche 24 impulsions plusieurs fois, on compte ce que l'on reçoit.
 
* si c'est supérieur à 20, on recule suffisamment on tourne du bon côté et on repart en marche avant.
 
La mise au point de ce code peut prendre beaucoup de temps.
 
  
'''Indications''' : le code pour émettre plusieurs fois peut être par exemple :
+
{| class="wikitable"
<source lang=c>
+
|-
count = 0;
+
| Position du capteur || extrême gauche || gauche || centre || droite || extrême droite
for(i=0;i<20;i++) { //left transmitter sends 20 pulses
+
|-
    L_Send40KHZ();
+
| poids du capteur || 24 || 12 || 0 || -12 || -24
    delayMicroseconds(600);   
+
|}
}
 
if(count>DISTANCE_IR)//if recieved a lot pulse , it means there's a obstacle
 
</source>
 
Ce code émet 20 fois 24 impulsions.
 
  
Le DISTANCE_IR du "if(count>DISTANCE_IR)" peut être défini par une constante. Divers essais chez moi on montré que la valeur 35 est un bon point de départ. Si vous augmentez cette valeur vous détecterez les obstacles plus près eet si vous la diminuez ce sera le contraire. Il est défini comme une constante DISTANCE_IR dans le code de la section suivante et '''nous vous encourageons très fortement d'utiliser cette technique pour la mise au point'''.
+
L'algorithme est le suivant :
 +
*initialiser pos à 0
 +
*initialiser nbCaptOnLine à 0
 +
*pour chaque capteur
 +
**si le capteur est sur la ligne
 +
***incrémenter nbCaptOnLine
 +
***ajouter le poids du capteur à pos : pos <- pos + poids[numeroCapteur]
 +
*normaliser pos : pos <- pos / nbCaptOnLine
  
==Travail à faire : exercice 3==
 
Vous devez mettre au point un code qui permette de ne jamais percuter des obstacles, c'est à dire qui évite les obstacles qu'il détecte à droite comme à gauche.
 
  
'''Indications''' : vous n'avez plus à gérer de temps maintenant. Autrement dit la technique utilisant "millis()" n'est plus nécessaire. "delay()" peut suffire car votre programme n'est plus sensé s'arrêter. Le code complet du setup() vous est donné ainsi que le code de loop() pour vous montrer l'architecture du programme recherché :
+
'''Exemples''' :
<source lang=c>
+
{| class="wikitable"
#define IR_IN  17//infrared receiver
+
|-
#define L_IR 13//infrared transmitter in the left side
+
|
#define R_IR 8//infrared transmitter in the right side
+
{| class="wikitable"
 +
|-
 +
| Position du capteur || ex gauche || gauche || centre || droite || ex droite
 +
|-
 +
| poids du capteur || 24 || 12 || 0 || -12 || -24
 +
|-
 +
| Valeur CAN || 100 || 100 || 10 || 20 || 100
 +
|-
 +
| Capteur sur la ligne || N || N || O || O || N
 +
|}
  
#define FORW 0     // value for forward
+
pos = (0 + (-12))/2 = -6
#define BACK 1        //value for go back
+
||
 +
{| class="wikitable"
 +
|-
 +
| Position du capteur || ex gauche || gauche || centre || droite || ex droite
 +
|-
 +
| poids du capteur || 24 || 12 || 0 || -12 || -24
 +
|-
 +
| Valeur CAN || 100 || 15 || 10 || 20 || 100
 +
|-
 +
| Capteur sur la ligne || N || O || O || O || N
 +
|}
  
#define SPEED 60
+
pos = (12 + 0 + (-12))/3 = 0
#define DISTANCE_IR 35
+
||
 +
{| class="wikitable"
 +
|-
 +
| Position du capteur || ex gauche || gauche || centre || droite || ex droite
 +
|-
 +
| poids du capteur || 24 || 12 || 0 || -12 || -24
 +
|-
 +
| Valeur CAN || 5 || 150 || 100 || 200 || 100
 +
|-
 +
| Capteur sur la ligne || O || N || N || N || N
 +
|}
  
int count;//count the motor speed pulse
+
pos = (24)/1 = 24
  
void setup()
+
|}
{
 
// moteur gauche
 
  pinMode(5,OUTPUT);
 
  pinMode(12,OUTPUT);
 
//moteur droite
 
  pinMode(6,OUTPUT);
 
  pinMode(7,OUTPUT);
 
// infra-rouge
 
  pinMode(L_IR,OUTPUT);//init the left transmitter pin
 
  pinMode(R_IR,OUTPUT);//init the right transmitter pin
 
  pinMode(IR_IN,INPUT);//init the ir receiver pin
 
  digitalWrite(R_IR,HIGH);
 
  digitalWrite(L_IR,HIGH);
 
// gestion des interruptions
 
  pcint0_init();
 
  sei();              //enable the interrupt
 
// Et en route pour l'aventure...
 
  MotorG(FORW,SPEED);//run left motor
 
  MotorD(FORW,SPEED);//run right motor
 
}
 
void loop() {
 
    Eviter_Obstacle();//obstacle avoidance
 
}
 
</source>
 
Ce code doit être naturellement complété par les morceaux de code donnés précédemment ainsi que par l'écriture du sous-programme "Eviter_Obstacle()" qui est le cœur même de ce que l'on cherche à faire. Vous pouvez noter qu'une constante SPEED est définie à 60 ce qui évite de faire de la casse. Une constante DISTANCE_IR est définie à 35 et devra être utilisée dans le test après réception.
 
  
La mise au point de la détection infra-rouge peut se faire sans mouvement. On utilisera le robot couché sur le côté et un seul moteur celui qui n'est pas sur la table, par exemple, pour tester quand se fait la détection. On le fait avancer sauf quand il y a détection.
+
==Vérification des capteurs==
  
'''Les tests se feront dans le labyrinthe NAO (salle G006)'''.
+
La première étape dans la conception du programme va consister à vérifier le {{CAN}}, en utilisant la led.
  
={{Bleu|Utilisation de l'infra-rouge pour suivre une ligne}}=
+
Ceci peut être réalisé par un programme affichant les données sur la liaison série :
Le robot mini-Q est équipé de cinq couples leds/photo-transistors (infra-rouge) dirigés vers le bas. Ils sont destinés à mesurer la réflexion du support sur lequel roule le robot. Si vous prenez un support blanc et que vous fixez un scotch noir vous arriverez à détecter le support noir qui n'a pas la même réflectance infra-rouge que le support blanc.
+
<source lang=c>
  
La mise au point sera difficile car sur le robot que nous avons essayé les sensibilités des capteurs ne sont pas identiques. La calibrage de chacun des capteurs peut se faire par le programme simple :
+
const uint8_t pinCapteur[5]={A0,A1,A2,A3,A4};
<source lang=C>
 
int data[5]={0X00,0X00,0X00,0X00,0x00};//save the analog value
 
  
void setup(){
+
void setup() {
 +
  // put your setup code here, to run once:
 
   Serial.begin(9600);
 
   Serial.begin(9600);
}
 
void Read_IRLine(void){ //read the analog value
 
// les capteurs A0, A1 sont peu sensibles sur le robot essayé !!!
 
    data[0]=analogRead(A0); // gauche
 
    data[1]=analogRead(A1);
 
    data[2]=analogRead(A2);
 
    data[3]=analogRead(A3);
 
    data[4]=analogRead(A4);  // droite
 
 
}
 
}
  
void loop(){
+
void loop() {
   Read_IRLine();
+
   int valeurCapteur[5];
   for (char i=0;i<5;i++){
+
  uint8_t i;
    Serial.print(data[i]);
+
  // put your main code here, to run repeatedly:
    Serial.print(" ");
+
   for (i=0;i<5;i++)
  }
+
  {
   Serial.println(" ");
+
    valeurCapteur[i]=analogRead( pinCapteur[i] );//store the value read from the sensors
   delay(1000);
+
    Serial.print(valeurCapteur[i]);
 +
    Serial.print(" - ");
 +
  }
 +
   Serial.println();
 +
   delay(500);
 
}
 
}
 
</source>
 
</source>
qui affichera toutes les secondes les valeurs des 5 photo-transistors infra-rouges.
 
==Travail à réaliser : Exercice 4==
 
Le travail à réaliser se décompose en plusieurs étapes :
 
  
{{Question|On vous demande de calibrer vos cinq capteurs avec une plaque blanche de test comprenant une piste en chatterton  noir.}}
 
  
Ce travail consiste à utiliser la liaison série pour calibrer vos 5 capteurs. Calibrer veut dire ici, trouver les seuils en-dessous desquels on considère que l'on a du noir. Ces seuils ne sont pas tous identiques pour tous les robots et pour un même robot pour tous les capteurs. Pour les trouver, vous positionnez une fois le capteur sur du blanc, une fois sur du noir et le seuil sera à mi-chemin.
+
Un essai avec un Robot a donné les résultats suivants.
 
+
{| class="wikitable"
Un moyen de faire cela de manière assez facile à ajuster consiste à définir des constantes comme ci-dessous :
+
|-
<source lang=c>
+
| Position du capteur || extrême gauche || gauche || centre || droite || extrême droite
#define SEUILGG 985
+
|-
#define SEUILG 970
+
| broche µc || 36 || 37 || 38 || 39 || 40
#define SEUIL 750
+
|-
#define SEUILD 700
+
| entrée CAN || ADC7 || ADC6 || ADC5 || ADC4 || ADC1
#define SEUILDD 750
+
|-
</source>
+
| entrée Arduino || A0 || A1 || A2 || A3 || A4
GG veut dire le plus à gauche, DD le plus à droite.
+
|-
 +
| BLANC ||836 || 982 || 980 || 974 || 970
 +
|-
 +
| NOIR || 210 || 390 || 338 || 305 || 305
 +
|-
 +
| Seuil || 523 || 686 || 659 || 639 || 637
 +
|}
  
{{Question|Une fois les seuils de chaque capteur trouvé, convertir l'ensemble des données en un nombre binaire sur 5 bits. Le bit de poids faible sera à 1 si une ligne noire est présente sous le capteur A0 et ainsi de suite jusqu'au bit b4. Tester de nouveau avec un affichage binaire. Commencez ensuite à lister les valeurs aberrantes et les valeurs possibles de ce nombre binaire.}}
+
=={{Bleu|Position de la ligne}}==
  
'''Indication''' : Serial.print(78, BIN) donne "1001110"
+
Il est temps maintenant de calculer la variable {{rouge|pos}} tel qu'indiqué ci-dessus.
  
Le prototype de "Read_IRLine sera changé comme :
+
{{Question|Calculer la valeur pos et l'afficher sur la liaison série}}
<source lang=c>
 
char Read_IRLine(void)
 
</source>
 
pour en faire une fonction qui retourne un nombre binaire.
 
  
'''Indication''' : La conversion binaire vous est partiellement donnée maintenant, mais il vous faut adapter les seuils de vos capteurs... et tester...
+
=={{Bleu|Marche}}==
<source lang=C>
 
//****** seuils très dépendants des ROBOTs
 
#define SEUILGG 941
 
#define SEUILG 500
 
#define SEUIL 400
 
#define SEUILD 880
 
#define SEUILDD 600
 
char Read_IRLine(void){ //read the analog value
 
    char result=0;
 
    data[0]=analogRead(A0); // gauche manque sensibilité sur mon robot
 
    data[1]=analogRead(A1); // manque sensibilité sur mon robot
 
    data[2]=analogRead(A2);
 
    data[3]=analogRead(A3);
 
    data[4]=analogRead(A4); // droite
 
    if (data[0] < SEUILDD) result |= 0x01; else result &= 0xFE;
 
    if (data[1] < SEUILD) result |=        else result &=    ;
 
    if (data[2] < SEUIL) result |=        else result &=    ;
 
    if (data[3] < SEUILG) result |=        else result &=    ;
 
    if (data[4] < SEUILGG) result |=      else result &=    ;
 
    return result;
 
}
 
</source>
 
  
{{Question|Vous commencerez ensuite à essayer de réaliser un programme qui suit une ligne fermée en avançant. Le principe est d'accélérer le bon moteur quand on dévie de la ligne.}}
+
{{Question|Il ne reste qu'à modifier la vitesse angulaire du robot (wr) en fonction de la variable pos}}
  
'''Indication''' : vous pourrez utiliser un "switch" en C qui n'utilise que les valeurs autorisées de Read_IRLine. La valeur 0x00 sera traitée comme valeur aberrante dans un premier temps.
+
'''Remarque''' : attention au signe, sinon la correction se fait dans le mauvais sens !

Version actuelle datée du 24 octobre 2022 à 17:00

Corrections uniquement accessibles aux enseignants


Programmation avec arduino

Le robot miniQ est architecturé autour d'un processeur ATMega32U4. C'est le processeur qui équipe les cartes Leonardo et il est d'ailleurs complètement compatible. Il faut donc changer de board qui est par défaut "Arduino UNO" qui est essentiellement utilisé pour les TPs.

Le processeur 32U4 est capable de gérer une liaison série USB sans l'aide d'un circuit spécialisé (FTDI par exemple).

Le schéma peut être trouvé sur cette page commerciale avec des exemples de code et des exercices en anglais.

En résumé :

  • La carte Arduino équivalente est la : Arduino Leonardo
  • Le programmateur d'origine est : AVR ISP
**********************************************
**********************************************
Attention : pour programmer aller dans le menu
Croquis : Téléverser avec un programmateur
**********************************************
**********************************************

Utilisation de analogWrite() pour la MLI

Commande d'un moteur

Vous trouverez des détails sur le moteur à courant continu et sa commande sur cette page

Vous pourrez consulter plus tard cette page pour comprendre le signal PWM/MLI


Pour faire varier la vitesse d'un moteur il suffit de faire varier sa tension de commande. En général ceci est réalisé avec un signal MLI ou PWM (signal à rapport cyclique variable), nous n'entrerons pas dans le détail dans ce TP.

Tout ceci se fait dans le monde Arduino avec une commande "analogWrite()"

  • analogWrite(broche,255); => tension moyenne de 5v sur la broche
  • analogWrite(broche,127); => tension moyenne de 2.5v sur la broche
  • analogWrite(broche,0); => tension moyenne de 0v sur la broche


Commande d'un moteur : :

  • Il y a deux sorties de commandes du moteur gauche (il faudra donc les positionner en sortie) :
    • broche 5 Arduino (PC6) pour la commande rapport cyclique variable : vitesse de rotation
    • broche 12 Arduino (PD6) pour le sens de rotation
  • On vous donne la fonction ci-dessous qu'il faudra utiliser pour changer la vitesse du moteur :
  • Le paramètre est une valeur entre -255 et 255 qui indique la valeur souhaitée pour la vitesse du moteur
void MotorG(int vitesse)//control the motor
{
  if (vitesse<0)
  {
     vitesse=-vitesse;
     digitalWrite(12,1);
  }
  else
  {
     digitalWrite(12,0);
  }
  if (vitesse>255) vitesse=255;
  analogWrite(5,vitesse);
}

Exemple d'utilisation

void setup()
{
   MoteurG(0);
}


On complète la commande du moteur gauche par celle du moteur droit.

  • Il y a deux sorties de commandes du moteur droit (il faudra donc les positionner en sortie) :
    • broche 6 Arduino (PD7) pour la commande rapport cyclique variable
    • broche 7 Arduino (PE6) pour le sens de rotation
  • La fonction suivante permet de changer la vitesse du 2ème moteur
void MotorD(int vitesse)//control the motor
{
  if (vitesse<0)
  {
     vitesse=-vitesse;
     digitalWrite(7,1);
  }
  else
  {
     digitalWrite(7,0);
  }
  if (vitesse>255) vitesse=255;
  analogWrite(6,vitesse);
}

Question.jpg Travail à faire Vous devez réaliser une commande du robot pour qu'il réalise un huit (deux cercles connectés par un point). Vous choisirez le rayon de vos cercles en jouant sur les rapports cycliques. Puis vous jouerez sur les temporisations pour gérer tout cela. Bien entendu, le fait qu'il n'y ait pas d'information de retour sur l'endroit où vous êtes complique un peu la mise au point.

Vous pouvez chercher à innover sur les trajectoires. Des étudiants, par exemple, ont mis deux obstacles et cherché à réaliser un créneau entre ces deux obstacles. Faites-vous plaisir. Il vous faut à tout prix comprendre comment on va en ligne droite et comment on tourne.

Suivre une source de lumière par Conversion Analogique Numérique

Le travail demandé dans cette section utilise encore la conversion analogique numérique.

La différence est que maintenant c'est la position d'une source de lumière qui va faire changer les valeurs analogiques.

Le capteur est connecté sur la broche A5

Étalonnage des capteurs

Détecteurs de lumière sur MiniQ version 2

Vous disposez de deux capteurs de lumière monté comme dans le schéma ci-contre. Utilisez une liaison série pour trouver les zones pour :

  • lumière au centre
  • lumière à droite
  • lumière à gauche

Question.jpg Ecrire un programme qui permet d'orienter le robot face à la lumière en utilisant l'information droite/centre/gauche

Correcteur proportionnel

Pour le moment, nous n'utilisons que 3 valeurs différentes pour faire le suivi de lumière. Afin de faire un suivi plus performant, nous allons calculer la vitesse de rotation du robot en fonction de la position de la lumière par rapport au robot :

Question.jpg Trouver une équation permettant de donner l'angle entre l'axe du robot et la source de lumière, en fonction de la valeur du CAN. On considérera qu'il s'agit d'une relation affine :

  • relever les valeurs de l'entrée analogique pour :
    • angle -45°
    • angle 0°
    • angle +45°
  • tracer la caractéristique angle en fonction de la valeur de l'entrée analogique
  • donner l'équation de la droite


La vitesse du robot peut être décomposée en une translation et une rotation. On aura donc :

  • vt : vitesse de translation (ex 20)
  • wr : vitesse de rotation
  • vitMoteurD = vt + wr
  • vitMoteurG = vt - wr
  • wr = k * positionAngulaireLumiere

Question.jpg Ecrire un programme permettant de faire le suivi de la lumière d'après ce principe.

Utilisation de l'infra-rouge pour suivre une ligne

On souhaite maintenant programmer un robot suiveur de ligne, qui sera de couleur noire.

Principe

5 capteurs photoréflectifs sont disposés sur le robot tel que résumé dans le tableau ci-dessous.

Position du capteur extrême gauche gauche centre droite extrême droite
broche arduino A0 A1 A2 A3 A4
entrée CAN ADC7 ADC6 ADC5 ADC4 ADC1

On peut considérer dans un premier temps que la valeur lue sur le CAN est :

  • inférieure à 300 sur du noir
  • supérieur à 300 pour le blanc

On décomposera la vitesse du robot de la même façon que précédemment :

  • vt : vitesse de translation, constante par ex 30
  • wr : vitesse de rotation, dépendra de la position du robot par rapport à la ligne
  • vitMoteurD = vt + wr
  • vitMoteurG = vt - wr

Position de la ligne

Le plus important est de trouver la position du robot par rapport à la ligne, que l'on notera pos.

Le principe est d'attribuer un poids à chaque capteur, d'autant plus grand que le capteur est excentré. Le signe donne le côté du capteur :

Position du capteur extrême gauche gauche centre droite extrême droite
poids du capteur 24 12 0 -12 -24

L'algorithme est le suivant :

  • initialiser pos à 0
  • initialiser nbCaptOnLine à 0
  • pour chaque capteur
    • si le capteur est sur la ligne
      • incrémenter nbCaptOnLine
      • ajouter le poids du capteur à pos : pos <- pos + poids[numeroCapteur]
  • normaliser pos : pos <- pos / nbCaptOnLine


Exemples :

Position du capteur ex gauche gauche centre droite ex droite
poids du capteur 24 12 0 -12 -24
Valeur CAN 100 100 10 20 100
Capteur sur la ligne N N O O N
pos = (0 + (-12))/2 = -6
Position du capteur ex gauche gauche centre droite ex droite
poids du capteur 24 12 0 -12 -24
Valeur CAN 100 15 10 20 100
Capteur sur la ligne N O O O N
pos = (12 + 0 + (-12))/3 = 0
Position du capteur ex gauche gauche centre droite ex droite
poids du capteur 24 12 0 -12 -24
Valeur CAN 5 150 100 200 100
Capteur sur la ligne O N N N N
pos = (24)/1 = 24

Vérification des capteurs

La première étape dans la conception du programme va consister à vérifier le Convertisseur Analogique Numérique, en utilisant la led.

Ceci peut être réalisé par un programme affichant les données sur la liaison série :

const uint8_t pinCapteur[5]={A0,A1,A2,A3,A4};

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

void loop() {
  int valeurCapteur[5];
  uint8_t i;
  // put your main code here, to run repeatedly:
  for (i=0;i<5;i++)
   {
     valeurCapteur[i]=analogRead( pinCapteur[i] );//store the value read from the sensors
     Serial.print(valeurCapteur[i]);
     Serial.print(" - ");
   }
  Serial.println();
  delay(500);
}


Un essai avec un Robot a donné les résultats suivants.

Position du capteur extrême gauche gauche centre droite extrême droite
broche µc 36 37 38 39 40
entrée CAN ADC7 ADC6 ADC5 ADC4 ADC1
entrée Arduino A0 A1 A2 A3 A4
BLANC 836 982 980 974 970
NOIR 210 390 338 305 305
Seuil 523 686 659 639 637

Position de la ligne

Il est temps maintenant de calculer la variable pos tel qu'indiqué ci-dessus.

Question.jpg Calculer la valeur pos et l'afficher sur la liaison série

Marche

Question.jpg Il ne reste qu'à modifier la vitesse angulaire du robot (wr) en fonction de la variable pos

Remarque : attention au signe, sinon la correction se fait dans le mauvais sens !