Tutorial · Intermedio · 35 min

Cinematica delle ruote Mecanum: quattro ruote, tre assi

Da un rullo a 45° ricava quattro equazioni di cinematica inversa per una base Mecanum, poi usa l'equazione ridondante per odometria e slittamento.

Un rullino determina tutto

Togli una ruota Mecanum dal robot e tienila in mano. Ruota sul proprio asse come qualsiasi ruota. Sul bordo ci sono otto o nove rulli a forma di barile, ciascuno sul proprio piccolo asse, ciascuno libero di ruotare e ciascuno inclinato a 45° rispetto all’asse della ruota.

Ora chiediti quale forza la ruota può esercitare sul pavimento.

Non può spingere lungo la direzione di rotazione del rullino: il rullino ruota semplicemente e non trasmette nulla. Può spingere soltanto lungo l’asse del rullino, l’unica direzione lungo la quale il rullino si rifiuta di ruotare. La forza della ruota sul terreno è quindi bloccata su un’unica retta del pavimento, a 45° rispetto al telaio, e nessuna quantità di coppia motrice cambia quale sia quella retta.

Questo è l’intero meccanismo. Tutto il resto è contabilità.

Una singola ruota Mecanum vista di lato sopra una linea del pavimento. Il pneumatico è tratteggiato con barre di rulli inclinate a 45 gradi, etichettate come rulli liberi di ruotare, e assi a 45 gradi. Dal punto di contatto con il pavimento una freccia rossa punta in basso a destra a 45 gradi ed è etichettata forza al suolo F per radice di due, limitata da μN. Una freccia ciano punta orizzontalmente lungo il pavimento ed è etichettata F utile; è tracciata come componente orizzontale della freccia rossa, con una linea tratteggiata che chiude il triangolo rettangolo e un arco che indica l'angolo di 45 gradi. La didascalia osserva che l'attrito limita l'intero vettore a 45 gradi, ma solo la parte orizzontale fa avanzare il robot, quindi la forza utile per ruota è μN diviso radice di due, circa il 71% di una ruota semplice.
L'intera penalità di trazione in un triangolo. Il rullino trasmette forza soltanto lungo il proprio asse, quindi la forza della ruota sul terreno resta a 45°: l'attrito limita l'intero vettore, mentre solo la componente orizzontale muove il robot. Scarica SVG

Il vincolo, una ruota alla volta

Imposta il solito sistema di riferimento del robot: x in avanti, y verso sinistra del robot, ω in senso antiorario. Questa è la convenzione ROS; usarne un’altra significa combattere con ogni libreria che toccherai.

Metti la ruota i nella posizione (xᵢ, yᵢ) di questo sistema di riferimento e assegna alla sua mano del rullino sᵢ = ±1, che indica lungo quale delle due rette a 45° si allineano i rulli. La velocità perimetrale vᵢ della ruota (in metri al secondo sulla gomma, non in radianti) è allora legata alla velocità del telaio da:

vᵢ = vx + sᵢ·vy + (sᵢ·xᵢ − yᵢ)·ω

Tre termini, ciascuno degno di una frase:

  • vx — ogni ruota contribuisce pienamente al movimento in avanti, qualunque sia la sua mano. Ecco perché l’avanti su una base Mecanum risulta del tutto normale.
  • sᵢ·vy — il movimento laterale aziona metà delle ruote in una direzione e metà nell’altra. La mano decide quale metà.
  • (sᵢ·xᵢ − yᵢ)·ω — il braccio di momento. Nota che non dipende soltanto dalla carreggiata: la mano del rullino è dentro l’espressione, ed è per questo che una ruota nell’angolo sbagliato rovina anche la rotazione oltre alla traslazione laterale.

Per passare dalla velocità perimetrale a ciò che comandi davvero al motore, dividi per il raggio della ruota: ωwheel = vᵢ / r, in rad/s.

Quattro ruote: la matrice

Impila queste quattro righe e ottieni una matrice 4 × 3 A, con la velocità del telaio ξ = (vx, vy, ω):

v = A · ξ

Per la disposizione standard — anteriore sinistra e posteriore destra con una mano, anteriore destra e posteriore sinistra con l’altra — scrivi k = lx + ly, dove lx è metà dell’interasse (dall’avanti al posteriore) e ly è metà della carreggiata (da sinistra a destra). Quindi:

Ruota vx vy ω
Anteriore sinistra 1 −1 −k
Anteriore destra 1 +1 +k
Posteriore sinistra 1 +1 −k
Posteriore destra 1 −1 +k

Sono le quattro righe che tutti scrivono:

float fl = vx - vy - K * omega;
float fr = vx + vy + K * omega;
float rl = vx + vy - K * omega;
float rr = vx - vy + K * omega;

Verifica con le quattro cose che sai già fare a un robot Mecanum:

Comando Velocità delle ruote (FL, FR, RL, RR) Cosa osservi
Avanti, vx = 1 1, 1, 1, 1 Tutte e quattro nello stesso verso. Le componenti laterali si annullano.
Traslazione a sinistra, vy = 1 −1, 1, 1, −1 Le coppie diagonali si oppongono. È l’effetto caratteristico.
Rotazione antioraria, ω = 1 −k, k, −k, k Lato sinistro indietro, lato destro avanti: una normale rotazione su posto.
Diagonale, vx = vy = 1 0, 2, 2, 0 Due ruote si fermano completamente. Tienilo a mente.
Quattro pannelli dall'alto dello stesso robot Mecanum orientato verso l'alto, ciascuno con la direzione di rotazione delle quattro ruote per un comando, e le velocità elencate come anteriore sinistra, anteriore destra, posteriore sinistra e posteriore destra, ridimensionate alla ruota più veloce. Avanti: più uno su tutte e quattro, frecce tutte nello stesso verso e nota che le componenti laterali si annullano. Traslazione a sinistra: meno uno, più uno, più uno, meno uno, con coppie diagonali opposte e una freccia ambra verso sinistra. Rotazione antioraria: meno uno, più uno, meno uno, più uno, lato sinistro indietro e lato destro avanti, con un arco ambra. Diagonale: zero, più uno, più uno, zero, con una freccia ambra in avanti a sinistra e la nota che due ruote fanno tutto mentre due non fanno nulla.
I quattro comandi, ricavati direttamente dalla matrice. Osserva l'ultimo: un movimento diagonale chiede tutto a due ruote e nulla alle altre due, da cui nasce il limite diagonale del 71%. Scarica SVG

L’esempio calcolato

Una base con lx = 75 mm, ly = 85 mm e ruote da 97 mm (r = 48.5 mm) riceve il comando vx = 0.30 m/s, vy = 0.20 m/s, ω = 0.50 rad/s. Quindi k = 0.160 m.

Ruota Calcolo Velocità perimetrale Velocità del motore
Anteriore sinistra 0.30 − 0.20 − 0.160 × 0.50 0.020 m/s 0.41 rad/s (3.9 rpm)
Anteriore destra 0.30 + 0.20 + 0.160 × 0.50 0.580 m/s 11.96 rad/s (114 rpm)
Posteriore sinistra 0.30 + 0.20 − 0.160 × 0.50 0.420 m/s 8.66 rad/s (83 rpm)
Posteriore destra 0.30 − 0.20 + 0.160 × 0.50 0.180 m/s 3.71 rad/s (35 rpm)

Ventinove volte la velocità su una ruota rispetto a un’altra, da un comando che non sembra estremo. Una trazione Mecanum passa quasi tutto il tempo con i suoi quattro motori che fanno cose radicalmente diverse, ed è per questo che «assegnano tutti lo stesso PWM e va dritto» non è una prova utile in questo contesto.

Saturazione: scala, non troncare

Se chiedi più di quanto possano fornire i motori, devi rinunciare a qualcosa. Ci sono esattamente due scelte e non sono equivalenti.

float peak = max(max(fabs(fl), fabs(fr)), max(fabs(rl), fabs(rr)));
if (peak > V_MAX) {            // SCALE: keep the direction, lose the speed
  float s = V_MAX / peak;
  fl *= s; fr *= s; rl *= s; rr *= s;
}

Rispetto a ciò che accade se scrivi soltanto constrain(fl, -255, 255) su ogni motore: troncare. Il troncamento conserva la velocità e scarta la direzione. Chiedi 0.60 m/s in avanti, 0.15 laterali e 0.8 rad/s di rotazione a un robot le cui ruote raggiungono al massimo 0.50 m/s:

