Go Down

Topic: encoder in quadratura (Read 2886 times) previous topic - next topic

max00

#30
Sep 20, 2012, 01:48 am Last Edit: Sep 20, 2012, 11:16 am by max00 Reason: 1
mi potresti dire come hai fatto e la logica cosi potrei riuscire a fare la retroazione in posizione

astrobeed


Non è vero, per un'applicazione che ho sviluppato a lavoro sono riuscito a leggere un encoder in quadratura da 500 imp/giro a circa 25rpm dell'albero, quindi ad una frequenza di 12KHz per canale. Ovviamente c'è da scordarsi le digitalRead nel gestore di interrupt, troppo lente.


Si però per gestire 24000 interrupt al secondo (12000 * 2) con l'ATmega 328 non riesci a fare altro,  per gli encoder con segnali che arrivano ad elevate frequenze tocca usare gli appositi IC oppure micro dotati dell'apposito modulo hardware.
Comunque 500 cpr in quadratura diventano 2000 ppr che a 25 rpm sono solo 833 Hz per canale, valore gestibile con Arduino anche se siamo al limite se vuoi fare pure altre cose.

Quote

Inoltre, rispondendo ad un post successivo, i micromotors li utilizziamo anche a lavoro e sono con due fasi, non con una.


Micromotors i motori te li fornisce come ti pare, ovvero senza encoder, con encoder a una fase o due fasi, tutti a bassa risoluzione, se non mi ricordo male il massimo che offrono loro sono 25 cpr, poi quelle che trovi in giro su i vari store è un altro paio di maniche.

astrobeed


mi potresti dire come hai fatto e la logica cosi potrei riuscire a fare la retroazione in posizione


Devi implementare un pid per il controllo della posizione.

Janos

#33
Sep 20, 2012, 02:15 pm Last Edit: Sep 20, 2012, 02:18 pm by Janos Reason: 1
@astro
perché solo 833Hz per canale? Comunque con tutti quegli interrupt, oltre al programma, ho un tempo ciclo di circa 150us, valore che acquisisco con la funzione micros() ad ogni inizio del loop.

@max
Code: [Select]
#define encInterrA 0
#define encInterrB 1
#define encA 2
#define encB 3

volatile unsigned long contEnc = 0; //Valore del conteggio dell'encoder

void encoderA() {
 unsigned char i = PINE;                   //Leggo il valore di PINE
 unsigned char a = i & (1 << PE4);         //Maschero gli altri bit per isolare quello corrisp. alla fase A
 unsigned char b = i & (1 << PE5);         //Maschero gli altri bit per isolare quello corrisp. alla fase B
 if (a == (1 << PE4)) {                    //Se A è alto
   if (b == 0) contEnc++;                  //e B è basso incrementa
   else contEnc--;                         //altrimenti decrementa
 }
 else {                                    //Se A è basso
   if (b == (1 << PE5)) contEnc++;         //e B è alto incrementa
   else contEnc--;                         //Altrimenti decrementa
 }
};

void encoderB() {
 unsigned char i = PINE;                   //Leggo il valore di PINE
 unsigned char a = i & (1 << PE4);         //Maschero gli altri bit per isolare quello corrisp. alla fase A
 unsigned char b = i & (1 << PE5);         //Maschero gli altri bit per isolare quello corrisp. alla fase B
 if (b == (1 << PE5)) {                    //Se B è alto
   if (a == (1 << PE4)) contEnc++;         //e A è alto incrementa
   else contEnc--;                         //altrimenti decrementa
 }
 else {                                    //Se B è basso
   if (a == 0) contEnc++;                  //e A è basso incrementa
   else contEnc--;                         //Altrimenti decrementa
 }
};

void setup() {
 digitalWrite(encA, HIGH);                           //Attivo i pullup degli ingressi dell'encoder
 digitalWrite(encB, HIGH);                           //Attivo i pullup degli ingressi dell'encoder
 attachInterrupt(encInterrA, encoderA, CHANGE);      //Attivo il gestore di interrupt per gli ingressi dell'encoder
 attachInterrupt(encInterrB, encoderB, CHANGE);      //Attivo il gestore di interrupt per gli ingressi dell'encoder
}


Considera che ho utilizzato un encoder con uscite npn, quindi ho attivato le resistenze di pullup interne. Queste, però, a 20KHz sono troppo grandi e quindi ne ho messe altre due esterne di valore più piccolo.
P.S. Questo codice è stato scritto per l'Arduino Mega 2560, quindi per il processore ATMega2560. Se usi l'Arduino Uno sicuramente non ti va bene perché i pin di interrupt non saranno sulla porta E. A tal riguardo ti consiglio di controllare il pin mapping dei relativi processori:
http://arduino.cc/en/Main/ArduinoBoardMega2560
http://arduino.cc/en/Main/ArduinoBoardUno

astrobeed


@astro
perché solo 833Hz per canale?


500 impulsi per rotazione diventano 2000 in quadratura, 25 rpm sono 25/60 = 0.41666 Hz, 2000 * 0.41666 = 833 Hz

max00

grazie per il codice ora cerco di capire la logica.
ps tu riesci a contare il num di impulsi?

Janos

@Astro
Hai ragione, ho sbagliato a dire io...   :smiley-mr-green:
L'encoder, che ha una ruota di 65mm di diametro, quindi 204mm di perimetro, mi misura una velocità di scorrimento di 5mt/sec. Facendo i calcoli viene che l'encoder gira a 24.5Hz, non rpm...  ;)

Go Up