[[guide:junction_speed:start]]

Questa è una vecchia versione del documento!


Jerk Limiting vs Junction Deviation

Simone Persiani 26/05/2018 13:00

I progetti Marlin ed MK4duo, a partire rispettivamente dalle versioni 1.1.9 e 4.3.6, hanno introdotto una nuova funzionalità nel tentativo di superare l'ormai datata gestione del jerk degli assi. Tale gestione non ha mai convinto del tutto gli sviluppatori di Marlin e ha causato loro molti grattacapi nel corso degli anni. Nel tentativo di superare tale algoritmo si sono ispirati ai codici sorgente di Grbl, un ben noto firmware per la gestione di macchine CNC, prendendo spunto dall'algoritmo della Junction Deviation (il tutto nel pieno rispetto delle licenze associate a tale prodotto). Ricordiamo che Marlin stesso è nato nell'agosto del 2011 proprio come fork di Grbl e di Sprinter.

Tali algoritmi (l'uno alternativo all'altro), si rendono necessari nel momento in cui il planner (il modulo software che si occupa dell'ottimizzazione dei movimenti della macchina) si trova a dover scegliere con quale velocità far terminare un blocco e cominciare il successivo, ovvero la velocità di giunzione dei due blocchi.

Per maggiori informazioni sui blocchi e sul loro funzionamento, far riferimento alla guida S-Curve Acceleration

In un mondo ideale stamperemmo tutti alla velocità della luce e otterremmo i pezzi stampati in un istante. Ciò ovviamente non è possibile: le nostre macchine hanno dei motori che possono raggiungere solo determinate velocità massime, hanno dei telai in grado di assorbire solo una certa quantità di vibrazioni e di sopportare carichi di forze/tensioni limitati, hanno delle parti in movimento con massa sicuramente diversa da zero, ecc. Le vibrazioni che si vengono a creare quando stampiamo ad alte velocità impattano sulla qualità dell'oggetto stampato (vedi effetto ghosting). Si rende quindi necessario trovare una strategia efficiente per gestire le accelerazioni di ciascun asse in modo da trovare un buon compromesso tra qualità e tempi di stampa.

Per la Legge Fondamentale della Dinamica (\vec{F}=m*\vec{a}) le forze esercitate dai motori sul telaio della stampante dipendono contemporaneamente sia dalle masse in movimento sia dalle accelerazioni che esse subiscono. Non è quindi possibile trovare un'accelerazione massima che sia corretta per ogni stampante, perché quest'ultima dipenderà dalla struttura meccanica di ciascuna macchina. In linea generale è corretto assumere che la massima accelerazione possa essere aumentata nel caso in cui si siano alleggerite le parti in movimento (il carrello dell'hotend e/o il piatto di stampa, a seconda della meccanica), e viceversa.

È quindi possibile definire nel firmware le accelerazioni massime per ciascun asse, compresi gli estrusori. Tali accelerazioni definiscono la rapidità con cui l'attuale velocità di un asse può essere aumentata/diminuita per raggiungere una velocità prefissata. I movimenti pianificati dalla macchina vengono quindi modellati rispettando le accelerazioni massime per ogni asse definite dall'utente.

Il planner si occupa inoltre di concatenare gli spostamenti in modo che la velocità con cui termina un blocco sia la stessa di quella con cui comincia il blocco successivo (\vec{v^{i}}_{finale}=\vec{v^{i+1}}_{iniziale}), con lo scopo di rendere più "fluido" il passaggio da uno spostamento all'altro. La scelta di questa velocità non è così scontata come potrebbe apparire ad una prima analisi ed è un fattore critico in grado di produrre effetti apprezzabili sui tempi di stampa.

Ogni spostamento è sempre associato ad una velocità: per raggiungerla è necessario effettuare una accelerazione[decelerazione], a seconda che la velocità attuale sia minore[maggiore] rispetto al target.

Supponiamo che la macchina abbia pianificato di dover eseguire due blocchi in successione: il blocco j a velocità \vec{v}_j ed il blocco k a velocità \vec{v}_k. La velocità di giunzione tra i due blocchi (incognita!) è \vec{v}_{junction}. Il blocco j è ora in esecuzione con velocità \vec{v}_j: gli rimane un tempo t_j per raggiungere \vec{v}_{junction}, ciò significa che si renderà necessaria una accelerazione \vec{a}_j = {\Delta \vec{v}}/{\Delta t} = {\vec{v}_{junction} - \vec{v}_j}/{t_j}. A questo punto il blocco k avrà a disposizione un tempo t_k per portarsi alla velocità \vec{v}_k, ciò significa che si renderà necessaria una accelerazione \vec{a}_k = {\Delta \vec{v}}/{\Delta t} = {\vec{v}_k - \vec{v}_{junction}}/{t_k}. In generale \vec{a}_j <> \vec{a}_k: ciò significa che il jerk (derivata dell'accelerazione nel tempo), assumerà un valore diverso da zero solo nell'intervallo di tempo durante la transizione da un'accelerazione all'altra, mentre sarà uguale a zero per il resto del tempo. Esso infatti è calcolato come \vec{jerk} = {\Delta \vec{a}} / {\Delta t} = {\vec{a}_k - \vec{a}_j}/{t_0}, laddove t_0 è un valore molto piccolo dell'ordine di pochi microsecondi. Il jerk è una variazione (aumento/diminuzione) di accelerazione che può produrre effetti indesiderati sulle stampe e questo sistema è in grado di mantenerlo a zero per la maggior parte del tempo.

Esiste una funzionalità che permette di mantenere sempre il jerk a zero. Per informazioni, riferirsi alla guida S-Curve Acceleration

Strategia

Uno dei problemi di questo sistema è che le accelerazioni e le decelerazioni richiedono tempo: un tempo relativamente piccolo che, moltiplicato per i milioni di movimenti richiesti per una stampa, può aumentare anche di molto i tempi di stampa.

Si è deciso quindi di evitare il più possibile tali fasi di accelerazione introducendo dei parametri modificabili dall'utente che qui chiameremo "max_jerk". In realtà tali valori si chiamano così perché incidono sul valore del jerk ma non possono essere considerati dei veri e propri jerk. Essi infatti dimensionalmente sono rappresentati da variazioni di velocità e sono quindi misurati in mm/s.

L'algoritmo

Riprendendo l'esempio di prima, avremo una variazione di velocità pari a \Delta \vec{v} = \vec{v}_k - \vec{v}_j:

  • se almeno una tra le componenti XYZ di \Delta \vec{v} supera il relativo "max_jerk" impostato, il firmware realizzerà il passaggio da \vec{v}_j a \vec{v}_k tramite accelerazioni. Stabilirà il valore incognito di \vec{v}_{junction} in modo tale che le variazioni di velocità lungo i tre assi non superino quelle impostate tramite max_jerk. In realtà l'algoritmo è nei fatti un po' più complesso di così: deve infatti tener conto anche di altri fattori tra i quali eventuali cambi di direzione degli assi (un qualunque asse deve rallentare fino a fermarsi prima di poter invertire la direzione del proprio moto);
  • altrimenti il passaggio da una velocità all'altra sarà istantaneo e non si perderà tempo per le accelerazioni/decelerazioni intermedie.

Configurazione dei parametri

Il "max_jerk" è quindi la minima variazione di velocità che richiede un'accelerazione: se \vec{v}_j e \vec{v}_k fossero abbastanza simili tra loro, il passaggio dall'una all'altra sarebbe istantaneo. Questo trucchetto permette di ridurre leggermente i tempi di stampa ma va impostato correttamente: più i valori di "max_jerk" vengono aumentati, maggiori saranno gli spostamenti (statisticamente) che verranno gestiti con il cambio di velocità istantaneo (e maggiori saranno quindi le vibrazioni prodotte).

Riassumendo, i "max_jerk" devono essere impostati tenendo a mente che abbassando tali valori si riducono le vibrazioni e i rumori prodotti dai motori ma si allungano conseguentemente i tempi di stampa, e viceversa.

Per abilitare il Jerk Limiting è sufficiente assicurarsi che il Junction Deviation sia disabilitato. Ecco un esempio di configurazione dei suoi parametri:

//#define JUNCTION_DEVIATION // per abilitare il Jerk Limiting e disabilitare il Junction Deviation

#define DEFAULT_XJERK 10

#define DEFAULT_YJERK 10

#define DEFAULT_ZJERK 0.4

#define DEFAULT_EJERK {5,5,5,5,5,5}

Strategia

L'algoritmo Jerk Limiting ragiona su ciascun asse separatamente, senza perciò tener in considerazione l'effettiva traiettoria generata dai movimenti pianificati nel planner. Il risultato è che nelle curve, che sono sempre composte da una moltitudine di segmenti più o meno "corti", il planner cerca di assicurare che ciascun asse non subisca variazioni troppo alte di velocità limitando separatamente le componenti \vec{v}_X, \vec{v}_Y e \vec{v}_Z, finendo spesso per limitare eccessivamente la velocità totale (data dalla loro somma vettoriale: \vec{v} = \vec{v}_X + \vec{v}_Y +\vec{v}_Z).

L'algoritmo Junction Deviation fornisce invece al planner una visione d'insieme migliore sulla coda di movimenti da eseguire, permettendogli di scegliere \vec{v}_{junction} tenendo conto solamente di fattori relativi alla traiettoria degli spostamenti. Il risultato è un algoritmo più semplice ed efficace, in grado di evitare rallentamenti eccessivi e quindi di velocizzare la percorrenza di tratti curvilinei. Alcuni utenti di Marlin, i primi ad aver testato tale algoritmo, hanno riferito di aver notato una diminuzione di circa il 20% sui tempi di stampa.

L'algoritmo

NOTA DELL'AUTORE: Attualmente la migliore spiegazione si trova qui: Improving Grbl cornering algorithm. È disponibile solo in lingua inglese e in alcuni passaggi è un po' sbrigativa e confusa, per lo meno agli occhi dell'autore di questa guida. Per questo motivo, se dovesse servire, potrei dedicarmi alla sua riscrittura in lingua italiana.

Configurazione dei parametri

Per attivare questa funzionalità è necessario assicurarsi di aver abilitato l'opzione JUNCTION_DEVIATION. I parametri attualmente disponibili sono i seguenti:

#define JUNCTION_DEVIATION // per abilitare il Junction Deviation e disabilitare il Jerk Limiting

#define JUNCTION_DEVIATION_MM 0.05 // valore decimale maggiore o uguale a 0

#define JUNCTION_ACCELERATION 1000

//#define JUNCTION_DEVIATION_INCLUDE_E
  • Per comprendere l'opzione JUNCTION_DEVIATION_MM è strettamente necessario aver capito a fondo il funzionamento dell'algoritmo. Si faccia riferimento alla guida di cui sopra è stato fornito il link. Si sappia che è un valore espresso in mm e che un range sicuro di possibili valori va da 0mm a 0,5mm. Ovviamente questi valori vanno testati sulla propria macchina procedendo per tentativi;
  • JUNCTION_ACCELERATION è il più semplice da immaginare: trattasi della massima accelerazione centripeta che la meccanica può sostenere. Durante i cambi di direzione il nuovo algoritmo cerca di mantenere costante la velocità: l'accelerazione centripeta è a_{centripeta} = {v^2}/{r}, dove r è il raggio di curvatura. \vec{v} e soprattutto r possono cambiare da un movimento all'altro, determinando di volta in volta un diverso valore di a_{centripeta}. JUNCTION_ACCELERATION permette quindi di limitare a_{centripeta};
  • Per fare in modo che per la valutazione dell'angolo di curvatura venga tenuto in conto anche l'avanzamento/ritrazione del filamento, è necessario abilitare l'opzione JUNCTION_DEVIATION_INCLUDE_E. Questa opzione è assolutamente sperimentale! Siccome abilitando tale opzione l'angolo verrebbe calcolato in uno spazio quadridimensionale XYZE, nemmeno gli sviluppatori del Junction Deviation sono in grado di predirne con sicurezza gli effetti! L'opzione è presente perché il planner ha a disposizione anche i dati relativi all'estrusore: siccome lo sforzo che sarebbe servito per aggiungere tale possibilità era davvero minimo, pur non riuscendo ad immaginarne gli effetti o l'utilità, gli sviluppatori hanno pensato di lasciare tale funzione e di permettere agli utenti di sperimentarla sulle loro macchine per verificare se ciò possa produrre miglioramenti apprezzabili o meno.

L'analogia dell'automobile

Se volessimo utilizzare un'analogia per far comprendere meglio il significato dei primi due parametri, faremmo sicuramente riferimento ad un'automobile che si appresta ad affrontare una curva stretta.

In questa analogia, tratta dalla guida sopra citata, JUNCTION_DEVIATION_MM rappresenta la larghezza della strada rispetto a quella dell'automobile: impostarlo a zero significa che la strada sarà della stessa larghezza della vettura, la quale sarà costretta (come se fosse su di un binario) a rallentare molto per affrontare la curva senza uscire dalla carreggiata. Viceversa, aumentare tale valore renderà la strada più larga e permetterà all'automobile di scegliere una traiettoria più veloce (con la differenza che nel caso della stampante la traiettoria rimarrà ovviamente la stessa ma sarà percorsa a velocità maggiore).

JUNCTION_ACCELERATION rappresenterebbe invece il "grip" (l'aderenza) delle gomme con l'asfalto: se l'aderenza è scarsa, la velocità di percorrenza della curva deve essere limitata di molto per evitare di scivolare fuori traiettoria. Viceversa, un valore alto significa che l'automobile è in grado di sopportare accelerazioni centripete più alte e quindi può premere più bruscamente i pedali del gas e del freno.

I due parametri vanno quindi impostati tenendo conto del loro significato fisico/geometrico. L'utente è libero di sperimentare per trovare i valori limite della propria stampante ma il consiglio è quello di non allontanarsi troppo dai valori di default, a meno che non si sappia esattamente cosa si stia facendo.

Simone Persiani 26/05/2018 13:00