Robot Autonome avec moteurs a encodeur

Bonjour,

Pour un projet pour le lycée, je dois réalisé (on est 5 en tout) un robot autonome qui a pour but de suivre une trajectoire et ramasser des balles, dans le cadre de "Eurobot junior 2017".

Comme idée pour suivre une trajectoire est de lui "apprendre" un paterne a suivre grâce a des moteur avec encodeur, pour me permettre de lui "dire" de faire 1tour, 1,5 tour, 2,5tours et calculer la distance parcourue avec le périmètre de la roue.

J'ai déjà les moteurs en question, avec un carte pour contrôler l'alimentation des moteurs.
Je précise que je débute avec l'arduino :D.

Voici ce que j'ai

Je sais déjà contrôler les moteurs avec la carte L298N en PWM, le problème actuellement est que je ne sais pas comment récupérer les valeurs de l'encodeur pour m'en servir pour la position du moteur

J'ai déjà essayé d'utilisé une library pour l'encodeur et j'ai réussie a récupérer une valeur, mais assez imprécise, le moteur tournais mais de temps en temps la valeur montais, redescendais sans aucune raison et de temps en temps il montais sans problème

library : GitHub - PaulStoffregen/Encoder: Quadrature Encoder Library for Arduino

Malheureusement je n'ai pas le code sous la main actuellement (du moins le peu que j'ai), je sais comment fonctionne l'encodeur avec les signaux carrés pour déterminé le sens de rotation et la vitesse avec la fréquence.
La library ici utilise un moyen différent de attachInterrupt() même si j'ai encore du mal à cerner exactement ce que sais, j'ai compris qu'il permettais à l'arduino de faire autre chose que de récupérer les informations de l'encodeur.

Comment tout est branché et alimenté?

Donc Voilà une image de tout le branchement (Génial Fritzing btw)

Avec quel cables est relié à quoi d'après le datasheet du moteur

