Regolare velocità motori con encoder

Ciao, sono qui a chiedere aiuto in merito ad un problema che vorrei risolvere.
Sono uno studente di informatica che frequenta la classe quinta e come progetto per l’esame di maturità ho pensato di portare un piccolo robot realizzato con arduino.
Ho delle basi sulla programmazione in Java e quindi riesco anche a destreggiarmi un pochino con C++.

Ora mi trovo con un problema, i due motori non girano alla stessa velocità e quindi il robot non segue una linea retta.

Mi hanno suggerito di utilizzare dei sensori a forcella (fototransistor) e applicarli alle ruote dentate che girano insieme alle due ruote. Così ho fatto, ho comprato i sensori e li ho applicati in modo che leggano i passaggi dei dentini delle ruote dentate.

Ora mi hanno suggerito di contare, in un intervallo di tempo da te definito, in cui i motori si muovono la differenza di impulsi tra il primi ed il secondo encoder e regolare di conseguenza la velocità del motore corrispondente per adattarla l’uno all’altro.

Ma mi trovo in difficoltà con il codice da scrivere.

Aspettando un vostro aiuto, vi ringrazio.

Saluti
Gabriele

Ci sono credo due possibilita' ... usare due interrupt per contare il tempo fra gli impulsi dei due encoder (ma credo sia piu complesso), oppure usare una temporizzazione singola (magari con millis) e contare gli impulsi dei due encooder nell'intervallo di tempo ...

Pero', di che encoder stiamo parlando ? ... calettati sugli alberi motore o sugli alberi delle ruote ? ... quanti impulsi per giro ?

Ciao Etemenanki, intanto ti ringrazio per il tuo interessamento al mio problema.
Per essere il più chiaro possibile allego una foto dove si vedono i fototransistor. Le ruote dentate hanno 16 denti, quindi 16 impulsi ogni giro di ruota.
L'idea che mi ero fatto era appunto contare gli impulsi in un dato tempo, compararli e in seguito adeguare la velocità del motore più veloce a quello più lento.

Aspetto tue notizie, grazie

Ciao
Gabriele

Etemenanki:
usare una temporizzazione singola (magari con millis) e contare gli impulsi dei due encooder nell'intervallo di tempo ...

Credo sia meglio contare gli impulsi con 2 interrupt e verificare le differenze ad ogni ciclo loop o ogni tot di tempo.

Con gli encoder messi come in foto, mi sa di si ... 16 impulso per giro delle ruote sono troppo pochi per fare il contrario ...

Vi ringrazio per l'aiuto, non è che per caso avere un codice da cui potrei prendere spunto?

Grazie, ciao
Gabriele

Controlla qui --> Arduino Playground - RotaryEncoders
Dovrebbe esserci anche un esempio con doppio interrupt.

Ciao ragazzi,
sono riuscito a gestire gli interrupt, a leggere gli impulsi e a salvarle in due variabili distinte, una per la ruota sx e una per la ruota dx.
Ora pensavo di fare un ciclo if dove controllo quale delle due è maggiore e di conseguenza adattare il valore PWM dei motori per rallentare quello più veloce.
Secondo voi è la strada giusta?

Grazie, saluti
Gabriele

Questo è il codice che ho pensato...
Potete darmi gentilmente un aiuto?

Grazie saluti
Gabriele

int pinDirA1=7;
 int pinDirA2=8;
 int pinDirB1=12;
 int pinDirB2=13;
 int pinPwmA=10;
 int pinPwmB=11;
 int velDx=200; //imposto la velocità iniziale a 200
 int velSx=200; //imposto la velocità iniziale a 200
volatile long contatoreDx = 0; //variabile usata per il conteggio degli impulsi         
volatile long contatoreSx = 0; //variabile usata per il conteggio degli impulsi
 
 void setup()
 {
   pinMode( pinDirA1,OUTPUT );
   pinMode( pinDirA2,OUTPUT );
   pinMode( pinPwmA,OUTPUT );
   pinMode( pinDirB1,OUTPUT );
   pinMode( pinDirB2,OUTPUT );
   pinMode( pinPwmB,OUTPUT );
   Serial.begin(9600);
   attachInterrupt(3, contaSx, RISING);   
   attachInterrupt(1, contaDx, RISING);
 }
 
 
 void contaDx(){                          
   contatoreDx++;
   //Serial.println(contatoreDx);
}

 void contaSx(){                          
   contatoreSx++;
   //Serial.println(contatoreSx);
}
 void loop()
 {
   digitalWrite( pinDirA1,LOW );
   digitalWrite( pinDirA2,HIGH );
   digitalWrite( pinDirB1,HIGH );
   digitalWrite( pinDirB2,LOW );
   analogWrite( pinPwmA,velDx );
   analogWrite( pinPwmB,velSx );
   delay(1000);

 if (contatoreSx!=contatoreDx)
 {
   if (contatoreSx>contatoreDx)
   {
     velSx--;
   }
   else
     velDx--;
 }
 else
 {

 }
 Serial.println("ContSX");
 Serial.println(contatoreSx);
 Serial.println("ContDX");
 Serial.println(contatoreDx);
 Serial.println("VELSx");
 Serial.println(velSx);
 Serial.println("VELDx");
 Serial.println(velDx);
 }

Quanti impulsi ti aspetti da ogni motore in un secondo?

Ciao Paolo, e grazie dell'interessamento.
Comunque i dati teorici dei motori indicano circa 90 rpm, quindi all'incirca 1,5 giri ogni secondo.
Contando che ho impostato la velocità a 200 e non al massimo, penso che farà circa 1 giro al secondo e quindi 16 impulsi.
Ovviamente il tutto in linea teorica.

Grazie ciao
Gabriele

Sedici impulsi a giro non sono tantissimi però puoi provare. Ad esempio avere una differenza di un impulso ogni 200 ti darebbe una migliore precisione che non una differenza di un impulso ogni 16.
Secondo me devi prendere un motore come riferimento e modificare la velocità dell'altro.
Inoltre devi temporizzare il controllo usando la funzione millis() e non il delay().
Guarda l'esempio dell'IDE "blink whitout delay".

Grazie Paolo dei suggerimenti,
stavo pensando al fatto che tu mi dici di verificare la differenza ogni 200 impulsi, ma così facendo mi troverei in una situazione in cui i motori inizialmente andrebbero a due velocità diverse.
Mi spiego meglio, prima che il contatore arrivi a 200 i motori girerebbero a velocità diverse, o sbaglio?

Grazie ciao
Gabriele

Non ho detto di fare la verifica ogni 200 impulsi ma che 16 impulsi giro sono pochi ed otterrai un errore maggiore di quello che otterresti con una ruota fonica che invia 200 impulsi.
Il controllo lo puoi fare ogni secondo, ogni mezzo secondo, ecc, però l'errore rimarrà altro e questo causerà numerose correzioni.

Scusa, avevo capito male.
Sicuramente 16 impulsi non sono molti, ma la ruota dentata che ho è fatta così.

Il codice che ho scritto secondo te potrebbe funzionare?

Grazie ciao
Gabriele