Récupération informations encodeur

Bonjour

Pour un nouveau projet (boitier de calage distribution pour moteur thermique) je souhaite faire un envoie de données, mais je bloque à ce niveau.

Au stade actuel, j'envoie les valeurs de mon encodeur HENGSTLER à mon arduino, et donc également sur le moniteur série. Jusque ici tout va bien, cela fonctionne. je vois correctement les valeurs en degré, positive ou négative.

Maintenant j'aimerais ajouter à mon maquettage un écran LCD 16,2 et y inscrivant des valeurs bien particulières. Et je bloque à ce niveau.

Car j'aimerais envoyer à mon écran LCD le défilement automatique de mon moniteur série. Est-ce possible ? Je précise que je souhaite récupérer le défilement automatique du moniteur, et non ce que l'on peut écrire dans le moniteur.

Est-ce possible ?

Si non, comment récupérer l'information position de l'encodeur pour l'envoyer sur mon écran ?

Je précise que pour le moment, je fais mon maquettage avec écran LCD 16,2 par défaut. Car dans le futur ( et surtout lorsque je l'aurai reçu, je ferais un maquettage avec écran TFT LCD).

Dans l'attente de vos réponses Cordialement Fred

Bonjour à tous

Je vous montre mon code pour avoir des infos supplémentaires pour vous.

#define pinA 2 
#define pinB 3

int compteur = 0 ;
bool etatA ;
bool dernierEtatA ;

long unsigned tempsA ;

void setup() {
  
  pinMode(pinA,INPUT);
  pinMode(pinB,INPUT);
  Serial.begin (115200); 
  attachInterrupt(digitalPinToInterrupt(pinA), changementA, CHANGE); // on attache un interrupt sur le pinA, qui appelle la fonction changementA, avec une valeur de declenchement CHANGE 
  dernierEtatA = digitalRead(pinA); // Etat de A au setup  
  tempsA = millis();  // memorisation du temps pour eviter des erreurs de changements d'etat    
}

void loop() {
}

void changementA(){
  
  // on mesure A
  etatA = digitalRead(pinA);

    // controle du temps pour eviter des erreurs    
    if( abs(millis() - tempsA) > 50 ){ 
      // Si B different de l'ancien état de A alors
      if(digitalRead(pinB) != dernierEtatA){
        compteur--;
      }
      else{
        compteur++;
      } 
       // memorisation du temps pour A     
       tempsA = millis(); 
    } 
    // memorisation de l'état de A 
    dernierEtatA = etatA ; 
    
    Serial.print("degré vilo :"); //affichage du compteur
    Serial.println(compteur);
}

Et dans le moniteur série, j'obtiens ceci (il y a "rafraichissement" de la valeur à chaque changement de position de l'encodeur) :

|500x336

Rappel du souhait :

pouvoir inscrire cette valeur sur un écran type 16;2, et y faire le rafraichissement dès que la valeur change.

J'ai essayé plusieurs codes, mais sans succès

Merci d'avance pour votre aide.

Fred

Je reviens vers vous.

J’ai essayé un nouveau code, celui semble fonctionner. l’information codeur est bien envoyée sur la 2ème ligne de mon écran

Voici le code :

#define pinA 2 
#define pinB 3

#include <LiquidCrystal.h>
LiquidCrystal lcd(12,11,7,6,5,4);

int compteur = 0 ;
bool etatA ;
bool dernierEtatA ;

long unsigned tempsA ;

void setup() {

  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print("Degré vilo");
  
  pinMode(pinA,INPUT);
  pinMode(pinB,INPUT);
  Serial.begin (115200); 
  attachInterrupt(digitalPinToInterrupt(pinA), changementA, CHANGE); // on attache un interrupt sur le pinA, qui appelle la fonction changementA, avec une valeur de declenchement CHANGE 
  dernierEtatA = digitalRead(pinA); // Etat de A au setup  
  tempsA = millis();  // memorisation du temps pour eviter des erreurs de changements d'etat    
}

void loop() {
      // Ecran LCD --------------------------------------------------
  lcd.setCursor(0, 1);
  lcd.print(compteur);
  }

