Micro contrôleurs AVR/AVR et robotique : ASURO

Leçons de niveau 14
Une page de Wikiversité, la communauté pédagogique libre.
Début de la boite de navigation du chapitre
AVR et robotique : ASURO
Icône de la faculté
Chapitre no 12
Leçon : Micro contrôleurs AVR
Chap. préc. :La conversion analogique numérique
Chap. suiv. :AVR et robotique : pololu
fin de la boite de navigation du chapitre
En raison de limitations techniques, la typographie souhaitable du titre, « Micro contrôleurs AVR : AVR et robotique : ASURO
Micro contrôleurs AVR/AVR et robotique : ASURO
 », n'a pu être restituée correctement ci-dessus.

ASURO est un robot mobile destiné à être monté soi-même. Son montage nécessite de bien connaître les composants et naturellement de savoir souder. Le Microcontrôleur qui anime ce robot est un Atmel AVR ATMega8. Ce robot mobile a été conçu en Allemagne. Il existe une page dans wikipédia allemand qui lui est consacrée :

On y apprend, par exemple, qu'ASURO est un acronyme pour "Another Small and Unique Robot from Oberpfaffenhofen" (Oberpfaffenhofen est une ville bavaroise allemande). Cet article de wikipédia n'est ni traduit en anglais, ni traduit en français.

ASURO est un robot différentiel. Un robot différentiel est un robot ayant deux roues autopropulsées indépendantes et une ou deux sphères directionnelles.

Présentation en Image[modifier | modifier le wikicode]

Voici une image vectorisée présentée ci-contre.

Modèle vectorisé de l'ASURO

On y distingue un certain nombre d'éléments :

  • quatre batteries de type AAA
  • un interrupteur marche/arrêt
  • deux moteurs à courant continu
  • le microcontrôleur de type ATMega8
  • a l'avant des capteurs de proximité (interrupteurs) permettant de détecter un contact
  • une démultiplication par roue dentées
  • une roue dentée avec alternance noir/blanc est aussi visible (en haut) pour une mesure de la position
  • une programmation par infra-rouge

