Go Down

Topic: Lire une roue codeuse (Read 3133 times) previous topic - next topic

Jean-François

Mar 11, 2009, 08:23 pm Last Edit: Mar 11, 2009, 08:24 pm by jfs Reason: 1
Bonsoir,

j'ai un moteur sur lequel est montée une roue codeuse et un fourche optique.
Le disque comporte 504 positions.

J'ai essayé de lire cet encodeur lors de la rotation de mon moteur, probablement vers les 100-200 t/min.

Dans les codes que j'ai essayés, j'incrémente de 1 une variable à chaque "top".

En lisant le signal directement sur une pin digital, j'ai environ 50 à 100 fois moins d'incrément que de "top" (même en tournant mon moteur à la main)

Pour un tour, je me retrouve avec une valeur de 74, 3-4 tours me donnent environ 200.

Code: [Select]


int codepin = 4;
int encoderpos = 0;

volatile int state = 0;

void setup()
{
 Serial.begin (19200);
}


void loop()
{
      digitalWrite(codepin,!state);
      if (digitalRead(codepin)==state)
{
      encoderpos++;
      state = !state;
}

 Serial.println (encoderpos,DEC);
}




Avec la fonction attachInterrupt(), j'ai des valeurs qui semblent correctes lorsque je tourne le moteur à la main, mais rotation rapide (c'est relatif environ 100-200 t/min), les valeurs retournées par le moniteur série sont espacées de plusieurs incréments (environ une centaines) et ces espaces sont variables.

Code: [Select]

int encoderpos = 0;

void setup()
{
 Serial.begin (19200);
 attachInterrupt(0,interrupt,RISING);
}

void loop()
{
 Serial.println (encoderpos,DEC);
}

void interrupt()
{
      encoderpos++;
}


Est-ce l'Arduino arrive a lire chaque top de mon disque ?

Les valeurs lisibles sur le moniteur série sont elles "décalées" par une latence de la liaison ?

J'aimerais pouvoir lire la position physique et temporelle de mon disque, est-ce possible avec l'Arduino ou faudrait-il passer par un autre CI pour cela ?

Merci pour vos réponses.
MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Luj06

Quel est le diamètre de ta roue ? C'est nécessaire pour savoir combien de µs sépare chacun des fronts montants.

Jean-François

#2
Mar 11, 2009, 08:42 pm Last Edit: Mar 11, 2009, 08:48 pm by jfs Reason: 1

Le disque fait 37 mm de diamètre.

A 60 t/min il devrait y avoir un top toutes les 2 ms ?
MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Luj06

J'ai trouvé le problème : tu utilises un "int" pour stocker la valeur, donc un entier entre 0 et 256. Comme tu es à 2-3 tours par seconde, à 504 ticks d'encodeurs, tu dépasses la capacité du int 6 fois par seconde :)

Il faut que tu utilises un "long", tout simplement.



Jean-François

#4
Mar 11, 2009, 10:39 pm Last Edit: Mar 11, 2009, 10:49 pm by jfs Reason: 1
J'avais déjà essayé avec un "long", mais dans le doute j'ai refait un essai :

- les valeurs retournées ne sont pas cohérentes et sont parfois affichées avec des lettres ou des signes.

Dans les references (extended) il est indiqué que les variables doivent être déclarées "volatile".

Seul le "int" fonctionne et m'affiche des valeurs entre approximativement  -32'800 et 32'800.

J'ai essayer en changeant le Baudrate, ça devient effectivement plus précis, à 57600 j'ai une perte d'affichage de 18 top et cela de façon régulière, j'ai l'impression que tous mes tops sont lus, mais que le temps nécessaire à la liaison série me fait "sauter" l'affichage de 18 tops (qui sont tout de même comptabilisés).
Par contre à 57600 et plus, la liaison est peu fiable et lorsqu'elle se "perd" j'ai un panic-Kernel et je dois rebooter mon ordi  :(

Donc il faut une solution qui me permette de faire une liaison avec un baudrate plus bas.
MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Luj06

Oui tu as raison, le "int" est suffisant, car Arduino utilise 2 octets (32767 exactement) contrairement au "int" d'AVR-GCC, j'ai confondu :)

J'ai enfin compris. Tu voudrais recevoir toutes les valeurs sur la liaison série ! en tout cas avec le code que tu as écrit, je confirme que l'Arduino compte bien, c'est juste que la liaison série n'a pas le temps de t'envoyer la valeur qu'il y a déjà une interruption. Dans ce cas là, il faut faire une interpolation du côté du receveur, par exemple estimer la vitesse à partir des 2 dernières réceptions, en déduire quand les 18 tops manquant vont arriver, et s'il y a eu un changement entre 2 réceptions, rectifier le coup suivant.

Jean-François

#6
Mar 11, 2009, 11:29 pm Last Edit: Mar 11, 2009, 11:31 pm by jfs Reason: 1

Cela corrobore ce que je pensais.

Je vais essayer d'avancer avec ça (pour l'interpolation je sens que je vais encore faire quelques nuits blanches  ;D ).

Merci pour tes réponses.  ;)
MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Luj06

Ok, je ferai des mesures de ton code à l'analyseur logique pour mesurer combien de temps entre deux envois sur la liaison série.

Jean-François

#8
Mar 12, 2009, 02:04 pm Last Edit: Mar 12, 2009, 08:59 pm by jfs Reason: 1
Merci, c'est très sympa de ta part.