void changementA(){
  
  // on mesure A
  etatA = digitalRead(pinA);

    // controle du temps pour eviter des erreurs    
    if( abs(millis() - tempsA) > 50 ){ 
      // Si B different de l'ancien état de A alors
      if(digitalRead(pinB) != dernierEtatA){
        compteur--;
      }
      else{
        compteur++;
      } 
       // memorisation du temps pour A     
       tempsA = millis(); 
    } 
    // memorisation de l'état de A 
    dernierEtatA = etatA ; 
    
    Serial.print("degré vilo :"); //affichage du compteur
    Serial.println(compteur);

 }

Seulement, je remarqué une anomalie.

Souvent lorsque je passe d’une valeur positive à négative, ou de négative à positive, mon écran affiche la valeur du moniteur avec un coef multiplicateur *10 !
Ce n’est pas toujours dans ce cas précis, mais le problème survient souvent dans ce cas

par exemple :

Moniteur : -70
Ecran : -700

Moniteur : 340
Ecran : 3400

Des idées pour solutionner ce problème ?

Fred

Il faut formater les valeurs, regarde sprintf(), ou plutôt snprintf().

define SIZE 6

char buf; snprintf(buf, SIZE, "%04d", valeur);

Ensuite tu affiches buf.

Bonjour, Tu affiches des espaces derrière pour effacer les 0 qui peuvent rester.

lcd.print(compteur);
lcd.print("  ");

kamill: Bonjour, Tu affiches des espaces derrière pour effacer les 0 qui peuvent rester.

lcd.print(compteur);
lcd.print("  ");

Je viens de compléter mon code avec ta modif, et ça fonctionne ! Merci !!!

Je remarque par contre une chose, un tour complet d'encodeur ne relève pas 360°. Je ne trouve pas vraiment la datasheet du modèle (RI41-O/720AR.11KB)

Est-il possible de lui faire apprendre 360° / tour d'encodeur ?

Maintenant pour terminer la partie encodeur de mon projet, j'aimerais ajouter deux choses :

  • Borner le nombre maxi de degré lu. J'aimerais que l'arduino affiche jusqu'à 720°, et -720° et qu'une fois 720° franchit il reparte de 0° sans aucun délais (pour qu'il n'y ait pas de désynchronisation) J'ai lu sur un sujet qu'il était possible d'utiliser ceci : #define NB_IMP_ENC 10000.0 Mais sans succès

  • J'aimerais ajouter à mon maquettage un simple bouton qui permet de faire la remise à zero du compteur de degrés qu'importe la position de l'encodeur, en soit en toutes conditions.

J'ai également lu sur un autre sujet qu'il y a avait possibilité d'ajouter la fonction Void Raz mais l'article n'était pas complet à ce sujet. ( il faut que cette fonction de remise à zéro opère uniquement sur ce compteur de degré de l'encodeur, car pour la suite de mon projet, j'aurai d'autres choses à mettre dans mon code. Comme d'autre relevés de valeurs venant de 2 comparateurs digitaux)

Avez-vous une piste ou plusieurs pistes pour moi ?

Fred

Bonjour à tous

Voici quelques informations concernant mon encodeur, pour ceux qui peuvent m’apporter de l’aide

https://www.hengstler.de/en/s_c10030220i1606/RI41_Incremental_RI41-O/720AR.11KB/521408.html

Voila pour les quelques informations trouvé sur le site du constructeur de mon encodeur : HENGSTLER

modèle : RI41-O/720AR.11KB

Donc pour la partie câblage, j’ai l’ai fais de la manière suivante :

Channel A White → Pin 2
Channel B Green → Pin 3
Red → + 5V
Black → GND

Pour le nombre d’impulsion, il est donc correspondant à 720.
Comment déterminer le nombre de click par tour d’encodeur du coup ?

Commençons par là car actuellement je n’obtiens pas 360° au moniteur pour 1 tour d’encodeur. Mais plutôt dans les 1500/1600°

Bonjour,

Tu regardes le nombre de pulses par tour dans les spécifications de l'encodeur et tu fais une règle de trois.

