[RESOLU]Comment avoir deux moteurs ayant exactement la même vitesse avec le PID?

Bonjour tout le monde,

J’ai deux moteurs encodeurs strictement identiques.

J’ai reglé les mêmes Setpoint avec les mêmes Kp , Ki et Kd mais ils ne tournent pas parfaitement à la même vitesse ce qui est tout à fait normal quand on regarde les 2 val-outpout qui sont très différent.

Mais dans le même temps, la vitesse détectée pour chaque moteur est la même, alors l’algorithme "pense "qu’il fait bien son boulot.

Ce qui est étrange, c’est que mes deux moteurs encodeurs sont strictement identiques. Ils ont chacun deux capteurs disposés en quadraures de phase.

Alors, quel pourrait être le problème?

Je pense que le problème est dans le programme mais où?

latestDurationCounta26.00
Setpointa25.00
val_outputa65.40
--------------------------latestDurationCount25.00
---------------------------Setpoint25.00
---------------------------val_output93.20
latestDurationCounta24.00
Setpointa25.00
val_outputa66.65
--------------------------latestDurationCount25.00
---------------------------Setpoint25.00
---------------------------val_output93.20
latestDurationCounta25.00
Setpointa25.00
val_outputa66.05
--------------------------latestDurationCount25.00
---------------------------Setpoint25.00
---------------------------val_output93.20
latestDurationCounta25.00
Setpointa25.00
val_outputa66.05
--------------------------latestDurationCount25.00
---------------------------Setpoint25.00
---------------------------val_output93.20

PREMIERDEUX.ino (8.41 KB)

bvking: Mais dans le même temps, la vitesse détectée pour chaque moteur est la même, alors l'algorithme "pense "qu'il fait bien son boulot.

De deux choses l'une: - soit les moteurs tournent bien à la même vitesse et ton appréciation de la vitesse est faussée - soit les moteurs ne tournent pas à la même vitesse et alors c'est ton procédé de captation de vitesse qui est défaillant.

fdufnews:

  • soit les moteurs ne tournent pas à la même vitesse et alors c’est ton procédé de captation de vitesse qui est défaillant.

Je pense aussi cela, j’ai inversé dans le void loop la captation et le controle PID des moteurs, mais j’ai toujours le meme problème, val_output est supérieur à val_outputa.

Il ya deux manière de capter la vitesse d’un moteur

A l’origine dans le programme j’avais

abs_duration=abs(duration);

puis on m’a conseillé çà, alors j’ai mis ça dans le programme

noInterrupts();
latestDurationCount = duration;
interrupts();
abs_duration = abs(latestDurationCount);

et j’ai un sous programme qui calcule la vitesse comme ceci:

void wheelSpeed()
{
 int Lstate = digitalRead(encoder0pinA);
 if((encoder0PinALast == LOW) && Lstate==HIGH)
 {
   int val = digitalRead(encoder0pinB);
   if(val == LOW && Direction)
   {
     Direction = false; //Reverse
   }
   else if(val == HIGH && !Direction)
   {
     Direction = true;  //Forward
   }
 }
 encoder0PinALast = Lstate;

 if(!Direction)  duration++;
 else  duration--;

}

Alors peut être dans void loop, je devrais changer

duration++ et duration–

par

LatestDurationCount++ et LatestDurationCount–

Merci Fdufnews

PREMIERDEUXclean.ino (6.31 KB)

fdufnews:

  • soit les moteurs ne tournent pas à la même vitesse et alors c’est ton procédé de captation de vitesse qui est défaillant.

Je pensais que mes deux moteurs n’ont pas exactement les capteurs en quadrature à la même place alors il se pouvaient qu’ils n’encodent pas la même vitesse.

Je mets mes résultats où je fais apparaître 3 fois la vitesse (duration) et la dernière vitesse perçue (Latestduration) qu’un programmeur m’a conseillé.

On voit pour les données pour les vitesses 60 et 120 pour chaque moteur

MOTORC
Setpoint60.00
latestDurationCount60.00--Duration: 87.00, 91.00, 95.00--val_output65.20
MOTORD
Setpointa60.00
latestDurationCounta59.00--Durationa: 89.00, 93.00, 97.00--val_outputa75.55

