Ignorer et passer au contenu

Livraison offerte à partir de 50€ d'achats, livrée sous 48h !

Livraison à partir de seulement 2.50€ !

Contents Menu Expand Light mode Dark mode Auto light/dark mode

Utiliser un codeur rotatif en code Arduino avec un ESP32

(Mis à jour le 09/01/2023)

apercu codeur rotatif KY 040

Un codeur rotatif est un type de capteur de position qui convertit la position angulaire (rotation) d’un axe en un signal de sortie utilisé pour déterminer la position et le sens de rotation. Il est utilisé essentiellement dans les moteurs pour faire de l’asservissement, mais également dans les interfaces utilisateurs pour remplacer les potentiomètres. En plus, la plupart des codeurs que l’on trouve dans les kits DIY sont munis d’un bouton-poussoir intégré !

exemple utilisation encodeur rotatif imprimante 3d

Le bouton de contrôle des imprimantes 3D est en général un codeur rotatif

Prendre en main un codeur rotatif : le KY-040

apercu codeur rotatif KY 040

Dans ce tutoriel, nous allons voir comment utiliser un module avec un codeur rotatif KY-040, très présent dans les kits DIY. On l’utilise souvent pour faire une interface utilisateur avec notre programme : sélection d’un menu, augmenter/diminuer une variable…

Différence entre codeur rotatif et potentiomètre

À première vue, le codeur rotatif KY-040 peut être confondu avec un potentiomètre. Mais en réalité, le potentiomètre est un capteur analogique alors que le codeur rotatif est numérique. Un potentiomètre modifie la valeur d’une résistance, mais possède un nombre de tours limité.

Le codeur rotatif, quant à lui, détecte un nombre de « pas » par tour et envoie un signal à chaque pas. Il tourne aussi à l’infini. On peut sentir la différence à travers le toucher : le potentiomètre tourne de manière fluide, alors que le codeur rotatif tourne de manière saccadée.

Le codeur rotatif peut être directement utilisé par un microcontrôleur puisqu’il envoie des niveaux logiques. Sa résolution est déterminée par le nombre de pas par tour, alors que la résolution du potentiomètre dépend de la résolution de l’ADC nécessaire pour estimer sa position.

Note

On utilise un potentiomètre pour régler des paramètres analogiques, comme le volume d’un ampli, tandis que le codeur rotatif est employé pour déterminer précisément une position angulaire et une direction.

Fonctionnement théorique d’un encodeur rotatif

Ce tutoriel ne rentre pas trop dans les détails techniques, mais il y a beaucoup de choses à dire 🤓. Si vous voulez connaître réellement le fonctionnement physique, les différentes technologies et les topologies classiques (par exemple, le comprendre le fonctionnement d’un encodeur rotatif optique à quadrature de phase 😨), je vous redirige vers la présentation théorique d’un encodeur rotatif .

Branchements de l’encodeur rotatif KY-040 sur l’ESP32

Ce codeur rotatif possède 2 signaux pour connaître la position : CLK et DT . La broche SW est reliée au bouton-poussoir intégré (SWitch).

Avertissement

Si vous utilisez un codeur rotatif seul (pas intégré dans un module), vous devrez rajouter des résistances pull-up sur les 3 broches logiques. En effet, comme sur le circuit basique du bouton-poussoir, elles sont nécessaires pour différencier correctement les niveaux logiques.

Voici une proposition de branchement sur une carte ESP32 d’uPesy:

Codeur Rotatif

ESP32

CLK

GPIO22

DT

GPIO23

SW

GPIO21

+

3V3

GND

GND

Le schéma à faire est le suivant :

ky40 rotary encoder circuit diagram esp32 breadboard

Circuit électronique à reproduire

Et voici un exemple de montage sur breadboard :

schéma breadboard codeur rotatif

Connaître la position angulaire du codeur rotatif KY-040 en code Arduino

Avec ce type d’encodeur incrémental, il ne renvoie pas précisément la position angulaire en degré mais plutôt le nombre d’incrément fait par l’utilisateur. C’est dans le programme que l’on peut en déduire l’angle. Ici, on veut juste connaître la valeur de l’incrément.