Et voilà le code que j'ai actuellement :
(Qui est une reprise du code pour un encoder simple pas d'un moteur)

int AVT=4; //IN3
int ARR=3; //IN4
int PWMB=10;
int val=0;
long oldPosition  = -999;
int encoder0PinA = 6;
int encoder0PinB = 5;
int encoder0Pos = 0;
int encoder0PinALast = LOW;
int n = LOW;

void setup() {
pinMode (AVT, OUTPUT);
pinMode (ARR, OUTPUT);

pinMode (encoder0PinA,INPUT);
pinMode (encoder0PinB,INPUT);

Serial.begin(9600);
Serial.println("Basic Encoder Test:");
}

void loop() {
   n = digitalRead(encoder0PinA);
   if ((encoder0PinALast == LOW) && (n == HIGH)) {
     if (digitalRead(encoder0PinB) == LOW) {
       encoder0Pos--;
     } else {
       encoder0Pos++;
     }
     Serial.print ("Position\n");
     Serial.println (encoder0Pos);
   } 
    if ( encoder0Pos < 40) {(val = 255);} else { (val=0); }
        encoder0PinALast = n;
   
digitalWrite(AVT, LOW);
digitalWrite (ARR, HIGH);  
analogWrite(PWMB, val );

/*delay(1000);
digitalWrite(AVT, HIGH);
digitalWrite (ARR, LOW);  
analogWrite(PWMB, 127 );
delay(1000);*/
}

Ou mettez vous n à jour ?

Passez aussi la console série à 115200 pas la peine de potentiellement tout ralentir (le timing est important avec des encodeurs) si vous saturez votre buffer série, l'appel a peint devient bloquant et vous allez rater des ticks (minimisez ce que vous imprimez)

On utilise souvent des interruptions pour gérer un encodeur de manière à ne pas trop dépendre de la loop()

Je met à jour "n" ici :

   n = digitalRead(encoder0PinA);

Ouai j'ai remarqué que le moteur overshotais quand je lui disais de s'arrêter a une certaine valeur, et il s'arrêtais ~30 + loin

Jpense que je vais ajouter un debug mode pour enlever les prints

J'ai vu qu'on utilisais souvent des interruptions, mais j'ai pas trop saisie comment cela fonctionnais et comment je pourrais l'utiliser ici :confused: Surtout que je veux pas uniquement contrôler que deux moteurs, mais aussi un servo moteur

Oops - vraiment il me faut mes lunettes :slight_smile:

Les interruptions ce sera sans doute mieux mais oui testez déjà sans les print (et passez quand même la console à 115200 ça ne fait pas de mal)

BON ! Sa fait longtemps que j'ai pas commenté et le Projet a beaucoup avancé ! J'ai découvert les fonctions et leurs utilités géniaux ! Bon le problème c'est que la fin d'année arrive et le Robot n'est absolument pas près coté mécanique ! Mais comme je m'occupe de la partir Programmation cela me tient à coeur de finir, et donc j'ai continué le code en repartant presque de zéro.

Les commentaires sont la pour expliquer d'ou viennent mes valeurs et mon principe de fonctionnement.
Je pense avoir fait un bon Programme, mais je rappelle que j'ai commencé Arduino et le language C il y a 2mois

Le problème avec le programme c'est que la variable "dist" n'est pas retourner dans tout le reste du programmes et donc aucun while ne peux être effectuer, et donc par extension je pense que la variable "fait" doit agir de même, pourtant je bien spécifié le return(dist); dans la fonction longueur. Et je confirme que NBimp fonctionne correctement car en l'imprimant elle est bien reset tout les 20Impulsions

Code :

unsigned int NBimp=0;
float dist=0;
const int PinA = 3;
int INMD1 = 7;  //Port contrôlant le sens du moteur DROIT
int INMD2 = 8;  //Idem
int INMG1 = 9;  //Port contrôlant le sens du moteur GAUCHE
int INMG2 = 10; //Idem
int PWMD = 11;      //Port contrôlant le Tension délivré au moteur DROIT
int PWMG;      //Port contrôlant le Tension délivré au moteur GAUCHE
int fait=1;

// ------------------------------------------------------------------
// INTERRUPTION     INTERRUPTION     INTERRUPTION     INTERRUPTION     INTERRUPTION 
// ------------------------------------------------------------------
void isr ()  {
      NBimp++ ; // Ajoute +1 à la variable NBimp, donc compte les impulsions de l'encodeur
    
    }


// ------------------------------------------------------------------
// SETUP    SETUP    SETUP    SETUP    SETUP    SETUP    SETUP    
// ------------------------------------------------------------------
void setup() {
  // Utile juste pour débugger (si besoin)
  Serial.begin(115200);

  // Les deux entrées de l'encodeur
  pinMode(PinA,INPUT);
  pinMode(INMD1,OUTPUT); //Controle direction moteur IN1 et IN2, soit 1 et 0 ou 0 et 1 pour définir le sens du moteur
  pinMode(INMD2,OUTPUT); // Pareil
  pinMode(INMG1,OUTPUT); // Pareil mais avec le deuxième moteur
  pinMode(INMG2,OUTPUT);
  pinMode(PWMD,OUTPUT);  //Valeur PWM Moteur Droit, pour définir la vitesse
  pinMode(PWMG,OUTPUT);  //Pareil mais avec le Gauche

  // Relie une pin de l'encodeur à l'interruption
  attachInterrupt(digitalPinToInterrupt(PinA), isr, FALLING);
  
  Serial.println("Start");
}
            
float longueur() {
  if (NBimp >= 20) {                      //Ici je compare NBimp avec 20 car j'ai calculé avec le périmètre de ma roue pour que j'ai une précision de 0,5cm car 20Imp=0,5cm
                    dist=dist+0,5;        //Ici la variable de distance ou on retrouve les 0,5cm
                    NBimp = 0;            //On reset NBimp
                   Serial.print(dist); 
                    return dist;
                   }
                }

void Direction(int dir) {  switch (dir) { //J'utilise une fonction plus un Switch pour évité de faire trop de fonction et de le rendre "opti"
                               case 1: // Direction Avant
                                 digitalWrite(INMD1,HIGH); digitalWrite(INMD2,LOW);
                                 digitalWrite(INMG1,HIGH); digitalWrite(INMG2,LOW);
                                 break;
                               case 2: // Direction Arrière
                                 digitalWrite(INMD1,LOW); digitalWrite(INMD2,HIGH);
                                 digitalWrite(INMG1,LOW); digitalWrite(INMG2,HIGH);
                                 break;
                               case 3: // 90° Avant Droit
                                 digitalWrite(INMD1,LOW); digitalWrite(INMD2,LOW);      //Moyen d'opti les quart de tours mais pas énormément grave
                                 digitalWrite(INMG1,HIGH); digitalWrite(INMG2,LOW);
                                 break;
                               case 4: // 90° Avant Gauche
                                 digitalWrite(INMD1,HIGH); digitalWrite(INMD2,LOW);
                                 digitalWrite(INMG1,LOW); digitalWrite(INMG2,LOW);
                                 break;
                               case 5: // 90° Arrière Droit
                                 digitalWrite(INMD1,LOW); digitalWrite(INMD2,HIGH);
                                 digitalWrite(INMG1,LOW); digitalWrite(INMG2,LOW);
                                 break;
                               case 6: // 90] Arrière Gauche 
                                 digitalWrite(INMD1,LOW); digitalWrite(INMD2,LOW);
                                 digitalWrite(INMG1,LOW); digitalWrite(INMG2,HIGH);
                                 break;                                                                                                
                               }
                    }
                    
void tout_droit(int nextdist) {Direction(1); //Set la Direction ici en l'occurence 1=Marche avant et sa on répète pour chaque fonction
                                      while(dist < nextdist) { //Compare la distance parcourue actuelle avec celle voulue entrée dans l'appelle de la fonction
                                         longueur();
                                         if(dist > nextdist*0.8) { //Ralenti de motié la vitesse une fois que 80% de la distance à été faite pour limité l'inertie du robot
                                                              analogWrite(PWMD,127); analogWrite(PWMG,127); }
                                                             else {
                                                              analogWrite(PWMD,255); analogWrite(PWMG,255); }
                                                          }
                                  analogWrite(PWMD,0); analogWrite(PWMG,0);
                                  dist = 0;         //reset la distance pour effectuer de nouvelles distances
                                  fait++;           //Ici c'est la variable pour spécifié au Switch du bas que on peux passer à l'instruction suivante
                               
}

void tout_arriere(int nextdist) { while(dist < nextdist) { 
                                         Direction(2);
                                         longueur();
                                         if(dist > nextdist*0.8) {
                                                              analogWrite(PWMD,127); analogWrite(PWMG,127); }
                                                             else {
                                                              analogWrite(PWMD,255); analogWrite(PWMG,255); }
                                                            }
                                  analogWrite(PWMD,0); analogWrite(PWMG,0);
                                  dist = 0;
                                  fait++;
                               
}

void quart_tour(int sens) { while(dist < 13,5) {  //13,5cm correspond a la distance angulaire qui a besoin d'être parcourue pour effectué 90° avec le robot avec la distance entre les deux roues
                                    Direction(sens);
                                    longueur();  // Appelle la fonction longueur pour lire la distance actuelle
                                         if(dist > 13,5*0.8) {
                                                              analogWrite(PWMD,127); analogWrite(PWMG,127);}
                                                             else {
                                                              analogWrite(PWMD,255); analogWrite(PWMG,255);
                                                             }
                                                            }  
                                  analogWrite(PWMD,0); analogWrite(PWMG,0);
                                  dist = 0;
                                  fait++;                                    
}
// ------------------------------------------------------------------
// LOOP        LOOP        LOOP        LOOP         LOOP
// ------------------------------------------------------------------
void loop() {
switch (fait) { //Ici on a les commandes que doit effectué le robot ce qui le rend modulable et permet d'ajouté des commandes à volonté
    case 1:
      { tout_droit(50); }
        break;
    case 2:
      { quart_tour(4); }
        break;
    case 3:
      { tout_droit(20); }
        break;
    case 4: 
      { quart_tour(3); }
        break;
      { tout_arriere(40); }
    case 5:
      { quart_tour(6); }
        break;
    case 6:
        break;
   }



}

Est ce que remplacer les if() dans tout_droit & tout arrière & quart_tour par des while() et balancer la fonction longueur() dans l'interruption serai pas une bonne idée ?