Positionnement du robot
Théorie, Implémentation, Génération de trajectoires...

OLIVIER COCHELIN (COCO)
coco_corp@yahoo.fr

-34- this file and other auxiliary files require to use the following -34- LaTeX packages: frenchle! -34- check or remove these files.Typesetting is aborted!

Contents

Chapter 1
Le positionnement du robot

On présente ici la couche mathématique qui permet au robot de connaître en permanence sa position.

1.1  Présentation

1.1.1  Architecture

Reprenons d'abord l'architecture matérielle et logicielle qui implémente l'asservissement et le positionnement.

Figure
Figure 1.1: Architecture en couches

L'asservissement est réalisé par les 2 LM629 qui décodent et comptent les impulsions en provenance des roues codeuses. A partir d'une roues codeuses délivrant 500 impulsions par tour sur 2 voies en quadrature, le LM compte 2000 impulsions. Le DSP vient périodiquement demander aux LM leurs positions qui correspondent au nombre d'impulsions comptées sur chaque roue. A l'origine, cette opération de polling était réalisée toutes les 10 millisecondes et elle est maintenant faite toutes les millisecondes 1.

1.1.2  Repère utilisé

Voyons maintenant le repère absolu qui a été utilisé.

Figure
Figure 1.2: Repère absolu utilisé

Le choix de ce repère présentait dans notre cas plusieurs avantages :

1.2  Conversions bas niveau

Les impulsions qui sont comptées par le LM ne correspond à aucune réalité physique. Or, pour faciliter la mise en oeuvre et la compréhension du système, il est pratique d'utiliser en haut niveau des unités courantes (m, cm, mmm...). De plus, on a constaté une dissymétrie en les deux roues codeuses et on a du introduire un facteur correctif. là aussi, il est plus convivial de pas avoir à se soucier de ce facteur en haut niveau.

D'autre part, le cablage et le montage des moteurs et des roues codeuses peuvent faire que les signes soient plus ou moins n'importe quoi. Or, on aimerait bien lorsqu'on dit aux deux roues d'avancer de 10 cm, qu'elles avancent (Je dis bien avancent et non reculent) de 10 cm. Ce qui est loin d'être gagné au départ.

C'est pourquoi, on a implémenté dans le DSP une sorte de couche bas niveau qui permet de convertir les données brutes en informations classiques et vice-versa. Les fonctions ou macros ainsi écrites permettent d'accéder à l'asservissement sans trop se soucier des conversions d'unités une fois que tout les paramètres de la couche basse sont bien réglés.

1.2.1  Conversion des distances

La seule unité de distance que le LM connaisse est ce que nous allons appelé le count. Ainsi avec une roue codeuse de 500 points, le LM s'incrémente de 2000 counts en un tour de roue. En haut niveau, on souhaite n'utiliser que des unités classiques ; le millimètre a été retenu bien qu'au final le mètre eu été préférable.

Notons N, le nombre de points que possèdent une roue codeuse. Le LM est alors capable de décoder 4 ×N counts sur cette roue codeuse. Donc un déplacement de 4N counts correspond à un déplacement effective de la roue d'une distance équivalente à sa circonférence qui vaut pD où D représente le diamètre de la roue codeuse.

La constante qui est utilisée dans le DSP pour les conversions de distances est COUNT_PER_MM qui représente le nombre de counts produits par le LM lorsqu'une roue codeuse avance d'un millimètre. Son unité est donc le count/mm. Pour déterminer cette constante, il suffit de faire avancer le robot de 2 m par exemple, de regarder le nombre de counts produits et d'en déduire la valeur du COUNT_PER_MM. Cette valeur est commune aux deux roues codeuses et correspond à la moyenne des valeurs de cette constantes pour chaque roue.

Comme on l'a déjà dit et répété, il y a une dissymétrie entre les circonférences des deux roues codeuses et c'est pour cette raison que l'on a introduit le facteur de correction SYM_LM. Une valeur positive de cette constante permet de corriger une dérive du robot verts la droite. Pour être ajustée, cette valeur nécessite beaucoup de tests. L'une des techniques les plus fiables consiste à faire effectuer au robot une trajectoire rectangulaire qui suit des lignes. Si au bout d'un certain nombre de tour le robot coupe les lignes de la gauche vers la droite, alors il faut augmenter la valeur du SYM_LM.

Ces deux conversions ont été regroupées en deux constantes :

COUNT_PER_MM_D = COUNT_PER_MM*(1-SYM_LM)
COUNT_PER_MM_G = COUNT_PER_MM*(1+SYM_LM)

Ainsi, que l'on veut envoyer une distance au LM il suffit de la multiplier par l'une de ces valeurs. Et inversement, quand on récupère une donnée du LM, il faut la diviser par l'une de ces constantes pour retrouver une valeur en mm.

