Aller au contenu


Photo
- - - - -

UGV à base d'éléments de trottinette ou d'hoverboard


411 réponses à ce sujet

#321 Sandro

Sandro

    Membre chevronné

  • Modérateur
  • PipPipPipPip
  • 1 321 messages
  • Gender:Male

Posté 11 avril 2023 - 10:32

Sur le robot du lien, vu qu'à chaque pas de temps tu multiplie i par Ki=0.001, en gros i est toujours quasi à 0. Donc pas "grave", sauf que tu avais en gros un controleur PD


Aidez-nous à vous aider : partagez toutes les informations pertinentes : description précise du problème, contexte, schéma de câblage, liens vers la documentation des composants, votre code (ou encore mieux un code minimal reproduisant le bug), ...

Vous recevrez ainsi plus de réponses, et elles seront plus pertinentes.


#322 Oracid

Oracid

    Pilier du forum

  • Modérateur
  • PipPipPipPipPip
  • 7 030 messages
  • Gender:Male

Posté 11 avril 2023 - 10:55

Sur le robot du lien, vu qu'à chaque pas de temps tu multiplie i par Ki=0.001, en gros i est toujours quasi à 0. Donc pas "grave", sauf que tu avais en gros un controleur PD

Je ne comprends pas.

La ligne entière des paramètres, c'est  : float Kp = 0.5625, Ki = 0.001, Kd = 0.055;  



#323 Oracid

Oracid

    Pilier du forum

  • Modérateur
  • PipPipPipPipPip
  • 7 030 messages
  • Gender:Male

Posté 11 avril 2023 - 11:01

Grace à ma fonction Trace(), j'ai récupéré les valeurs de Throttle (pwm) et de HallSpeed (Hz) avec une version précédente de mon programme où on a :

    Throttle = map(analogRead(POT_PIN_IN),0,1023,0,255);

 

J'ai fait un tableau Excel, dans lequel, on peut voir que la roue commence à tourner à partir d'un PWM égal à environ 100 pour une fréquence d'environ 7,5Hz, et s'arrête de tourner pour un PWM égal à environ 150, et une fréquence d'environ 190Hz.

 

Je pense donc déterminer la vitesse de référence, variable Speed_Target, en la mappant ainsi :  Speed_Target = map( Throttle, 0, 150, 0, 190)

 

Mais si on considère que ce moteur est différent de ceux montés sur le robot, on pourrait considérer qu'une bonne approximation serait l'égalité entre le PWM et la vitesse de référence.  Avec, Speed_Target = Throttle  

 

J'hésite.

 

 

Graphique.png

Fichier joint  Vitesse-data.txt   70,33 Ko   62 téléchargement(s)



#324 Sandro

Sandro

    Membre chevronné

  • Modérateur
  • PipPipPipPip
  • 1 321 messages
  • Gender:Male

Posté 11 avril 2023 - 11:05

la formule que tu utilises pour i est : i = Ki* (i+err)

 

Donc :

à t=0 : i=0

à t=1, i=0.001 * err(t=1)
à t=2, i=0.001 * (i + err(t=2)) = 0.001 * (0.001 * err(t=1) + err(t=2)) = 10^-6 * err(t=1) + 10^-3*err(t=2)

à t=3, i=...=10^-9 * err(t=1) + 10^-6*err(t=2) + 10^-3*err(t=3)

...

à t=n, i=somme(10^(-3*k) * err(t=k), pour k de 1 à n).

 

Autrement dit, le plus gros terme, c'est celui de t=n, qui a un coefficient 10^-3 (qui est déjà négligeable devant Kp=0.5625), et les autres sont tellement négligeables que je ne suis même pas sûr qu'ils ne soient pas supprimés par l'arrondi.

 

Donc en gros, c'est presque comme si Ki valait 0 (dans un vrai PID), donc il ne reste que le P et le D qui ont une influance non négligeable


Aidez-nous à vous aider : partagez toutes les informations pertinentes : description précise du problème, contexte, schéma de câblage, liens vers la documentation des composants, votre code (ou encore mieux un code minimal reproduisant le bug), ...

Vous recevrez ainsi plus de réponses, et elles seront plus pertinentes.


#325 Oracid

Oracid

    Pilier du forum

  • Modérateur
  • PipPipPipPipPip
  • 7 030 messages
  • Gender:Male

