Scusami, comunque ho provato a toglierlo, ma non ha dato nessun beneficio
Queste sono quattro righe del processo (prese a caso dal codice iniziale):
// esecuzione movimento
GuideStepper.runToPosition();
// inizializzazione nuovo movimento
GuideStepper.setCurrentPosition(0);
GuideStepper.moveTo(posGuiON);
// esecuzione movimento
GuideStepper.runToPosition();
Si è detto che il codice è bloccante, perché il metodo runToPosition impedisce di fare qualsiasi altra cosa finché il suo lavoro non è terminato.
Per usare il metodo non bloccante run (che fa un solo passo alla volta), senza racchiuderlo in un ciclo che a sua volta diventa bloccante, bisogna cominciare a pensare (e riscrivere ogni cosa) a fasi/stati:
if (125 == fase) { // esecuzione movimento fase 125
GuideStepper.run(); // esecuzione singolo passo
if (GuideStepper.distanceToGo() == 0) { // se arrivato
// inizializzazione nuovo movimento
GuideStepper.setCurrentPosition(0);
GuideStepper.moveTo(posGuiON);
fase = 296; // fase che gestirà nuovo movimento
}
}
else if (296 == fase) { // esecuzione movimento fase 296
GuideStepper.run(); // esecuzione singolo passo
if (GuideStepper.distanceToGo() == 0) { // se arrivato
....
fase = ...;
}
}
O con un equivalente switch:
switch (fase) {
case 125:
GuideStepper.run(); // esecuzione singolo passo
if (GuideStepper.distanceToGo() == 0) { // se arrivato
// inizializzazione nuovo movimento
GuideStepper.setCurrentPosition(0);
GuideStepper.moveTo(posGuiON);
fase = 296; // fase che gestirà nuovo movimento
}
break;
case 296:
GuideStepper.run(); // esecuzione singolo passo
if (GuideStepper.distanceToGo() == 0) { // se arrivato
....
fase = ...;
}
break;
}
Questa struttura (basata su if/if else, oppure switch) va eseguita ad ogni ciclo di loop. La variabile 'fase' stabilisce momento dopo momento quale parte verrà eseguita.
Il concetto è di pensare tutto il sistema nei termini di tante situazioni in cui si può trovare (mutuamente esclusive): "se sono in questa fase, e succede questo, faccio questo (e eventualmente cambio fase)".
Naturalmente deve esistere anche una fase "idle" in cui semplicemente si attende la condizione di avvio.
Cosa?
Invece di togliere serviva di rispondere
Comunque...
Invece per la macchina a stati
Concordiamo in pieno
Pero noi evitiamo come la lebbra gli else if
Peggiorano la leggibilita del codice
E forse anche la sua stesura
Visto che la stragrande maggioranza delle volte che lo abbiamo visto applicato c'erano poi errori
Scusami ma allora non ho capito cosa mi volevi chiedere.
@Claudio_FF ok, i numeri del case a cosa si riferiscono? (Scusami la domanda)
Noi crediamo che se tu no riesci a capire le domande a minor ragione troverai le risposte, anche quella relative ai tuoi problemi di programmazione
comunque, se son rose fioriranno
Scusami, non vorrei essere inutilmente polemico, ma la tua domanda non è così chiara, "in particolare fai attenzione alle scritte..." cosa vuol dire?, dato che il tuo aiuto è "volontariato" ho voluto cercare (con le mie conoscenze basiche) di interpretare quello che mi volevi dire, e quindi come prima prova ho voluto capire se il comando serial.println poteva in qualche modo influenzare il ciclo. Ad ogni modo grazie del tuo aiuto, se vuoi metterti al mio livello e cercare di darmi degli spunti per informarmi e crescere va bene...sennò amici come prima e arrivederci.
Valori arbitrari che assegni tu alle "situazioni" / fasi / stati in cui in ogni momento il sistema/programma si può venire a trovare. Tipicamente tutti i casi in cui c'è da aspettare qualcosa (un input, un timeout, un finecorsa ecc).
Io di solito enumero gli stati in modo da rendere più leggibile il codice.
enum States { IDLE = 0, HOME, POS1, POS2, POS3};
uint8_t state = IDLE;
......
switch (state) {
case States::IDLE :
// Stai a riposo
break;
case States::HOME :
// Fai il ciclo di homing
break;
case States::POS1 :
// Vai alla posizione 1
break;
// Eccetera eccetera...
}
Grazie!
Ora mi applico, con questo metodo la velocità e accelerazione non sono più gestibili corretto?
Perché no?
La imposti prima di far avviare il movimento e poi lasci fare alla libreria con il metodo run()
La chiave però è fare in modo che le istruzioni di "setup" del movimento vengano eseguite una sola volta.
Ad esempio potresti aggiungere una fase RUN dove vai ad eseguire il movimento vero e proprio. Contemporaneamente controlli che il motore non abbia finito (distanceToGo() == 0) e quando questo accade torni in IDLE.
Immaginavo facesse un passo e quindi di fatto non riuscisse mai ad arrivare alla vel max. Ottimo!
Grazie dell'aiuto!
Funziona anche così?
enum {IDLE=0, HOME, POS1, POS2, POS3}; // Anche senza specificarlo parte da 0.
uint8_t state = IDLE;
......
switch (state) {
case IDLE:
// Stai a riposo
break;
case HOME:
// Fai il ciclo di homing
break;
case POS1:
// Vai alla posizione 1
break;
// Eccetera eccetera...
}
Si certo.
Io però di solito preferisco il primo metodo cosi non corro il rischio di enumerare due volte con lo stesso nome (che a quel punto può essere anche molto breve e semplice da identificare).
Un po' più scomodo da scrivere, però meno soggetto ad errori che diventano difficilissimi da scovare.
Ad esempio in questo esempio specifico, @fabiod82 potrebbe decidere di usare uno switch/case per ciascun motore e a quel punto gli basta solo cambiare l'identificatore dell'enumerazione.
Sì... Potrei fare un enum con {BIANCO, NERO, GIALLO, VERDE} e un altro con {NORD, SUD, OVEST, EST} e BIANCO varrebbe zero come NORD. Se, però, li uso in switch diversi, il problema non sussiste.
enum {BIANCO, NERO, GIALLO, VERDE}; // Da 0 a 3.
enum {NORD, SUD, OVEST, EST}; // Da 0 a 3.
loop:
colore=BIANCO;
switch (colore)
{
case BIANCO:
...
break;
...
}
direzione=NORD; // direzione=BIANCO darebbe lo stesso risultato, ma non ha senso!
switch (direzione)
{
case NORD:
...
break;
...
}
Programma funzionante!!!
Ho fatto due switch uno per Homing degli assi eseguito solo la prima volta dopo l'accensione, poi uno per il ciclo della macchina.
Grazie delle dritte a tutti!