Orientamento Avanti Rotazione Verdetto
Richiesto 14.0° 0.60 m/s 0.80 rad/s —
Scala 14.0° 0.34 m/s 0.46 rad/s Più lento su ogni asse, esattamente nella direzione indicata
Troncamento 5.6° 0.46 m/s 0.28 rad/s Più veloce in avanti, 8.4° fuori rotta e il 40% di rotazione in meno

La parte più insidiosa è che il troncamento sembra corretto sui comandi con cui le persone fanno le prove. Una diagonale pura chiede 2 a due ruote e 0 alle altre due; gli zeri sono già entro il limite, quindi troncamento e scala producono numeri identici e il bug si nasconde. Compare più avanti, sotto un robot seguilinea, come un robot che esce dalle curve senza una ragione che nessuno riesca a trovare. Osserva entrambi i limitatori nella stessa esecuzione: la differenza è una curva visibile.

In senso inverso: odometria

La cinematica diretta è la stessa matrice letta al contrario. Ma A è 4 × 3 — quattro misurazioni, tre incognite — quindi non esiste un’inversa. Esiste una soluzione ai minimi quadrati:

ξ = (Aᵀ A)⁻¹ Aᵀ v

Per la disposizione standard, AᵀA risulta diagonale e tutto si riduce a tre righe che puoi caricare su un Arduino:

vx    = (fl + fr + rl + rr) / 4.0;
vy    = (-fl + fr + rl - rr) / 4.0;
omega = (-fl + fr - rl + rr) / (4.0 * K);

Integrale rispetto all’orientamento del robot a ogni passo e ottieni una stima per integrazione:

float dt = (now - last) * 1e-6f;
theta += omega * dt;
x += (vx * cosf(theta) - vy * sinf(theta)) * dt;
y += (vx * sinf(theta) + vy * cosf(theta)) * dt;

Funziona esattamente quanto bene funziona l’ipotesi sottostante, cioè che le ruote non slittino. Su una base Mecanum, lo slittamento è il punto di funzionamento previsto della ruota, quindi considera l’odometria laterale il dato meno attendibile del robot.

La quarta equazione che nessuno usa

Quattro equazioni, tre incognite. L’equazione ridondante non è uno spreco: è l’unica diagnostica gratuita dell’intera trazione.

Se il robot rigido è stabile e ogni ruota aderisce, le quattro velocità perimetrali non possono essere arbitrarie. Somma le prime due righe e le ultime due righe della matrice: entrambe danno 2·vx, quindi:

FL + FR = RL + RR

sempre, esattamente, per qualsiasi moto che un telaio Mecanum rigido possa eseguire. Calcola quindi il residuo a ogni ciclo:

float residual = (fl + fr) - (rl + rr);   // should be ~0 forever

Un valore diverso da zero significa che i quattro encoder descrivono un moto impossibile per un oggetto solido. Possibili cause, in ordine approssimativo di probabilità: una ruota sollevata da terra, una ruota su una zona bagnata, un rullino bloccato, un accoppiamento che slitta, un canale encoder morto — oppure una ruota montata nell’angolo sbagliato, che rende il residuo grande e costante anziché discontinuo.

Sii onesto su ciò che non può vedere: se tutte e quattro le ruote slittano nello stesso modo e nello stesso istante, il residuo resta a zero e il robot scivola lateralmente fuori rotta in totale silenzio. Questa cecità è il motivo per cui l’odometria Mecanum fallisce in silenzio anziché rumorosamente e per cui le costruzioni serie aggiungono un IMU o ruote passive non motorizzate invece di fidarsi degli encoder della trazione.

Le due conseguenze dei 45°

Entrambe derivano dalla matrice e nessuna si può eliminare.

Il movimento diagonale è limitato a 1/√2. Un comando a 45° impone vx + vy a due ruote e 0 alle altre due, quindi la coppia impegnata raggiunge il limite di velocità quando il robot si muove soltanto a V_MAX / √2 ≈ 71% della sua velocità massima in rettilineo. Motori più veloci alzano il limite; non lo eliminano.

Anche la trazione è limitata a 1/√2, ma per un motivo diverso. La forza motrice utile F del motore è lungo la direzione di rotazione, ma la forza effettiva al terreno è F·√2 lungo l’asse del rullino, e l’attrito limita quella. Per ogni ruota la forza utile è quindi limitata a μN/√2 e il limite di accelerazione del robot è:

a_max = μ·g / √2