Posté 11 avril 2023 - 11:16

donc il ne reste que le P et le D qui ont une influance non négligeable

Ah, ok, j'ai compris.



#326 Sandro

Sandro

    Membre chevronné

  • Modérateur
  • PipPipPipPip
  • 1 321 messages
  • Gender:Male

Posté 11 avril 2023 - 12:44

Pour ton avant dernier message Oracid, l'avantage avec le PID, c'est que tu n'as pas besoin de connaitre de manière précise la relation entre PWM et vitesse. Tu choisis ta vitesse cible, et le PID s'occupe, comme par magie, d'adapter le PWM pour que tu obtienne la vitesse souhaitée.

 

Pour le réglage du PID, c'est "simplement" dire de quelle manière tu veux tenter de corriger la vitesse :

- P : si je suis trop lent, j'appuis sur l'accélérateur, si je suis trop rapide, j'appuie sur le frein (nb : si tu es pile à la bonne vitesse, tu laches l'accélérateur : tu vas donc naturellement ralentir). Un controleur avec que du P aura tendence à être toujours un peu trop lent (ou alors à osciller si Kp est trop grand et que ton robot a trop d'inertie)

- I : si ça fait un bout de temps que je suis en dessous de ma vitesse cible, j'accélère un peu (en voiture : sur du plat, tu garde ton accélérateur dans une position constante (=V_target). Quant tu arrives à une montée, cette position de l'accélérateur te donne une vitesse (<V_target) plus faible que souhaité. Après quelques secondes, tu te rends compte que tu vas pas assez vite, donc tu appuie un peu plus sur l'accélérateur)

- D : si ta vitesse est en train de monter vite, alors tu réduis les gaz (en voiture : tu sors de ville, et tu accélères pied au plancher pour atteindre les 80km. Si tu gardes le pied au plancher à 79.9 km/h, tu vas surement faire un excès de vitesse. Donc quand tu vois que ta vitesse augmente rapidement, tu appuie un peu moins fort sur l'accélérateur


Aidez-nous à vous aider : partagez toutes les informations pertinentes : description précise du problème, contexte, schéma de câblage, liens vers la documentation des composants, votre code (ou encore mieux un code minimal reproduisant le bug), ...

Vous recevrez ainsi plus de réponses, et elles seront plus pertinentes.


#327 Oracid

Oracid

    Pilier du forum

  • Modérateur
  • PipPipPipPipPip
  • 7 030 messages
  • Gender:Male

Posté 11 avril 2023 - 06:23

Ce n'est pas la première fois que je lis une analogie du PID avec l'accélérateur d'une voiture, mais c'est c'est la première que cette analogie est poussée jusqu'au détail de chaque paramètre.

Sandro, tu devrais écrire un livre sur le PID. Un livre du style, "Le PID pour les Nuls". Tu aurais un grand succès !

Merci Sandro

 

"l'avantage avec le PID, c'est que tu n'as pas besoin de connaitre de manière précise la relation entre PWM et vitesse. Tu choisis ta vitesse cible, et le PID s'occupe, comme par magie, d'adapter le PWM pour que tu obtienne la vitesse souhaitée."

 

Là, par contre, je suis largué ! 

 

J'ai extrapolé la droite du tableau Excel. Pour un PWM de Throttle=255, je trouve un Target_Speed, d'environ 350Hz.

 

Donc, dans le loop(), je peux faire :

      Throttle = map( analogRead(POT_PIN_IN), 0, 1023, 0, 255);

      Target_Speed = map( Throttle, 0, 255, 0, 350 );

puis, dans la fonction P_I_D() :

      pid_Speed = map( (unsigned int) pid_Speed, 0, 350, 0, 255 );

puis dans le loop():

      analogWrite(PWM_PIN_OUT, pid_Speed);

 

Peut-être, ne suis-je pas très clair.

Je teste cela demain et je publie la nouvelle version du programme en entier, ce sera peut-être plus clair.

 



#328 pat92fr

pat92fr

    Membre passionné

  • Membres
  • PipPipPip
  • 796 messages
  • Gender:Male

Posté 12 avril 2023 - 07:05

Grace à ma fonction Trace(), j'ai récupéré les valeurs de Throttle (pwm) et de HallSpeed (Hz) avec une version précédente de mon programme où on a :

    Throttle = map(analogRead(POT_PIN_IN),0,1023,0,255);

 

J'ai fait un tableau Excel, dans lequel, on peut voir que la roue commence à tourner à partir d'un PWM égal à environ 100 pour une fréquence d'environ 7,5Hz, et s'arrête de tourner pour un PWM égal à environ 150, et une fréquence d'environ 190Hz.

 

Je pense donc déterminer la vitesse de référence, variable Speed_Target, en la mappant ainsi :  Speed_Target = map( Throttle, 0, 150, 0, 190)

 

Mais si on considère que ce moteur est différent de ceux montés sur le robot, on pourrait considérer qu'une bonne approximation serait l'égalité entre le PWM et la vitesse de référence.  Avec, Speed_Target = Throttle  

 

J'hésite.

 

 

attachicon.gifGraphique.png

attachicon.gifVitesse-data.txt

 

Bonjour,

 

L'approximation "Vitesse donne PWM", même si elle est faite à vide au début (à refaire sur sa terrasse avec son robot, plus tard), peut être utilisée en complément de l'asservissement à base de PID.

PWM = PID(erreur_vitesse) + Kff * consigne_vitesse

avec Kff : le coefficient qui te permet d'approcher la valeur de PWM en fonction de la vitesse de consigne.

 

Note : FF pour Feed-Forward.

 

Evidemment, le terme ff ne marche pas à très basse vitesse. Mais ca permet d'approcher la vitesse d'évolution en condition "normale".

 

Avec la carte hoverboard, je constate aussi que le 'trou' dans la plage [0,50]. Le PID bien réglé va en grande partie compenser ce problème.

 

En général, je règle dans l'ordre :

1) Kff,

2) Kp,