ATTENTION : Toutes les valeurs qui sont transmises au LM sont des entiers alors que les calculs sont fait en virgule flottante sur le DSP et ceci pour des raisons de précision. Il na faut donc pas oublier de les convertir avant de les envoyés.

1.2.2  Conversion des vitesses

La seul unité de vitesse que le LM connaisse est le count/sample. Curieuse unité me direz-vous alors essayons d'éclaircir la chose. Le count, on a déjà vu avec les distances maintenant qu'est que le sample. le sample est l'unité de temps du LM, elle correspond à la période de la boucle d'asservissement qui est de 2048/fCLK où fCLK est la fréquence de l'oscillateur qui pilote le LM. Donc, pour un oscillateur à 8 MHz, un sample correspond à 256 ms. Dans le code DSP, cette constante a été appelée SAMPLING_PERIOD et son unité est la seconde/sample.

Mais la ruse du LM ne s'arrête pas là. En fait, lorsque l'on charge une vitesse dans le LM, on l'envoie sur 32 bits. Or, seuls les 16 bits de poids forts correspondent à des counts/sample alors que les 16 bits de poids faible correspondent à la partie décimale.

Si on dispose d'une vitesse v_DSP en cm/s que l'on souhaite l'envoyer au LM droit sur 32 bits dans v_LM, il faut appliquer la formule suivante pour la convertir :

v_LM = v_DSP * 10 * COUNT_PER_MM_D * SAMPLING_PERIOD * 65536

Si on récupère une vitesse du LM sur 32 bits et que l'on veut la convertir en cm/s, on appliquera :

v_DSP = v_LM / (10 * COUNT_PER_MM_D * SAMPLING_PERIOD * 65536)

ATTENTION : Les vitesses envoyées au LM sont sur 32 bits et certaines de celles que l'on peut récupérer sont sur 16 bits seulement. Dans ce cas, il ne faut pas oublié de décaler de 16 bits vers la droite la valeur récupérée. Lorsque l'on, ne récupère que 16 bits, il s'agit des 16 bits de poids forts dont l'unité est le count/sample.

1.2.3  Conversion des accélérations

Comme pour la vitesse, le LM ne connaît que des accélérations en counts/sample/sample. Et là aussi les 16 bits de poids forts correspondent à la entière et les 16 bits de poids faible à la valeur décimale.

Si on dispose d'une accélération a_DSP en cm/s2 que l'on souhaite l'envoyer au LM droit sur 32 bits dans a_LM, il faut appliquer la formule suivante pour la convertir :

a_LM = a_DSP * 10 * COUNT_PER_MM_D * SAMPLING_PERIOD * SAMPLING_PERIOD * 65536

Si on récupère une vitesse du LM sur 32 bits et que l'on veut la convertir en cm/s, on appliquera :

v_DSP = v_LM / (10 * COUNT_PER_MM_D * SAMPLING_PERIOD * SAMPLING_PERIOD * 65536)

ATTENTION : Là aussi le LM renvoie dans certains cas les accélérations sur 16 bits.

Ces routines de conversion bas niveau permettent de s'abstraire légèrement du matériel dans le code de traitement. Cependant, nous avons commencé un peu tard à vouloir faire une coche de conversion bas niveau si bien qu'elle n'est pas vraiment opérationnelle et que l'on retrouve souvent les formules de conversion au milieu du code. Ces conversions gagneraient sans doute à être intégrées dans des routines bas niveau d'accès au LM.

1.3  Positionnement du robot

Le positionnement du robot est obtenu par odométrie, c'est à dire que la position est obtenue par intégration des déplacements. L'intérêt de l'odométrie est qu'elle est assez simple à mettre en oeuvre et qu'elle est fiable. Par contre, quand on intègre les déplacements, on intègre aussi l'erreur ce qui fait que l'erreur de position croît avec le temps.

Voyons maintenant comment on réalise concrètement ce positionnement. Comme je l'ai dit, le DSP vient lire régulièrement (toutes les 1/10 ms) la position de chaque roue codeuse. Entre deux lectures, on peut savoir de combien s'est déplacée chaque roue codeuse et il faut à partir de cela en déduire la position du robot.

Figure
Figure 1.3: Positionnement du robot

Il y a en fait deux manières d'approximer la trajectoire élémentaire parcourue par le robot pendant ce temps Te :

Sur le robot, il n'y a que l'approximation par des segments qui a été implémentée et elle donnait de bons résultats. Par contre, l'approximation par des arcs de cercle a été réalisée en simulations sous MATLAB et elle n'a pas fait apparaître de différences notoires lorsque la fréquence d'échantillonnage 1/Te reste suffisamment élevée. Avec les valeurs utilisées sur le robot, on ne voit absolument aucune différence.