Bonjour Kamill
Merci pour ta réponse et pour ton aide. C’est agréable d’avoir de l’aide comme cela pour un novice tel que moi.

J’aimerais comprendre le fonctionnement car j’ai beau regarder sur internet, je ne trouve pas d’explication suffisamment complète.
A moins que se soit moi qui ne soit pas très malin :smiley:
Mais clairement je ne connais pas le principe de fonctionnement de l’encodeur.

Je n’arrive pas à lier nombre de click et nombre de pulses.

Si mon encodeur est un 720 pulses, cela signifie t-il que mon encodeur est en 360 click / tr ?

Les valeurs jusqu’à présent obtenues dans le compteur de mon moniteur est en fait le nombre de pulse mesurées par l’encodeur et non les degrés de rotation encodeur ?

Bonjour Fredblock

de ce que je comprend du liens datasheet que tu as mis, ton encodeur a une résolution de 720 clock / tour!

en gros, il te mesure les demi dégrée, pour un tour!

si il t'affiche 1500/1600 pour un tour, y'a des chances que quelque part tu multiplies par deux dans ton programme:(hypothèse, car je ne vois pas où, tu le ferais...mais 720*2 =1440 donc valeur asse proche pour relever le hic!)

ta peut être aussi un phénomène de rebond qui te génère des impulsions que tu n'as pas!

ou eventuellement..un encodeur encore plus précis que ce que tu penses!

Pour lui "apprendre" je pense pas!! Pour que tu l’interprète, bas divise tes clock par deux dans le prog, ou adapte tes valeurs, genre 1tr = 720 clock! et toi tu print (clock/2)!

pour remettre a zero:

Void razEncoding(){

monCompteurDeClock =0; // remet a zero le compteur que tu incrémentes sur ton attachInterrupt }

tu appel la fonction razEncoding(); quand t'appui sur le bouton voulu!

have fun!

fredblock: Si mon encodeur est un 720 pulses, cela signifie t-il que mon encodeur est en 360 click / tr ?

Les valeurs jusqu'à présent obtenues dans le compteur de mon moniteur est en fait le nombre de pulse mesurées par l'encodeur et non les degrés de rotation encodeur ?

Oui si ton codeur est spécifié pour 720 pulses c'est 720 pulses par tour Tu peux calculer l'angle float angle=compteur/720.0*360;

Attention suivant que tu utilise RAISING ou CHANGE dans ton attachInterrupt tu peux avoir le double d'interruptions.

Kamill!!

bien vu!! voila qui explique la multiplication par 2!! d'ou les 1500/1600

le CHANGE!!

Je me douter d'un truc qu'il multiplier! ;) là tu lui sort une bien belle épine!!

Wah que de réponses :slight_smile:

Merci à vous

Tout d’abord, j’ai changé le CHANGE par RISING, et j’obtiens bien 720 pulses / tr
Pour le vérifier, je me suis imprimé un support pour disque gradué à mettre sur l’encodeur, et malgré la précision qui est plutôt moyenne, je lis 720 pulses pour environ 360°

En revanche, j’ai observé un phénomène avec ce changement, c’est l’inversion du sens de rotation.
En sens horaire mes valeurs devenaient négatives, et en sens anti-horraire positives.
J’ai inversé les pins 2 et 3 (channel A et B ) pour retrouver un sens que je jugeais correct.
Ce n’est certainement pas la manière la plus propre, mais ça fonctionne.
Point réglé, au moins ça progresse :wink:

Mais pour le reste, je suis encore plus perdu avec toutes les choses que j’ai essayées :roll_eyes:

Pour terminer la partie encodeur de mon projet, j’ai besoin de :

définir 360 ° / tr
de compter jusqu’à 720 ° et une fois 720 ° lu, repartir à 0 °
d’ajouter un code pour bouton de remise à zéro en toute condition.

J’ai essayé pas mal de chose, comme de définir max_pulse = 720° et le float angle=compteur/720.0*360.0;

et également essayé une condition if pour remettre le compteur à 0 si compteur==720

sans succès …

Si vous pouvez me donner encore un coup de papate

Je vous montre mon code actuel :

#define pinA 2 
#define pinB 3

