Moteur avec encodeur – asservissement

On a vu que les programmes précédents ne permettaient pas une super exactitude de positionnement car, bien que le positionnement soit suivi avec précision grâce aux encodeurs, le moteur continue de tourner une fois la position atteinte et l’alimentation coupée.

Première façon assez « bourrine » mais efficace, si on a besoin de 720 pas de rotation, par exemple, retirer dans le programme une centaine de pas qui seront faits moteur coupé. Cette correction est constante pour une valeur pwm donnée et une tension donnée à condition de ne pas s’occuper de rotations de moins d’un tour.

Deuxième façon, recourir à une fonction d’asservissement. Je me suis inspiré de cet article qui m’a bien aidé car je ne connaissais rien de ce domaine.

On utilise un timer pour lancer une action d’échantillonnage à intervalles réguliers et suivant l’écart entre la position actuelle et la cible, on ajuste la vitesse du moteur et, éventuellement, on fait marche arrière si on a été trop loin.

Les paramètres ont été trouvés par ajustements successifs, si vous avez du matériel différent il faudra sans doute les modifier. La précision obtenue est satisfaisante avec des erreurs maxi autour de 3%. Les déplacements inférieurs à un tour sont à éviter.


/*
   Moteur encodeur V6

avec asservissement de type P  
 

*/
 
 #include <Encoder.h>
 
 // le moteur a deux encodeurs
 // en quadrature et
 // chaque pin est controlee
 // par interruption
 
 int A = 2; // pin encodeur A
 int B = 3; // pin encodeur B
 
Encoder position_moteur1(A,B);

// position cible exprimée en 
// nb de ticks
// 1 tour arbre moteur = 360 ticks

long position_cible_M1=0;

// un utilise une librairie
// pour commander l'echantillonage

#include <SimpleTimer.h>

SimpleTimer timer;

// Intervalle de temps entre deux mesures
// ici 80 ms

int intervalle_echantillonage=80;

// constante de correction
// coeff proportionnel
// asservissement de type P

float kp=0.95; 
 
int E1 = 5; //M1 Controle de vitesse PWM
 
int M1 = 4; //M1 Controle du sens de rotation

// valeur mini et maxi pwm
// si trop bas degradation des balais
// et certains moteurs ne tournent pas


int pwm_max=255;

int pwm_min=120;

// fonction de controle des moteurs
 
void marche_avant(int a) //Marche avant
{
     if ( a >= pwm_min) {
      analogWrite (E1,a); // PWM (reglage vitesse)
      digitalWrite(M1,HIGH); // sens de rotation
     } 
  else analogWrite(E1,0);; 
 
} 
 
void marche_arriere (int a) //Marche arrière
{
     
   if ( a >= pwm_min) {
       analogWrite (E1,a); // PWM (reglage vitesse)
       digitalWrite(M1,LOW); // sens de rotation
       } 
   else analogWrite(E1,0);
}

 
void setup() {
   
   // initialiser la communication serie
    
   Serial.begin(9600);
   
   // pin moteur
    
   pinMode(E1, OUTPUT); // E1 est utilisee en sortie    
   pinMode(M1, OUTPUT); // M1 est utilisee en sortie
   
   // pin encodeurs
   
   pinMode(A,INPUT); 
   pinMode(B,INPUT); 
   
   // pour que les capteurs à effet Hall fonctionnent
   // il faut activer la resistance pull-up
   // de l'Arduino
   
   digitalWrite(A,HIGH);
   digitalWrite(B,HIGH);
   
   // initailiser la position de l'axe moteur
   
   position_moteur1.write(0); 
   
   // la position que l'on veut atteindre
   // exprimée en degrés
   // remarquer que ce n'est pas un appel de fonction
   
   position_cible_M1=5000; 
   
   //demander au timer de lancer l'echantillonage
   
   timer.setInterval(intervalle_echantillonage,asservissement);    
    
}
 
// executee en boucle
 
void loop() {
  
   timer.run();              
    
   Serial.print("*** Dans loop, position actuelle :");
   
   Serial.println(position_moteur1.read());        
   
   // la position finit par se stabiliser
   // mais la fonction d'asservissement continue
   // cependant sans relache
   // à envoyer des ordres au moteur
   // Ceux-ci ne font pas tourner le moteur
   // car la vitesse demandee est trop faible  
}

// la fonction appelée par le timer

void asservissement()

{
   
  long erreur;
  
  int valeur_pwm;
    
  erreur = position_cible_M1 -  position_moteur1.read()  ;      
  
  valeur_pwm = kp * erreur;
  
  if (valeur_pwm >= 255) {
     valeur_pwm = pwm_max;
  }

  else   
  if (valeur_pwm <= -255) {
     valeur_pwm = -pwm_max ;
  }
  
  // petits ajustements avec map sur
  // les valeurs pwm
  // pour obtenir davantage de valeurs
  // actives
  
    if (valeur_pwm > 0) {
       valeur_pwm=map(valeur_pwm,0,255,80,255);   
       marche_avant(valeur_pwm);
     }
     
     else { valeur_pwm=map(valeur_pwm,-255,0,-255,-80);         
            marche_arriere(-valeur_pwm) ; 
          }
    
}