Asservir des moteurs en vitesses

Objectif

Obtenir des moteurs qu’ils tournent à la vitesse désirée, exprimée en unité compréhensible (des millimètres par seconde dans notre cas).

Pré-requis

Vous avez suivi avec succès les parties :

  • Faire tourner les moteurs
  • Lire les codeurs

Vous avez également intégré les fonctions de temps à votre code (comme indiqué dans « Mise en route d’un PAMI »)

L’asservissement

Le principe de l’asservissement consiste à ajuster la commande d’un actionneur en fonction d’un capteur qui mesure le comportement de cet actionneur. Dans notre cas, l’actionneur est notre moteur, le capteur le codeur.

Vocabulaire et schéma de principe

La consigne est la valeur que l’actionneur doit atteindre, la vitesse souhaitée dans notre cas.

L’erreur est l’écart entre la consigne et la valeur mesurée par le capteur.

Le correcteur est le système qui calcule la commande à partir de l’erreur

La commande est la grandeur qui va piloter l’actionneur. Dans notre cas, ce sera la valeur envoyée au module PWM

Le gain du capteur : pour calculer l’erreur, il est nécessaire que le retour du capteur soit dans la même unité que la consigne. Dans notre cas, nous mesurons la vitesse en impulsions par milliseconde et exprimons la consigne en millimètres par seconde. Cette conversion sera gérée dans la partie de la lecture des codeurs.

Pourquoi asservir ?

Un système non-asservi, parfois décrit comme « en boucle ouverte » réagira très différemment en fonction des perturbations auxquelles est soumis le système. Un exemple concret ? Commander les moteurs des PAMI à 90 %. Soulever le PAMI et notez la vitesse des moteurs. Posez le PAMI et comparez !

#Donner les valeurs de nos PAMIs.

Quel type d’asservissement ?

L’asservissement le plus simple à réaliser consiste à commander à fond l’actionneur tant que la consigne n’est pas atteinte et à couper la commande lorsqu’elle est dépassée. C’est rustique, vous pourrez peut-être sentir des vibrations, mais ça marche. Cela s’appelle un correcteur « tout ou rien ».

Le correcteur que nous vous proposons est de type PID. C’est un correcteur pour lequel vous trouverez de la littérature sur internet, dans vos cours ou dans une bibliothèque technique. Notre but n’est pas de présenter la théorie du PID mais de vous permettre de l’expérimenter.

Le principe du PID est de créer une commande proportionnelle à l’erreur.

commande_P = erreur * gain_P

Bien qu’efficace, cette correction seule ne permet pas de s’approcher suffisamment de la consigne. Pour cela, nous rajoutons une commande proportionnelle à l’intégration de l’erreur.

cumul_erreur = cumul_erreur + erreur * pas_de_temps
commande_I = cumul_erreur * grain_I

Enfin, si l’on souhaite réduire le temps de réponse, il est possible de rajouter une commande proportionnelle à la dérivée de l’erreur.

commande_D = (erreur – erreur_précédente)/ pas_de_temps * gain_D
erreur_précédente = erreur

Enfin la commande s’obtient en sommant les commandes précédentes :

commande = commande_P + commande_I + commande_D

Voila pour le correcteur. Maintenant, il reste deux tâches. Régler les gains, ce sera votre travail, mais surtout structurer le code pour mettre en œuvre ce correcteur.

Structure du code

Partie centrale

Pour asservir les moteurs, il vous faut lire les codeurs et commander les moteurs. Dans votre code d’initialisation, appelez ces fonctions :

QEI_init()
Moteurs_init()
AsserMoteur_init()
Temps_init()

Dans la boucle principale, utilisez les fonctions de temps pour n’exécuter votre code qu’à intervalles réguliers.

temps_ms=0 ;
while(1){
  if(Temps_get_ms()!= temps_ms){
    if(Temps_get_ms() % pas_de_temps == 0){
      // Votre futur code ici
    }
  }
}

Dans votre code cyclique, appelez la fonction de mise à jour des QEI puis votre fonction pour asservir vos moteurs

