Non ho capito perché dovrei perdere dei passi per il calcolo. Ti faccio un esempio pratico con la mia attuale configurazione: encoder 1000 passi (250x4); vite 400 passi; passo vite 3,175mm (8 filetti per pollice) Poniamo di voler costruire un passo da 2mm, questo vuol dire ad ogni giro mandrino (quindi 1000 passi) lo stepper della vite dovrà eseguire: (400/3.175)*2 = 251,96 che arrotondiamo all'intero più prossimo quindi 252. Per via dell'arrotondamento avrò certamente una lieve differenza rispetto al passo nominale ed in particolare questa sarà così calcolata: (3.175/400)*252 = 2.00025 mm. Ovvero avrò un errore sul passo di 0.25 micron
Calcolato quindi che lo stepper dovrà eseguire 252 passi ad ogni giro del mandrino, questo vorrà dire che dovrò eseguire un passo stepper ogni: 1000/252 = 3,9682 passi del mandrino.
Poiché non posso frazionare i passi, devo eseguire passi interi con una sequenza tale che mi permetta di raggiungere, alla fine di ogni singolo giro del mandrino, i 252 passi stepper che ho calcolato. Per fare questo creo un array che contiene tanti valori quanti sono i passi stepper da eseguire (quindi 252 celle), in ognuna delle quali inserisco un numero intero che indica quanti passi mandrino si dovranno attendere prima di fare il passo stepper e passare quindi alla cella dell'array successiva (o precedente, dipende ovviamente dalla direzione di filettatura). Una volta creato l'array eseguo un controllo atto a verificare che la somma di tutti i passi mandrino contenuti nell'array sia esattamente 1000, ovvero il giro mandrino completo. Può capitare che, a causa degli arrotondamenti nei calcoli ad approssimazione successiva, ci sia un passo in più o uno in meno, in questo caso aggiusto l'ultimo valore in modo da far tornare il conto ed avere quindi i 1000 passi richiesti. Tutto questo viene fatto PRIMA di iniziare la routine di filettatura.
Nella routine di filettatura l'array viene scandito regolarmente rispettando i passi mandrino richiesti ed eseguendo il passo stepper ad ogni cambio cella. In questo modo non eseguo alcun conto durante la routine ma mi limito a scandire l'array che verrà ripetuto dall'inizio una volta terminato, come se fosse una lista circolare.
Ora viene la parte critica ovvero quella in cui devo verificare che il codice non sia troppo lento e ogni interrupt venga gestito correttamente. Immaginiamo di far girare il mandrino a 1000 giri al minuto (che in filettatura sono troppi comunque); il che vuol dire 1000/60 = 16,666 giri al secondo. Il che significa che ad ogni secondo varranno generati 16,666*1000 = 16666 interrupt, uno per ogni impulso encoder. Ovvero, avrò interrupt a distanza regolare con frequenza di 16,666Khz, ovvero un interrupt con periodo 60 microsecondi. Il processore di ARDUINO ha un clock a 16Mhz, quindi con un ciclo/clock di 62,5 nanosecondi. Il processore è in architettura RISC con un set di 131 istruzioni la stragrande maggioranza delle quali viene eseguita con un solo ciclo di clock. Facciamo anche una media conservativa e diciamo che siano 1,5 per stare larghi, questo vuol dire che il micro, tra un interrupt e l'altro, sarà in grado di eseguire 640 istruzioni in codice macchina non complesse.
Questa è la mia routine di interrupt: ************ void InterruptEncoderFilettatura() { static byte prev_encoder; //definizione di variabile byte (1 ciclo di clock: 62,5 nanosecondi) byte port; //definizione di variabile byte (1 ciclo di clock: 62,5 nanosecondi)
port = PIND & B00001100; //and logico tra due valori e trasferimento indiretto (3 cicli di clock: 187,5 nanosecondi) port |= prev_encoder; //or logico tra due valori e trasferimento indiretto (3 cicli di clock: 187,5 nanosecondi) steps += encoder[port]; //addizione tra due valori e trasferimento indiretto (3 cicli di clock: 187,5 nanosecondi) absolute_encoder_steps += encoder[port]; //addizione tra due valori e trasferimento indiretto (3 cicli di clock: 187,5 nanosecondi) port >>= 2; //shift a destra di due posizioni (2 cicli di clock: 125 nanosecondi) prev_encoder = port; // load indiretto (2 cicli di clock: 125 nanosecondi) step_flag = true; // cambio di stato logico (1 ciclo di clock: 62,5 nanosecondi) } //END of the Interrupt Service Routine ************** In totale sono 1187,5 nanosecondi. Ovvero 1,1875 microsecondi. Se vuoi aggiungiamo il tempo di chiamata dell'interrupt, il pop e il push dello stack, ma anche con quelli direi che con 60 microseocndi ci sto dentro...
Quindi, mi spieghi dove dovrei perdere i passi ?
_________________ McMax
“None of us can change the things we’ve done. But we can all change what we do next.” – Fred Johnson
fulminato in tenera età
|