#include <LiquidCrystal.h>
LiquidCrystal lcd(12,11,7,6,5,4);

int compteur = 0 ;
bool etatA ;
bool dernierEtatA ;

long unsigned tempsA ;

void setup() {

  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print("Degre vilo");
  
  pinMode(pinA,INPUT);
  pinMode(pinB,INPUT);
  Serial.begin (115200); 
  attachInterrupt(digitalPinToInterrupt(pinA), changementA, RISING ); // on attache un interrupt sur le pinA, qui appelle la fonction changementA, avec une valeur de declenchement RISING 
  dernierEtatA = digitalRead(pinA); // Etat de A au setup  
  tempsA = millis();  // memorisation du temps pour eviter des erreurs de changements d'etat  
 
}

void loop() {
  
   // Ecran LCD
  lcd.setCursor(0,1);
  lcd.print( compteur );
  lcd.print(" ");
  
  }

void changementA(){
  
  // on mesure A
  etatA = digitalRead(pinA);

    // controle du temps pour eviter des erreurs    
    if( abs(millis() - tempsA) > 0.5){ 
      // Si B different de l'ancien état de A alors
      if(digitalRead(pinB) != dernierEtatA){
        compteur--;
      }
      else{
        compteur++;
      } 
       // memorisation du temps pour A     
       tempsA = millis(); 
    } 
    // memorisation de l'état de A 
    dernierEtatA = etatA ; 
        
    Serial.print(" degre vilo : "); //affichage du compteur
    Serial.println( compteur );

 }

Fred

fredblock: Wah que de réponses :)

Merci à vous

Tout d'abord, j'ai changé le CHANGE par RISING, et j'obtiens bien 720 pulses / tr Pour le vérifier, je me suis imprimé un support pour disque gradué à mettre sur l'encodeur, et malgré la précision qui est plutôt moyenne, je lis 720 pulses pour environ 360°

En revanche, j'ai observé un phénomène avec ce changement, c'est l'inversion du sens de rotation. En sens horaire mes valeurs devenaient négatives, et en sens anti-horraire positives. J'ai inversé les pins 2 et 3 (channel A et B ) pour retrouver un sens que je jugeais correct. Ce n'est certainement pas la manière la plus propre, mais ça fonctionne. Point réglé, au moins ça progresse ;)

Mais pour le reste, je suis encore plus perdu avec toutes les choses que j'ai essayées :roll_eyes:

Pour terminer la partie encodeur de mon projet, j'ai besoin de :

définir 360 ° / tr de compter jusqu'à 720 ° et une fois 720 ° lu, repartir à 0 ° d'ajouter un code pour bouton de remise à zéro en toute condition.

J'ai essayé pas mal de chose, comme de définir max_pulse = 720° et le float angle=compteur/720.0*360.0;

et également essayé une condition if pour remettre le compteur à 0 si compteur==720

sans succès ...

Si vous pouvez me donner encore un coup de papate

Bonsoir Je n'ai pas bien compris ce que tu cherche exactement à faire 8) mais : si 720 pulses indiquent une course (rotation angulaire) de 360° en CW ou CCW (sens horaire ou anti-horaire) 1440 pulses indiquent donc une course de 720°

si tu veux faire une RAZ tout les 1440 pulses (soit exactement 2 rotations completes ) il te suffit de travailler en modulo 1440 et de faire la RAZ pour total_pulses %1440 =0

Hello :)

Alors j'essaye d'écrire ce code pour faire un boitier de calage de la distribution d'un moteur thermique 4 temps. Cette partie de code ( partie encodeur ) servira à connaitre la position angulaire du bas-moteur ( plus précisément la position angulaire du vilebrequin ).

Les extrêmes pour cette position doivent etre de 0° et de 720 °. ( Mini à 0°, et maxi à 720°, et donc pas de valeur négative) Car je dois pouvoir lire les valeurs exacts des positions angulaires situées entre 0 et 720°, soit 2 tours de vilebrequin, soit 2 x 360°. Une décimale serait également appréciable. A voir si c'est possible. Mais à tout moment je peux tourner dans le sens anti horaire ( donc au lieu de passer de 360° à 361°, et bien passer de 360° à 359 °.

