Les servos moteurs comme périphérique d’entrée

  • PascalP

Partage et review :

Introduction

Description

Qu’est ce qu’un servo?

Le mot “servo” signifie bien plus que ces petits moteurs servos radio commandés que l’on utilise d’habitude. Servo est un terme général pour définir un système de contrôle de boucle fermée en utilisant un retour négatif.

Le cruise control d’une voiture est un exemple de système de servo. Il mesure la vitesse et envoie le retour au circuit de contrôle qui ajuste le courant au moteur pour maintenir l’accélération.

Les servo-moteurs et leur retours

servo1

Boucle ouverte et fermée

Un système à boucle ouverte n’offre pas de retour, il n’y a donc pas de moyen de vérifier si tout a fonctionné comme prévu. Une expression commune au sein de la communauté des ingénieurs est « Vous ne pouvez contrôler ce que vous ne pouvez mesurer ».

servo2

Les systèmes à boucle fermée peuvent utiliser un signal de retour pour ajuster la vitesse et la direction du moteur pour obtenir le résultat désiré. Dans le cas d’un servo moteur RC, le retour prend la forme d’un potentiomètre connecté sur la sortie de l’arbre du moteur. La sortie du potentiomètre est proportionnelle à la position de l’arbre du servo.

servo3

Le problème lorsque vous essayez de contrôler un servo RC standard depuis un microcontrôleur, c’est que vous travaillez avec une boucle close dans votre boitier de servo, mais que le microcontrôleur, lui, travaille par défaut avec une boucle ouverte. Vous pouvez dire à votre circuit de contrôle de servo comment vous souhaitez positionner votre arbre, mais vous n’avez aucun moyen de vérifier si l’arbre s’est correctement positionné et même si il a déjà fait le travail ou pas.

servo4

Mais, grâce aux fils de feedback du servo, vous pouvez le brancher sur le microcontrôleur. Du coup, vous fermez la boucle aussi au niveau du microcontrôleur et ainsi avoir vos informations de retour sur celui-ci.

servo5

Comment utiliser le retour!

La question que l’on peut logiquement se poser, est la suivante : « si un servo fait ce qu’on lui demande, pourquoi aurait-on besoin d’avoir un retour de sa part? »

Les servos RC font en général ce qu’on leur demande de faire, mais malheureusement pour nous, il y a quelques cas où il ne va pas obtempérer. Ces cas sont en autres:

  • Taille du moteur insuffisante
  • Alimentation insuffisante
  • Interférence physique
  • Interférence électrique
  • Perte de connexion

Dans ces cas-là, grâce au feedback, vous êtes en mesure de savoir qu’il y a un problème.

Mais même dans le cas où, tout est bon au niveau de la taille du moteur ou de son alimentation, un servo va toujours mettre un certain temps avant d’exécuter une commande. Il y a un tas d’applications en robotique, qui demandent de savoir exactement quand la position a été atteinte.

Le fragment de code suivant provient de la librairie Servo d’Adafruit. Petite note, le délai de 15 après le myservo.write(val) est complètement arbitraire.

void loop() {
val = analogRead(potpin); // lit la valeur du potentiomètre (valeur entre 0 et 1023)
val = map(val, 0, 1023, 0, 179); // mise à l'échelle de la valeur pour l'utiliser avec le servo (valeur entre 0 et 180)
myservo.write(val); // écrit la position au servo en fonction de la valeur mise à l'échelle
delay(15); // attend que le servo se mette en place

}

 

Sans retour, la plupart des programmes utilisant des servos ne peuvent qu’essayer de devenir le temps que va mettre le servo pour se mettre en place. Ce qui est le cas dans le code ci-dessus, on attend en effet 15ms le temps de laisser le servo se mettre en place. Mais, si le fait d’ajouter un temps d’attente arbitraire peut fonctionner correctement sur des projets simples, il peut en être tout autre pour des projets qui utilisent un grand nombre de servos. En effet, si on doit attendre un délai fixe à chaque fois qu’un servo bouge, et qu’en plus il faut synchroniser l’ensemble de ces mouvements car ils dépendent les uns des autres. Vous vous retrouverez vite avec un système très lent qui passera la plupart de son temps à attendre.

Cela peut même être pire, si le délai n’est pas assez long, il se peut que les servos n’aient pas atteint la position demandée. Ce qui peut faire dysfonctionner votre projet ou pire endommager du matériel. Par exemple, pour un projet tournant sur batterie, les servos bougeront de moins en moins vite au fur et à mesure que les batteries vont se décharger.

retour1

Lire le retour, tu devras!

Le signal de retour est récupéré via un plot situé sur l’arbre du servo. Vous pouvez connecter le câble blanc du retour sur n’importe quel pin analogique et ensuite, il vous suffit de lire la valeur renvoyée via la ligne de code « analogRead([numéro de la pin à lire]) »

int feedback = analogRead(feedbackin);

Calibrer le retour

Le retour brut d’un servo est un voltage. Pour convertir ce voltage en une position exploitable, il faut calibrer celui-ci vers le servo. En lisant la valeur de retour à deux positions connues, nous pouvons interpoler les valeurs de retour entre ces deux positions.