3) Kd

4) optionnel Ki.

 

Avec ces moteurs et les contrôleurs BLDC pour EPDM, qui ont un PID intégré avec une faible bande passante, je me suis retrouvé à régler dans l'ordre :

1) Kff

2) Ki,

3) optionnel : Kp et Kd.

 

Les deux derniers ont conservé des valeurs faibles. Car ils apportent plus de problèmes que de véritables gains/performances.

 

Je suis preneur de votre retour d'expérience au niveau des réglages (et de vos valeurs, même si ca dépend de beaucoup de paramètres dont la cadence du PID et les unités de mesure/consigne employées).

 

Bon courage.

Patrick.



#329 Oracid

Oracid

    Pilier du forum

  • Modérateur
  • PipPipPipPipPip
  • 7 030 messages
  • Gender:Male

Posté 12 avril 2023 - 08:39

Merci Patrick pour toutes ces précisions.

Actuellement, je travaille à vide sur mon banc de test, mais effectivement, j'ai bien conscience que lorsque le robot sera posé au sol, il faudra revoir les paramètres du PID.

Intéressant, le paramètre Kff. Je mets ça dans un coin de ma tête.

L'ordre de réglage des paramètres, oui, ça fait parti de la prise de tête.

Pour aujourd'hui, je vais continuer à mapper les PWM en Hz.

 

Dans cette page, conseillée par Mike, https://www.pm-robot...robot-autonome/ , il y a déjà quelques temps, on peut voir une fonction PID avec un calcul de i très classique.

Je n'arrive pas à faire l'équivalence entre ce que j'utilise dans mon programme, méthode conseillée par toi Sandro, et le calcul de ce programme.

Sandro :           i = i+(Ki*err);   

pm-robotix :      errSum += error;   i = errSum * ki;

 

Voici ce programme :

 

//Nos trois coefficients
static int kP=100;
static int kI=10;
static int kD=50;
int ComputePID(int error)
{
 
    static int lastError=0;
    static int errSum=0;
 
    int P,I,D;
 
    errSum += error;                 //Somme les erreurs depuis le début 
 
    errDif = error - lastError;      //Calcule la variation de l'erreur
    lastError = error;
 
    P = error * kP;                  //Proportionnelle
    I = errSum * kI;                 //Intégrale
    D = errDif * kD;                 //Dérivée
 
    return P + I + D;                //Le résultat est la somme des trois
                                     //composantes calculées précédemment
}

 



#330 Oracid

