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.

Una única rueda mecanum dibujada de lado sobre una línea de suelo. El neumático está rayado con barras de rodillo montadas a 45 grados, etiquetadas como rodillos libres de girar, con ejes a 45 grados. Desde la zona de contacto con el suelo, una flecha roja apunta hacia abajo y a la derecha a 45 grados, etiquetada como fuerza sobre el suelo F raíz de dos, y está rematada por μN. Una flecha cian apunta horizontalmente a lo largo del suelo, etiquetada como fuerza útil F, dibujada como la componente horizontal de la flecha roja, con una línea discontinua que cierra el triángulo rectángulo y un arco que marca el ángulo de 45 grados. Un pie de foto señala que el rozamiento limita todo el vector de 45 grados pero solo su parte horizontal mueve al robot, así que la fuerza útil por rueda es μN sobre raíz de dos, alrededor del 71 por ciento de una rueda lisa.
Toda la penalización de tracción en un triángulo. El rodillo solo transmite fuerza a lo largo de su propio eje, así que la fuerza de la rueda sobre el suelo queda clavada a 45° — el rozamiento limita ese vector entero mientras solo su componente horizontal mueve al robot. Descargar SVG

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.
Cuatro paneles en vista cenital del mismo robot mecanum con la morro arriba, cada uno mostrando en qué sentido giran las cuatro ruedas para una orden, con las velocidades de rueda listadas como frontal izquierda, frontal derecha, trasera izquierda, trasera derecha, escaladas a la rueda más rápida. Avance: más uno en las cuatro, todas las flechas en el mismo sentido, anotado como que las partes laterales se cancelan. Desplazamiento a la izquierda: menos uno, más uno, más uno, menos uno, con los pares diagonales opuestos y una flecha ámbar apuntando a la izquierda. Giro antihorario: menos uno, más uno, menos uno, más uno, lado izquierdo atrás y lado derecho delante, con un arco ámbar. Diagonal: cero, más uno, más uno, cero, con una flecha ámbar apuntando a delante-izquierda y una nota de que dos ruedas lo hacen todo mientras dos no hacen nada.
Las cuatro órdenes, sacadas directamente de la matriz. Fíjate en la última: una diagonal pide todo a dos ruedas y nada a las otras dos, y de ahí sale el techo diagonal del 71 %. Descargar SVG

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.

Gráfico de la velocidad lateral frente a la velocidad de avance en metros por segundo, mostrando todas las velocidades que puede alcanzar un robot mecanum con ruedas de 0.60 metros por segundo. El conjunto alcanzable es un rombo cian relleno con vértices en más y menos 0.60 en cada eje. Se dibuja a modo de comparación un círculo discontinuo gris de radio 0.60, etiquetado como sin penalización por dirección. Hay marcadores ámbar en 0.60 metros por segundo de avance y 0.60 metros por segundo lateral, en los vértices del rombo, y un marcador rojo en la arista diagonal etiquetado como 0.424 metros por segundo en la diagonal.
Todas las velocidades que el robot puede alcanzar, resueltas dirección a dirección. Recto adelante y recto al lateral son gratis; la arista diagonal del rombo es donde la orden te cuesta 1/√2. Solo un tren motriz sin ningún 45° dentro consigue el círculo. Descargar SVG

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

Referencias