MOTORC
Setpoint120.00
latestDurationCount121.00--Duration: 174.00, 182.00, 190.00--val_output133.40
MOTORD
Setpointa120.00
latestDurationCounta120.00--Durationa: 178.00, 186.00, 194.00--val_outputa137.00

En observant les résultats, on voit bien les 3 durations superieurs pour le moteur D.
Donc latestduration n’est pas une bonne mesure et il y a un problème avec duration.

Je mets le programme au cas où…

PETITPETITUnobizarre.ino (6.54 KB)

        Setpoint= 120;// 20 --> val=53// 15--> val= 50;//Set =35--> val= 55 //Setpoint=  25--> val= 55 // Setpoint = 55--> val-output 68
        // Setpoint=45-->val=61.5
        advance();
        
      result=myPID.Compute();//PID conversion is complete and returns 1

Tel que c'est codé ici, tu pilotes ton moteur avec les infos qui ont été calculée au tour précédent. Ce qui introduit un retard de phase entre le calcul de la consigne et son application. Ne serait-il pas plus logique de faire

        Setpoint= 120;// 20 --> val=53// 15--> val= 50;//Set =35--> val= 55 //Setpoint=  25--> val= 55 // Setpoint = 55--> val-output 68
        // Setpoint=45-->val=61.5

        result=myPID.Compute();//PID conversion is complete and returns 1
        advance();

et ainsi commander le moteur avec une consigne "fraiche".

Autre chose, Serial utilise les interruptions. Pour ne pas perturber ton programme, la logique voudrait que tu limites au maximum les sorties par Serial. Il serait bon de réduire la quantité d'informations transmises en limitant la partie constante des impressions. Par exemple remplacer:

Serial.print("latestDurationCount");

par: Serial.print("lD");Voir juste séparer les valeurs avec des virgules en plaçant une lettre en tête pour savoir à quel moteur les valeur sont associées.

Cette ligne est inutile puisque tu recalcules la valeur 4 lignes plus loin (pareil pour l'autre moteur)

    // Moteur C (droit assigné enablePinC)
   //
     abs_duration=abs(duration);

Dans les routines d'interruptions ou veut aller vite

  int Lstate = digitalRead(encoder0pinA);
  if((encoder0PinALast == LOW) && Lstate==HIGH)
  {
    int val = digitalRead(encoder0pinB);

Lstate et val pourrait être définis comme des unsigned char ou des byte

Ne pas perdre de vue non plus que loop() s'exécute assez rapidement et que donc les interruptions sont désactivées assez souvent ce qui peut entrainer des erreurs de mesure.

Autre chose, tu sembles ne faire tourner tes moteurs que dans un sens et tu perds du temps à calculer une valeur absolue de vitesse.

Merci fdufnews. Ca fonctionne les deux moteurs sont bien à la même vitesse.

[/quote]

fdufnews:
Autre chose, tu sembles ne faire tourner tes moteurs que dans un sens et tu perds du temps à calculer une valeur absolue de vitesse.

J’ai besoin de la valeur absolue car quand je force le moteur à aller dans l’autre sens, je veux que le programme le fasse changer de sens.

Je suis super content d’avoir atteint cette étape.

Aussi, je me demande si il est possible de faire en sorte que si je bloque le moteur un certain temps celui - ci en plus de revenir à sa vitesse initiale rentre en phase (à la même position) que le premier.
Est ce faisable avec un programme ou faudrait t’il deux capteurs supplémentaires pour savoir la position de chaque moteur?

Tes capteurs fournissent une information relative de position. Ils ne sont pas adaptés pour le pilotage de la phase des moteurs il faudrait soit:

  • remplacer tes capteurs actuels par des capteurs qui retournent la valeur absolu de la position.
  • ajouter à tes capteurs actuels un index qui permette de fixer un zéro à partir duquel la position absolue serait calculée en additionnant/soustrayant la valeur retournée par les codeur incrémentaux.
  • ajouter à tes capteurs actuels un index qui permette de fixer un zéro à partir duquel la position absolue serait calculée en additionnant/soustrayant la valeur retournée par les codeur incrémentaux.

un capteur optique du style opto end stop, avec une roue avec des trous, fixé sur l'axe du moteur pourrait faire l'affaire?

Oui une fourche optique ou un capteur par réflexion. Par contre il faut un seul repère (trou ou masque) sur la roue pour coder une position unique de référence sur le tour.