Oracid

    Pilier du forum

  • Modérateur
  • PipPipPipPipPip
  • 7 030 messages
  • Gender:Male

Posté 12 avril 2023 - 11:09

Voici la dernière version de mon programme (V3).

Spoiler

 

Et voici la trace :

Spoiler

 

Dans le programme, notez que Kp = 1.02,  Ki = 0.000,  Kd = 0.00

Dans cette trace, on peut voir que les valeurs des variables Throttle et TargetSpeed sont respectivement très proches des valeurs des variables pidSpeed et pid. J'ai bloqué le potentiomètre pour Throttle=110 pwm.

Avec ma main gantée, j'ai freiné la roue. On s'en aperçoit grâce à la valeur de la variable  HallSpeed qui vaut environ 33Hz et qui passe à 25Hz.

Mais les valeurs de pidSpeed et pid ne sont pas modifiées.

 

C'est trop beau que ce soit bon du premier coup, et en paramétrant seulement Kp=1.02

Il y a surement un loup. Pourquoi les valeurs de pidSpeed et pid ne varient pas ?



#331 pat92fr

pat92fr

    Membre passionné

  • Membres
  • PipPipPip
  • 796 messages
  • Gender:Male

Posté 12 avril 2023 - 05:40

Si la vitesse réelle est différente de la vitesse consigne, et que la valeur de PWM donnée par la sortie PID ne varie pas de telle sorte à réduire l'erreur de vitesse .... c'est que ca ne marche pas du tout ! :-)

 

Pour tester ton PID, tu peux afficher :

1) consigne de vitesse

2) vitesse réelle

3) valeur PWM (=sortie PID).



#332 pat92fr

pat92fr

    Membre passionné

  • Membres
  • PipPipPip
  • 796 messages
  • Gender:Male

Posté 12 avril 2023 - 05:57

Tu peux supprimer un paquet de conversions de plages de valeurs, remonter PID() avant analogwrite() et limiter la plage de valeur en sortie du PID.

Pour mieux contrôler la vitesse (voir mon test en pente), tu peux exploiter le signe de la sortie du PID pour freiner la roue. Attention, au sens de rotation (inverser 0 et 1 si besoin).

void loop() {
  if (! digitalRead(pb)) { Serial.print("\n\t Operator Interrupt !!!"); delay(400); analogWrite(PWM_PIN_OUT,0); resetFunc(); }
 
  Throttle = analogRead(POT_PIN_IN);                // the Throttle [0..1023]
  Target_Speed = map(Throttle,0,1023,0,max_Hz);                        // convert the Throttle into speed (Hz)

  if ( new_tick == prev_tick) { Period = 0; HallSpeed = 0; }          // stop the wheel if no order

  P_I_D(); // convert speed error into signed WM [-255,+255]

  analogWrite(PWM_PIN_OUT, abs(pid_Speed));                                // the PWM is determined by the | P_I_D() |
if(pid_Speed >=0 )                                                    // the DIRECTION is determined by the sign of P_I_D()
  digitalWrite(DIR_PIN_OUT, 0);                 
else
  digitalWrite(DIR_PIN_OUT, 1);                 

  Trace();
}
 
void P_I_D(){  
  err = Target_Speed - HallSpeed;                                                         // getting err
  p = Kp*err;  
  i = i+(Ki*err);  // note : limiter la valeur de i, par exemple : i = constrain(i+Ki*err,-255,255);
  d = Kd*(err-lastErr);  
  lastErr = err;  
  pid = p+i+d;       // calculation of the PID
  pid_Speed = constrain(pid ,-255,255);                                      // clamp [0..255[
}


#333 Oracid

Oracid

    Pilier du forum

  • Modérateur
  • PipPipPipPipPip
  • 7 030 messages
  • Gender:Male

Posté 12 avril 2023 - 06:32

Merci Patrick. Je vais revoir tes propositions dès demain matin.

 

Pour ce soir, j'ai fait une nouvelle version, car effectivement cela ne fonctionne pas du tout.

Le gros problème, c'est que la première instruction de la fonction P_I_D(),   err = Target_Speed - HallSpeed;   ne fonctionne absolument pas.

j'ai tracé la variable err , c'est comme si la variable HallSpeed était toujours égale à 0.

 

Spoiler

 

Voici la trace:

Spoiler


#334 Oracid