On présentera quand même ici les deux méthodes pour voir en quoi elles différent et pourquoi elles convergent lorsque Te devient suffisamment petit. Par contre, il faut garder à l'esprit qu'aucune de ces méthodes n'est absolument exacte.

1.3.1  Approximation par des segments de droites

Appelons Dd et Dg les distances (en mm) parcourues respectivement par les roues droites et gauches entre deux lectures des LM soit un intervalle de temps Te. Connaissant la pose du robot à l'instant n-1, on cherche la pose à l'instant n. On emploie volontairement ici le terme "pose" en accord avec de nombreuses publications. En effet, la pose représente à la fois la position du robot (x,y) et son orientation q. En général, on utilise dans la littérature le terme "position" pour le doublet (x,y), le terme "pose" pour la triplet (x,y,q) et le terme "posture" (x,y,q,k) où k représente le courbure. Il faut remarquer que le terme position est souvent utilisé abusivement 3 pour désigner un état du robot qui peut intégrer bien d'autres paramètres que sa position (x,y).

Figure
Figure 1.4: Approximation par des segments de droite

On a donc :
Dmoyn = [(Ddn + Dgn)/2]
Ddifn = Ddn - Dgn
Dxn = Dmoyn cosqn
Dyn = Dmoyn sinqn
Dqn = [(2 Ddifn)/L]

En effet, lorsque le robot fait un tour sur lui-même (2p radians), la différence de parcours entre les deux roues est de 2L. Ce qui donne une différence de L/2 pour une rotation de 1 radian. Il s'agit là d'ailleurs de la définition du radian. Cette constante L/2 a été appelée MM_PER_RADIAN dans le code DSP.

Ainsi,
xn = xn-1 + Dxn
yn = yn-1 + Dyn
qn = qn-1 + Dqn

Or, l'orientation du robot doit toujours rester dans l'intervalle [-p,+p]. Ce choix est totalement arbitraire mais il nous est apparu comme étant le plus pertinent et le plus facile à utiliser; on aurait pu choisir [0,2p]. On a donc du écrire une fonction réalisant un modulo dont le résultat est toujours dans [-p,+p], cette fonction nommée fmod_pmpi peut être trouvée dans math.c. C'est pourquoi on trouvera dans le code :
pos.angle = fmod_pmpi(pos.angle + (diff_d - diff_g)/MM_PER_RADIAN);

Le calcul et le stockage de la position sont désormais effectués sur des float. En effet, lors des premiers tests réalisés sur le portable, nous utilisions des float pour le calcul et des nombres entiers pour le stockage de la position en dixièmes de millimètres. Ce type de stockage engendrait une perte de précision non négligeable. C'est pourquoi nous réalisons maintenant tous les calculs en float ce qui apporte une souplesse d'utilisation importante et surtout ne prend pas plus de temps de calcul sur le DSP.

1.3.2  Approximation par des arcs de cercles

En reprenant les mêmes notations que précédemment, on obtient la figure suivante :

Figure
Figure 1.5: Approximation par des arcs de cercle

On a toujours :
Dmoyn = [(Ddn + Dgn)/2]
Ddifn = Ddn - Dgn
Dqn = [(2 Ddifn)/L]

Si on tourne vers la droite (Ddn > Dgn) :
Ddn = Dqn ×(R+L/2)
Dgn = Dqn ×(R-L/2)
par contre, si on tourne vers la gauche (Ddn < Dgn) :
Ddn = Dqn ×(R-L/2)
Dgn = Dqn ×(R+L/2)

On en tire :
R = L[(Dmoy)/(Ddif)]
Dxn = R [cos(qn-1+p/2) + cos(qn-p/2)]
Dyn = R [sin(qn-1+p/2) + sin(qn-p/2)]
ou encore,
Dxn = R [sin(qn) - sin(qn-1)]
Dyn = R [cos(qn-1) + cos(qn)]

Il faut bien voir qu'il est nécessaire de prévoir un cas spécial lorsque les deux roues parcourent exactement la même distance. Dans ce cas, l'arc de cercle se transforme en segment ce qui correspond à un cercle de rayon infini. Bien sûr, on ne peut pas faire de calcul avec une valeur infinie, c'est pourquoi, il faut prévoir un cas spécial.

Ce calcul doit absolument être effectué en virgule flottante (float) car il nécessite une dynamique très importante : rayon très grand et déplacement des roues très petits.

Or,
qn = qn-1 + Dqn

Ce qui donne après développement :
Dxn = R [sin(qn-1)cos(Dqn) + cos(qn-1)sin(Dqn) + sin(qn-1)
Dyn = R [sin(qn-1)sin(Dqn) - cos(qn-1)cos(Dqn) + cos(qn-1)

On retombe alors sur l'approximation par des segments de droites si on suppose que Dqn est très petit. En effet, dans ce cas :
cos(Dqn) » 1
sin(Dqn) » 0

ce qui donne :
Dxn = R [sin(qn-1) + sin(qn-1)
Dyn = R [-cos(qn-1) + cos(qn-1)

L'approximation Dqn très petit est d'autant plus justifiée que la fréquence d'échantillonnage 1/Te est très grande et que l'angle varie très peu entre deux estimations de la position 4. Ceci explique donc que les deux méthodes d'approximations convergent lorsque l'on diminue la période d'échantillonnage.

Chapter 2
La génération de trajectoires

On va maintenant s'intéresser à la génération de trajectoires, c'est à dire comment faire pour aller d'un point A à un point B. On ne s'intéressera ici qu'à la génération de trajectoires rectilignes qui a été utilisée pour la Coupe de France de Robotique. Depuis cette date, la génération de trajectoires courbes a été étudiée et une implémentation est disponible. Cependant, comme cette deuxième technique est beaucoup plus complexe que la première, elle fera l'objet d'un autre document.

On souhaite donc faire passer le robot d'une pose de départ (xn-1,yn-1,qn-1) à une position d'arrivée (xn,yn). Pour l'arrivée, on ne spécifie pas d'orientation puisqu'elle ne présentait pas d'intérêt dans notre cas. En effet, il n'y a pas vraiment de cas où la spécification de l'angle à l'arrivée apporte un plus. Si on souhaite arriver à un point avec un angle précis 5 la carte principale doit utiliser un point intermédiaire qui permettra lors du déplacement vers le point désiré d'avoir la bonne orientation.

Figure
Figure 2.1: Génération de trajectoire

Au départ comme à l'arrivée, la vitesse du robot est nulle. Cette contrainte est due aux LM629 qui utilisé en mode "Position" ne permettent de relier des configurations où la vitesse nulle. Pour passer d'une position à l'autre, on réalise un trajectoire composée de 2 mouvements :

2.1  Calcul de l'angle et de la distance

Pour réaliser cette trajectoire, il suffit donc de calculer l'angle q duquel il faut tourner sur place et la distance d qu'il faut parcourir en ligne droite.

Pour la distance, la formule est assez simple :


d =
Ö
 

(xn-xn-1)2 + (yn-yn-1)2
 

Pour l'angle, ça n'est pas beaucoup plus compliqué :


q = fmod_pmpi( atan2(yn-yn-1,xn-xn-1) - qn-1 )

Le fmod_pmpi externe permet de minimiser la rotation en ramenant toujours l'angle dans l'intervalle [-p;+p]. On évite ainsi au robot de tourner de 3p/2 au lieu de -p/2.

atan2 est une arc-tangente un peu particulière qui est implémentée dans la majorité des langages. Contrairement à l'arc-tangente classique qui est modulo p, cette version améliorée est modulo 2p et retourne en général 6 un angle compris entre -p et +p. En lui indiquant une ordonnée et une abscisse, cette fonction très pratique retrouve l'angle correspondant sur le cercle trigonométrique.

2.2  Calcul des consignes pour les LM

Voila, une fois que l'on a l'angle q et la distance d, il ne reste plus qu'à envoyer des ordres aux LM. Il y aura en fait deux trajectoires pour chaque LM.

La première trajectoire correspond à la rotation sur place. Il suffit d'imposer au LM droit de se déplacer de q×MM_PER_RADIAN/2 et au LM gauche de se déplacer de -q×MM_PER_RADIAN/2. A partir de cela, les LM vont générer en interne des profils de vitesse qui leur permette d'atteindre ces positions en respectant les contraintes de vitesse et d'accélération.

La seconde trajectoire correspond à la ligne droite et il suffit là d'envoyer la même consigne de position aux 2 LM en leur demandant de se déplacer de la distance d après avoir pris soin de la convertir en mm.


Footnotes:

1Il n'y a pas de différences majeures entre ces deux périodes au niveau des résultats.

2Il faut éviter de choisir des repères ou des systèmes d'unités qui obligent à se torturer le cerveau pour leur donner une signification pratique

3Ce qui sera certainement le cas ici aussi

4De la posturepose devrais-je dire !

5Pour l'approche d'un panier par exemple

6Ca dépend beaucoup des environnements utilisés. Le mieux c'est de testé pour être sûr et éventuellement de rajouter un fmod_pmpi si besoin est.


File translated from TEX by TTH, version 2.79.
On 29 Sep 2002, 17:52.