Lettura encoder anomala

Salve a tutti, sto pilotando un encoder incrementale a microstep per una applicazione di test per muovere un cursore di un software di fotoritocco.

Ho aggiunto un display oled che mi grafica delle frecce in funzione del verso di rotazione (dx e sx) dell'encoder.

Seppur perfettamente funzionante in termini di attuazione del comando di rotazione (il cursore sul software si muove correttamente e secondo gli step previsti), sul display vedo graficare due volte le frecce.

Mi spiego meglio:

  • Se ruoto l'encoder di uno step a dx vedo comparire susseguendosi velocemente sul display due volte la freccia a destra anche se il cursore si muove correttamente di uno step a dx.

  • Se ruoto invece l'encoder di uno step a sx vedo comparire susseguendosi velocemente sul display due frecce, la prima a sx e poi di nuovo una a dx anche se il cursore si muove correttamente di uno step a sx.

Di seguito riporto il codice che sto utilizzando:

  aState = digitalRead(PIN_A);              
  if (aState != aLastState){                  
     if (digitalRead(PIN_B) != aState) {    
      rotateLeft();
      sx(); //qui richiamo la funzione che grafica la freccia a sx
    } else {
      rotateRight();
      dx(); //qui richiamo la funzione che grafica la freccia a dx
    }
    aLastState = aState;                    
  }

Di seguito le funzioni richiamate:

void rotateLeft(){                          
      Keyboard.press(KEY_DOWN_ARROW);
      Keyboard.releaseAll();
  }

void rotateRight(){
      Keyboard.press(KEY_UP_ARROW);
      Keyboard.releaseAll();
  }

Qualcuno potrebbe aiutarmi a capire il perché di questa doppia apparizione delle frecce sul display?
Grazie

Quel pezzo di codice è più o meno il "classico" esempio dell'uso di encoder, per cui se è nel loop è ok.

Per cui potrebbe essere qualcosa di software ossia del "resto" del codice, che non ci hai mostrato (ad esempio quali pin usi per l'encoder?).

Poi quale encoder stai usando esattamente? Ha una breakout board o è collegato "secco"? Do' per scontato che non ci siano problemi nei collegamenti tra l'encoder e Arduino, ma dato che sicuramente ci sono altri componenti collegati ad altri pin, come sono collegati e come li gestisci?

Come dico spesso, se c'è un problema provare prima ad isolarlo, ossia andare per gradi. Fai un semplice sketch derivato dal tuo, dove al posto della keyboard e dell'LCD (che disconnetterai oltre a commentare le righe dove li gestisci) mandi su seriale i click che leggi dall'encoder e verificare così cosa succeda.

Se con questo non accade nulla di negativo, come penso, allora inizia a rimettere l'LCD (ma ancora senza Keyboard, con la seriale usata solo per debug degli eventi) e vedi se cambia qualcosa (e mi pare la cosa più probabile).

Secondo me non c'è nulla che non va, ma con molta più probabilità è l'encoder che fa due o più letture. Prova ad isolare nella gestione dell'encoder (intendo le codifiche che fai sugli impulsi dell'encoder) alcuni valori letti in modo tale da saltarli, vedrai che l'encoder sarà meno "impulsivo" se così vogliamo definirlo e le letture saranno più accurate, e con molta probabilità non avrai questo effetto. Io addirittura per ridurre a 0 le false letture, nonostante l'encoder montava due filtri RC, l'ho modificato fotoaccoppiando il segnali, risultato: tutta un'altra storia!

miky_police:
Secondo me non c’è nulla che non va, ma con molta più probabilità è l’encoder che fa due o più letture.

Si ma se vedi il codice che ha postato, secondo me se fosse l’encoder dovrebbe passare 2 volte per le if() e quindi mandare al progrtamma su PC due volte freccia su/giù. Lui invece dice che funziona, ma sul display è come se “flashasse” un impulso in più. Ci mancano le funzioni sx() e dx() ma comunque…