Oracid

    Pilier du forum

  • Modérateur
  • PipPipPipPipPip
  • 7 030 messages
  • Gender:Male

Posté 13 avril 2023 - 07:36

Pour mieux contrôler la vitesse (voir mon test en pente), tu peux exploiter le signe de la sortie du PID pour freiner la roue. 

J'ai fait une nouvelle version où j'ai bien pris en compte tes modifications, mais par contre, je ne comprends pas cette dernière remarque.

Pour l'instant, je ne vais pas m'occuper du changement de sens de rotation, pour faire au plus simple.

 

Néanmoins, cela ne fonctionne toujours pas. L'instruction, err = Target_Speed - HallSpeed;  dans la fonction P_I_D() ne fonctionne pas.

La variable err est toujours égale à Target_Speed.

 

La nouvelle version :

Spoiler
 
La trace:
Spoiler


#335 pat92fr

pat92fr

    Membre passionné

  • Membres
  • PipPipPip
  • 796 messages
  • Gender:Male

Posté 13 avril 2023 - 09:05

Dans ta fonction de calcul du PID, tu écris : 

err = Target_Speed - HallSpeed; 

Juste avant l'appel PID(), tu écris :

if ( new_tick == prev_tick) { Period = 0; HallSpeed = 0; } 

Et dans ta routine d'IT qui estime la vitesse courante, tu as :

prev_tick = new_tick ;     

Effectivement, le calcul de l'erreur ne se passe pas comme prévu ! 

 

Patrick.

 



#336 Oracid

Oracid

    Pilier du forum

  • Modérateur
  • PipPipPipPipPip
  • 7 030 messages
  • Gender:Male

Posté 13 avril 2023 - 10:49

Merci Patrick.

 

J'ai mis la ligne du if en commentaire, mais je pense qu'il va falloir la supprimer.

Dans la fonction P_I_D(), j'ai modifié cette ligne en   pid_Speed = constrain(pid ,0,255);   pour n'avoir que des valeurs positives. On verra plus tard pour le changement de direction.

 

Le résultat est plutôt encourageant. En basse vitesse, les variations de vitesses sont très importantes, mais à plus haute vitesse, il y a une certaine stabilisation. Je mets les 2 traces correspondantes.

Je suppose qu'il va falloir que je trouve les bonnes valeurs du PID pour éviter ces à-coups.

 

Avec : Kp = 2.1,  Ki = 0.0,  Kd = 0.0

Basse vitesse : 

Spoiler

 

Haute vitesse :

Spoiler


#337 pat92fr

pat92fr

    Membre passionné

  • Membres
  • PipPipPip
  • 796 messages
  • Gender:Male

Posté 13 avril 2023 - 11:20

Ok.

 

Pour tester ton PID, tu peux afficher :

1) consigne de vitesse (Hz)

2) vitesse réelle (Hz)

3) valeur PWM (=sortie PID) [-255..255]

 
Ce sera plus simple à lire pour nous pauvres lecteurs ! :-)


#338 pat92fr

pat92fr

    Membre passionné

  • Membres
  • PipPipPip
  • 796 messages
  • Gender:Male

Posté 13 avril 2023 - 11:23

Un bon test de PID est de faire une 'marche' de vitesse :

 

Test #1 : vitesse 0 => 100Hz. 

Test #2 : vitesse 100=> 200Hz

 

Si tu traces la courbe vitesse réelle vs vitesse consigne, ca donnera des indications pour le réglage des Kx.



#339 Oracid

Oracid

    Pilier du forum

  • Modérateur
  • PipPipPipPipPip
  • 7 030 messages
  • Gender:Male

Posté 13 avril 2023 - 01:26

Avec Kp = 1.0, Ki = 0.0, Kd = 0.0 

 

Trace de 0Hz à 100Hz. Le moteur ne tourne pas.

Spoiler

 

Trace de 100Hz à 200Hz

Spoiler


#340 pat92fr

pat92fr

    Membre passionné

  • Membres
  • PipPipPip
  • 796 messages
  • Gender:Male

Posté 13 avril 2023 - 01:48

Et maintenant, il fait régler le PID ! Tu peux commencer par le kp.



Répondre à ce sujet



  


2 utilisateur(s) li(sen)t ce sujet

0 members, 2 guests, 0 anonymous users