La programmation se fait à l'aide d'un bootloader (traduit par Chargeur d'amorçage dans Wikipédia). Cette programmation sans contact est une très bonne idée pour mettre au point des programmes. En effet, comme son nom l'indique, la robotique mobile est mobile ! Chaque fois que vous envoyez un programme dans le robot, son test consiste à se déplacer. Une programmation par contact (appelée programmation in-situ) nécessitera alors de débrancher les contacts... À noter que les anciennes versions proposaient une programmation par RS232 ou par USB. Aujourd’hui seul l’USB est proposé. Cela nécessite un logiciel spécifique de programmation. Celui-ci est disponible pour Windows et pour Linux.

Nous allons maintenant nous intéresser à la schématique électronique et ses liens avec la programmation en c.

Étude de la détection d'obstacles[modifier | modifier le wikicode]

Le schéma électronique de la détection d'obstacles est donné maintenant :

Les détecteurs de contact de l'ASURO

Comme le montre le schéma les broches ADC4 et PD3 sont utilisées. Il est temps maintenant de partir de ce schéma et de se demander comment peut-on détecter un choc sur l'un des capteurs ?

Étude de la partie odométrie[modifier | modifier le wikicode]

Comment mesure-t-on la vitesse ?

Nous allons nous intéresser dans cette section à la mesure de vitesse de chacun des moteurs et de ses conséquences sur le positionnement du robot. C'est ce que l’on appelle Odométrie.

Nous commençons par présenter la façon utilisée pour mesurer la vitesse. On peut voir sur la figure ci-dessous une roue dentée sur lequel des secteurs angulaires noirs sont alternés avec des secteurs blancs.


Prenez bien le temps de voir tout cela pour bien comprendre, en particulier en regardant les deux côtés du robot pour voir comment tout ceci est assemblé.

Étude de la cinématique d'un robot différentiel[modifier | modifier le wikicode]

Dans la suite tout ce qui concerne la roue droite sera indicée d et la roue gauche indicé g.

Imaginons le robot différentiel suivant représenté ci-contre.

Robot différentiel

Nous noterons :

  • et les déplacements respectifs des roues gauche et droite
  • et les vitesses respectives des roues gauches et droite
  • le déplacement du robot
  • le rayon des roues de propulsion du robot
  • la vitesse du robot
  • l'écart entre les deux roues, sa largeur de voie
  • la vitesse angulaire de rotation autour de l'axe du cercle

Il est facile d'écrire la vitesse de rotation du robot autour de l'axe du cercle à partir des deux vitesses linéaires des roues :

Cette formule peut être généralisée en remarquant que comme R peuvent dépendre du temps :

Il est facile d’en déduire les deux formules :

Il vient finalement :

Le fait que l'intégration soit linéaire permet de trouver facilement :

D(t) est la distance parcourue par le centre de l'axe des moteurs, et représentent les distances parcourues par respectivement la roue gauche et la roue droite. Quant à l'angle, il est donné par :

si L est l’entre-axe des roues.

Application pratique aux calculs[modifier | modifier le wikicode]

Si l’on repart des deux formules de la distance parcourue et de l'angle :

D(t) est la distance parcourue par le centre de l'axe des moteurs, et représentent les distances parcourues par respectivement la roue gauche et la roue droite. Quant à l'angle, il est donné par :

si L est l’entre-axe des roues.

Il est facile de les généraliser aux variations. Ces formules deviennent facilement :

L'intégration se fait alors par :

On peut déterminer les variations de l'angle et de la position du robot comme le squelette de programme le fait ci-après :

dAlpha = (dRight-dLeft); //variation de l'angle
dDelta = (dRight+dLeft)/2; //variation de l'avancement
//conversion en radian
alpha += dAlpha / entraxeEnTick; //calcul des décalages selon X et Y
dX = cosf(alpha) * dDelta;
dY = sinf(alpha) * dDelta;
//conversion de la position en mètre
X += dX / tickParMetre;
Y += dY / tickParMetre;

Ce code devra être adapté à vos unités.

Panneau d’avertissement Le calcul du cosinus et du sinus sont des opérations lourdes dans les architectures 8 bits. Ils ne devront ainsi en aucun cas se trouver dans le code d'une interruption.

Étude de l'électronique[modifier | modifier le wikicode]

Voici le schéma électronique correspondant à cette odométrie.

La mesure de vitesse

Comme il est très visible sur ce document, l'électronique présentée est associée à un côté : LEFT pour la gauche et RIGHT pour la droite.

Marier l'électronique et la cinématique[modifier | modifier le wikicode]

Nous avons donné plus haut les équations de la cinématique directe. Elles font intervenir des vitesses de rotation, mais nous sommes intéressé par une transformation de ces équations avec des données que notre microcontrôleur est capable de connaître. Le microcontrôleur est incapable de connaître la vitesse instantanée mais peut par contre détecter une alternance de secteur noirs et blancs (ce que l’on appellera tick dans la suite).

Voici donc les équations de navigation à l'estime (dead reckoning) pour les coordonnées (x et y), à partir de () pour un robot différentiel avec des encodeurs sur chaque roue :

est le nombre de ticks enregistré sur la roue une, est le nombre de ticks enregistré sur la roue deux, est le rayon de chacune des roues, est la séparation entre les deux roues, et est le nombre ticks pour une rotation complète de la roue.

Le calcul de ces équations par un microcontrôleur est un défi sur la taille programme. En effet le calcul d'un cosinus et sinus est très consommateur. Nous vous recommandons d’utiliser l'algorithme CORDIC.

Un calcul CORDIC en format Q3.13[modifier | modifier le wikicode]

Le format Q3.13 est un format virgule fixe, sur 16 bits (3+13) avec 3 bits de partie entière et 13 bits de partie fractionnaire. Il est choisi ici pour contenir les angles en radian comme les résultats des sinus et cosinus sur 16 bits pour éviter les calculs trop longs sur une architecture 8 bits.

Nous donnons en brut un programme qui sera amélioré plus tard. La grande amélioration consiste à noter les valeurs données par la deuxième boucle (d'affichage) pour initialiser manuellement le tableau "atantb" et ainsi éviter la première boucle et donc les appels aux fonctions "atan" et "pow" très consommatrices de ressources !

//TODO Faire disparaitre complètement math.h
// Format utilisé ici : Q3.13 (virgule fixe)
#include <stdio.h>
//#include <math.h>
float HexQ3_13ToFloat(int val);
int float2HexQ3_13(float val);
 int main()
{
    int nb_iter; // Nombre d'itérations
    int K = 0x136F; //=0.6073 en Q3.13
    int x = K, y = 0; // Valeur approchante de cos(beta) et sin(beta)
    int x_Nouveau; // Variable temporaire
    int beta = 0; // Angle à chercher
// tableau de valeurs précalculées rempli
    int atantb[14]={0x1921,0xED6,0x7D6,0x3FA,0x1FF,0xFF,0x7F,0x3F,0x1F,0xF,0x7,0x3,0x2,0x1}; 
    int i = 0; // declaration de l'indice d'iteration

    printf("Calcul par la méthode CORDIC de sinus : \n\n\n Veuillez entrer beta\n");
// scanf("%d",&beta); // entrer la valeur de beta
// beta = float2HexQ3_13(0.7853);
    beta = float2HexQ3_13(-1.047);
// scanf("%d",&nb_iter); // Entrer le nombre d'itération
    nb_iter = 14;
// itération CORDIC proprement dite : 
    for(i = 0; i < nb_iter; i++) {
         // Si beta<0 rotation dans le sens trigo
         if(beta < 0) {
            x_Nouveau = x + (y>>i);
            y -= x>>i;
            beta += atantb[i];
         }
         // sinon dans l'autre sens
         else {
            x_Nouveau = x - (y>>i);
            y += (x>>i);
            beta -= atantb[i];
         }
         x = x_Nouveau;
    }
// Affichage du résultat :
    printf("cos(beta) = %f , sin(beta) = %f \n", HexQ3_13ToFloat(x),HexQ3_13ToFloat(y)); 
    return 0;
}

float HexQ3_13ToFloat(int val){
  float temp;
  int i_temp;
  char i;
  if (val < 0) i_temp = -val; else i_temp = val;
  temp = ((i_temp & 0x6000)>>13);
  for (i=0;i<13;i++)
    if (i_temp & (1<<i)) temp += pow(2,(i-13));
  if (val < 0) return -temp; else return temp;
}

int float2HexQ3_13(float val){ //OK checked
  int temp;
  char i;
  float f_temp;
  if (val < 0) f_temp = -val; else f_temp = val;
  temp = ((int) floor(f_temp)<<13);
  f_temp = f_temp - floor(f_temp);
  for (i=0;i<13;i++) {
    temp|=((int)floor(2*f_temp)<<(12-i));
    f_temp = 2*f_temp - floor(2*f_temp);
   }
   if (val < 0) return -temp; else return temp;
}

Notez dans ce programme l'absence de multiplications qui ont été remplacées par des décalages (dans le programme principal). Les seules ressources importantes sont dans les fonctions d'affichage ("printf") mais qui ne sont là que pour réaliser des tests. Leur suppression en remplaçant l’affichage et la demande d'angle par des fonctions réalisées dans un hyperterminal permet de passer d'un programme initialement de 8 ko à 1,1 ko.


Quelles en sont les conséquences pour une mesure des vitesses en C ?

Étude de la partie commande des moteurs[modifier | modifier le wikicode]

La commande des moteurs de l'ASURO utilise le timer 1. Nous allons donc commencer par une documentation correspondante.

Comparaison et PWM pour le timer 1 de l'ATMega8[modifier | modifier le wikicode]

Voici la documentation du timer 1 de l'ATMega8. Il s'agit d'un timer 16 bits comme déjà évoqué mais qui possède un mode de fonctionnement sur 8 bits comme l'indique la figure ci-dessous.

Commande des moteurs[modifier | modifier le wikicode]

Voici l'électronique de commande des moteurs du robot mobile ASURO.

Les deux commandes de moteurs du robot mobile ASURO

Exercice[modifier | modifier le wikicode]

ASURO est un robot mobile différentiel (2 roues propulsées par deux moteurs et une demi-balle de ping pong comme roue (point ?) libre. L'ensemble est commandé par un ATMega8. Sa commande de propulsion est réalisée par le montage ci-dessus.

1°) Analyse du schéma. Pour les trois entrées PD5, PD4 et PB1 pouvez-vous examiner les 8 possibilités pour la commande du moteur "LEFT" en précisant quelles combinaisons feront des courts-circuits ?

2°) Le sous-programme "MotorState est donné maintenant :

 /** 
  * Motor configuration. 
  * values: FWD, RWD, BREAK, FREE 
  * @param left left motor 
  * @param right right motor 
  */ 
 inline void MotorState(unsigned char left, unsigned char right) 
 { 
 	PORTD = (PORTD &~ ((1 << PD4) | (1 << PD5))) | left; 
 	PORTB = (PORTB &~ ((1 << PB4) | (1 << PB5))) | right; 
 }

En vous aidant de la question 1°) pouvez-vous expliquer ce que fait l'instruction

