Robot se repérant dans l’espace grâce à ses encodeurs

Robot se repérant dans l’espace grâce à ses encodeurs

Salut à tous c’est Vince574,

Je vous présenter mon premier tutoriel en tant qu’ambassadeur Conrad qui concerne la localisation précise du robot dans l’espace grâce à ses encodeurs sur le moteur.
Je vais vous expliquer les différentes étapes de fabrication, de mise en place de l’électronique et du développement software.

Le robot affichera sa position exacte dans une pièce grâce à un écran LCD qui indiquera sa position en X, Y et son angle de rotation.

  1. Voici une petite vidéo de démonstration du robot
  2. 1) La première étape consiste à fabriquer le robot. Pour cela j'ai usiné une plaque d'aluminium de 20 x 30cm. Il est nécessaire de réaliser les perçages aux bons endroits pour pouvoir placer les différents éléments sur la plaque qui sont : les moteurs et les roues, l'afficheur LCD, les billes de manutention, la batterie, la carte électronique et l'Arduino. Libre à vous de disposer les composants comme vous le désirez mais je vous joint le résultat sur mon robot.

    Les moteurs sont des moteurs 12V avec encodeur directement intégré.

    Pour les placements des roues j'ai réalisé une découpe pour que les roues ne dépassent pas trop du robot.

    Attention : Lorsque vous fixez les éléments, faites attention à ne pas réaliser un court circuit sur l'aluminium. Vous le remarquerez vite de toute manière ...
  3. 2) La deuxième étape consiste à réaliser le câblage entre les différents composants. Je ne vais pas refaire une explication du câblage du robot car c'est le même que celui dans mon ancien tutoriel dont voici le lien : https://makeitwithconrad.fr/tutoriel/robot-autonome-intelligent-controlable-par-bluetooth/

    Les seules différences sont les branchements de l'écran LCD que j'explique dans l'étape suivante et la câblage de l'encodeur du moteur.

    Voici une photo du robot câblé :

    Certes le câblage n'est pas beau mais je n'ai pas encore eu le temps de réaliser le "cable management" mais je le ferai à l'avenir pour avoir un résultat plus esthétique. Il est possible de mettre une coque de protection en faisant attention à laisser l'affichage de l'écran dépasser.
  4. 3) Voici le schéma de câblage de l'écran LCD :

    1 : Gnd
    2: +5V
    3 : Gnd ou Patte du milieu d'un potentiomètre 10k entre le 5V et la masse, cela permet de régler le contraste
    4 : Broche 12 Arduino
    5 : Gnd
    6 : Broche 11 Arduino
    7 à 10 : Ouvert
    11 : Broche 5 Arduino
    12 : Broche 4 Arduino
    13 : Broche 3 Arduino
    14 : Broche 2 Arduino
    15 : Broche 7 Arduino ou alim 5V avec une résistance de 220 Ohms (permet de régler le rétro éclairage)
    16 : Gnd


    Pour plus d'informations vous trouverez des tutoriels vidéos en ligne concernant l'écran LCD 16x2
  5. 4) Test de l'écran LCD. Avant d'aller plus loin il est nécessaire de tester la fonctionnalité de l'écran LCD.

    Voici le code permettant de le tester (il faut l'adapter si vous avez branché la pin 15 sur l'Arduino mais je vous conseille de laisser à 5V)


    #include

    LiquidCrystal lcd (12,11,5,4,3,2); // définition des pins de l'écran

    void setup () {
    lcd.begin(16,2); // taille de l'écran
    lcd.setCursor(5,0); // placement du message
    lcd.print("Message"); // texte à écrire
    }

    void loop () {
    }



  6. 5) L'étape suivante est le câblage des encodeurs moteurs. Il existe différents types d'encodeurs.

    Il est possible de les avoir directement intégrés sur le moteur ou de les placer sur une roue libre. En ce qui me concerne, ils sont directement sur le moteur et se câblent de la manière suivante :

    - les fils jaunes et blancs permettent de récupérer les signaux des encodeurs, ils vont sur la broche 2 et 3 de l'Arduino. Vous n'avez pas le choix car ce sont les seules entrées interruptions de l'Arduino Uno
    - les fils bleus (+5V) et verts (Gnd) sont l'alimentation +5V des encodeurs

    Voici une image d'un câblage sur un Arduino Mega

    Attention : Il est nécessaire de brancher les entrées de l'encodeur sur des entrées interruption
  7. 6) Il faut ensuite tester le bon fonctionnement des encodeurs moteurs

    Pour cela il faut connaître le nombre d'impulsions par tour. En ce qui me concerne c'est 1120 impulsions/tour de roue. Il est aussi nécessaire de connaitre le diamètre de la roue pour connaitre la distance parcourue.

    Voici le code commenté permettant de tester le fonctionnement des encodeurs :



    int codeurInterruptionA = 0; // nom interruption
    int codeurInterruptionB = 1;
    int codeurPinA = 2; // broche interruption
    int codeurPinB = 3;
    long ticksCodeur = 0;
    float distance = 0;




    void setup() {
    pinMode(codeurPinA, INPUT);
    pinMode(codeurPinB, INPUT);
    digitalWrite(codeurPinA, HIGH); // activation de la résistance de pullup
    digitalWrite(codeurPinB, HIGH); // activation de la résistance de pullup
    attachInterrupt(codeurInterruptionA, GestionInterruptionCodeurPinA, CHANGE);
    Serial.begin(9600);
    }

    void loop() {
    Serial.println(ticksCodeur);
    distance = (ticksCodeur/1120.0)*3.14*7.31; // calcul de la distance parcourue à l'aide du diamètre roue et du nombre d'impulsion. C'est à cette endroit qu'il faut mettre les bonnes valeurs
    Serial.println(distance);
    delay(1000);
    }

    void GestionInterruptionCodeurPinA(){
    if (digitalRead(codeurPinA) == digitalRead(codeurPinB)) {
    ticksCodeur--;
    }
    else {
    ticksCodeur++;
    }
    }



    Je vous joint une image des signaux transmis par les décodeurs. En effet, comme vous avez pu le remarquer dans le code le fonctionnement est simple.

    Nous nous calons sur un front montant d'un signal et lorsque les deux signaux ont la même valeur le nombre d'impulsion est décrémenté et lorsqu'ils sont différents le nombre d'impulsion est incrémenté.
  8. 7) Une fois ces deux éléments fonctionnels nous pouvons réaliser des applications de plus haut niveau.

    Le but du projet est de pouvoir localiser précisément le robot dans l'espace. Il faut donc connaître sa position en X et en Y.

    L'objectif est de partir d'un point de départ qui sera l'origine est de calculer le déplacement du robot. Je vais vous expliquer comment nous allons utiliser un encodeur pour déduire la position du robot.

    Nous allons utiliser les formules de trigonométrie et plus particulièrement le fameux théorème de Pythagore

    La position sur l'axe X va être déterminé de la manière suivante : posX = posX + déplacement*cos(angle)
    La position sur l'axe Y va être déterminé de la manière suivante : posY = posY + déplacement*sin(angle)

    Lorsque le robot va avancer en ligne droite la posX va s'incrémenter. Lorsque le robot va avancer perpendiculairement à la position de départ, c'est seulement la posY qui va s'incrémenter.

    Lorsque le robot avancera dans un autre angle les deux positions vont s'incrémenter.

    Mais comment calculons nous l'angle ?

    Il faut réaliser des essais pour connaitre le nombre d'impulsions en fonction de la position de rotation. Il est conseillé de prendre un grand nombre de tour sur lui même et relever le nombre d'impulsions pour avoir l'erreur la plus faible possible.

    Il est possible qu'il y ai des formules pour trouver la valeur exacte mais pour l'instant je n'ai pas eu le temps de faire des recherches dans ce domaine, je voulais d'avoir finaliser le projet même si le résultat sera un peu moins précis mais bon tout de même.

  9. 8) Je vous transmets donc l'algorithme que j'ai développé.

    Voici le code commenté en détail qui permet de mieux comprendre la situation et d'obtenir un robot fonctionnel qui indique sa localisation précise à chaque instant.

    Pour l'instant je demande au robot de réaliser des déplacements aléatoires en fonction du temps mais il est tout à fait possible d'utiliser une commande Bluetooth comme expliqué dans mon ancien tutoriel.

    Attention : Il est nécessaire de réaliser plusieurs adaptations comme la taille des roues et le nombre d'impulsions du codeur


    #include
    LiquidCrystal lcd (13,12,11,10,9,8);
    const int rd = 0; // définitions des pins pour chaque côté des roues
    const int rde = 7;
    const int rg = 4;
    const int rge = 1;
    const int vrd = 5;
    const int vrg = 6;
    int codeurInterruptionA = 0;
    int codeurInterruptionB = 1;
    int codeurPinA = 2;
    int codeurPinB = 3;
    long ticksCodeur = 0;
    long ticksCodeura = 0;
    float distance = 0;
    float a = 0; // déclaration des différentes variables utilisées par la suite
    float b = 0;
    float c= 0;
    int d =0;
    int x;
    int y;
    int k;
    float angle;
    int rot;
    int st;

    void setup() {
    lcd.begin(16,2);
    lcd.setCursor(0,0);
    lcd.print("X = ");
    lcd.setCursor(9,0);
    lcd.print("Y = ");
    lcd.setCursor(2,1);
    lcd.print("DEGRES = ");
    pinMode(rd, OUTPUT);
    pinMode(rde, OUTPUT);
    pinMode(rg, OUTPUT);
    pinMode(rge, OUTPUT);
    pinMode(vrd, OUTPUT);
    pinMode(vrg, OUTPUT);
    pinMode(codeurPinA, INPUT);
    pinMode(codeurPinB, INPUT);
    digitalWrite(codeurPinA, HIGH);
    digitalWrite(codeurPinB, HIGH);
    attachInterrupt(codeurInterruptionA, GestionInterruptionCodeurPinA, CHANGE);
    analogWrite(vrd, LOW);
    digitalWrite(vrg, LOW);
    digitalWrite(rd, HIGH);
    digitalWrite(rde, LOW);
    digitalWrite(rg, HIGH);
    digitalWrite(rge, LOW);
    }

    void loop() {
    delay(6000);
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("X = ");
    lcd.setCursor(9,0);
    lcd.print("Y = ");
    lcd.setCursor(2,1);
    lcd.print("DEGRES = ");

    if(d == 0){
    // définition du chemin à parcourir par le robot, bien sûr il peut aussi être commandé par Bluetooth

    delay(3000);

    }
    else if (d == 1){
    st =2;
    b=13; // offset pour la première mesure qui est décalé
    digitalWrite(rd, HIGH);
    digitalWrite(rde, LOW);
    digitalWrite(rg, HIGH);
    digitalWrite(rge, LOW);
    delay(100);
    digitalWrite(vrd, HIGH);
    digitalWrite(vrg, HIGH);
    delay(1000);
    digitalWrite(vrd, LOW);
    digitalWrite(vrg, LOW);
    }
    else if (d == 2){
    st =0;
    digitalWrite(rde, HIGH);
    digitalWrite(rd, LOW);
    digitalWrite(rg, HIGH);
    digitalWrite(rge, LOW);
    delay(100);
    digitalWrite(vrd, HIGH);
    digitalWrite(vrg, HIGH);
    delay(467);
    digitalWrite(vrd, LOW);
    digitalWrite(vrg, LOW);
    }
    else if (d == 3){
    st =2;
    digitalWrite(rd, HIGH);
    digitalWrite(rde, LOW);
    digitalWrite(rg, HIGH);
    digitalWrite(rge, LOW);
    delay(100);
    digitalWrite(vrd, HIGH);
    digitalWrite(vrg, HIGH);
    delay(1000);
    digitalWrite(vrd, LOW);
    digitalWrite(vrg, LOW);
    }
    else if (d == 4){
    st =1;
    digitalWrite(rd, HIGH);
    digitalWrite(rde, LOW);
    digitalWrite(rge, HIGH);
    digitalWrite(rg, LOW);
    delay(100);
    digitalWrite(vrd, HIGH);
    digitalWrite(vrg, HIGH);
    delay(700);
    digitalWrite(vrd, LOW);
    digitalWrite(vrg, LOW);
    }
    else if (d == 5){
    st =2;
    digitalWrite(rd, HIGH);
    digitalWrite(rde, LOW);
    digitalWrite(rg, HIGH);
    digitalWrite(rge, LOW);
    delay(100);
    digitalWrite(vrd, HIGH);
    digitalWrite(vrg, HIGH);
    delay(1100);
    digitalWrite(vrd, LOW);
    digitalWrite(vrg, LOW);
    }
    else {
    delay(1000);
    digitalWrite(vrd, LOW);
    digitalWrite(vrg, LOW);
    }
    delay(1000);

    d++;
    lcd.setCursor(11,1);
    lcd.print(k); // affichage de l'angle
    x = a;
    y = b;
    delay(100);
    lcd.setCursor(4,0);
    lcd.print(x); // affichage des positions X et Y
    lcd.setCursor(13,0);
    lcd.print(y);
    delay(2000);

    }

    void GestionInterruptionCodeurPinA(){ // calcul de la position si le robot recule
    if ((digitalRead(codeurPinA) == digitalRead(codeurPinB)) && st == 3){
    a = a - ((1/1120.0)*3.14*7.31)*sin(angle);
    b = b - ((1/1120.0)*3.14*7.31)*cos(angle);
    }

    else if ((digitalRead(codeurPinA) != digitalRead(codeurPinB)) && st ==2){ // calcul de la position si le robot avance
    a = a + ((1/1120.0)*3.14*7.31)*sin(angle);
    b = b + ((1/1120.0)*3.14*7.31)*cos(angle);
    }

    else if ((digitalRead(codeurPinA) != digitalRead(codeurPinB)) && st == 0){ // calcul de l'angle si le robot tourne dans le sens horaire
    c = c + ((1/1050.0)*90.0);
    k = c;
    k = k % 360;
    angle = (k*3.14)/180.0;
    }

    else if ((digitalRead(codeurPinA) == digitalRead(codeurPinB)) && st == 1){ // calcul de l'angle si le robot tourne dans le sens anti-horaire
    c = c - ((1/1050.0)*90.0);
    k = c;
    k = k % 360;
    angle = (k*3.14)/180.0;
    }

    }
  10. 9) N'hésitez pas à me soumettre vos remarques pour améliorer la localisation du robot. Je pense que c'est une bonne base pour avoir une localisation plus ou moins précise. Certes avec des calculs plus approfondies la localisation pourra être plus précise et grâce aux encodeurs qui disposent de grands nombres d'impulsions il est possible d'être précis au mm !

    A+ les amis !
Réalisé par
Posté le
Univers
Robotique & RC
Temps de fabrication
1 jour
Niveau de difficulté
Expert
Matériel(s)
1
Arduino
2
roues
2
moteurs brushless
1
Encodeur
1
PCB de prototypage
1
Afficheur LCD 1602
1
Batterie lipo 11.1V
1
Circuit intégré L293D (ou compatible)
Outils
1
Scie sauteuse
1
perceuse
1
Fer à souder

Aucun commentaire. Soyez le premier à en écrire un !

Vous devez être connecté pour laisser un commentaire.