Le petit code suivant fait cette manipulation. Si vous appelez la fonction « calibrate » dans la fonction de setup, elle calibrera le servo sur les deux points que vous aurez spécifié. Les servos opèrent généralement sur des angles allant de 0 à 180°. Pour plus de précision, il est préférable d’utiliser les variables « minPos » et « maxPos » en tant que point de calibration. Par exemple, 0 pour « minPos » et 180 pour « maxPos ». Ces deux variables représentent donc l’angle minimum et l’angle maximum que votre servo peut atteindre. Néanmoins, si vous souhaitez utiliser votre servo sur un angle plus restreint, il vous suffit de modifier ces valeurs comme c’est le cas dans l’exemple ci-dessous.

#include  //inclus dans le projet la librairie de contrôle des servos 

Servo myservo;  

// Pins de contrôle et de retour
int servoPin = 9;
int feedbackPin = A0;
 
// Valeur de calibrage
int minDegrees;
int maxDegrees;
int minFeedback;
int maxFeedback;
int tolerance = 2; // erreur maximum d'erreur de retour
 
/*
  Cette fonction établit les valeurs de retour pour deux positions du servos.
Avec cette information, on peut interpoler les valeurs pour les positions intermédiaires.
*/
void calibrate(Servo servo, int analogPin, int minPos, int maxPos)
{
  // Se déplace à la position minimale et enregistre la valeur.
  servo.write(minPos);
  minDegrees = minPos;
  delay(2000); // Laisse le temps au servo de se mettre en position
  minFeedback = analogRead(analogPin);
  
  // Se deplace en position maximale et enregistre la valeur.
  servo.write(maxPos);
  maxDegrees = maxPos;
  delay(2000); // Laisse le temps au servo de se mettre en position
  maxFeedback = analogRead(analogPin);
}
 
 
void setup() 
{ 
  myservo.attach(servoPin); 
  
  calibrate(myservo, feedbackPin, 20, 160);  // Calibration pour un mouvement de 20 à 160°
} 
 
void loop()
{
}

Utiliser le retour dans votre code

Maintenant que nous avons calibré le signal de retour, nous pouvons facilement convertir une position en voltage de retour et inversement via notre code.

La bonne position, tu attendras
Le bout de code qui suit va rechercher le moment où le servo atteint une position et nous prévenir dès que celle-ci est atteinte. Il n’y a pas de besoin de mettre de délais au niveau de cette boucle puisque le signal de retour se fait en temps réel. Nous saurons donc exactement quand nous sommes arrivés en position.

void Seek(Servo servo, int analogPin, int pos)
{
  // Démarre le mouvement...
  servo.write(pos);
  
  // Calcule la valeur cible pour la position demandée
  int target = map(pos, minDegrees, maxDegrees, minFeedback, maxFeedback); 
  
  // Boucle tant que la valeur souhaitée n'est pas obtenue avec une différence inférieure à la tolérance requise
  while(abs(analogRead(analogPin) - target) > tolerance){} // wait...
}

Savoir où tu te situes, tu devras

Un autre truc sympa avec le retour, c’est que vous n’avez pas besoin d’écrire de code pour savoir où vous vous êtes arrêté la dernière fois. En effet, si vous avez besoin de savoir en quelle position se situe le servo, il suffit de lui demander.

Une fois que vous avez calibré votre servo via le setup initial. La ligne de code suivante vous permettra de connaitre la position de votre servo.

int getPos(int analogPin)
{
  return map(analogRead(analogPin), minFeedback, maxFeedback, minDegrees, maxDegrees);
}

La possibilité de simplement lire la position du servo, ouvre la possibilité d’utiliser ce même servo en tant que dispositif d’entrée.

Les servos comme dispositif d’entrée

entrer1

Une autre fonctionnalité très sympa avec les servos et leur retour, c’est la possibilité de pouvoir se servir du servos comme périphérique d’entrée. La démo Enregistre/Joue, vous permet d’enregistrer une série de mouvement sur votre servo et ensuite de les rejouer. Les positions enregistrées sont sauvées dans l’EEPROM (mémoire permanente de votre arduino). Du coup, vous pouvez les récupérer même après avoir éteint celui-ci.

Pour faire cette démo, il faut câbler votre servo en suivant le diagramme ci-dessous:

Composant utilisé:

  • Arduino Uno
  • Servo à retour
  • 2x boutons poussoirs
  • LED de 3 ou 5mm
  • résistance de 220 ohm
  • une planche de câblage
  • une nappe de câble à pin

entrer2

Ensuite, downloader le code de démo sur GitHub

Code Démo

Pour faire tourner cette démo, il vous faudra:

  • Envoyer le code servo_recordplay vers l’arduino
  • pousser sur le bouton du dessus pour démarrer l’enregistrement (La led devrait s’allumer)
  • pousser le bouton du dessus une deuxième fois pour arrêter l’enregistrement
  • Pousser le bouton du dessous pour rejouer les mouvements
  • Vous pouvez repousser sur le boutton play autant de fois que vous le voulez
  • Pour enregistrer une nouvelle séquence, il suffit de recommencer à l’étape 2

NB: Vous pouvez enregistrer jusqu’à 512 échantillons (environ 12.8 secondes). Quand vous aurez atteint la limite, La led s’éteind et l’enregistrement s’arrête automatiquement.

La vidéo ci-dessous (en anglais) vous montre tout cela en détails.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *