Login

mercredi, 04 juillet 2007 17:47

Détails du code de l'odométrie

Écrit par 
Évaluer cet élément
(0 Votes)

 L'odométrie c'est quoi ?

L’odométrie est une technique permettant d'estimer la position d'un véhicule en mouvement. Le terme vient du grec hodos (voyage) et metron (mesure).

Sur le robot Pilou, on dispose de capteurs sur chaque roue. Le processeur chargé de l'odométrie va donc calculer le déplacement et la vitesse de chaque roue.

Voyons comment on fait :

 Le déplacement

 Principe 

Les capteurs utilisé par roue sont deux senseurs situés à 90° au centre desquels tourne une petite roue munie d'aimants... Il y a 3 aimants.

On va donc avoir 6  inversion de polarité sur chaque capteur par tour de moteur donc 12 au total.

Le moteur est doté d'un réducteur 1:30 : on obtiendra donc 360 changements de polarité par tour de roue soit 1 changement par degré.

Les roues font 10cm de diamètre donc : une inversion = 0,87mm

Pour connaitre le sens de rotation, il faut lire les 2 capteurs : le changement de polarité de l'un avec l'état de l'autre nous donne le sens de rotation du moteur... 

 Le logiciel

  Le logiciel doit être suffisamment rapide car il aura a agir 2 fois tous les 0,87mm ... pour un robot qui parcours 3 mètres par seconde, cela fait 7000 fois par seconde donc tous les 140 µ secondes.

Pour ce faire, il existe sur le microprocesseur 4 entrées (RB4 à RB7) qui ont comme propriété de provoquer une interruption dès que l'un d'eux change d'état... On va donc connecter les 4 capteurs à ces broches et attendre les interruptions.

Pour avoir un code rapide comme l'éclair, on utilise la technique suivante :

on crée un octet composé de deux fois les 4 bits  actuels et précédents

On mémorise les 4 bits actuels pour les utiliser comme précédent la prochaine fois

On utilise l'octet pour chercher une valeur dans une table : cette valeur peut être 0 , +1, -1 suivant qu'on doit ne rien faire ou ajouter un ou retrancher un  au déplacement. Il existe une table pour la roue gauche et une table pour la roue droite. Chaquer table fait 256 octets.

Voilà....  le plus fastidieux est de garnir les 2 tables : il faut analyser, roue par roue quelle est la situation actuelle, quelle était la précédente et déduire s'il faut touvher au compteur de distance...

Mais c'est plus rapide que l'éclair (environ 50 instructions machine)

Voici donc le code de l'interrupt

/****************************************
/ Interrupt changement d'état RB4 RB7
****************************************/
// Pour les encodeurs de roues droite et gauche

#int_RB
void RB_isr() {
   codeur_N = input_b() & 0xF0;       // 4 bits poids fort = nouvel état
   codeur_A >>=4;                     // ancien état sur 4 bits poids faible
   codeur_N += codeur_A;              // ou pour faire l'index
   codeur_A = codeur_N & 0xF0;        // mémorisation du nouvel état dans l'ancien
   deplacement_G += dep_G[codeur_N];  // déplacement roue gauche
   deplacement_D += dep_D[codeur_N];  // déplacement roue droite
}

 et les tables utilisées :


signed byte const dep_D[256] =
     {
         0,0,0,0, 0xFF,0xFF,0xFF,0xFF, 1,1,1,1, 0,0,0,0,
         0,0,0,0, 0xFF,0xFF,0xFF,0xFF, 1,1,1,1, 0,0,0,0,
         0,0,0,0, 0xFF,0xFF,0xFF,0xFF, 1,1,1,1, 0,0,0,0,
         0,0,0,0, 0xFF,0xFF,0xFF,0xFF, 1,1,1,1, 0,0,0,0,
        
         1,1,1,1, 0,0,0,0, 0,0,0,0, 0xFF,0xFF,0xFF,0xFF,
         1,1,1,1, 0,0,0,0, 0,0,0,0, 0xFF,0xFF,0xFF,0xFF,
         1,1,1,1, 0,0,0,0, 0,0,0,0, 0xFF,0xFF,0xFF,0xFF,
         1,1,1,1, 0,0,0,0, 0,0,0,0, 0xFF,0xFF,0xFF,0xFF,
        
        
         0xFF,0xFF,0xFF,0xFF, 0,0,0,0, 0,0,0,0, 1,1,1,1,
         0xFF,0xFF,0xFF,0xFF, 0,0,0,0, 0,0,0,0, 1,1,1,1,
         0xFF,0xFF,0xFF,0xFF, 0,0,0,0, 0,0,0,0, 1,1,1,1,
         0xFF,0xFF,0xFF,0xFF, 0,0,0,0, 0,0,0,0, 1,1,1,1,
        
         0,0,0,0, 1,1,1,1, 0xFF,0xFF,0xFF,0xFF, 0,0,0,0,
         0,0,0,0, 1,1,1,1, 0xFF,0xFF,0xFF,0xFF, 0,0,0,0,
         0,0,0,0, 1,1,1,1, 0xFF,0xFF,0xFF,0xFF, 0,0,0,0,
         0,0,0,0, 1,1,1,1, 0xFF,0xFF,0xFF,0xFF, 0,0,0,0,
     };

