Problème de Contrôle de Moteur Arduino avec Capteur Rotatif : Valeurs Erronées et Réglage de la Vitesse

Bonjour à tous,

Je suis novice en développement pour Arduino, et je bloque depuis quelques jours sur un problème de développement. Laissez-moi vous expliquer :

J'ai à ma disposition :

  • Un module de contrôle de moteur (shield) qui permet de contrôler deux moteurs standard.
  • Un capteur rotatif pour mesurer le déplacement d'un moteur.
  • Un Arduino Uno.

J'ai trouvé sur internet un bout de code qui me permet de mesurer le déplacement de mon moteur (nommé "updateEncoder").

Lorsque j'utilise ce programme seul et que je tourne manuellement l'arbre du moteur, je n'ai aucun problème, et je peux voir les valeurs s'incrémenter correctement sur mon moniteur série. Cependant, lorsque je couple ce bout de code au pilotage de mon moteur (le moteur A), les valeurs affichées sont incorrectes et fluctuent entre -1 et 0.

En outre, lorsque j'associe ce code au pilotage du moteur, je rencontre un autre problème : je ne peux utiliser le moteur qu'à pleine puissance (255). Si j'essaie de définir une valeur intermédiaire, le moteur ne se met pas en marche, alors que lorsque j'utilise uniquement le code de pilotage du moteur, je peux facilement ajuster la vitesse du moteur.

Auriez-vous des idées pour que je puisse obtenir des valeurs de mon capteur rotatif qui s'incrémentent tout en pouvant régler la vitesse de mon moteur ?

Merci à vous.

Voici le code de mon capteur rotatif :

#define outputA 3
#define outputB 4

volatile int counter = 0; 
int aState;
int aLastState;  

void setup() {
  pinMode(12, OUTPUT);
  pinMode(9, OUTPUT);

  pinMode(outputB, INPUT);
  aLastState = digitalRead(outputA);
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(outputA), updateEncoder, CHANGE);


}

void loop() {

}

void updateEncoder() {
  aState = digitalRead(outputA);
  if (aState != aLastState) {
    if (digitalRead(outputB) != aState) {
      counter++;
    } else {
      counter--;
    }
    Serial.print("Position: ");
    Serial.println(counter);
  }
  aLastState = aState;
}


Bonjour axellle1

Tu aurai avantage à utiliser une bibliothèque comme Encoder.h

Mets un lien sur ce shield.
Une possibilité de dysfonctionnements de ton programme est que le shield utilise des ports de l'Arduino que tu utilises également, d'où cause possible d'erreurs. Une fois le type de ta carte connu, on pourra voir ça.

La pin que tu utilises pour ça as t elle l'attribut PWM?
image
Le tilde à côté du numéro de port.

A+
Cordialement
jpbbricole


Merci pour votre réponse, jpbbricole.

Je vous joins une image de mon montage pour que vous ayez une meilleure idée de mon installation.

Pour ce qui est du modèle du shield, il s'agit du moteur shield de base de la marque Arduino, comme vous pouvez le voir sur la photo que j'ai jointe.

Normalement, je n'utilise pas le PIN 10.

Je vais vous montrer le code que j'utilise actuellement (qui ne fonctionne pas correctement lorsque j'ajoute le code du capteur rotatif).

#define outputA 3
#define outputB 4

int counter = 0;
int aState;
int aLastState;

int vitesse;
int moteur;
bool valeursRecues = false; // Variable pour indiquer si les valeurs ont été reçues

void setup() {
  pinMode(outputB, INPUT);
  aLastState = digitalRead(outputA);
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(outputA), updateEncoder, CHANGE);
  pinMode(12, OUTPUT);
  pinMode(9, OUTPUT);


  // Setup Channel A
  pinMode(12, OUTPUT); // Initiates Motor Channel A pin
  pinMode(9, OUTPUT);  // Initiates Brake Channel A pin

  // Setup Channel B
  pinMode(13, OUTPUT); // Initiates Motor Channel B pin
  pinMode(8, OUTPUT);  // Initiates Brake Channel B pin
}


