Tutorial · Intermedio · 35 min de lectura
Cinemática de ruedas Mecanum: cuatro ruedas en tres ejes
Deduce la cinemática inversa de una base mecanum a partir del rodillo a 45°, inviértela para odometría y usa la cuarta ecuación para detectar patinamiento.
Un rodillo lo decide todo
Quita una rueda mecanum al robot y sostenla en la mano. Gira sobre su eje como cualquier rueda. Alrededor de su llanta se sientan ocho o nueve rodillos con forma de barril, cada uno sobre su propio eje diminuto, cada uno libre de girar, y cada uno montado a 45° respecto al eje de la rueda.
Ahora pregúntate qué fuerza puede meter esa rueda en el suelo.
No puede empujar a lo largo de la dirección de rodadura del rodillo — el rodillo simplemente gira y no se transmite nada. Solo puede empujar a lo largo del eje del rodillo, la única dirección en la que el rodillo se niega a rodar. Así que la fuerza de la rueda sobre el suelo está fijada a una única recta en el suelo, a 45° respecto al chasis, y ningún par de motor cambia qué recta es.
Ese es todo el mecanismo. Todo lo de abajo es contabilidad.
La restricción, rueda a rueda
Fija el marco habitual del robot: x hacia delante, y a la izquierda del robot, ω antihorario. Esta es la convención de ROS, y usar cualquier otra significa pelearte con todas las bibliotecas que vayas a tocar jamás.
Pon la rueda i en la posición (xᵢ, yᵢ) de ese marco, y dale una mano de rodillo sᵢ = ±1 que dice cuál de las dos rectas a 45° siguen sus rodillos. Entonces la velocidad de llanta vᵢ (en metros por segundo en el neumático, no en radianes) se relaciona con la torsión del chasis así:
vᵢ = vx + sᵢ·vy + (sᵢ·xᵢ − yᵢ)·ω
Tres términos, y cada uno merece una frase:
- vx — toda rueda contribuye por completo al avance, sea cual sea su mano. Por eso avanzar en una base mecanum se siente completamente normal.
- sᵢ·vy — el movimiento lateral hace girar la mitad de las ruedas en un sentido y la otra mitad en el contrario. La mano decide qué mitad.
- (sᵢ·xᵢ − yᵢ)·ω — el brazo de momento. Ojo, no es solo la vía; la mano de rodillo está dentro, y por eso una rueda en la esquina equivocada arruina también la rotación además del desplazamiento lateral.
Para pasar de la velocidad de llanta a lo que realmente mandas a un motor, divide por el radio de la rueda: ωrueda = vᵢ / r, en rad/s.
Cuatro ruedas: la matriz
Apila esas cuatro filas y tienes una matriz 4 × 3 A, con la torsión del chasis ξ = (vx, vy, ω):
v = A · ξ
Para la disposición estándar —frontal izquierda y trasera derecha con una mano, frontal derecha y trasera izquierda con la otra— escribe k = lx + ly donde lx es la mitad de la distancia entre ejes (de delante a atrás) y ly es la mitad de la vía (de izquierda a derecha). Entonces:
| Rueda | vx | vy | ω |
|---|---|---|---|
| Frontal izquierda | 1 | −1 | −k |
| Frontal derecha | 1 | +1 | +k |
| Trasera izquierda | 1 | +1 | −k |
| Trasera derecha | 1 | −1 | +k |
Que son las cuatro líneas que escribe todo el mundo:
float fl = vx - vy - K * omega;
float fr = vx + vy + K * omega;
float rl = vx + vy - K * omega;
float rr = vx - vy + K * omega;
Compruébalo contra las cuatro cosas que ya sabes que hace un robot mecanum:
| Orden | Velocidades de rueda (FI, FD, TI, TD) | Lo que ves |
|---|---|---|
| Avance, vx = 1 | 1, 1, 1, 1 | Las cuatro igual. Las partes laterales se cancelan. |
| Desplazamiento a la izquierda, vy = 1 | −1, 1, 1, −1 | Los pares diagonales se oponen. Este es el truco de fiesta. |
| Giro antihorario, ω = 1 | −k, k, −k, k | Lado izquierdo atrás, lado derecho delante — un giro de tanque normal. |
| Diagonal, vx = vy = 1 | 0, 2, 2, 0 | Dos ruedas se paran del todo. Ten presente esta. |
El ejemplo trabajado
Una base con lx = 75 mm, ly = 85 mm, ruedas de 97 mm (r = 48,5 mm), a la que se le pide vx = 0,30 m/s, vy = 0,20 m/s, ω = 0,50 rad/s. Así que k = 0,160 m.
| Rueda | Aritmética | Velocidad de llanta | Velocidad de motor |
|---|---|---|---|
| Frontal izquierda | 0.30 − 0.20 − 0.160 × 0.50 | 0.020 m/s | 0.41 rad/s (3.9 rpm) |
| Frontal derecha | 0.30 + 0.20 + 0.160 × 0.50 | 0.580 m/s | 11.96 rad/s (114 rpm) |
| Trasera izquierda | 0.30 + 0.20 − 0.160 × 0.50 | 0.420 m/s | 8.66 rad/s (83 rpm) |
| Trasera derecha | 0.30 − 0.20 + 0.160 × 0.50 | 0.180 m/s | 3.71 rad/s (35 rpm) |
Veintinueve veces la velocidad de una rueda frente a otra, a partir de una orden que no parece extrema. Un tren motriz mecanum pasa la mayor parte de su vida con sus cuatro motores haciendo cosas salvajemente distintas, y por eso «les pongo a todos el mismo PWM y va recto» no es una prueba que signifique nada aquí.
Saturación: escala, nunca recorte
Si pides más de lo que tienen los motores, tienes que renunciar a algo. Hay exactamente dos opciones y no son equivalentes.
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;
}
Frente a lo que pasa si simplemente escribes constrain(fl, -255, 255) en cada motor: recorte. El recorte conserva la velocidad y tira la dirección. Pide 0,60 m/s de avance, 0,15 lateral y 0,8 rad/s de giro en un robot cuyas ruedas topan en 0,50 m/s:
| Rumbo | Avance | Giro | Veredicto | |
|---|---|---|---|---|
| Ordenado | 14.0° | 0.60 m/s | 0.80 rad/s | — |
| Escala | 14.0° | 0.34 m/s | 0.46 rad/s | Más lento en todos los ejes, exactamente hacia donde apuntabas |
| Recorte | 5.6° | 0.46 m/s | 0.28 rad/s | Más rápido hacia delante, 8.4° fuera de rumbo y un 40 % menos de giro |
Lo peor del recorte es que parece correcto con las órdenes que la gente prueba. Una diagonal pura pide 2 a dos ruedas y 0 a las otras dos; los ceros ya están dentro del límite, así que el recorte y la escala producen números idénticos y el bug se esconde. Aparece más tarde, bajo un seguidor de trayectoria, como un robot que se inclina hacia fuera en las curvas sin razón que nadie encuentre. Mira los dos limitadores en la misma pasada y la diferencia es una curva que se ve.
Yendo hacia atrás: odometría
La cinemática directa es la misma matriz leída al revés. Pero A es 4 × 3 — cuatro medidas, tres incógnitas— así que no hay inversa. Hay una solución de mínimos cuadrados:
ξ = (Aᵀ A)⁻¹ Aᵀ v
Para la disposición estándar AᵀA sale diagonal y todo el asunto se reduce a tres líneas que puedes poner en un Arduino:
vx = (fl + fr + rl + rr) / 4.0;
vy = (-fl + fr + rl - rr) / 4.0;
omega = (-fl + fr - rl + rr) / (4.0 * K);
Integra eso a través del rumbo del robot en cada tick y tienes dead reckoning:
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;
Que funciona exactamente tan bien como la suposición que tiene debajo — que las ruedas no patinan. En una base mecanum, el patinaje es el punto de diseño de la rueda, así que trata la odometría lateral como el número menos fiable del robot.
La cuarta ecuación que nadie usa
Cuatro ecuaciones, tres incógnitas. Esa ecuación de sobra no es desperdicio — es el único diagnóstico gratis de todo el tren motriz.
Si el robot es rígido y todas las ruedas agarran, las cuatro velocidades de llanta no pueden ser arbitrarias. Suma las dos primeras filas de la matriz y las dos últimas: ambas dan 2·vx, así que:
FL + FR = RL + RR
siempre, exactamente, para cualquier movimiento que un chasis mecanum rígido pueda ejecutar. Así que calcula el residuo en cada bucle:
float residual = (fl + fr) - (rl + rr); // should be ~0 forever
Que sea distinto de cero significa que los cuatro encoders están describiendo un movimiento que ningún objeto sólido puede hacer. Causas, en orden aproximado de probabilidad: una rueda fuera del suelo, una rueda sobre un charco húmedo, un rodillo agarrotado, un acoplamiento que patina, un canal de encoder muerto — o una rueda montada en la esquina equivocada, que hace que el residuo sea grande y constante en vez de a ráfagas.
Sé honesto sobre lo que no puede ver: si las cuatro ruedas patinan igual y a la vez, el residuo se queda en cero y el robot se desliza lateralmente fuera de rumbo en total silencio. Esa ceguera es exactamente la razón por la que la odometría mecanum falla en silencio en vez de en voz alta, y la razón por la que los montajes serios añaden una IMU o ruedas muertas sin motor en lugar de confiar en los encoders de la transmisión.
Las dos consecuencias de los 45°
Las dos se desprenden de la matriz, y ninguna se puede comprar.
El movimiento diagonal está limitado a 1/√2. Una orden a 45° pone vx + vy en dos ruedas y 0 en las otras dos, así que el par que trabaja llega al límite de velocidad cuando el robot solo se mueve al V_MAX / √2 ≈ 71 % de su velocidad máxima en línea recta. Motores más rápidos suben el techo; no lo eliminan.
La tracción también está limitada a 1/√2, por otro motivo. La fuerza de avance útil F del motor va a lo largo de la dirección de rodadura, pero la fuerza real sobre el suelo es F·√2 a lo largo del eje del rodillo, y el rozamiento limita eso. Así que por rueda la fuerza útil está limitada a μN/√2, y el techo de aceleración del robot es:
a_max = μ·g / √2
Con μ = 0,85 eso son 5,9 m/s², donde el mismo robot sobre ruedas lisas tendría 8,3. La masa del robot se cancela en ambos casos, así que la lastre no ayuda — una lección que va exactamente al revés que en un robot sumo, donde el peso es toda la estrategia.
En el firmware
Pon la geometría en un solo sitio y no la dejes nunca escribirse dos veces.
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
}
};
Mide lx y ly de centro de rueda a centro de rueda, y luego divide por dos — no sobre la chapa del chasis, que suele ser más ancha. Equivocar k no impide que el robot conduzca; hace que la rotación y la translación se filtren una en otra, así que una orden de giro puro se arrastra y una orden de desplazamiento lateral puro se curva. Si tu robot se arrastra mientras gira sobre sí mismo, sospecha de k antes que del código.
Resolución de problemas
| Síntoma | Causa probable | Qué comprobar |
|---|---|---|
| Avance bien, el desplazamiento lateral curva y gira | Una rueda en la esquina equivocada | La comprobación en X de arriba; el residuo será grande y estable |
| Se desplaza al revés de lo ordenado | Las cuatro ruedas espejadas | Intercambia el par izquierdo con el derecho |
| Girando sobre sí mismo también se traslada | k mal, o lx/ly medidos sobre el chasis en vez de las ruedas | Vuelve a medir de centro de rueda a centro de rueda |
| La diagonal es mucho más lenta que el avance | El techo de 1/√2 — no es un fallo | Nada que arreglar; diseña en torno a ello |
| El robot se inclina hacia fuera en las curvas bajo un seguidor de trayectoria | Recorte por motor en vez de escalado | Escala la orden entera por la peor rueda |
| La odometría deriva rápido lateralmente, bien hacia delante | Patinaje de rodillos, funcionando como está diseñado | IMU para el rumbo, ruedas muertas para la posición |
| El residuo se dispara solo en una superficie | Ese trozo es resbaladizo, o un rodillo está agarrotado | Gira todos los rodillos a mano |
Siguiente
Ejecuta los números contra un robot que pueda patinar: el simulador de locomoción mecanum mete estas mismas ecuaciones en un modelo de rozamiento, así que puedes ver cómo la odometría y el suelo discrepan. Después haz que las ruedas aguanten de verdad las velocidades que calculaste —control en lazo cerrado de la velocidad de rueda— y haz que «avanzar» signifique avanzar en el suelo y no en el robot con orientación en campo.
Explora el grafo
Forma parte de estos montajes
Proyectos y rutas de aprendizaje que incluyen este tutorial.
Lecturas adicionales