Les codeurs incrémentaux

Un codeur incrémental est un capteur de position (linéaire ou angulaire).

Principes de fonctionnement

Codeur de système ABS de moto

Quelle que soit la technologie, l’information de position est basée sur la détection et le comptage  de « zones détectables » placées sur un support en mouvement. Ces zones peuvent être de différentes natures, imposants certains types de détecteurs :

  • matière/vide : capteurs inductifs ou capacitifs
  • surface réfléchissante/non réfléchissante : émetteur+récepteur optique
  • matière translucide/opaque : émetteur+récepteur optique
  • matériau conducteur/isolant : circuit avec balais et collecteur

Pas d’un codeur

Selon le type de mouvement, les « zones détectables » se trouvent régulièrement réparties …

  • … sur un disque ou un cylindre : mouvement de rotation

  • … sur une bande : mouvement de translation

Le pas du codeur est déterminé par la géométrie du support en mouvement.

Mesure de la vitesse

Le codeur délivre alors un signal logique de période proportionnelle à la vitesse du mouvement du support :

  • zone détectée : état logique haut
  • zone non détectée : état logique bas

\(Large{text{vitesse}=\frac{text{pas}}{text{période}}}\)

Mesure de la position

La position est plus complexe à obtenir. Toutes les « zones détectables » sont identiques : une zone seule ne donne pas d’information de position. Il faut les compter !

Le microcontrôleur de la chaîne d’acquisition doit mettre en œuvre un compteur qui peut fonctionner de différentes manières :

  • comptage d’un seul front du signal (montant ou descendant) : \(position=pas \times compteur\)
  • comptage des deux fronts : \(position=\frac{1}{2}pas \times compteur\)

La résolution du codeur est donc définie par le pas du support (un angle ou une distance selon le type de mouvement).

La mesure de la position est relative à une position initiale, qu’il faut maitriser !

  • Procédure de remise à zéro (manuelle ou bien automatique lors de l’initialisation)
  • Capteur de début ou fin de course du mouvement,

Détermination du sens du mouvement

Pour déterminer le sens du mouvement, il faut employer un deuxième capteur (de même nature que le premier) et faire en sorte qu’il délivre un signal identique à celui du premier, mais déphasé d’un quart de période.

Ainsi si l’on nomme A et B les signaux délivrés par les deux capteurs, le sens du mouvement sera déterminé par le signe du déphasage temporel :

  • sens 1 : B en avance par rapport à A
  • sens 2 : B en retard par rapport à A.

Décodage des signaux

Résolution normale

Il s’agit maintenant de déterminer la position (relative à une position initiale) et le sens du mouvement.

Une solution simple consiste à :

  • utiliser une interruption pour détecter précisément les fronts descendants (ou bien montants) d’un des deux signaux,
  • comparer l’état de l’autre signal à l’instant de ce front, ce qui donnera le sens du mouvement.
int pinA = 2;   // Le port D2 est associé à l'interruption 0
int pinB = 4;
volatile int pos = 0;  // Position (en nombre de pas) du codeur

void setup()  {
   Serial.begin(115200);
   Serial.println("Codeur incremental");
   pinMode(pinB, INPUT);
   attachInterrupt(0, front, FALLING);  // Détection des fronts descendants
}

void loop()   {
   delay(10);
}

void front()   {
   int s = digitalRead(pinB);
   if (s == LOW)   {
      ++pos;
   }
   else   {
      --pos;
   }
   Serial.println(pos);   // Ligne à supprimer après les tests, car elle ralenti le dispositif
}

Résolution fine

Pour diviser par deux la résolution (et par conséquent augmenter la précision du dispositif), il faut détecter les deux fronts d’un signal (les montants et les descendants).

Le sens du signal est alors déterminé en comparant les états des deux signaux après les fronts : s’ils sont égaux ou s’ils sont différents.

int pinA = 2;   // Le port D2 est associé à l'interruption 0
int pinB = 4;
volatile int pos = 0;  // Position (en nombre de pas) du codeur

void setup()  {
   Serial.begin(115200);
   Serial.println("Codeur incremental");
   pinMode(pinB, INPUT);
   attachInterrupt(0, front, CHANGE);  // Détection des deux types de fronts
}

void loop()   {
   delay(10);
}

void front()   {
   int sA = digitalRead(pinA);
   int sB = digitalRead(pinB);
   if (sA == sB)   {
      ++pos;
   }
   else   {
      --pos;
   }
   Serial.println(pos);     // Ligne à supprimer après les tests, car elle ralenti le dispositif
}