Sauf que, au stade actuel de mon code, je ne lis que des impulsions (compris visiblement entre - infini et + infini ) Et non des degrés de rotation. J'imagine que pour obtenir des degrés sur mon écran au lieu du nombre d'impulsions, je dois définir le nombre d'impulsion / tr et écrire la conversion impulsion / degré Malgré de nombreux essais, je n'arrive pas à l'écrire.

Mais faire cette conversion n'est pas l'unique besoin manquant. Je dois également modifier mon code pour que mon ecran m'indique les valeurs entre et 0 et 720° autant dans le sens horraire que anti-horraire. J'imagine à nouveau qu'il faut que j'ajoute une condition de remise à zero lorsque les 720° sont atteint. Et dans le sens inverse (rotation en sens anti-horraire) lorsque le 0 est atteint, il reprendre sur 720 ° puis 719° puis 718° etc etc Mais une nouvelle fois je n'arrive pas à l'écrire :confused:

Voilà vous savez tout

fredblock:
Je dois également modifier mon code pour que mon ecran m’indique les valeurs entre et 0 et 720° autant dans le sens horraire que anti-horraire.
J’imagine à nouveau qu’il faut que j’ajoute une condition de remise à zero lorsque les 720° sont atteint.
Et dans le sens inverse (rotation en sens anti-horraire) lorsque le 0 est atteint, il reprendre sur 720 ° puis 719° puis 718° etc etc
Mais une nouvelle fois je n’arrive pas à l’écrire :confused:

Voilà vous savez tout

Bonjour
ton encodeur offre une resolution de 0.5° (360°/720 pulses )
regarde le code ci-dessous
Compile OK , pas testé
au reset/démarrage , c’est considéré comme point 0 (origine)
l’affichage devrait evoluer ensuite pour degrés entre -720 et +720 selon le sens de rotation (horaire ou anti-horaire)
une raz devrait intervenir pour exactement 2 tours complet de l’encodeur depuis le dernier point 0

#define pinA 2
#define pinB 3

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 7, 6, 5, 4);

int compteur = 0 ;
int modtour=0;
bool etatA ;
bool dernierEtatA ;

long unsigned tempsA ;

void setup() {

  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("RESET ORIGINE 0");
  delay(1000);
  pinMode(pinA, INPUT);
  pinMode(pinB, INPUT);
  Serial.begin (115200);
  attachInterrupt(digitalPinToInterrupt(pinA), changementA, RISING ); // on attache un interrupt sur le pinA, qui appelle la fonction changementA, avec une valeur de declenchement RISING
  dernierEtatA = digitalRead(pinA); // Etat de A au setup
  tempsA = millis();  // memorisation du temps pour eviter des erreurs de changements d'etat

}

void loop() {

  // Ecran LCD
  lcd.setCursor(0, 1);
  lcd.print( compteur / 2 ); // pour encodeur 720 pulses/tour  = resolution 1/2 ° amplitude -720 +720 
  lcd.print(" ");
 modtour= compteur % 1440; // modulo 1440 compteur

   if (modtour = 0) { // RAZ AUTO compteur pour 2 tours complets
      compteur = 0;
    }

}

void changementA() {

  // on mesure A
  etatA = digitalRead(pinA);

  // controle du temps pour eviter des erreurs
  if ( abs(millis() - tempsA) > 0.5) {
    // Si B different de l'ancien état de A alors
    if (digitalRead(pinB) != dernierEtatA) {
      compteur--;
    }
    else {
      compteur++;
    }
    // memorisation du temps pour A
    tempsA = millis();
  }
  // memorisation de l'état de A
  dernierEtatA = etatA ;

  // Serial.print(" degre vilo : "); //affichage du compteur
  // Serial.println( compteur );


}

Bonjour
ton encodeur offre une resolution de 0.5° (360°/720 pulses )
regarde le code ci-dessous
Compile OK , pas testé
au reset/démarrage , c’est considéré comme point 0 (origine)
l’affichage devrait evoluer ensuite pour degrés entre -720 et +720 selon le sens de rotation (horaire ou anti-horaire)
une raz devrait intervenir pour exactement 2 tours complet de l’encodeur depuis le dernier point 0