QEI_update()
AsserMoteur_gestion()

pour envoyer les valeurs à l’ordinateur, depuis un RP2040, nous utilisons une boucle infinie qui sera appelé sur le second cœur. Il faut activer ceci lors de l’initialisation.

Partie du module

  • AsserMoteur_init() : la fonction d’initialisation ne fait pas grand-chose, elle initialise les variables du module telles que les vitesses consignes ou l’intégration des erreurs.
  • AsserMoteur_gestion() :
    • Lit la vitesse des moteurs
    • Calcule l’erreur de vitesses
    • Calcule la commande à partir de l’erreur
    • Envoie la commande aux moteurs
  • AsserMoteur_setConsigne_mm_s(vitesse, moteur) : stocke la consigne de vitesse pour le moteur sélectionné

#LIEN vers code complet

Finalisation

Ce qu’il manque pour régler votre asservissement, c’est une consigne de vitesse adéquate. Ce que nous vous recommandons fortement, c’est d’utiliser un signal carré que vous construirez dans votre boucle principale. En initialisation :

float consigne_vitesse = 200; // Consigne en mm/s.
int demi_periode = 2000; // Temps haut ou bas du créneau (en ms)

A l’intérieur de votre « if(Temps_get_ms()!= temps_ms){ … } » :

if(Temps_get_ms() % demi_periode  == 0){
  consigne_vitesse = - consigne_vitesse;
  AsserMoteur_setConsigne_mm_s(consigne_vitesse, MOTEUR_A);
  AsserMoteur_setConsigne_mm_s(consigne_vitesse, MOTEUR_B);
}

#IMG signal carré

Envoyez une consigne à 200 mm/s qui s’inverse toutes les deux secondes. Vous adapterez si nécessaire par la suite.

Les signaux intéressants à observer sont :

  • la consigne ;
  • la vitesse d’un moteur.

Superposez les dans Teleplot pour avoir un graphique vraiment parlant. Avec ceci, vous avez ce qu’il vous faut pour régler votre asservissement.

Réglage de l’asservissement

Le réglage d’un asservissement est autant une science (avec ses théories et ses modélisations) qu’un art. Vous allez régler le vôtre de manière empirique. Ne cherchez pas à peaufiner vos gains à 1 % près. Observez plutôt les écarts de comportement entre le cas où 1 seul moteur tourne et celui où les deux tournent. Entre une rotation et une translation, l’inertie du robot diffère, créant une « perturbation » qui mettra votre asservissement à l’épreuve.

Pour commencer, mettez les gains I et D à 0. Pour le gain P, choisissez le pour avoir :

commande_max = gain_P * vitesse_max

Avec un tel réglage, vous devriez obtenir une réponse molle.

#IMG :Ajouter image du graphique

Multiplier successivement votre gain par 2 jusqu’à avoir une réponse plus dynamique

#IMG : gain_P dynamique.

Réglez ensuite votre gain I, en prenant comme première valeur gain_I = gain_P/10. Ajustez-le de la même manière que le gain_P

#IMG : gain_I réglé

Pour le gain_D, débrouillez-vous ! Nous, nous ne nous en servons pas…

Codes de démonstration

Nous vous proposons deux codes de démonstration

Trajectoire circulaire

Donnez 2 vitesses fixes mais différentes à vos moteurs pour obtenir un PAMI qui suit une trajectoire circulaire. Essayez les vitesses de 100 mm·s et 200 mm/s. Observez également à quel point votre PAMI se décale (ou non) au fil des passages.

#Vidéo PAMI

Aller-retours

Comme dans le code de réglage de l’asservissement, faites avancer puis reculer votre PAMI, mais augmentez le temps des créneaux et diminuez la vitesse pour qu’il parcoure 40 cm en 4 secondes.

Si votre coefficient de conversion des pas du codeur en millimètres parcourus par la roue est bon, vous devriez observer que le déplacement réel correspond globalement à celui programmé (à la fois en termes de vitesse et en termes de distance).

Observez également le décalage de votre PAME d’un aller-retour à l’autre !

#Vidéo PAMI