MotorState(FWD,FWD);

si la constante FWD est définie comme :

#define FWD		(1 << PB5) /* (1 << PD5) */

Pourquoi RWD est-il défini comme :

#define RWD		(1 << PB4) /* (1 << PD4) */

3°) Pouvez-vous donner parmi les instructions suivantes du sous-programme Init() (fourni avec ASURO), celles qui sont absolument nécessaires à la réalisation gestion du timer2.

 void Init(void) { 
 	//-- serial interface programmed in boot routine and already running -- 
 	//  prepare 36kHz for IR - Communication 
 	TCCR2 = (1<<WGM20)|(1<<WGM21)|(1<<COM20)|(1<<COM21)|(1<<CS20); 
 	OCR2  = 0x91; // duty cycle for 36kHz 
 	TIMSK |= (1 << TOIE2); // 36kHz counter for sleep 
 	// prepare RS232 
 	UCSRA = 0x00; 
 	UCSRB = 0x00;	 
 	UCSRC = 0x86; // No Parity | 1 Stop Bit | 8 Data Bit 
 	UBRRL = 0xCF; // 2400bps @ 8.00MHz 
 	// I/O Ports 
 	DDRB = IRTX | LEFT_DIR | PWM | GREEN_LED; 
 	DDRD = RIGHT_DIR | FRONT_LED | ODOMETRY_LED | RED_LED; 
 	// for PWM (8-Bit PWM) on OC1A & OC1B 
 	TCCR1A = (1 << WGM10) | (1 << COM1A1) | (1 << COM1B1); 
 	// tmr1 running on MCU clock/8 
 	TCCR1B = (1 << CS11); 
 	// A/D Conversion 
 	ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1); // clk/64 
 	 
 	ODOMETRY_LED_OFF; 
 	FrontLED(OFF); 
 	BackLED(ON,ON); 
 	BackLED(OFF,OFF); 
 	StatusLED(GREEN); 
 	MotorState(FWD,FWD); 
 	MotorSpeed(0, 0); 
 	sei(); 
 }