Hello :slight_smile:

Je viens de tester ta proposition, et la remise à zéro ne fonctionne pas. J’ai fais quelques ajustements (modification du print pour afficher " degré vilo " à l’écran, et au moniteur.
Mais la conversion 720 pulses en 360 ° fonctionne
on progresse :wink:

Voici le code actuel avec les quelques ajustements et une partie de la proposition que tu as faite (donc sans la partie RAZ car non opérationnelle :

#define pinA 2
#define pinB 3

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 7, 6, 5, 4);

int compteur = 0 ;
bool etatA ;
bool dernierEtatA ;

long unsigned tempsA ;

void setup() {
  
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("Degre vilo");

  pinMode(pinA, INPUT);
  pinMode(pinB, INPUT);
  Serial.begin (115200);
  attachInterrupt(digitalPinToInterrupt(pinA), changementA, RISING ); // on attache un interrupt sur le pinA, qui appelle la fonction changementA, avec une valeur de declenchement RISING
  dernierEtatA = digitalRead(pinA); // Etat de A au setup
  tempsA = millis();  // memorisation du temps pour eviter des erreurs de changements d'etat
}

void loop() {

  // Ecran LCD
  lcd.setCursor(0, 1);
  lcd.print( compteur / 2 ); // pour encodeur 720 pulses/tour, pour obtenir la valeur en ° -> 720/2
  lcd.print(" ");  
}

void changementA() {

  // on mesure A
  etatA = digitalRead(pinA);

  // controle du temps pour eviter des erreurs
  if ( abs(millis() - tempsA) > 0.05) {
    // Si B different de l'ancien état de A alors
    if (digitalRead(pinB) != dernierEtatA) {
      compteur--;
    }
    else {
      compteur++;
    }
    // memorisation du temps pour A
    tempsA = millis();
  }
  // memorisation de l'état de A
  dernierEtatA = etatA ;

  Serial.print(" degre vilo : "); //affichage du compteur en " degré vilo "
  Serial.println( compteur / 2 ); // toujours / 2 car encodeur 720 pulses / tr

}

Je dois également modifier mon code pour que mon ecran m’indique les valeurs entre et 0 et 720° autant dans le sens horraire que anti-horraire.
J’imagine à nouveau qu’il faut que j’ajoute une condition de remise à zero lorsque les 720° sont atteint.
Et dans le sens inverse (rotation en sens anti-horraire) lorsque le 0 est atteint, il reprendre sur 720 ° puis 719° puis 718° etc etc
Mais une nouvelle fois je n’arrive pas à l’écrire :confused:

Voilà vous savez tout

Ce n’est effectivement pas très clair si on lit uniquement cette partie, mais un peu plus haut dans mon ancien post, je dis que mes valeurs doivent se situer entre 0 et 720 °.
Je souhaite donc que ma plage de mesure soit de 0° à 720 °. Pas de valeurs négatives

fredblock: Hello :)

Je viens de tester ta proposition, et la remise à zéro ne fonctionne pas.

bourde classique :grin: == et pas = la portion de code doit etre

if (modtour == 0) { // RAZ AUTO compteur pour 2 tours complets
      compteur = 0;
    }

Ah les fautes de se genre .. un fléau ! :grin: J'en fais tellement, je ne suis pas assez vigilant et pas assez expérimenté pour les voir directement.

Puré t'es un génie ! ça fonctionne

Mais j'ai encore les valeurs négatives ( de - 1 ° à - 720 ° ) comment faire pour les supprimer ? car ma plage de mesure doit être entre 0 et + 720 °

En tout cas milles merci !!!

Essaies un truc du genre :

if(compteur >= 0)
{
compteur_positif = compteur ;
}

if(compteur <0)
{
compteur_positif = - compteur ;
}

Je suis pas matheux mais si j’ai bien compris ce que tu voulais et qu’Excel ne dit pas de bêtises , ça devrait te faire une dynamique pour compteur_positif qui va de 720_0_720 quand compteur va de -720_0_720 …