Problème lecture régime sur deux roues (double interruption)

Bonjour à tous,

Je suis en train de faire un petit robot à deux roues motrice et une roue folle.

J'ai passé pas mal de temps à réussir à mesurer un régime, asservir la vitesse en réglant la boucle d'asservissement. Tout fonctionne nickel je suis assez content. Et maintenant je viens de passer l'après midi à optimiser ce code pour pouvoir l'utiliser sur deux moteurs....et ça ne marche pas.

Après une rapide investigation, je me suis rendu compte que c'est parce que je ne mesurais pas correctement le régime de mes roues. Après investigation (rapide) encore, je me suis rendu compte que l'Arduino me renvoyait presque uniquement que les changements d'états sur un seul moteur. D'où un calcul de régime erroné.

Pour plus de clarté, voici le code que j'ai utilisé pour isoler mon problème :

const int RPWM_Output_G = 5;
const int LPWM_Output_G = 6;
const int RPWM_Output_D = 7;
const int LPWM_Output_D = 8;

const byte encodeur_moteur[] = {2, 3};//Pin interruption de l'Arduino MEGA

volatile int compteur[2] = {0, 0};


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


  //Définition des sorties
  pinMode(RPWM_Output_G, OUTPUT);
  pinMode(LPWM_Output_G, OUTPUT);
  pinMode(RPWM_Output_D, OUTPUT);
  pinMode(LPWM_Output_D, OUTPUT);


  //Pullup de l'Arduino
  for (byte i = 0; i <= 1; i++)
  {
    pinMode(encodeur_moteur[i], INPUT_PULLUP);
  }

  attachInterrupt(digitalPinToInterrupt(encodeur_moteur[0]), interruption_moteur_G, CHANGE);
  attachInterrupt(digitalPinToInterrupt(encodeur_moteur[1]), interruption_moteur_D, CHANGE);

}

void loop() {

  //Je fais tourner mes deux moteurs
  analogWrite(LPWM_Output_G, 20);
  analogWrite(RPWM_Output_G, 0);

  analogWrite(LPWM_Output_D, 20);
  analogWrite(RPWM_Output_D, 0);
}

//A partir de là mes deux fonctions d'interruption
void interruption_moteur_G()
{
  compteur[0] = compteur[0]++;
  Serial.println("M0");
}

void interruption_moteur_D()
{
  compteur[1] = compteur[1]++;
  Serial.println("M1");
}

Le retour sur le port série est :

M-
M-
M++
M-
M++
M-
M++
M-
M++
M-
M++
M-
M++
M-
M++
M-
M++
M-
M++
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-
M-

Donc je "vois" bien les top sur les deux roues au début et presque immédiatement ensuite tout disparaît.

Evidemment, si je supprime cette ligne

  attachInterrupt(digitalPinToInterrupt(encodeur_moteur[0]), interruption_moteur_G, CHANGE);

Je ne vois que

M++

Et l'inverse est vrai.

J'en fais donc appel à vos compétences et votre expérience. Spontanément je dirais que c'est parce que l'Arduino MEGA ne calcule pas assez vite et en conséquence quand une première interruption est en cours, impossible de voir la seconde, mais je suis surpris car je peux faire tourner un seul moteur bien plus vite (consigne commande 512) sans avoir le moindre problème.

Du coup je ne comprends pas vraiment...

D'avance merci pour votre/vos retour(s)!