void loop() {
 


  if (Serial.available() > 0) { // verifie qu'il y a des donnée dans le port serie
    int bymoteur = Serial.parseInt(); // recupére un entier qui correspond au comportement que l'on demande a un moteur (voir plus bas moteur)
    int byvitesse = Serial.parseInt(); // récupére les donnée qui son lié à la vitesse

    while (Serial.available() > 0) {  // boucle qui vide la memoire tempon serie
      Serial.read();
    }
    moteur = bymoteur;
    vitesse = byvitesse;






//condition qui verifie que les valeur saisie  son bien formater
    if (moteur >= 1 && moteur <= 12 && vitesse >= 0 && vitesse <= 255) {
      // Si les valeurs reçues sont valides
      valeursRecues = true; // Définis la variable à true lorsque les valeurs sont reçues
    } else {
      // Si les valeurs reçues ne sont pas valides
      valeursRecues = false; // Définis la variable à false pour éviter d'exécuter les commandes du moteur
    }
  }

  // Exécute les commandes de contrôle du moteur uniquement si les valeurs ont été reçues
  if (valeursRecues) {

    if (vitesse >= 0 && moteur > 0) {
     

        
      if (moteur == 1) { // si moteur = 1 le moteur 1 tournera dans le sens des éguille d'une montre

        digitalWrite(12, HIGH); // sens de rotation du moteur (12 = moteur 1 et high = direction sens des éguille d'une montre)
        digitalWrite(9, LOW);   // paramatrage frein moteur (9 = moteur 1 et low = sans frein )
        analogWrite(3, vitesse); // reglage de la vitesse (3 = moteur 1 et vitesse = la vitesse qui vas de 0 à 255)

      
      } else if (moteur == 2) { // si variable  "moteur" = 2 le moteur 1 tournera dans le inversse du sens des éguille d'une montre

        digitalWrite(12, LOW);  // sens de rotation du moteur (12 = moteur 1 et low = direction  inverse sens des éguille d'une montre)
        digitalWrite(9, LOW);   //  paramatrage frein moteur (9 = moteur 1 et low = sans frein )
        analogWrite(3, vitesse); // reglage de la vitesse (3 = moteur 1 et vitesse = la vitesse qui vas de 0 à 255)



      
      } else if (moteur == 11) { // si variable  "moteur" = 11 le moteur 2 tournera dans le sens des éguille d'une montre

        digitalWrite(13, HIGH); // sens de rotation du moteur (13 = moteur 2 et high = direction sens des éguille d'une montre)
        digitalWrite(8, LOW);   // paramatrage frein moteur (8 = moteur 2 et low = sans frein )
        analogWrite(11, vitesse); // reglage de la vitesse (11 = moteur 2 et vitesse = la vitesse qui vas de 0 à 255)

      } else if (moteur == 12) { // si variable "moteur" = 12 le moteur 2 tournera dans le inversse du sens des éguille d'une montre

        digitalWrite(13, LOW);  // sens de rotation du moteur (13 = moteur 2 et low = direction  inverse sens des éguille d'une montre)
        digitalWrite(8, LOW);   // paramatrage frein moteur (8 = moteur 2 et low = sans frein )
        analogWrite(11, vitesse); // reglage de la vitesse (11 = moteur 2 et vitesse = la vitesse qui vas de 0 à 255)

      } }else {
      // Arrêter le moteur
      digitalWrite(9, HIGH); //   paramatrage frein moteur (9 = moteur 1 et hight = avec frein )
      digitalWrite(8, HIGH); //   paramatrage frein moteur (8 = moteur 2 et hight = avec frein )

    }
  }
}

void updateEncoder() {
  aState = digitalRead(outputA);
  if (aState != aLastState) {
    if (digitalRead(outputB) != aState) {
      counter++;
    } else {
      counter--;
    }
    Serial.print("Position: ");
    Serial.println(counter);
  }
  aLastState = aState;
}

Ce code me permet d'envoyer des commandes au moteur par le port série, et j'aimerais qu'il me renvoie les informations du capteur rotatif pendant que le moteur A tourne...

Merci.

Bonjour axellle1

Peut être à cause de ce conflit à l'attribution des pin, tu écris la vitesse sur la même pin (3) que l'entrée A du codeur.

#define outputA 3
et
analogWrite(3, vitesse); // reglage de la vitesse ...

J'ai corrigé la pin A de l'encodeur selon:

Il n'est pas pratique d'utiliser les numéros de pin, directement, il est mieux de déclarer en début de programme, ces pin en leur attribuant un nom explicite.
Déclarer tout ça au début du programme te permet d'avoir une vue d'ensemble de tes attributions et, ainsi, éviter ce genre de conflits.