Cette solution est légèrement moins performante du point de vue de la vitesse maximale de commutation, car il faut lire les états des deux signaux. Ça prend un peu plus de temps…

Calcul de la vitesse

La vitesse d’un mouvement est la dérivée par rapport au temps de sa position : \(v(t)=\frac{dx(t)}{dt}\)

Ce qui est équivalent à : \(v(t)=\lim\limits_{dt\rightarrow 0} \frac{x(t+dt)-x(t)}{dt}\)

D’un point de vue pratique, on calcule la dérivée d’un signal grâce au taux d’accroissement entre deux points mesurés, soit une « distance » égale à la résolution.

\(v(t)\approx\frac{x(t_{i+1})-x(t_i)}{t_{i+1}}=\frac{résolution}{t_{i+1}}\)

Par conséquent, il faudra aussi mesurer les temps auxquels ont lieu les fronts du signal.

int pinA = 2;   // Le port D2 est associé à l'interruption 0
int pinB = 4;
volatile int pos = 0;          // Position (en nombre de pas) du codeur
volatile float vit = 0;        // Vitesse (en nombre de pas par seconde) du codeur
volatile unsigned long t = 0;  // temps "courant" (en microsecondes)

void setup()  {
   Serial.begin(115200);
   Serial.println("Codeur incremental");
   pinMode(pinB, INPUT);
   attachInterrupt(0, front, CHANGE);  // Détection des deux types de fronts
   t = micros();                       // Initialisation du temps "courant"
}

void loop()   {
   delay(10);
}

void front()   {
   unsigned long dt = micros() - t;   // Temps écoulé depuis le dernier front
   t += dt;
   int sA = digitalRead(pinA);
   int sB = digitalRead(pinB);
   int apos = pos;                    // Mémorisation de la position précédente
   if (sA == sB)   {
      ++pos;
   }
   else   {
      --pos;
   }
   
   if (dt > 0)   {
      vit = 1e6*(pos-apos)/dt;         // Calcul de la vitesse (ici en pas par seconde)
   }
   
   Serial.print(pos);      // Lignes à supprimer après les tests, car elles ralentissent le dispositif
   Serial.print("\t");
   Serial.println(vit);
}

Codeurs optiques

Ce sont les codeurs les plus fréquemment rencontrés. On en trouve dans les imprimantes par exemple, et dans les vieilles souris à boule !

La plupart des codeurs optiques sont composés d’un émetteur infrarouge (diodes électroluminescentes – LED) émettant une lumière qui peut traverser les zones translucides d’un support mobile (un disque ou une bande selon le type de mouvement).

Situés de l’autre côté du support, en face de la LED, des récepteurs (phototransistors) réagissent à la lumière qu’il reçoivent :

  • Lumière reçue : phototransistor saturé (laisse passer le courant)
  • Lumière non reçue : phototransistor bloqué (ne laisse pas passer le courant)

Remarque : pour l’implantation du deuxième phototransistor (celui qui permettra de connaître le sens du mouvement), à défaut de pouvoir rapprocher suffisamment les deux phototransistors, on place souvent une grille entre la LED et le support mobile :

Exemples de mise en œuvre de codeurs optiques

Vous aimerez aussi...

3 réponses

  1. Charles dit :

    Bonsoir,
    Merci beaucoup pour ces explications! J’aimerai essayer le dispositif mais je ne parviens pas a savoir comment on extrait les information… A therme j’aimerai les faire arriver directement sur mon pc dans un document mais je ne sais pas comment m’y prendre… pouvez vous m’éclairer? Merci d’avance.
    Henri

    • cfaury dit :

      Bonjour
      Pour récupérer des données en provenance d’un Arduino, il existe différentes solutions :
      1) Faire afficher les données dans le moniteur série (voir Bibliothèque Serial) : l’Arduino doit rester en liaison avec le PC (câble USB, bluetooth, zigbee, …). Il suffit alors de copier les données affichées et de les coller dans un tableur.
      2) Utiliser un autre programme de réception, que l’on peut faire soi-même (en Python par exemple) ou que l’on peut trouver sur Internet (mots clef Arduino + Oscilloscope)
      J’écrirai sans doute un article détaillé là dessus un de ces jours …
      CF

  2. Coillote dit :

    Merci pour cet article qui m’est d’une grande aide !

Répondre à Coillote Annuler la réponse

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