hello
un lien sur tes moteurs ? (et codeurs s'ils sont séparés ?)

Oui bien sûr : Pololu - 131:1 Metal Gearmotor 37Dx73L mm 12V with 64 CPR Encoder (Helical Pinion)

Pour info je cherche toujours en parallèle, j'ai 16 impulsions par tour, soit 32 changements d'état, soit avec un ratio de 131.25 - 4200 tops par tour, soit 2100 impulsions par secondes à 30 tours/minutes.

2,1kHz ça me semble peu au regard des 16MHz de la Mega... Je ne comprends pas ça devrait fonctionner...mais preuve en est, c'est le contraire!

Edit : j'ai également essayé d'inverser les broches 2 et 3. La 2 reste bien prioritaire, c'est toujours celle là qui prends le dessus.

Bonjour,

Les traitement d'interruptions devraient être le plus courts possible et ne devraient pas utiliser de fonction utilisant aussi les interruptions. En particulier on ne devrait pas faire de Serial.print() en interruption.
Cependant, il faut bien reconnaitre que quelquefois c'est bien pratique pour débugger. Dans ce cas il faut afficher des messages le plus court possible et avec un baudrate le plus haut possible.
Paramètres la transmission à 115200 bds avec Serial.begin(115200)

Merci Kamil.

En parralèle j'ai cherché aussi de mon ^coté et suis arrivé à la même conclusion, du coup j'ai fait différemment mais pour arriver au final au même résultat :

Je me suis donc dit que c'était peut-être la commande sur le port série qui mettait le bazar dans l’interruption, car longue à exécuter comme tu dis.

J'ai donc utilisé ce programme, en gros j'ai rajouté un timer qui affiche les deux compteurs chaque seconde puis les remet à 0 :

#include <SimpleTimer.h>
SimpleTimer timer;

const int RPWM_Output_G = 5;
const int LPWM_Output_G = 6;
const int RPWM_Output_D = 7;
const int LPWM_Output_D = 8;

const byte encodeur_moteur[] = {3, 2}; //Pin interruption de l'Arduino MEGA


int compteur_g = 0;
int compteur_d = 0;


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


  //Définition des sorties
  pinMode(RPWM_Output_G, OUTPUT);
  pinMode(LPWM_Output_G, OUTPUT);
  pinMode(RPWM_Output_D, OUTPUT);
  pinMode(LPWM_Output_D, OUTPUT);


  //Pullup de l'Arduino
  for (byte i = 0; i <= 1; i++)
  {
    pinMode(encodeur_moteur[i], INPUT_PULLUP);
  }

  attachInterrupt(digitalPinToInterrupt(encodeur_moteur[1]), interruption_moteur_D, CHANGE);
  attachInterrupt(digitalPinToInterrupt(encodeur_moteur[0]), interruption_moteur_G, CHANGE);

  timer.setInterval(1000, serial);

}

void loop() {
  timer.run();
  //Je fais tourner mes deux moteurs
  analogWrite(LPWM_Output_G, 510);
  analogWrite(RPWM_Output_G, 0);

  analogWrite(LPWM_Output_D, 510);
  analogWrite(RPWM_Output_D, 0);


}

//A partir de là mes deux fonctions d'interruption
void interruption_moteur_G()
{
  compteur_g = compteur_g+1;
}

void interruption_moteur_D()
{
  compteur_d = compteur_d+1;
}

void serial()
{
  Serial.print(millis());
  Serial.print  ("\t");
  Serial.print  (compteur_g);
  Serial.print  ("\t");
  Serial.println  (compteur_d);
  compteur_d = 0;
  compteur_g = 0;
}

Le résultat :

1000 3507 3639
2000 4311 4500
3000 4316 4507
4000 4320 4511
5000 4321 4510
6000 4325 4515
7000 4326 4514
8000 4347 4518
9000 4346 4522
10000 4329 4518
11000 4332 4521
12000 4338 4519
13000 4357 4529

En gros, ça fonctionne. Il y a des petits écarts mais c'est normal les moteurs ne sont pas asservis en régime je met juste du courant dedans.

Donc c'est pas un problème de puissance de la MEGA, je suis rassuré. Mais mon programme de base ne fonctionne toujours pas.

Je vous tiens au courant.

Me revoilà.

En fait le problème dans mon "gros" programme était bien un problème de communication via le port série. En effet, pour des questions de debug et autre, j'avais une multitude de données qui partait via le port et je suppose que ça encombrait considérablement la carte et entrainait un mauvais comportement de mon programme.

Donc c'est résolu! Par contre je vais devoir être vigilant à l'avenir avec ça car je n'en suis qu'au tout début de mon programme! On verra bien.

Merci à vous et désolé du dérangement.

Configures ta liaison à 115200 bds. Ça perturbera déjà moins le programme.

Ok ça marche je vais faire les deux ce n'est pas con! Merci!!!!