Je t'ai intégré Encoder.h, ainsi tu peux voir la facilité avec laquelle on peut lire un codeur rotatif, contrairement à la méthode "faite à la main" :wink:
J'ai laissé les lignes, devenues inutile, en remarque.

Le programme:

#include <Encoder.h>     // https://www.arduino.cc/reference/en/libraries/encoder/

#define encodeurPinA 2
#define encodeurPinB 4
Encoder encodeur(encodeurPinA, encodeurPinB);

int counter = 0;
int counterMemoire = 0;     // Pour mémoriser la précédente valeur
//int aState;
//int aLastState;

const int moteur1vitessePin = 3;   // Moteur 1 réglage de la vitesse
const int moteur2vitessePin = 11;   // Moteur 2 réglage de la vitesse

int vitesse;
int moteur;
bool valeursRecues = false; // Variable pour indiquer si les valeurs ont été reçues

void setup() {
	//pinMode(outputB, INPUT);
	//aLastState = digitalRead(encodeurPinA);
	Serial.begin(9600);
	
	encodeur.write(0);     // Mettre le compteur de l'encodeur à 0

	//attachInterrupt(digitalPinToInterrupt(encodeurPinA), updateEncoder, CHANGE);
	pinMode(12, OUTPUT);
	pinMode(9, OUTPUT);


	// Setup Channel A
	pinMode(12, OUTPUT); // Initiates Motor Channel A pin
	pinMode(9, OUTPUT);  // Initiates Brake Channel A pin

	// Setup Channel B
	pinMode(13, OUTPUT); // Initiates Motor Channel B pin
	pinMode(8, OUTPUT);  // Initiates Brake Channel B pin
}


void loop() {
	counter = encodeur.read();     // https://www.pjrc.com/teensy/td_libs_Encoder.html
	if (counter != counterMemoire)     // Si changement de valeur
	{
		Serial.println(counter);
		counterMemoire = counter;     // On mémorise la nouvelle valeur
	}

	if (Serial.available() > 0) { // verifie qu'il y a des donnée dans le port serie
		int bymoteur = Serial.parseInt(); // recupére un entier qui correspond au comportement que l'on demande a un moteur (voir plus bas moteur)
		int byvitesse = Serial.parseInt(); // récupére les donnée qui son lié à la vitesse

		while (Serial.available() > 0) {  // boucle qui vide la memoire tempon serie
			Serial.read();
		}
		moteur = bymoteur;
		vitesse = byvitesse;

		//condition qui verifie que les valeur saisie  son bien formater
		if (moteur >= 1 && moteur <= 12 && vitesse >= 0 && vitesse <= 255) {
			// Si les valeurs reçues sont valides
			valeursRecues = true; // Définis la variable à true lorsque les valeurs sont reçues
			} else {
			// Si les valeurs reçues ne sont pas valides
			valeursRecues = false; // Définis la variable à false pour éviter d'exécuter les commandes du moteur
		}
	}

	// Exécute les commandes de contrôle du moteur uniquement si les valeurs ont été reçues
	if (valeursRecues) {

		if (vitesse >= 0 && moteur > 0) {
			
			if (moteur == 1) { // si moteur = 1 le moteur 1 tournera dans le sens des éguille d'une montre

				digitalWrite(12, HIGH); // sens de rotation du moteur (12 = moteur 1 et high = direction sens des éguille d'une montre)
				digitalWrite(9, LOW);   // paramatrage frein moteur (9 = moteur 1 et low = sans frein )
				analogWrite(moteur1vitessePin, vitesse); // reglage de la vitesse (3 = moteur 1 et vitesse = la vitesse qui vas de 0 à 255)

				
				} else if (moteur == 2) { // si variable  "moteur" = 2 le moteur 1 tournera dans le inversse du sens des éguille d'une montre

				digitalWrite(12, LOW);  // sens de rotation du moteur (12 = moteur 1 et low = direction  inverse sens des éguille d'une montre)
				digitalWrite(9, LOW);   //  paramatrage frein moteur (9 = moteur 1 et low = sans frein )
				analogWrite(moteur1vitessePin, vitesse); // reglage de la vitesse (3 = moteur 1 et vitesse = la vitesse qui vas de 0 à 255)



				
				} else if (moteur == 11) { // si variable  "moteur" = 11 le moteur 2 tournera dans le sens des éguille d'une montre

				digitalWrite(13, HIGH); // sens de rotation du moteur (13 = moteur 2 et high = direction sens des éguille d'une montre)
				digitalWrite(8, LOW);   // paramatrage frein moteur (8 = moteur 2 et low = sans frein )
				analogWrite(moteur2vitessePin, vitesse); // reglage de la vitesse (11 = moteur 2 et vitesse = la vitesse qui vas de 0 à 255)

				} else if (moteur == 12) { // si variable "moteur" = 12 le moteur 2 tournera dans le inversse du sens des éguille d'une montre

				digitalWrite(13, LOW);  // sens de rotation du moteur (13 = moteur 2 et low = direction  inverse sens des éguille d'une montre)
				digitalWrite(8, LOW);   // paramatrage frein moteur (8 = moteur 2 et low = sans frein )
				analogWrite(moteur2vitessePin, vitesse); // reglage de la vitesse (11 = moteur 2 et vitesse = la vitesse qui vas de 0 à 255)

				} }else {
				// Arrêter le moteur
				digitalWrite(9, HIGH); //   paramatrage frein moteur (9 = moteur 1 et hight = avec frein )
				digitalWrite(8, HIGH); //   paramatrage frein moteur (8 = moteur 2 et hight = avec frein )

			}
		}
	}

	//void updateEncoder() {
	//aState = digitalRead(encodeurPinA);
	//if (aState != aLastState) {
	//if (digitalRead(outputB) != aState) {
	//counter++;
	//} else {
	//counter--;
	//}
	//Serial.print("Position: ");
	//Serial.println(counter);
	//}
	//aLastState = aState;
	//}