Il existe différentes façons de procéder pour déterminer l’incrément du codeur. Idéalement on voudrait une méthode fiable, qui compte bien tous les pas sans être bloquante dans le programme. En effet, si on utilise une approche simple, qui regarde dans une boucle en permanence si des signaux logiques sont reçus depuis le codeur, il risque d’y avoir des pas qui ne seront pas pris en compte si on tourne très rapidement le codeur.

Note

Parfois le programme compte dans le mauvais sens s’il n’arrive plus à suivre la cadence. (Un bug classique)

Ils existent beaucoup de code sur le Net pour utiliser des encodeurs rotatifs, mais tous ne se valent pas ! L’approche optimale c’est d’utiliser des interruptions hardware qui vont se déclencher dès qu’un changement de niveau logique est détecté. Elles seront complètement détachées du CPU: le code sera en prime non bloquant.

Note

On peut avoir des interruptions sur n’importe quelle broche de sorties de l’ESP32 (Contrairement à l’Arduino ou il y en a seulement quelques-unes…)

Les librairies Arduino compatibles avec l’ESP32

Même si l’on peut le faire tout le code nous-même, il est préférable d’utiliser des librairies. Je vous en conseille 2 qui sont optimisées pour le fonctionnement sur un ESP32 :

  • AiEsp32RotaryEncoder : Librairie qui utilise l’approche les interruptions hardware avec un calcul de l’incrément dans la routine d’interruptions. Elle est spécifiquement adaptée pour être utilisé avec codeur rotatif muni d’un bouton-poussoir intégré. Elle est donc parfaite avec le codeur KY-040. Je vous conseille d’utiliser celle-ci si c’est pour faire une interface utilisateur (Sélection menu, modifier valeur d’un paramètre…)

  • ESP32Encoder : Cette librairie utilise un périphérique hardware de l’ESP32 PCNT pour faire le comptage. Il n’y a aucun traitement CPU nécessaire contrairement à l’autre : tout est fait en hardware, les performances sont donc au rendez-vous. Par contre, ses fonctionnalités sont plus limitées : il n’y a pas d’interruptions à chaque incrément, pas de gestion d’un bouton-poussoir… Je recommande d’utiliser cette librairie pour lire l’encodeur rotatif intégré à un moteur , où il y aura des centaines d’incréments par seconde. Votre code pourra lire l’incrément actuel à tout moment via une fonction.

    Note

    La librairie permet de gérer jusqu’à 8 encodeurs rotatifs en même temps uniquement avec le PCNT hardware de l’ESP32.

Les 2 librairies s’installent facilement depuis l’Arduino IDE :

Utiliser un codeur rotatif pour une interface utilisateur avec la librairie AiEsp32RotaryEncoder

La librairie s’installe depuis le gestionnaire de bibliothèque dans l’Arduino IDE.

installation librairie Arduino pour encodeur rotatif sur ESP32

Voici un code squelette pour montrer les possiblités de cette librairie :

#include "AiEsp32RotaryEncoder.h"
#include "Arduino.h"

#define ROTARY_ENCODER_A_PIN 23
#define ROTARY_ENCODER_B_PIN 22
#define ROTARY_ENCODER_BUTTON_PIN 21
#define ROTARY_ENCODER_VCC_PIN -1
#define ROTARY_ENCODER_STEPS 4

//instead of changing here, rather change numbers above
AiEsp32RotaryEncoder rotaryEncoder = AiEsp32RotaryEncoder(ROTARY_ENCODER_A_PIN, ROTARY_ENCODER_B_PIN, ROTARY_ENCODER_BUTTON_PIN, ROTARY_ENCODER_VCC_PIN, ROTARY_ENCODER_STEPS);

void rotary_onButtonClick()
{
    static unsigned long lastTimePressed = 0; // Soft debouncing
    if (millis() - lastTimePressed < 500)
    {
            return;
    }
    lastTimePressed = millis();
    Serial.print("button pressed ");
    Serial.print(millis());
    Serial.println(" milliseconds after restart");
}