De mon coté j'ai continué ma prospection, voici le code que j'ai actuellement :

Code: [Select]

volatile int encoderpos = 0;
int index = 0;
int senspin= 7;
unsigned long oldTime = 0;
volatile int rpmcount = 0;
unsigned int rpm = 0;

void setup()
{
 Serial.begin (38400);
 
}


void loop()
{

//if (rpmcount>=20)

rpm = 120/(millis() - oldTime)*rpmcount;
oldTime = millis();
rpmcount=0;

if (digitalRead(senspin) == 1){
  detachInterrupt(0);
  attachInterrupt(0,interrupt1,CHANGE);
 if (encoderpos >= 25200){encoderpos=0;index++;}
 
}
else if (digitalRead(senspin) == 0){
  detachInterrupt(1);
  attachInterrupt(0,interrupt0,CHANGE);
  if (encoderpos<=-25200){encoderpos=0;index--;}
 
}
 
 
 Serial.print ("   time ");
 Serial.print (millis(),DEC);
 Serial.print ("   rpm ");
 Serial.print(rpm,DEC);
 Serial.print ("   pos ");
 Serial.print (encoderpos,DEC);
 Serial.print ("   index ");
 Serial.println (index,DEC);
 
}


void interrupt1()
{
      encoderpos++;
      rpmcount++;    
}


void interrupt0()
{
      encoderpos--;
      rpmcount++;
}


Mon moteur est branché sur un autre Arduino avec un motor shield et une manette Nunchuck cette carte me renvoi 1 ou 0 pour indiquer le sens de rotation, je récupère cette info sur la pin D7.

Ensuite je ne vais pas expliquer la fonction attachinterrupt() ...  ;)
que je détache et attache suivant le sens de rotation, ainsi j'incrémente ou décremente mes tics.

La fonction millis() me sert a déterminer le temps depuis le début du process ainsi qaue pour le calcul des rpm moteur (attachinterrupt() également).

en utilisant des "int" je suis limité  à 32768, comme ce n'est pas un multiple de 504, je m'arrête à 25200 (50 rotations) et j'incrémente ou décrémente un index qui m'indique chaque "lot" de 50 rotations.
Avec un "unsigned" je pourrais m'arrêter à 50400 (100 rotations), mais aprés je n'arrive pas à décrémenter en négatif.

Je suppose que lors du passage 25200 à 0 je pers quelques tic ...  :-?, mais pour l'instant je ne sais pas faire mieux  ::)
MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Luj06

Il y a une erreur dans "detachInterrupt(1)" : 1 à la place de 0.

Le detachInterrupt n'est pas nécessaire quand tu fais un attachInterrupt derrière. Et pourquoi ne pas faire le test du sens dans l'interruption, puisque c'est la liaison série qui est lente, il ne faut pas surcharger la boucle avec des changements d'interruptions.

Jean-François

En fait j'ai fait des test en mettant le traitement du sens dans attachInterrupt(), ça me donne un affichage complètement chaotique et au bout d'un moment la liaison série plante.


Je ferai un essai sans les "detachInterrupt()".
MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Jean-François

Effectivement les "detachInterrupt()" ne sont pas nécessaire.

Merci Luj06.   ;)
MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Luj06

De rien, car je ne sais pas si ça a pu améliorer le temps de traitement.

Pour comparaison, voici mon code:

Code: [Select]

#include <Servo.h>

Servo servL;
Servo servR;

int consigneLeft = 0;
long counterLeft = 0;

int consigneRight = 0;
long counterRight = 0;


void setup() {
 // init serial communication
 Serial.begin(38400);
 //  
 servL.attach(10);
 servR.attach(9);
 //
 pinMode(3,INPUT);  
 attachInterrupt(1, interruptRight, CHANGE);
 //
 consigneLeft = 1;
 consigneRight = 1;
}

void loop() {
 //
 if (consigneLeft > 0)
 {
   servL.write(0);
   if (counterRight > 600) {
     consigneLeft = -1;  
   }
 }
 //
 if (consigneLeft < 0)
 {
   servL.write(255);
   if (counterRight < 400) {
     consigneLeft = 1;  
   }
 }  
 //
 if (consigneRight > 0)
 {
   servR.write(255);
   if (counterRight > 600) {
     consigneRight = -1;  
   }
 }
 //
 if (consigneRight < 0)
 {
   servR.write(0);
   if (counterRight < 400) {
     consigneRight = 1;  
   }
 }  

 //
 int val = (int) counterRight;
 //  
 Serial.print( 0xff, BYTE);
 Serial.print( (val >> 8) & 0xff, BYTE);
 Serial.print( val & 0xff, BYTE);

}

void interruptRight()
{
 if (consigneRight > 0)
 {
   counterRight++;
 }
 else {
   counterRight--;    
 }
}


Archive dispo en fin d'article : tu verras que de l'autre côté de la liaison série, on visualise une ligne très régulière.

Jean-François

#13
Mar 15, 2009, 12:40 am Last Edit: Mar 15, 2009, 01:00 am by jfs Reason: 1
Merci pour le lien vers cet article (que j'avais déjà consulté  ;) ), tu me conseillerai d'utiliser un AOP ?

Par contre les roues utilisées dans cet article ont moins de tic que la mienne, je pense que ça a une énorme influence dans les résultats que j'obtiens (trop de précisions nuit à la vitesse de traitement).
MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Luj06

Pas forcément, ça dépend le signal que sort ta fourche optique : tu as sa référence ?

Go Up