Leggere bene tre encoder con Arduino UNO

Sezione dedicata all'elettronica di controllo cnc.
tecno67
Member
Member
Messaggi: 391
Iscritto il: lunedì 26 febbraio 2007, 14:25
Località: Prov. di Milano

Re: Leggere bene tre encoder con Arduino UNO

Messaggio da tecno67 » venerdì 15 maggio 2020, 23:02

Il classico algoritmo è in effetti una macchina a stati.
Capita alle volte di far qualcosa senza sapere che altri gli hanno già dato un nome. Non l'ho fatto Apposta! :) O ti riferisci al sito?
Nel guardare il disassemblato della funzione su Arduino sono comunque rimasto sorpreso che lo shift a sinistra di 2 bit sia fatto con una somma.
Non pensavo che atmel non avesse lo shift (o non capisco perché il compilatore non l'ha usato).
Ti riferisci al mio listato o a quello del sito?

in ogni caso l'AVR lo shift cè l'ha: LSR ed LSL senza Carry / ROR ed ROL con Carry ha pure un ASR aritmetic shift Right che, confesso la mia ignoranza, non so bene per cosa la si usi.

Non ha, se non ho visto male, una istruzione di shift di n posizioni in singola istruzione.

Non è che è un 'ADIW', che è una somma di un valore immediato su word? Tra l'altro è un po strana perchè puoi sommare solo da 0 a 63 .... Dovrei capire esattamente di cosa parli.

Poi scusa se sommi ad un valore se stesso fai uno shift di un bit, per farlo di due devi ripetere due volte la somma.

tecno67
Member
Member
Messaggi: 391
Iscritto il: lunedì 26 febbraio 2007, 14:25
Località: Prov. di Milano

Re: Leggere bene tre encoder con Arduino UNO

Messaggio da tecno67 » venerdì 15 maggio 2020, 23:40

Nel guardare il disassemblato della funzione su Arduino sono comunque rimasto sorpreso che lo shift a sinistra di 2 bit sia fatto con una somma.
Non pensavo che atmel non avesse lo shift (o non capisco perché il compilatore non l'ha usato).
Ho capito solo ora, parlavi del tuo di listato... Non lo so... Bisorrebbe chiederlo a chi ha fatto il compilatore, l'istruzione c'era... Poi in fondo è lo stesso.

beh! Sempre da praticone, ti dirò... ho l'impressione che se devi fare qualcosa di stra-veloce e stra efficiente, l'alto livello è si comodo, ma se devi poi ricontrollarti tutto quello che ti sputa il compilatore per verificare che abbia fatto la cosa migliore, è lo stesso una palla! Ma è l'opinione di un Niubbo in queste cose. #-o

Avatar utente
hellfire39
God
God
Messaggi: 3414
Iscritto il: domenica 16 dicembre 2012, 9:04
Località: AN

Re: Leggere bene tre encoder con Arduino UNO

Messaggio da hellfire39 » sabato 16 maggio 2020, 8:57

Generalmente oggi, i compilatori sono stra-ottimizzati. Grazie anche alla velocità dei computer odierni, i compilatori sono molto abili a riconoscere parti di codice ottimizzabile. E spesso hanno molte più ottimizzazioni di quelle che possono venire in mente ad un singolo programmatore!
Con alcune eccezioni. Una l'avevo già accennata: MPLABX, versione gratuita, lascia fuori parecchie ottimizzazioni.
Va bene per uno smanettone, può non bastare per un'azienda che deve fare un prodotto efficiente, soprattutto in quei casi in cui velocità e spazio sono fondamentali.


Prima o poi andrò a vedere le varie differenze di codice prodotto per gli interrupt.


Ho visto la spiegazione del discorso del +2/-2 sul codice di encoder.h. Se hai interrupt solo su A, sei nella condizione in cui puoi interpretare l'encoder in modalità 2x. Ma allora avrai solo valori pari (quindi una "falsa" risoluzione doppia).
Ne riesco a giustificare l'uso solo per mantenere la consistenza di conteggio con il caso 4x.

tecno67
Member
Member
Messaggi: 391
Iscritto il: lunedì 26 febbraio 2007, 14:25
Località: Prov. di Milano

Re: Leggere bene tre encoder con Arduino UNO

Messaggio da tecno67 » sabato 16 maggio 2020, 14:02

Codice: Seleziona tutto

Ho visto la spiegazione del discorso del +2/-2 sul codice di encoder.h. Se hai interrupt solo su A, sei nella condizione in cui puoi interpretare l'encoder in modalità 2x. Ma allora avrai solo valori pari (quindi una "falsa" risoluzione doppia).
Ne riesco a giustificare l'uso solo per mantenere la consistenza di conteggio con il caso 4x.
In effetti è la motivazione che ne da l'autore. Io so solo che avevo provato uno sketch con quella libreria usando appunto la condizione di 2 encoder con un interrupt ciascuno, quindi un modalità x2. Solo che non so se per un mio errore o per altro mi accadeva che se con uno stesso encoder collegato col canale A in ingresso ad entrambi gli ingessi A dei due encoder e lo stesso per i B visulizzano sul monitor seriale entrambi i conteggi incrementavano e decremetavano visualizzando sempre lo sesso numero. Se invece invertivo i canali per un encoder uno contava in positivo e l'altro in negativo, come è normale, solo che se io ruotavo l'encoder avanti e indietro continuamente, capitava che i due valori avessero valori diversi di uno anche due count, ma quello che è peggio è che a avolte questi errori si accumulavano, diventando magari anche 4 o 8 o più. Quello che mi è suonato veramente strano è che la cosa avvenisse solo quando i canali ai due encoder erano scambiati. Se fosse stato che andavo troppo veloce con l'encoder (lo muovevo a mano con le dita) sarebbe dovuto accadere in entrambi i casi. Boh! :? :?

Avatar utente
hellfire39
God
God
Messaggi: 3414
Iscritto il: domenica 16 dicembre 2012, 9:04
Località: AN

Re: Leggere bene tre encoder con Arduino UNO

Messaggio da hellfire39 » sabato 16 maggio 2020, 15:36

Ho fatto una prova veloce con quella libreria.
A circa 90 kHz di interrupt, non perde (quasi!) un colpo (singolo encoder).

Raddoppiando ancora la frequenza, non conta più (da 11 a 5 us di delay tra un passo e l'altro).
Con 8 us di delay conta male (circa 120 kHz) perdendo quasi la metà dei passi.
Anche con 9 us perde un 15-20% dei conteggi.
Con 10 us perde ancora qualche passo ogni 100000.

Orientativamente, quindi, è questo il limite massimo, tenendo conto che non rimane più tempo per fare null'altro.

Diciamo che l'ipotesi di 10kHz con un 10% di occupazione di cpu, ci sta.

Nota: non ho ancora attivato il seguente #define:

#define ENCODER_OPTIMIZE_INTERRUPTS



Edit: ho provato ad attivare il define. Non cambia praticamente nulla. Riesco a tenere i 10 us di delay rispetto agli 11 us dell'altro caso.
Ma se provo a fare "qualcosa", tipo richiede la lettura del conteggio via seriale, già perdo conteggi.
Non hai i permessi necessari per visualizzare i file e le foto allegati in questo messaggio. Per visualizzare tali file devi registrarti ed effettuare il Login

Avatar utente
hellfire39
God
God
Messaggi: 3414
Iscritto il: domenica 16 dicembre 2012, 9:04
Località: AN

Re: Leggere bene tre encoder con Arduino UNO

Messaggio da hellfire39 » sabato 16 maggio 2020, 16:02

Nell'immagine allegata c'è il risultato del codice originale dell'esempio.
Si vede la fine del treno di impulsi dell'encoder e come cambia il treno di impulsi generato dal codice di esempio quando è impegnato a contare gli impulsi encoder e quando no.

I "buchi" rappresentano grossomodo il tempo passato da arduino a servire l'interrupt.
Non hai i permessi necessari per visualizzare i file e le foto allegati in questo messaggio. Per visualizzare tali file devi registrarti ed effettuare il Login

tecno67
Member
Member
Messaggi: 391
Iscritto il: lunedì 26 febbraio 2007, 14:25
Località: Prov. di Milano

Re: Leggere bene tre encoder con Arduino UNO

Messaggio da tecno67 » sabato 16 maggio 2020, 16:24

Sta piovendo li da te?

tecno67
Member
Member
Messaggi: 391
Iscritto il: lunedì 26 febbraio 2007, 14:25
Località: Prov. di Milano

Re: Leggere bene tre encoder con Arduino UNO

Messaggio da tecno67 » sabato 16 maggio 2020, 16:27

Visto che hai gia tutto collegato, prova col mio di programma, quello da 3 encoder, così per curiosità. Se ti va ovviamente!

Avatar utente
hellfire39
God
God
Messaggi: 3414
Iscritto il: domenica 16 dicembre 2012, 9:04
Località: AN

Re: Leggere bene tre encoder con Arduino UNO

Messaggio da hellfire39 » domenica 17 maggio 2020, 13:57

Ho provato il tuo programma collegando solo un encoder simulato (come nei casi precedenti).
Sono riuscito ad andare un po' più veloce, senza perdere conteggi.
Sono arrivato fino a delayMicrosecond(9).
Prima ero a 11 per non perdere conteggi. Con 10 us, ogni tanto andava, ogni tanto perdeva qualche conteggio, tipo 99994 su 100000.
Direi che ero al limite.

La frequenza raggiunta è quella evidenziata in figura, circa 109,5 kHz
Non hai i permessi necessari per visualizzare i file e le foto allegati in questo messaggio. Per visualizzare tali file devi registrarti ed effettuare il Login

Avatar utente
hellfire39
God
God
Messaggi: 3414
Iscritto il: domenica 16 dicembre 2012, 9:04
Località: AN

Re: Leggere bene tre encoder con Arduino UNO

Messaggio da hellfire39 » domenica 17 maggio 2020, 20:04

Per la cronaca, ho fatto un'ultima prova.
Ho tolto dalle palle tutto l'assembler, lasciando solo codice in C.

Ho fatto l'attachInterrupt() del codice seguente:

Codice: Seleziona tutto

void updateEncoder()
{
  FastGPIO::Pin<12>::setOutput(HIGH);
  
  static int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
  // 0111 -1 (7)
  // 0010 +1 (2)
  //static int8_t unoper_states[] = {0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0};
  static uint8_t old_AB = 0;

  int p1 = FastGPIO::Pin<2>::isInputHigh();
  int p2 = FastGPIO::Pin<3>::isInputHigh();
  
  // stato precedente
  old_AB <<= 2;
  
  // stato attuale
  old_AB |= ( (p1 << 1) | p2 );
  encoderValue += ( enc_states[( old_AB & 0x0f )]);
  
  FastGPIO::Pin<12>::setOutput(LOW);
}
Sono arrivato a delayMicrosecond(12). Se tolgo la scrittura del digitale di uscita, riesco ad arrivare a 11 us senza errori.
Sono circa 89,9 kHz. Sul singolo encoder la differenza è davvero minima, pur avendo un codice portabile.

Tutto sommato il compilatore fa un buon lavoro.

Nell'immagine allegata c'è un esempio di cattura con l'uscita digitale attivata. E' interessante notare la latenza di circa 3 us dal fronte del segnale encoder al fronte dell'uscita alzata all'inizio dell'interrupt.
Circa 3 us. Si nota anche che l'intero codice dell'interrupt (senza i vari pop... aggiunti dal compilatore) dura più o meno lo stesso tempo.
Non hai i permessi necessari per visualizzare i file e le foto allegati in questo messaggio. Per visualizzare tali file devi registrarti ed effettuare il Login

tecno67
Member
Member
Messaggi: 391
Iscritto il: lunedì 26 febbraio 2007, 14:25
Località: Prov. di Milano

Re: Leggere bene tre encoder con Arduino UNO

Messaggio da tecno67 » lunedì 18 maggio 2020, 0:09

Me lo aspettavo. Il limite in fondo è quello. La novità nella mia routine è il controllo simultaneo di tre encoder, non l'efficienza della ISR. Daltronde se consideri che la routine in Assembler dura come detto nei commenti in fondo, 61 cicli più 22 per ogni encoder letto, cui devi aggiungere i 3 cicli del JMP dalla locazione del vettore di interrupt, fanno 86 cicli + più probabilmente ancora qualcosa che si piglia il micro per salvare il ProgramCounter, si potrebbe essere tentati di dire che la frequenza massima sia: 16000000/86=186KHz circa (con 3 encoder sarebbero 125Khz), ma sebbene l'interrupt PCINT è il più alto come priorità, come tu hai già detto, l'impulso potrebbe arrivare appena dopo aver effettuato la lettura del PORT dove è connesso l'encoder e quindi dover attendere l'interrupt successivo perchè sia conteggiato, oppure, potrebbe arrivare mentre un altra routine di servizio dell'interrupt che è già stata riconosciuta In questo caso, sebbene di priorità inferiore, prima viene portata a termine quella e poi quella dell'impulso. Come la tua prova a dimostrato bisogna prendere all'incirca la metà della frequenza calcolata sopra o anche meno se si usano altre funzioni.

La considerazione da fare è che quando viene scritta e rilasciata una libreria, sarebbe buona norma da parte di chi la scrive, aggiungere alle info relative alla stessa: Che periferiche usa, quali interrupt usa e quale è la durata della relativa ISR nel peggiore dei casi. Perchè come tu stesso hai fatto notare, non serve a nulla scrivere una ISR ultra-breve ed ultra-efficiente se poi si usano altre funzioni per svolgere i compiti del resto del programma senza sapere quali e quante risorse usano. Anzi direi che sarebbe una buona cosa che nella documentazione delle stesse funzioni di base di Arduino venisse fatta la stessa cosa.

In ultimo per tornare al tuo paragone del limone, forse sarebbe meglio dire che se hai un limone da spremere, il succo o lo metti da una parte o dall'altra. Se vuoi leggere un encoder con frequenze dell'ordine delle decine di KHz, non puoi poi pretendere di generare anche dei treni di impulsi in SW. Se ti riesce di farlo ad esempio coi timer ed una leggera varianza sull'istante di avvio del treno la puoi tollerare bene, altrimenti come tu stesso dici ti devi affidare o a dei micro con capacità di uno o più ordini di grandezza superiori, o se lo puoi fare mantenendo il micro che stai usando ti devi affidare a periferiche esterne. Direi che puoi fare in SW una sola delle cose onerose.
Va anche detto però, che quando è un hobbysta o comunque una persona che lo fa una volta a spot, il maggior costo nell'uso di HW più prestanti, non è dato tanto dalla differenza di costo del micro, che spesso è di pochi €. Il costo/difficoltà vera è proprio il fatto di doversi approcciare ad un nuovo oggetto coi relativi linguaggi e tool di sviluppo ecc. Per quanto deprecabile (solo in parte!), prima si cerca sempre di fare ciò che si ha in mente con ciò che si conosce già.

Avatar utente
hellfire39
God
God
Messaggi: 3414
Iscritto il: domenica 16 dicembre 2012, 9:04
Località: AN

Re: Leggere bene tre encoder con Arduino UNO

Messaggio da hellfire39 » lunedì 18 maggio 2020, 8:49

Per i calcoli all'inizio, sei troppo ottimista.
Primo perché se un micro legge solo l'encoder senza fare altro è inutile! Secondo perché, ci sono altri ritardi, a partire dal fatto che che l'interrupt non viene gestito istantaneamente, ma ci sono almeno 4 cicli di clock prima di vedere il flag alto.

Riguardo al fatto che dovrebbero essere pubblicati i dettagli delle librerie, penso che la cosa non interessi al 95% delle persone che utilizzano arduino. E che il rimanente 5%, se ne ha bisogno, vada a leggersi i sorgenti, se è sufficientemente determinato a spaccare il microsecondo.
Comunque, grossomodo, un'idea di quello che fa una libreria lo puoi immaginare dalle risorse che usa (I2C, SPI, UART, ecc.)

In ogni caso penso che se un hobbista ha necessità così spinte, non abbia altra scelta che trovare un prodotto che non lo costringa a fare i salti mortali. A partire da processori più potenti che possano essere programmati con Arduino.
I PIC sono scomodi, sono io il primo a dirlo, ma offrono una serie infinita di CIP (core independent peripherals) di ogni tipo. Spesso ti semplificano anche la parte HW, grazie alle periferiche interne.

Sicuramente, leggere un encoder è una di queste. Io ho un tastatore della heidenhain che risolve 0,5 um valutato 4x, e ti assicuro che è praticamente impossibile leggere il suo dannato valore e visualizzare il valore letto su un display oled. Qualche conteggio lo perdo sempre.

Utilizzando un PIC con QEI integrato (un dsPic33) sono riuscito a leggerlo senza problemi. Tranne bestemmiare una settimana per fare il porting della libreria per gli oled!

tecno67
Member
Member
Messaggi: 391
Iscritto il: lunedì 26 febbraio 2007, 14:25
Località: Prov. di Milano

Re: Leggere bene tre encoder con Arduino UNO

Messaggio da tecno67 » lunedì 18 maggio 2020, 11:08

Tranne bestemmiare una settimana per fare il porting della libreria per gli oled!
Appunto! Quello che dicevo.

Quanto hai calcoli dei cicli, vale certamente quel che hai detto tu. Però precisione per precisione vorrei farti notare una cosina. Non che questo tolga nulla alla validità delle considerazioni da te fatte circa i micro più prestanti e le CIP, che sono certamente la scelta più appropriata.

Tu dici:

Togliendo tutto l'Assembler di mezzo, si passa da 109.5 KHz a 89.9KHz. A prima vista sono solo 19.6KHz di differenza, ma 19.6 su 89.9, sono più del 20% di differenza come impiego risorse (se leggo una frequenza minore, vuol dire che la ISR generata alla fine è più lunga). Come dire che se un singolo encoder nella mia ISR in assembler usa (61+22=83) cicli, quella generata dal compilatore ne usa 83+20%=99.6 ovvero 17 cicli in più. Se poi consideri che questo spreco può avvenire 90000 volte in un secondo, ecco che su 16000000 cicli a disposizione ne abbiamo buttati (si fa per dire) 1530000. Direi che usando il C invece dell'assembler ci giochiamo ad esempio tutti i cicli che ci servono per trasmettere le letture in seriale e forse anche altro. Solo per fare un esempio.... Se il limone è già piccolo, la prima, cosa direi che è evitare di far cadere una parte del succo fuori dal bicchiere quando lo spremi.

Questo per quanto riguarda la tua domanda iniziale.
Evitare l'assembler e lasciare che il compilatore faccia il suo lavoro?
Questo comunque sempre per accademico spirito di voler spaccare il capello in quattro, non perché tutti questi discorsi abbiano poi nella pratica giornaliera una qualche utilità effettiva.

In ogni caso a parte il motor-control che tu hai citato, gli encoder NPN o PNP, già per ragioni più legate all'imunità ai disturbi e quant'altro, difficilmente vengono impiegati sopra i 15-20KHz e molti PLC, quando offrono contatori integrati nella CPU (solitamente non più di quattro) dichiarano frequenze massime di 50KHz solo con elettronica line-driver ed usando al loro interno micro ben più prestanti di un Arduino. Producendo alla fine tempi di ciclo di scansione sempre dell'ordine dei mSec. Quindi in ogni caso con frequenze di elaborazione del ciclo 'Nobile' diciamo così, di almeno due ordini di grandezza rispetto la frequenza massima leggibile dall'encoder.

In definitiva, l'essere riusciti a leggere più encoder a frequenze così alte con un Arduino è già di per se un risultato di buon livello. Poi valutare la bontà di una singola libreria (la mia non è nemmeno quello dato che va riadattata ogni volta) senza valutare l'applicazione nel suo complesso lascia il tempo che trova. Ma ovviamente questo lo puoi fare solo di volta in volta su di un applicazione ben specifica.

In astratto puoi solo e soprattutto conviene, prescindere dall'HW impiegato e discutere della metodologia impiegata per la lettura, evidenziandone pregi e difetti. Non puoi fare altro. Se ti spingi oltre esci dal merito del tema proposto e si entra in un ginepraio, come stiamo facendo noi in queste due pagine di post. Anche se entrambi abbiamo il merito (prendiamocelo dai!) di aver sviscerato, ad uso di chi ha avuto la pazienza di leggerci, alcune delle problematiche e dei limiti del buon vecchio caro Arduino.

La finiamo qui senza tediare ulteriormente i nostri lettori?

Avatar utente
hellfire39
God
God
Messaggi: 3414
Iscritto il: domenica 16 dicembre 2012, 9:04
Località: AN

Re: Leggere bene tre encoder con Arduino UNO

Messaggio da hellfire39 » lunedì 18 maggio 2020, 11:32

Mah, fintanto che si sviscerano informazioni utili, il dibattito va sempre bene.


Personalmente non ho mai preso in considerazione encoder che non abbiano uscite line-driver differenziali.
Anche perché quelli che mi capitano tra le mani al lavoro, di solito, son fatti così.

Anche il tastatore dell'Heidenhain di cui parlavo sopra è fatto in quel modo.

----------
P.S. i PLC che programmo io (Siemens S7, tipicamente) hanno schede dedicate per la lettura degli encoder differenziali. Un avanzo che dovrei avere nell'armadio (ET200S 1COUNT) , se non ricordo male, legge fino a 500 kHz.
Se riesco ad aprirlo senza romperlo, provo a vedere che elettronica monta.

tecno67
Member
Member
Messaggi: 391
Iscritto il: lunedì 26 febbraio 2007, 14:25
Località: Prov. di Milano

Re: Leggere bene tre encoder con Arduino UNO

Messaggio da tecno67 » lunedì 18 maggio 2020, 13:24

Ricordi male.

L'ET200S, sia sulla IM151-7 che sulla IM151-8 non ha ne ingressi, ne uscite, ne contatori sulla CPU. Ha un modulo separato di conteggio (quello che hai tu nel cassetto probabilmente) che arriva a 100KHz, ma è una periferica a se. Non è un ingresso integrato nella CPU.
Le CPU della serie 300, di cui l'ET200S nelle versioni dette sopra sono la versione con CPU della periferia decentrata su base 8 canali/modulo sviluppata per la serie 300, che hanno funzioni di conteggio integrate, sono la 313 e la 314, che uso spesso. Ti allego l'estratto del data-shet sotto forma di cattura in .jpg. Siamo ai valori che ti ho detto più o meno. Idem se usi ad esempio un CP1x od un CJ2 Omron per restare sui PLC che conosco io. Se poi servissero 9 encoder a conti fatti spesso conviene usare direttamente encoder in PROFIBUS o PROFINET (magari pure multigiro ed assoluto) e trovarsi direttamente il valore di conteggio bello e pronto in un'area dati nel PLC, ma parliamo in ogni caso di 100/200€ ad encoder. Altro livello di orizzonte rispetto a quello di uno smanettone. Va detto però che l'S7-300 ormai ha i suoi anni.
Non hai i permessi necessari per visualizzare i file e le foto allegati in questo messaggio. Per visualizzare tali file devi registrarti ed effettuare il Login

Rispondi

Torna a “Elettronica CNC”