void rotary_loop()
{
    //dont print anything unless value changed
    if (rotaryEncoder.encoderChanged())
    {
            Serial.print("Value: ");
            Serial.println(rotaryEncoder.readEncoder());
    }
    if (rotaryEncoder.isEncoderButtonClicked())
    {
            rotary_onButtonClick();
    }
}

void IRAM_ATTR readEncoderISR()
{
    rotaryEncoder.readEncoder_ISR();
}

void setup()
{
    Serial.begin(115200);

    //we must initialize rotary encoder
    rotaryEncoder.begin();
    rotaryEncoder.setup(readEncoderISR);
    //set boundaries and if values should cycle or not
    //in this example we will set possible values between 0 and 1000;
    bool circleValues = false;
    rotaryEncoder.setBoundaries(0, 1000, circleValues); //minValue, maxValue, circleValues true|false (when max go to min and vice versa)

    /*Rotary acceleration introduced 25.2.2021.
   * in case range to select is huge, for example - select a value between 0 and 1000 and we want 785
   * without accelerateion you need long time to get to that number
   * Using acceleration, faster you turn, faster will the value raise.
   * For fine tuning slow down.
   */
    //rotaryEncoder.disableAcceleration(); //acceleration is now enabled by default - disable if you dont need it
    rotaryEncoder.setAcceleration(250); //or set the value - larger number = more accelearation; 0 or 1 means disabled acceleration
}

void loop()
{
    //in loop call your custom function which will process rotary encoder values
    rotary_loop();
    delay(50); //or do whatever you need to do...
}

Voici ce que l’on obtient dans le moniteur série quand on tourne le codeur :

termnial série encodeur rotatif esp32

Vous remarquerez que les valeurs n’augmentent pas toujours de manière linéaire. En fait, c’est parce que le mode “Acceleration” est activé ! Il permet d’augmenter plus rapidement la valeur quand on tourne rapidement le codeur. C’est très pratique pour changer la valeur d’un paramètre. Vous pouvez la désactiver via la fonction rotaryEncoder.disableAcceleration() . Sinon vous pouvez modifier son comportement avec la fonction rotaryEncoder.setAcceleration(0-1000) .

Avec cette librairie, le comptage se fait en arrière-plan, même si on retire la fonction rotary_loop() de la loop() . Le code présenté ci-dessus peut vous servir de code “squelette” que vous pourrez modifier pour votre projet. Pour connaître toutes les possibilités de la librairie, vous pouvez consulter la doc sur le dépôt GitHub .

Connaître la position angulaire d’un encodeur rotatif en utilisant le compteur matériel de l’ESP32 (PCNT) avec la lib ESP32Encoder

La librairie ESP32Encoder s’installe directement depuis l’Arduino IDE :

installation librairie Arduino pour encodeur rotatif sur ESP32

Le code est beaucoup plus simple que la librairie précédente, mais en même temps, on peut récupérer uniquement la valeur de l’incrément du codeur.

#include <ESP32Encoder.h>

#define CLK 22 // CLK ENCODER
#define DT 23 // DT ENCODER

ESP32Encoder encoder;

void setup () {
  encoder.attachHalfQuad(DT, CLK);
  encoder.setCount(0);
  Serial.begin ( 115200 );
}

void loop () {
  long newPosition = encoder.getCount();
  Serial.println(newPosition);
  delay(25);
}

On obtient également dans le terminal série la valeur qui s’incrémente progressivement. Même si l’on mettait un délai de 500ms dans la loop() le compte sera quand même correct, car le comptage est entièrement fait par le périphérique hardware PCNT. La fonction getCount() ne fait que récupérer la valeur du registre du compteur matériel, qui lui compte dans son coin.

Note

Si vous avez malgré tout des pas qui sont manqués, vous pouvez activer la fonction setFilter() pour filtrer au maximum l’entrée du signal au niveau du compteur matériel (PCNT).

Il existe une documentation brute pour connaître les différentes fonctions de cette librairie.