signed byte const dep_G[256] =
    {
      0,1,0xFF,0, 0,1,0xFF,0, 0,1,0xFF,0, 0,1,0xFF,0,
         0xFF,0,0,1, 0xFF,0,0,1, 0xFF,0,0,1, 0xFF,0,0,1,
         1,0,0,0xFF, 1,0,0,0xFF, 1,0,0,0xFF, 1,0,0,0xFF,
         0,0xFF,1,0, 0,0xFF,1,0, 0,0xFF,1,0, 0,0xFF,1,0,
        
      0,1,0xFF,0, 0,1,0xFF,0, 0,1,0xFF,0, 0,1,0xFF,0,
         0xFF,0,0,1, 0xFF,0,0,1, 0xFF,0,0,1, 0xFF,0,0,1,
         1,0,0,0xFF, 1,0,0,0xFF, 1,0,0,0xFF, 1,0,0,0xFF,
         0,0xFF,1,0, 0,0xFF,1,0, 0,0xFF,1,0, 0,0xFF,1,0,
        
        
      0,1,0xFF,0, 0,1,0xFF,0, 0,1,0xFF,0, 0,1,0xFF,0,
         0xFF,0,0,1, 0xFF,0,0,1, 0xFF,0,0,1, 0xFF,0,0,1,
         1,0,0,0xFF, 1,0,0,0xFF, 1,0,0,0xFF, 1,0,0,0xFF,
         0,0xFF,1,0, 0,0xFF,1,0, 0,0xFF,1,0, 0,0xFF,1,0,
        
      0,1,0xFF,0, 0,1,0xFF,0, 0,1,0xFF,0, 0,1,0xFF,0,
         0xFF,0,0,1, 0xFF,0,0,1, 0xFF,0,0,1, 0xFF,0,0,1,
         1,0,0,0xFF, 1,0,0,0xFF, 1,0,0,0xFF, 1,0,0,0xFF,
         0,0xFF,1,0, 0,0xFF,1,0, 0,0xFF,1,0, 0,0xFF,1,0,
       
       
    };

   en résultat, on a deux "long" qui contiennent la distance parcourue par chaque roue : deplacement_G et deplacement_D.

Simple non?

Eh bien pas tout à fait : il faut prévoir le débordement des compteurs au bout d'un moment.... mais ceci n'est pas traité dans ce processeur mais dans le processeur de navigation..... 

 

La vitesse

  Puisque ce processeur est dédié à l'odométrie, on en profite pour qu'il calcule en permanence la vitesse de chaque roue... en effet, il faut mieux la calculer dans un processeur qui a peu de traitement compliqués et qui assurera un calcul fiable.

Qu'est ce que la vitesse? C'est la distance parcourue par unité de temps... oui mais quelle unité de temps  choisir pour calculer? une fois par heure? trop long, une fois par 10msec? trop court...

Principe

On va mettre en interruption horloge toutes les 10 msec, un programme qui va

  • Stocker la différence de déplacement pae rapport au dernier passage dans un buffer "tournant"

  • Calculer le déplacement réalisé durant les 50 dernières millisecondes  : ce sera la vitesse en unité de déplacement par 50msec.

On fait donc un calcul toutes les 10 milisecondes qui correspond à la vitesse moyenne des 50 dernières millisecondes 

Le Logiciel

 Voici donc le code du logiciel qui tourne sous interruption horloge 10 msec :

/***************************************
/ Interrupt Timer 0 (toutes les 10msec)
***************************************/
#int_TIMER0
void TIMER0_isr()
 {
       byte ilire;
       byte index;
       byte tempVitesseG;
       byte tempVitesseD;
      
       set_timer0(VAL_TMR0); //période = 10,0352 msec

       // stockage de la vitesse dans le bon slot
       cptTabVitesse++;                              // échantillonnage tics/10,0352msec
       if (cptTabVitesse== NBTABVIT ) cptTabVitesse=0;
       tabVitesseG[cptTabVitesse]= deplacement_G - oldDeplacementG ;   
       tabVitesseD[cptTabVitesse]= deplacement_D - oldDeplacementD ;
       oldDeplacementG = deplacement_G; // mémorisation valeur précédente du déplacement
             oldDeplacementD = deplacement_D;
       // calcul de la vitesse sur les x derniers slots
             cptLireVitesse++;
             if (cptLireVitesse== NBTABVIT ) cptLireVitesse=0;
             tempVitesseG=tempVitesseD=0;
       for (index=0; index<NBSLOTSVITESSE ; index++){
            ilire=cptLireVitesse+index;
            if (ilire>=NBTABVIT) ilire =ilire-NBTABVIT;
            tempVitesseG += tabVitesseG[ilire];
            tempVitesseD += tabVitesseD[ilire];            
       }
       vitesseG= tempVitesseG ;                      // maj vitesse : pas besoin d'inhibit pour la lire
        vitesseD= tempVitesseD ;

  } 

  et les déclarations dans le fichier .h :

// Calcul de la vitesse
#define NBTABVIT 10             // taille totale de la table
byte tabVitesseG[10];            // table des vitesses instantanées
byte tabVitesseD[10];
#define NBSLOTSVITESSE 5         // nombre de slots de 10msec pour calculer la vitesse
byte cptTabVitesse;              // le compteur de remplissage
byte cptLireVitesse;             // le compteur de début de lecture pour le calcul de vitesse
byte  vitesseG;                  // la vitesse lissée sur les NBSLOTSVITESSE dernières 10sec
byte  vitesseD;
byte accelG;                     // l'accélérationgauche
byte accelD;                     // l'accélération roue droite
long oldDeplacementG;            // valeur ancienne du déplacement
long oldDeplacementD;

 

simple ?  oui .. ici, pas de problèmes

  Fin

Voilà.... il reste au processeur d'odométrie à transmettre ces informations par le bus I2C au processeur d'asservissement quand ce dernier voudra bien venir  les chercher....Il aura alors la dernière valeur toute fraiche du déplacement et de la vitesse


 

 

 

Lu 8040 fois Dernière modification le jeudi, 05 janvier 2012 10:01
Connectez-vous pour commenter