Les encodeurs en quadrature

. Par : Jean-Luc. URL : https://www.locoduino.org/spip.php?article82

Les encodeurs ressemblent aux potentiomètres rotatifs mais ont un comportement très différent. Leur usage est également un peu différent. On va dans un premier temps examiner leur fonctionnement. Dans un deuxième temps nous verrons leur mise en œuvre sur l’Arduino et enfin, dans un troisième temps, nous verrons leur usage.

Fonctionnement d’un encodeur

Un encodeur est donc un dispositif permettant de détecter une rotation ainsi que le sens de rotation. On le retrouve employé comme compte tour sur les moteurs ou bien comme dispositif d’entrée. Un encodeur de ce dernier type et muni d’un bouton poussoir est présenté ci-dessous en vue avant et arrière.

Encodeur sans son bouton
Encodeur sans son bouton

Celui-ci est un encodeur muni d’un poussoir sur son axe, cas très fréquent. Les deux broches visibles sur un des côtés, photo de droite, correspondent au poussoir. Nous ne reviendrons pas sur la mise en œuvre d’un poussoir. Vous pouvez vous reporter à « Bouton poussoir ». Sur le côté opposé, photo de gauche, on dispose de 3 broches. Sur ce modèle, la broche centrale est commune à deux interrupteurs et les deux autres broches correspondent à la seconde borne de chacun des interrupteurs. Sur d’autres modèles, la broche commune peut être ailleurs, il faut bien entendu consulter la datasheet.

Utilisé comme dispositif d’entrée, un encodeur est cranté. Le nombre de crans par tour complet de l’encodeur est habituellement d’une vingtaine. Le passage d’un cran engendre une impulsion sur chaque interrupteur. C’est à dire que chaque interrupteur colle momentanément. L’ordre dans lequel les interrupteurs collent correspond au sens de rotation. Les captures d’écran ci-dessous montrent les impulsions engendrées par chacun des interrupteurs.

Impulsions envoyées par l'encodeur vues à l'oscilloscope.
Impulsions envoyées par l’encodeur vues à l’oscilloscope.
Le signal jaune correspond à la broche de gauche sur la photo de l’encodeur, le signal bleu à la broche de droite.
À gauche, les impulsions quand un cran de l’encodeur est passé dans le sens anti-horaire. À droite, les impulsions quand un cran est passé dans le sens horaire.

Mise en œuvre avec l’Arduino

On peut voir notamment sur ces captures d’écran les temps caractéristiques : au minimum l’interrupteur reste collé pendant environ 20ms mais peut descendre à un peu plus de 10ms en cas de rotation rapide. Dans les deux cas, c’est amplement suffisant pour détecter les impulsions. On peut détecter ces impulsions par scrutation de manière répétitive dans loop(). Si loop() est un peu long, notamment parce qu’on a utilisé delay(), il est tout à fait possible que des impulsions soient loupées.

Une méthode plus astucieuse consiste à utiliser les interruptions externes. Si vous n’êtes pas sûr de savoir ce que c’est, reportez vous à « Les interruptions (1) ».

On peut par exemple connecter le signal jaune à une entrée d’interruption de l’Arduino Uno, par exemple INT0 c’est à dire la broche 2. En mettant en place une ISR qui s’exécutera à chaque transition de HIGH vers LOW, soit FALLING, on détecte les passages de cran de l’encodeur. Pour déterminer le sens de rotation, il suffit de lire le signal bleu. Si le signal bleu est LOW, alors il s’agit d’une rotation dans le sens horaire. Si il est HIGH, il s’agit d’une rotation dans le sens anti-horaire. Comme il s’agit d’un dispositif mécanique, des rebonds sont possibles, on mettra donc en œuvre un anti-rebond comme vu dans « Les interruptions (1) » pour les ILS.

Voici donc un programme test qui compte les passages de cran et affiche le compteur correspondant sur un LCDKeypad shield :

#include <LiquidCrystal.h>
#include <LCDKeypad.h>
 
LCDKeypad lcd;
 
const byte pinEncodeurA = 2;
const byte pinEncodeurB = 3;
 
volatile byte compte = 0;
 
const unsigned long dureeAntiRebond = 10;
 
void encodeurTickA()
{
  static unsigned long dateDernierChangement = 0;
  
  unsigned long date = millis();
  if ((date - dateDernierChangement) > dureeAntiRebond) {
    if (digitalRead(pinEncodeurB) == LOW) {
      compte++;
    }
    else {
      compte--;
    }
    dateDernierChangement = date;
  }
}
 
void setup()
{
  lcd.begin(16, 2);
  lcd.clear();
  lcd.print("Test encodeur");
  
  pinMode(pinEncodeurA,INPUT);
  pinMode(pinEncodeurB,INPUT);
  
  attachInterrupt(0, encodeurTickA, FALLING);
  
  delay(1000);
  lcd.clear();
}
 
void loop()
{
  lcd.setCursor(0,0);
  lcd.print(compte);
  lcd.print("  ");
  delay(20);
}

setup() initialise le LCDKeypad shield, programme les broches où est connecté l’encodeur en entrée et met en place l’ISR. loop() affiche toutes les 20ms la valeur de la variable compte. L’anti-rebond est géré via la variable dateDernierChangement qui mémorise la dernière date où l’ISR a pris en compte le transition HIGH vers LOW du signal jaune. Une nouvelle prise en compte n’est possible que si au moins 10ms se sont écoulées. Si la prise en compte est possible, le signal bleu est lu et la variable compte est incrémentée ou décrémentée selon la valeur du signal bleu.

Le montage correspondant demande de mettre des résistances de pull-up externes à l’Arduino. En effet, des résistances de 10kΩ sont recommandées alors que les résistances de pull-up font plusieurs dizaines de kΩ.

Montage de test de l'encodeur
Montage de test de l’encodeur

Pourquoi utiliser un encodeur au lieu d’un potentiomètre ?

La différence fondamentale est que le potentiomètre rotatif va donner une grandeur absolue qui dépend de son angle alors que l’encodeur donne une grandeur relative. Par conséquent, avec un encodeur, c’est le programme qui décide de la valeur initiale, l’encodeur ne fait que signaler une augmentation ou une diminution de cette valeur.

Cette différence prend tout son sens dans le contexte d’un réseau semi-automatisé. Imaginons une commande de locomotive et une infrastructure matérielle et logicielle permettant d’avoir des locomotives conduites par le système pendant que l’on conduit l’une d’entre elles en manuel. Imaginons que l’on puisse, au vol, laisser la conduite de notre locomotive au système tandis que l’on prend le contrôle d’une autre. Avec un potentiomètre, il va être nécessaire de demander au conducteur de remettre le potentiomètre à 0 et donc d’arrêter la locomotive avant de lui donner la main. Avec un encodeur, il suffit de fixer la nouvelle vitesse à celle de la locomotive dont on prend le contrôle, nul besoin d’une procédure de ré-étalonnage.

De même la navigation dans des menus hiérarchiques sur un écran LCD est aisée avec un encodeur. On peut sélectionner un item grâce au poussoir et, le fait que l’encodeur fournisse une grandeur relative : item suivant, item précédent, est tout à fait adapté.

L’autre propriété de l’encodeur est qu’il n’y a pas de butée. Il existe également des potentiomètres sans butée mais dans ce cas, la résistance saute de la valeur maximum à 0 ou inversement selon le sens de rotation.