logo T-Bot FAQ presents

Chercher
Dernière page modifiée : LaGravure le 21/06/11 00:17:24

LaPageCoco

retour à LaFaq



Coco


Salut à tous,

Ayant travaillé un peu sur le fonctionnement du LM et la planification de trajectoires je pense pouvoir donner quelques infos.

Tout d'abord, le LM629 fait de l'asservissement de position et uniquement de l'asservissement de position, même quand on l'utilise en mode vitesse. J'insiste sur ce point qui est fondamental.
Le LM se contente de prendre la position désirée (recalculée à chaque tout de boucle) de lui soustraire la position réelle pour obtenir l'erreur puis cette erreur est filtrée par le PID pour obtenir une consigne de PWM.

Quand on utilise le LM en mode position :
On lui fournit une position à atteindre, une limite de vitesse et une accélération (qui sert aussi pour la déccélération). A partir de ça, il calcule un profil de vitesse représentant la vitesse instantannée en fonction du TEMPS. Une fois ça fait, on est prêt pour démarrer la trajectoire.
A chaque tour de boucle d'asservissement (2048/f_clock il me semble) :
- le LM prend l'ancienne position désirée pd(k-1) et lui ajoute la vitesse du profil de trajectoire correspondant à l'instant présent vd(k) : pd(k)=pd(k-1)+vd(k). Ca peut paraitre bizarre d'additionner une position et une vitesse mais comme la vitesse est en COUNT/SAMPLE (COUNT = impulsion de roue codeuse comptée par le LM ; SAMPLE = période de la boucle d'asservissement) et que l'on multiplie implicitement la vitesse par 1 SAMPLE le tout est homogène.
- Ensuite, il soustrait la position réelle pr(k) à la position désirée pd(k) pour obtenir l'erreur e(k)=pr(k)-pd(k).
- Finalement, on filtre cette erreur pour obtenir une consigne : u(k)=pid_filter(e) je passe la formule expliquée en long en large et en travers un peu partout.
- Les signaux PWM et SIGN découlent directement de cette consigne u.

Qu'est-ce qui change quand on l'utilise en mode vitesse ?
On lui fournit, une vitesse de consigne et une accélération/déccélération utilisée quand il doit changer de vitesse. Dans ce cas, la génération de profil de vitesse est très sommaire :
- si la nouvelle vitesse de consigne est la même que la précédente, y'a rien à faire
- si la nouvelle vitesse de consigne vc2 est différente de la précédente vc1, le profil se résume à un segment reliant vc1 à vc2 et ayant une pente de +/- l'accélération spécifiée. Là aussi on est près pour l'asservissement.
A chaque tour de boucle d'asservissement (2048/f_clock il me semble) :
- le LM prend l'ancienne position désirée pd(k-1) et lui ajoute la vitesse du profil de trajectoire correspondant à l'instant présent vd(k) : pd(k)=pd(k-1)+vd(k). Donc tant que la vitesse de consigne n'est pas atteinte, vd(k) vaut quelque-chose entre vc1 et vc2 et une fois quelle est atteinte vd(k)=vc2. Le LM fait augmenter la position désirée à la vitesse vc2 pour faire en sorte que la vitesse réelle suive et vale aussi vc2.
- et le reste c'est comme pour le mode position


La première chose qui me "choque" dans ce que tu proposes Julien, c'est que tu travailles en terme de distance. Au niveau des profils et de ce qui est désiré (et différent du réel), je te le déconseille fortement. Il vaut mieux travailler en terme de temps. pourquoi ?
- Quand tu travailles en raisonnant sur les temps tu peux savoir dès le début de la trajectoire quand est-ce que tu vas la finir (si tout se passe bien). Ca n'est pas forcément le cas si tu raisonnes en terme de distance.
- Si tu travailles en distance tu risques implicitement de faire une deuxième couche d'asservissement par dessus le PID. Et les asservissements imbriqués, c'est très périlleux en terme de stabilité et c'est très difficile à bien contrôler.


Il est également question d'oscillations du robot en fin de trajectoire si il y a un dépassement. Je confirme, les LM corrigent les dépassements en fin de trajectoires. En fait, ces oscillations dues à un dépassement se présentent en général dans les cas suivants (tous vérifiés en pratique) :
- on a spécifié une vitesse que le robot ne peut pas physiquement atteindre
- on a spécifié une accélération/déccélération que le robot ne peut pas physiquement atteindre
- le PID est trop mou
Je vous renvoie ici pour comprendre exactement ce qui se passe :
http://lm629.fr.st/
Rubrique : Le LM629
Page : Utilisation - Comportements limites - Fonctionnement Interne
§ Comportements limites

Maintenant, ces oscillations ne sont pas du tout souhaitables et trahissent un mauvais réglage du PID ou des consignes dépassant les capacités physiques du robot.


Il a été proposé d'envoyer les ordres en avance pour compenser les délais de réactions. Là encore ça me semble pas viable car c'est trop dépendant de la constante mécanique du système. En plus, si on est obligé d'avancer la consigne, c'est que le système n'arrive pas à faire ce qu'on lui a demandé dans le délai escompté, ce qui signifie que l'on a voulu dépasser le limites physiques du système.


Ton système doit absolument rester quelque-chose de prédictible comme le LM (même si c'est pas toujours évident à prévoir). Si tu commences à rentrer dans un système flou, ce sera très difficile de comprendre pourquoi ça marche pas.


Asservissement de vitesse ou asservissement de position ? Comme dit Gaël, tout dépend de ce qu'on veut faire avec. Ton système se destine clairement à la propulsion de robots à roues différentielles. Donc, il faut que ton système soit pratique pour CETTE application. Si je peux te donner un conseil n'essaie pas de transformer ton système en truc à tout faire, ça va devenir une usine à gaz inutilisable. A la limite, si tu veux que ça puisse servir pour autre chose, tu écris un code complètement distinct qui utilise éventuellement le même hard.
Pour revenir à nos moutons :
- l'asservissement de position est ce qui est le plus utile pour un système de déplacement standard. Le µC host se trouve déchargé d'un maximum d'opérations (génération de profil nottamment) qui sont effectuées par le périphérique d'asservissement. C'est bien, mais il faut pas trop vouloir sortir du cadre.
- l'asservissement de vitesse déporte un certain nolbre de tâche sur le µC host puisque les opérations réalisées par le périphérique d'asservissement sont minimales. Par contre, ça offre une plus grande souplesse pour faire des choses exotiques. Par exemple, quand nous avons implémenté notre système de trajectoires courbes nous avons dû utiliser les LM en mode vitesse et rafraichir la consigne toutes les ms.

Si tu veux faire quelque chose d'assez versatile tu peux faire comme le LM :
- toujours un asservissement de position
- deux modes : position/vitesse pour lesquels les différences se trouvent essentiellement au niveau du générateur de profils de vitesse.


En fait l'asservissement de vitesse "pur" est pas tellement conseillé. En effet, ici le retour se fait par un codeur incrémental qui délivre par nature des états discrets. La position ressemble donc à un signal en marche d'escaliers. Quand on dérive ce genre de choses pour obtenir une vitesse, ça génère du bruit sur le signal que l'on présente à l'entrée de l'asservissement.
- à faible vitesse
  • avec un asservissement à période constante, on asservit de manière très imprécise avec beaucoup de bruit de dérivation
  • avec un asservissement à incréments constants, on asservit précisément mais avec des temps de latence qui peuvent devenir trop importants

- à vitesse élevée :
  • avec un asservissement à période constante, on asservit de manière beaucoup top précise, on a même des impulsions à ne plus savoir qu'en faire
  • avec un asservissement à incréments constants, on asservit toujours avec la même précision mais pour le coup les temps de latence peuvent devenir si faibles que l'asservissement va plus suivre


Donc le fait de passer par un asservissement de position, même en mode vitesse, permet :
- de lisser par intégration le signal en entrée du PID
- d'asservir en vitesse de manière assez précise même à basse vitesse grâce à la possibilité de rentrer des vitesses non entières.


Même si je suis le premier à médire sur le LM, enfin surtout sur sa doc totalement insuffisante, quand on l'épluche de près que la manière dont c'est fait dedans n'est pas mal pensée.


La différentiation accélération/déccélération a un intérêt pratique très limité. Ca pourrait avoir un intérêt avec des robots ayant une répartition des masses favorisant largement l'une ou l'autre des célérations. Mais pour des robots de la coupe, il est souvent préférable d'avoir quelque chose de bien équilibré. Donc tu fais comme tu veux.
En fait, pour l'avoir faite, la génération de profil est pas si compliquée que ça. Et séparer accélération/déccélération n'augmente pas de façon phénoménale la complexité. Y'a essentiellement 2 cas à traiter :
- le cas où la distance que la roue doit parcourir est suffisante pour atteindre la vitesse max
- le cas où la distance que la roue doit parcourir est insuffisante pour atteindre la vitesse max


Tiens d'ailleurs voilà un bout de script Matlab permettant de générer un profil sur une ligne droite. C'était intégré dans quelque chose de plus général donc c'est pas forcément réutilisable tel quel mais ça donne déjà une idée.

Pour cette appli, les consignes pour l'asservissement se présentait sous forme d'un tableau avec 3 colonnes :
[durée, accélération roue gauche, accélération roue gauche]
Exemple :
[0.526, +1.1, -1.1]
[1.254, +1.1, 1.1]
Pendant 526 ms, il faut appliquer une accélération de 1.1 m/s² sur la roue gauche et de -1.1 m/s² sur la roue droite.
Ensuite pendant 1.254 secondes ....

Là, j'utilisais donc un profil d'accélération et non un profil de vitesse. Pour avoir un profil de vitesse faut que tu modifies un peu les formules.


Code:

% Distance entre le point de départ et le point d'arrivée
straight_dist = hypot(x_g1,y_g1,x_g2,y_g2);

% On teste si la vitesse à avoir au point d'arrivée est supérieure
% ou inférieure à la vitesse au point de départ
% Dans ton cas, tu doit avoir v_1=v_2=0
if( v_2 > v_1 ) % Accélération sur la ligne droite
  reached_v_2 = min(v_2, sqrt(v_1^2+2*A_MAX*straight_dist));
elseif( v_2 < v_1 ) % Déccélération sur la ligne droite
  if( v_1^2 > 2*A_MAX*straight_dist )
  reached_v_2 = max(v_2, sqrt(v_1^2-2*A_MAX*straight_dist));
  else
  reached_v_2 = max(v_2, 0);
  end;
else
  reached_v_2 = v_2;
end;


% On recalcule un coup le distance entre le point de départ et le point
% d'arrivée. je sais plus du tout pourquoi mais devais y avoir une raison
d = hypot(x_g1,y_g1,x_g2,y_g2);


% On calcule le temps qu'il faudrait pour faire la trajectoire si
% la vitesse n'était pas limitée
t_f = ( -(v_1+v_2) + sqrt(2*(2*A_MAX*d+v_1^2+v_2^2)) )/A_MAX;


% On calcule l'instant à partir duquel il faudrait déccélérer si il n'y avait pas de limitaion de vitesse
t_intersec = (A_MAX*t_f+v_2-v_1)/(2*A_MAX);

% On en déduit la vitesse à cette instant
v_intersec = (v_1+A_MAX*t_intersec);


% Si on peut atteindre la vitesse max :
if( v_intersec > V_MAX )
  % Accélération rectiligne
  cc_path(cc_path_index,:) = [(V_MAX-v_1)/A_MAX, A_MAX, A_MAX];
  cc_path_index = cc_path_index + 1;
  % Droite à vitesse constante
  cc_path(cc_path_index,:) = [(d-(V_MAX^2-(v_1^2+v_2^2)/2)/A_MAX)/V_MAX, 0, 0];
  cc_path_index = cc_path_index + 1;
  % Deccélération rectiligne
  cc_path(cc_path_index,:) = [(V_MAX-v_2)/A_MAX, -A_MAX, -A_MAX];
  cc_path_index = cc_path_index + 1;

% Sinon :
else
  % Accélération rectiligne
  cc_path(cc_path_index,:) = [(v_intersec-v_1)/A_MAX, A_MAX,A_MAX];
  cc_path_index = cc_path_index + 1;
  % Deccélération rectiligne
  cc_path(cc_path_index,:) = [(v_intersec-v_2)/A_MAX, -A_MAX, -A_MAX];
  cc_path_index = cc_path_index + 1;
end;





Citation:

Le pb c'est que comme l'asservissement se fait sur les 2 moteurs et qu'il vaut mieux que leurs vitesse soit bien egale pour aller droit (si on cherche a aller droit), il faut quand meme un asservissement de vitesse qui tienne la route.
Si a la fin du profil on est bien a la bonne position mais que le robot a fait des zigzags dans tous les sens pour y parvenir c'est pas top non plus



Quand on utilise des LM ou autres, on a en fait 2 asservissements indépendants. or, pour le déplacement des robots à roues différentielles, c'est pas tant la position de chaque roue qui nous intéresse que celle de la plateforme entière. Beuacoup on pu remarqué qu'une très faible erreur sur le positionnement angulaire se traduisait par une dérive importante de la position au bout de 2 m de trajet.

Donc avec 2 asservissements indépendants on donne la même consigne à chaque roue et on prie pour qu'elles fassent exactement ce qu'on leur a demandé. C'est là, que ça devient très intéressant d'avoir un PID très serré. Mais si y'a la roue gauche vient à être freinée (voire bloquée) par un obstacle, la roue droite continue comme si de rien n'était. Ce qui amène une erreur sur la position angulaire qui est très péjudiciable à la fin de la trajectoire.

Idéalement, il faudrait coupler les 2 roues de manière à ce que lorsqu'une roue est retardée l'autre l'attende pour toujours garder la bonne orientation. J'avais commencé à m'intéresser à la chose mais j'ai jamais eu le temps de le mettre en pratique. Si tu veux plus d'info là-dessus fait une recherche avec "cross coupling controller".


Citation:

Je penche plutot sur un systeme d'asservissement de vitesse pendant l'acceleration et la phase a vitesse max, et ensuite passer sur un asserv de position pour la deceleration...
Mais plus facile a dire qu'a faire c'est quand meme deux choses differentes.



Je vais pas répéter tout ce que j'ai déjà dis mais je te conseille pas de faire un double asservissement ou un changement d'asservissement en cours de route. T'obtiendras un truc "batard" dont le comportement est peu prévisible. l'un des problème se situera au niveau des transitions entre les 2 asservissements. C'est toujours problématique les transistions.

Citation:

Tu as tout à fait raison! On a fait des essais de linéarité de trajectoire avec non LM629 l'an dernier. On peut voir en y allant à la loupe que le robot fait un imperceptible zig-zag. Mais bon, il faut là être pragmatiques, ce qui compte c'est que x, Y et théta du robot soient les bons à la fin de chaque trajectoire.



Oui, mais pour que le x,y soit bon à la fin de la trajectoire, il faut que le theta colle le mieux possible à la consigne tout au long du trajet.

Pour donner un ordre d'idée sur la tête des positions/vitesses/accélérations, voici quelques liens vers des données que nous avons enregistrées en 2002 :
http://www.chez.com/cochelol/Robot/Divers/TestPosition.pdf
http://www.chez.com/cochelol/Robot/Divers/TestOrientation.pdf
http://www.chez.com/cochelol/Robot/Divers/TestErreurs.pdf
http://www.chez.com/cochelol/Robot/Divers/TestVitesse1.pdf
http://www.chez.com/cochelol/Robot/Divers/TestAcceleration.pdf

La plateforme était un robot à roues différentielles. Les roues codeuses étaient indépendantes des roues motrices. Les moteurs étaient des moteurs de modélisme pas top, type mabuchi 540. La transmission était pleine de jeu.
Malgré celà, une fois tout bien réglé, on pouvait se balader pendant 1 min 30 sur le terrain et avoir une erreur de position de l'ordre de 5/10 cm.


Voilà, ce que j'en pense. Julien, j'espère que ça t'aidera à faire avancer ton projet.
Désolé pour les longueurs mais c'est un sujet passionnant sur lequel y'aurait encore beaucoup à dire.



Coco








Julien a écrit:

Bon, je vois encore une petite question :
Quelle est la condition d'arret du LM629 ? quand est-ce qu'il considère que la commande en position est finie ?



Grande question que nous avons étudiée en son temps.

Le LM considère que la trajectoire est finie (lève le flag correspondant) quand la position désirée atteint la consigne de position donnée dans l'ordre de trajectoire. La position réelle peut être à des années lumières mais si tout se passe bien c'est normalement pas le cas.

En fait, ce qu'on avait typiquement quand le robot oscillait au point d'arrivée, c'est que le LM disait que la trajectoire était finie au gros dès qu'on passait le point d'arrivée mais après le PID continuait à "corriger" et à faire osciller le robot. Inutile de dire que dans ces conditions, si tu enchaines immédiatement dans la foulée une seconde trajectoire tu obtiens n'importe quoi.
M'enfin si tout est bien réglé, ça oscille pas et les choses restent acceptables.

Ca c'est pour le mode position en mode vitesse, je crois qu'il fait comme si la position était jamais atteinte : il lève pas du tout de flag.

C'est comme ça dans le LM. Ca vaut ce que ça vaut, c'est pas parfait mais c'est pas évident de définir une condition d'arrêt qui tienne vraiment la route.

Citation:

Je suppose que c'est quand on a : Et la distance atteinte (erreur a 0) et aussi la vitesse lue sur le moteur moteur qui est nulle. Une seule de ces deux conditions realisee ne me semble pas suffisant.


C'est pas plus stupide qu'autre chose comme solution. Tant qu'on y ait on peut aussi rajouter que tous les dérivées de la vitesse jusqu'à n=20 doivent être nulles. Mais c'est p'têt poussé un peu loin.

En fait, j'ai un peu peur que ce soit trop restrictif ton critère. Pour que l'erreur et la vitesse soient simultanéemment pile-poil nulles sur les 2 roues, ça risque de demander beaucoup de temps : le temps que le robot s'immobilise parfaitement. Résultat, tu risques d'être obligé d'attendre plusieurs secondes avant de commencer la trajectoire suivante alors que tu aurais très bien pu repartir avant.

On peut aussi mettre des seuils pour que ce soit plus souple mais ça fait encore 2 degrés de liberté à régler.


Comme ce qui nous intéresse réellement, c'est la position (x,y,theta) du robot, il serait p'têt aussi judicieux de juger de la fin d'une trajectoire sur ces critères à un niveau plus élevé. Par exemple en définissant un rayon d'erreur pour (x,y) et une tolérance pour theta.
Je pourrais pas le garantir, mais c'est p'têt bien ce qu'on avait fait au final sur le robot.





Julien
Bon ben je vais faire la meme chose que le LM, tout en continuant l'asservissement de position ensuite.

Le temps que le donneur d'ordre reagisse, il y a des chances que la position reelle se soit stabilise

Faire que la position desire = la consigne c'est quand meme se simplifier pas mal la vie. Meme pas besoin d'attendre que la position reelle ait atteint la bonne position (ce qui peut ne jamais arriver cela dit en passant, suivant les coefs du PID).

C'est pas bete en tout cas, on est sur de le finir ... dans le temps imparti

Sinon je vois une difference importante entre l'asservissement de vitesse et celui de position (en mode vitesse).

Normalement en asservissement de vitesse la vitesse reste toujours a peu pres egale a la vitesse demandee, aux erreurs et oscillations du PID pres. Sauf si bien sur la roue est bloquee d'une facon ou d'une autre, et/ou que le moteur peut pas aller assez vite.

En asservissement de position en mode vitesse, la vitesse va etre bien egale a la vitesse demandee si tout se passe bien. C'est meme plus precis en terme de deplacement du robot parce que toute erreur a un instant t sur la position en fonction du temps et contrebalance le coup d'apres (ca apparait dans l'erreur du t+1)
Par contre si a un moment donne la roue se bloque, et bien ensuite l'asservissement va faire en sorte de ratraper son retard ... ce qui veut dire qu'il va aller achement plus vite que ce qui est demande dans le vmax
Ce qui explique aussi les problemes si moteur n'arrive pas a attendre une vitesse donnee.

Enfin bon fo le savoir quoi !




Coco

Julien a écrit:

Par contre si a un moment donne la roue se bloque, et bien ensuite l'asservissement va faire en sorte de ratraper son retard ... ce qui veut dire qu'il va aller achement plus vite que ce qui est demande dans le vmax

Oui tout à fait, et le corollaire de ça c'est que la vitesse max que l'on donne dans les consignes doit toujours être inférieure à la vitesse max que le robot peut atteindre.

Si ton robot est physiquement limité à une vitesse de 1 m/s et que dans tes ordres de déplacement tu spécifies 1 m/s pour la vitesse max, ça va mal marcher. En effet, si une roue se trouve retardée, le PID va essayer de corriger mais il va rien pouvoir corriger car avec cette consigne il était déjà pied au plancher.

Pour que le PID puisse corriger quelque chose, il faut se garder un peu de réserve au niveau vitesse et accélération. Je dirais qu'il faudrait pas dépasser 80 % de ce que le robot peut physiquement réaliser.

Bien sûr, l'inconvénient c'est qu'en moyenne on sous-exploite la puissance disponible. Mais on peut pas avoir le beurre et l'argent du beurre.



retour à LaFaq


Page non modifiable

Retour à LaFaq WikiListe des pages

Chercher