Il codice l'ho isolato così come ho disconnesso gli altri device dal dispositivo.
Utilizzo i pin 4 e 5 in quanto i pin 2 e 3 mi servono per la I2C del display che riconnetterò.

Ho inserito una visualizzazione su monitor seriale in sequenza alle chiamate di funzione di rotazione a dx e sx.

Continua a funzionare "bene" come dicevo ma osservo sul monitor seriale che effettivamente esegue comunque un passaggio per "rotazione a dx".

Se ruoto l'encoder di uno step a dx vedo comparire sul monitor due volte la scritta "rotazione a destra" anche se il cursore si muove correttamente di uno step a dx.

Se ruoto l'encoder di uno step a sx vedo comparire sul monitor una volta la scritta "rotazione a sinistra" e poi una scritta "rotazione a destra" anche se il cursore si muove correttamente di uno step a sx.

Il codice è questo:

  aState = digitalRead(PIN_A);              
  if (aState != aLastState){                  
     if (digitalRead(PIN_B) != aState) {    
      rotateLeft();
      Serial.print("rotazione a sinistra"); //stampo su monitor seriale cosa succede
    } else {
      rotateRight();
      Serial.print("rotazione a destra"); //stampo su monitor seriale cosa succede
    }
    aLastState = aState;                    
  }
aState = digitalRead(PIN_A);             
if ((aState != aLastState) && (LOW == aState)) {
    if (digitalRead(PIN_B) != aState) {
        rotateLeft();
        Serial.print("rotazione a sinistra");
    } else {
        rotateRight();
        Serial.print("rotazione a destra");
    }
}
aLastState = aState;

Gli encoder a scatti producono una sequenza di 4 passi in codice gray per ogni scatto!

Anni fa inventai questa funzione, che funziona bene, e la uso sempre:

 void encoder()
{        // PD 76543210
S=3-(PIND>>3)&B00000011; // Gli I/O 3 e 4 sono PD3 e PD4, perciò scorro a destra di 3. 
// Il valore binario di S rappresenta A e B. Il centrale dell'encoder è a massa,
// quindi faccio complemento a 3 (11)  
S^=S>>1; // Faccio XOR (^) fra S (gray) e il suo bit 1, facendolo scorrere a Dx: AB XOR A,
// ottenendo un binario che per ogni scatto fa 0-1-2-3-0 oppure 0-3-2-1-0.
if (S!=So && S==0) X=0;
if (X==0)
  {
  if (So==1&&S==2)
    {E=1; X=1; Bip();}
 
  if (So==3&&S==2)
    {E=-1; X=1; Bip();}
 
  if (S==0)
    {E=0; X=0;}
  So=S;  
  }
}

Grazie Claudio_FF
Con questa versione di codice si sono risolti i problemi della "doppia scrittura".
Il display adesso grafica bene e sul monitor seriale vedo i comandi una sola volta.

Claudio_FF:

aState = digitalRead(PIN_A);             

if ((aState != aLastState) && (LOW == aState)) {
   if (digitalRead(PIN_B) != aState) {
       rotateLeft();
       Serial.print("rotazione a sinistra");
   } else {
       rotateRight();
       Serial.print("rotazione a destra");
   }
}
aLastState = aState;

Il problema è che il cursore del software adesso si muove ad impulsi alterni (ogni due) e non recepisce rotazioni continue dell'encoder..

Mi correggo, adesso funziona tutto.
Avevo una variabile che regolava l'accuratezza dell'encoder impostata a 2.
Mi faceva perdere gli impulsi a step alterni.
Grazie ancora

Datman:
Gli encoder a scatti producono una sequenza di 4 passi in codice gray per ogni scatto!

Infatti quella di questo post è la "versione povera" della lettura dell'encoder. Gestendo invece i quattro step del codice gray, non solo si ottiene un comando ad ogni scatto, ma anche l'effetto collaterale di un bel debounce software senza bisogno di millis ecc.