Con μ = 0.85 è 5.9 m/s², mentre lo stesso robot su ruote semplici avrebbe 8.3. La massa del robot si cancella in entrambi i casi, quindi la zavorra non aiuta: una lezione opposta a quella del robot sumo, per il quale il peso è l’intera strategia.

Grafico della velocità laterale rispetto alla velocità in avanti, espresse in metri al secondo, che mostra ogni velocità raggiungibile da un robot Mecanum con ruote da 0.60 metri al secondo. L'insieme raggiungibile è un rombo cyan pieno con vertici a più e meno 0.60 su ciascun asse. Per confronto è tracciato un cerchio grigio tratteggiato di raggio 0.60, etichettato assenza di penalità direzionale. Marcatori ambra si trovano a 0.60 metri al secondo in avanti e 0.60 metri al secondo lateralmente, sui vertici del rombo, mentre un marcatore rosso sul bordo diagonale è etichettato 0.424 metri al secondo in diagonale.
Ogni velocità che il robot può raggiungere, risolta direzione per direzione. Dritto in avanti e dritto lateralmente non costano nulla; il bordo diagonale del rombo è il punto in cui il comando costa 1/√2. Solo una trasmissione priva di 45° ottiene il cerchio. Scarica SVG

Nel firmware

Metti la geometria in un solo punto e non permettere mai che venga digitata due volte.

struct Mecanum {
  float lx, ly, r;                 // half wheelbase, half track, wheel radius (m)
  float k() const { return lx + ly; }

  // twist -> four wheel angular velocities, rad/s
  void inverse(float vx, float vy, float w, float out[4]) const {
    out[0] = (vx - vy - k() * w) / r;   // FL
    out[1] = (vx + vy + k() * w) / r;   // FR
    out[2] = (vx + vy - k() * w) / r;   // RL
    out[3] = (vx - vy + k() * w) / r;   // RR
  }

  // four measured wheel angular velocities -> twist, plus the residual
  float forward(const float in[4], float &vx, float &vy, float &w) const {
    float fl = in[0] * r, fr = in[1] * r, rl = in[2] * r, rr = in[3] * r;
    vx = (fl + fr + rl + rr) * 0.25f;
    vy = (-fl + fr + rl - rr) * 0.25f;
    w  = (-fl + fr - rl + rr) * 0.25f / k();
    return (fl + fr) - (rl + rr);       // the free diagnostic
  }
};

Misura lx e ly da centro ruota a centro ruota, poi dimezza: non sulla piastra del telaio, che di solito è più larga. Se sbagli k, il robot continua a muoversi, ma rotazione e traslazione si contaminano: un comando di sola rotazione deriva e una traslazione laterale curva. Se il robot deriva mentre ruota sul posto, sospetta di k prima del codice.

Risoluzione dei problemi

Sintomo Causa probabile Cosa controllare
L’avanti funziona, la traslazione laterale curva e ruota Una ruota è nell’angolo sbagliato Il controllo X descritto sopra; il residuo sarà grande e stabile
Si sposta lateralmente nel verso opposto al comando Tutte e quattro le ruote sono specchiate Scambia la coppia sinistra con quella destra
Ruotando sul posto si sposta anche lateralmente k è sbagliato, oppure lx/ly sono stati misurati sul telaio anziché sulle ruote Rimisura da centro ruota a centro ruota
Il movimento diagonale è molto più lento dell’avanti Limite 1/√2: non è un guasto Niente da correggere; progetta tenendolo conto
Il robot esce dalle curve sotto un robot seguilinea Troncamento per motore invece che scala Scala l’intero comando in base alla ruota peggiore
L’odometria deriva rapidamente lateralmente, mentre regge in avanti Slittamento dei rulli, come previsto IMU per l’orientamento, ruote passive per la posizione
Il residuo presenta picchi solo su una superficie Quella zona è scivolosa, oppure un rullo è bloccato Gira ogni rullo a mano

Prossimo passo

Esegui i calcoli su un robot che può slittare: il simulatore della trazione Mecanum applica queste precise equazioni a un modello di attrito, così puoi osservare l’odometria e il pavimento che divergono. Poi fai in modo che le ruote mantengano davvero le velocità calcolate con il controllo in anello chiuso della velocità delle ruote e fai in modo che «avanti» significhi avanti sul terreno, non sul robot, con la trazione orientata al campo.

Esplora il grafo

Fa parte di queste costruzioni

Progetti e percorsi di apprendimento che includono questo tutorial.

Per approfondire

Fonti