A ta disposition pour toutes questions.

Cordialement
jpbbricole

Avec le motor shield, ces broches sont imposées par le hardware du shield.
Tu ne peux pas les affecter à d'autres fonctions.

Function pins per Ch. A pins per Ch. B
Direction D12 D13
PWM D3 D11
Brake D9 D8
Current Sensing A0 A1

Pour que l'encodeur tourne bien, il vaut mieux que l'une des broches soit sur une entrée d'interruption. Il faudrait utiliser D2 pour ça.

Bonsoir fdufnews

C'est corrigé, merci.

Cordialement
jpbbricole

  • List item

La bonne nouvelle, c'est que maintenant je peux régler la vitesse du moteur A comme je le souhaite. Cependant, il y a un problème avec le code de la bibliothèque Encoder. Dans mon code d'origine, lorsque le moteur tourne dans le sens des aiguilles d'une montre, la variable 'counter' augmente, tandis que lorsque le moteur tourne à l'envers, 'counter' devrait normalement diminuer.

Avec le nouveau code que j'ai essayé, je n'obtiens qu'une valeur qui oscille entre 0 et 1. J'ai même essayé d'ajouter 'counter++', mais cela n'a pas résolu le problème.

Je ne suis pas sûr de la manière dont je peux aborder ce problème, même en consultant l'exemple sur le site de l'éditeur, car leur code semble très différent et encore plus complexe que le mien.t:

	//aState = digitalRead(encodeurPinA);
	//if (aState != aLastState) {
	//if (digitalRead(outputB) != aState) {
	//counter++;
	//} else {
	//counter--;
	//}
	//Serial.print("Position: ");
	//Serial.println(counter);
	//}
	//aLastState = aState;
	counter = encodeur.read();     // https://www.pjrc.com/teensy/td_libs_Encoder.html
	if (counter != counterMemoire)     // Si changement de valeur
	{
//counter++
		Serial.println(counter);
		counterMemoire = counter;     // On mémorise la nouvelle valeur
	}

@ jpbbricole

Votre code fonctionne à la perfection ! Je tiens à vous remercier chaleureusement pour votre aide. :slight_smile:

Je n'avais pas remarqué que vous aviez modifié la sortie (outputA) de 3 à 2, ce qui explique pourquoi le code ne renvoyait que des 0 et -1. Il manquait en effet un signal !

J'ai maintenant correctement branché sur le pin 2, et tout fonctionne parfaitement !

Un grand merci à vous deux pour toute l'assistance que vous m'avez apportée ! De plus, je suis maintenant plus informé sur les broches à éviter avec le motor shield.

Bonsoir axellle1

Super, bonne nouvelle :wink:

Bonne continuation.

Cordialement
jpbbricole

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.