4°) Quel est le mode de fonctionnement choisi pour le Timer2 ?

Documentation supplémentaire :

(COM21,COM20)2

00 : Opération normale OC0 déconnecté

01 : Réservé

10 : RAZ de OC0 quand comparaison

11 : Mise à 1 de OC0 quand comparaison

Quel est le rapport cyclique choisi ?

5°) À partir du schéma donné, pouvez-vous dire quel timer est utilisé pour la gestion du PWM ? Pouvez-vous donner parmi les instructions du sous-programme Init() (ci-dessus), celles qui sont absolument nécessaires à la gestion du timer correspondant. Dans quel mode PWM est-il ?

6°) La gestion des deux vitesses par MLI est confiée à un sous-programme que l’on vous demande de compléter.

 /** 
  * sets motor speed. range: 0..255 
  * @param left_speed left motor 
  * @param right_speed right motor 
  */ 
 inline void MotorSpeed(unsigned char left_speed, unsigned char right_speed) 
 { 
	 = left_speed; // a compléter
	 = right_speed; // a compléter
 }

La programmation[modifier | modifier le wikicode]

L'Atmel AVR ATMega8 est naturellement programmable en C. Le robot est livré avec une librairie écrite en C.

Voir aussi[modifier | modifier le wikicode]

Livre sur les capteurs