Tutorial · Intermediário · 35 min

Cinemática da roda Mecanum: quatro rodas, três eixos

Derive a cinemática inversa de uma base Mecanum a partir de um rolete a 45°, inverta-a para odometria e use a equação extra para detectar derrapagem.

Um rolete decide tudo

Retire uma roda Mecanum do robô e segure-a. Ela gira no eixo como qualquer roda. Ao redor de sua borda ficam oito ou nove roletes em forma de barril, cada um em seu pequeno eixo, cada um livre para girar e cada um posicionado a 45° em relação ao eixo da roda.

Agora pergunte qual força essa roda pode aplicar no piso.

Ela não pode empurrar ao longo da direção de rolamento do rolete — o rolete simplesmente gira e nada é transmitido. Ela só pode empurrar ao longo do eixo do rolete, a única direção na qual o rolete se recusa a girar. Portanto, a força da roda no chão fica travada em uma única linha no piso, a 45° em relação ao chassi, e nenhuma quantidade de torque do motor muda qual linha é essa.

Esse é todo o mecanismo. Tudo abaixo é apenas registro matemático.

Uma única roda Mecanum desenhada de lado acima de uma linha do piso. O pneu é hachurado com barras de roletes a 45 graus, rotuladas como roletes livres para girar, e eixos a 45 graus. A partir do ponto de contato com o piso, uma seta vermelha aponta para baixo e para a direita a 45 graus, rotulada força no chão F raiz de dois, limitada por mu N. Uma seta ciano aponta horizontalmente ao longo do piso, rotulada F útil, desenhada como a componente horizontal da seta vermelha, com uma linha tracejada fechando o triângulo retângulo e um arco marcando o ângulo de 45 graus. Uma legenda observa que o atrito limita todo o vetor de 45 graus, mas apenas sua parte horizontal movimenta o robô, portanto a força útil por roda é mu N sobre raiz de dois, cerca de 71 por cento de uma roda comum.
A perda total de tração em um triângulo. O rolete só transmite força ao longo do próprio eixo, então a força da roda no chão fica presa a 45° — o atrito limita esse vetor inteiro, enquanto apenas sua componente horizontal movimenta o robô. Baixar SVG

A restrição, uma roda por vez

Defina o referencial usual do robô: x para a frente, y para a esquerda do robô, ω no sentido anti-horário. Essa é a convenção do ROS, e usar qualquer outra significa lutar contra todas as bibliotecas que você vier a usar.

Coloque a roda i na posição (xᵢ, yᵢ) nesse referencial e atribua a ela um sentido de roletes sᵢ = ±1, que indica em qual das duas linhas de 45° eles estão. Então a velocidade periférica da roda vᵢ (em metros por segundo no pneu, não em radianos) se relaciona com o movimento do chassi por:

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

São três termos, e cada um merece uma frase:

  • vx — todas as rodas contribuem totalmente para o movimento para a frente, qualquer que seja o sentido de seus roletes. É por isso que avançar em uma base Mecanum parece completamente normal.
  • sᵢ·vy — o movimento lateral faz metade das rodas girarem em um sentido e metade no outro. O sentido decide qual metade.
  • (sᵢ·xᵢ − yᵢ)·ω — o braço de momento. Observe que não é apenas a bitola; o sentido dos roletes está dentro dele, e é por isso que uma roda no canto errado estraga tanto a rotação quanto o deslocamento lateral.

Para obter o comando de cada motor a partir da velocidade da roda — a cinemática inversa — divida pelo raio da roda: ωwheel = vᵢ / r, em rad/s.

Quatro rodas: a matriz e a cinemática inversa

Empilhe essas quatro linhas e você terá uma matriz 4 × 3 A, com o vetor de movimento do chassi ξ = (vx, vy, ω):

v = A · ξ

Para o arranjo padrão — dianteira esquerda e traseira direita com um sentido de roletes, dianteira direita e traseira esquerda com o outro — escreva k = lx + ly, em que lx é metade do entre-eixos (da frente para trás) e ly é metade da bitola (da esquerda para a direita). Então:

Roda vx vy ω
Dianteira esquerda 1 −1 −k
Dianteira direita 1 +1 +k
Traseira esquerda 1 +1 −k
Traseira direita 1 −1 +k

Estas são as quatro linhas que todo mundo escreve:

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

Confira isso contra as quatro coisas que você já sabe que um robô Mecanum faz:

Comando Velocidades das rodas (FL, FR, RL, RR) O que se vê
Para a frente, vx = 1 1, 1, 1, 1 Todas as quatro no mesmo sentido. As partes laterais se cancelam.
Deslocamento para a esquerda, vy = 1 −1, 1, 1, −1 Pares diagonais se opõem. Este é o movimento característico.
Giro anti-horário, ω = 1 −k, k, −k, k Lado esquerdo para trás, lado direito para a frente — um giro de tanque.
Movimento diagonal, vx = vy = 1 0, 2, 2, 0 Duas rodas param completamente. Guarde essa ideia.
Quatro painéis em vista superior do mesmo robô Mecanum com a frente para cima, cada um mostrando o sentido de giro das quatro rodas para um comando, com as velocidades listadas como dianteira esquerda, dianteira direita, traseira esquerda e traseira direita, escaladas para a roda mais rápida. Para a frente: mais um em todas as quatro, todas as setas no mesmo sentido, observado que as partes laterais se cancelam. Deslocamento para a esquerda: menos um, mais um, mais um, menos um, com pares diagonais se opondo e uma seta âmbar apontando para a esquerda. Giro anti-horário: menos um, mais um, menos um, mais um, lado esquerdo para trás e lado direito para a frente, com um arco âmbar. Movimento diagonal: zero, mais um, mais um, zero, com uma seta âmbar apontando para a frente e para a esquerda e uma observação de que duas rodas fazem tudo enquanto duas não fazem nada.
Os quatro comandos, diretamente da matriz. Observe o último: um movimento diagonal pede duas rodas para tudo e duas para nada, e é daí que vem o teto diagonal de 71%. Baixar SVG

O exemplo numérico

Uma base com lx = 75 mm, ly = 85 mm, rodas de 97 mm (r = 48,5 mm), solicitada a operar com vx = 0,30 m/s, vy = 0,20 m/s, ω = 0,50 rad/s. Portanto, k = 0,160 m.

Roda Conta Velocidade da roda Velocidade do motor
Dianteira esquerda 0,30 − 0,20 − 0,160 × 0,50 0,020 m/s 0,41 rad/s (3,9 rpm)
Dianteira direita 0,30 + 0,20 + 0,160 × 0,50 0,580 m/s 11,96 rad/s (114 rpm)
Traseira esquerda 0,30 + 0,20 − 0,160 × 0,50 0,420 m/s 8,66 rad/s (83 rpm)
Traseira direita 0,30 − 0,20 + 0,160 × 0,50 0,180 m/s 3,71 rad/s (35 rpm)

Uma roda gira vinte e nove vezes mais rápido que outra, a partir de um comando que não parece extremo. Um trem de rodas Mecanum passa a maior parte da vida com seus quatro motores fazendo coisas muito diferentes, e é por isso que “todos recebem o mesmo PWM e ele anda em linha reta” não é um teste que signifique alguma coisa aqui.

Saturação: aplique uma escala, nunca recorte

Peça mais do que os motores podem fornecer e será preciso abrir mão de alguma coisa. Existem exatamente duas escolhas, e elas não são 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;
}

Isso é diferente do que acontece se você simplesmente escrever constrain(fl, -255, 255) em cada motor: recorte. O recorte mantém a velocidade e descarta a direção. Peça 0,60 m/s para a frente, 0,15 lateral e 0,8 rad/s de giro em um robô cujas rodas chegam no máximo a 0,50 m/s:

Orientação Para a frente Giro Veredito
Comandado 14,0° 0,60 m/s 0,80 rad/s —
Escala 14,0° 0,34 m/s 0,46 rad/s Mais lento em todos os eixos, exatamente na direção indicada
Recorte 5,6° 0,46 m/s 0,28 rad/s Mais rápido para a frente, 8,4° fora da direção solicitada e 40% menos giro

A parte mais traiçoeira é que o recorte parece bem funcionar nos comandos que as pessoas testam. Um movimento diagonal puro pede 2 às duas rodas e 0 às outras duas; os zeros já estão dentro do limite, então recorte e escala produzem números idênticos e o defeito se esconde. Ele aparece depois, sob um seguidor de caminho, como um robô que se inclina para fora das curvas sem que ninguém descubra o motivo. Veja os dois limitadores na mesma execução e a diferença é uma curva que você pode observar.

Odometria: a cinemática direta

A cinemática direta é a mesma matriz lida ao contrário. Mas A é 4 × 3 — quatro medições, três incógnitas — portanto não existe uma inversa matricial. Existe uma solução por mínimos quadrados:

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

Para o arranjo padrão, AᵀA sai diagonal e tudo se reduz a três linhas que você pode colocar em um Arduino:

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

Integre esses valores usando a orientação do robô a cada ciclo e você terá navegação estimada:

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;

Isso funciona tão bem quanto a suposição sob a qual se baseia — que as rodas não estão derrapando. Em uma base Mecanum, a derrapagem é inerente ao projeto da roda, portanto trate a odometria lateral como o número menos confiável do robô.

A quarta equação que ninguém usa

Quatro equações, três incógnitas. Essa equação extra não é desperdício — é o único diagnóstico gratuito de todo o trem de rodas.

Se o robô é rígido e todas as rodas estão em contato firme com o piso, as quatro velocidades das rodas não podem ser arbitrárias. Some as duas primeiras linhas da matriz e as duas últimas, e ambas dão 2·vx, portanto:

FL + FR = RL + RR

sempre, exatamente, para qualquer movimento que um chassi Mecanum rígido possa executar. Calcule o resíduo a cada ciclo:

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

Um valor diferente de zero significa que os quatro encoders estão descrevendo um movimento que nenhum objeto sólido pode fazer. Causas, em ordem aproximada de probabilidade: uma roda fora do chão, uma roda sobre uma área molhada, um rolete travado, um acoplamento deslizando, um canal de encoder sem sinal — ou uma roda instalada no canto errado, o que torna o resíduo grande e constante, em vez de intermitente.

Seja honesto sobre o que ele não consegue ver: se todas as quatro rodas derraparem da mesma forma ao mesmo tempo, o resíduo continuará em zero e o robô deslizará lateralmente para fora da trajetória solicitada em total silêncio. Essa cegueira é exatamente a razão pela qual a odometria Mecanum falha de forma silenciosa em vez de ruidosa, e a razão pela qual projetos sérios adicionam uma IMU ou rodas mortas sem alimentação em vez de confiar nos encoders da tração.

As duas consequências de 45°

As duas decorrem da matriz, e nenhuma pode ser eliminada.

O movimento diagonal é limitado a 1/√2. Um comando a 45° coloca vx + vy em duas rodas e 0 nas outras duas, portanto o par ocupado atinge o limite de velocidade quando o robô está se movendo a apenas V_MAX / √2 ≈ 71% de sua velocidade máxima em linha reta. Motores mais rápidos elevam o teto; não o removem.

A tração também é limitada a 1/√2, por outro motivo. A força útil F do motor fica ao longo da direção de rolamento, mas a força real no chão é F·√2 ao longo do eixo do rolete, e o atrito limita essa força. Assim, por roda, a força útil é limitada a μN/√2, e o teto de aceleração do robô é:

a_max = μ·g / √2

Com μ = 0,85, isso dá 5,9 m/s², enquanto o mesmo robô com rodas comuns teria 8,3. A massa do robô cancela nos dois casos, portanto lastro não ajuda — uma lição que vai exatamente na direção oposta à de um robô sumo, no qual o peso é toda a estratégia.

Um gráfico de velocidade lateral em função da velocidade para a frente, em metros por segundo, mostrando todas as velocidades que um robô Mecanum com rodas de 0,60 metro por segundo pode alcançar. O conjunto alcançável é um losango ciano preenchido com vértices em mais e menos 0,60 em cada eixo. Um círculo tracejado cinza de raio 0,60 é desenhado para comparação e rotulado como sem penalidade direcional. Marcadores âmbar ficam em 0,60 metro por segundo para a frente e 0,60 metro por segundo lateralmente, nos vértices do losango, e um marcador vermelho na borda diagonal é rotulado 0,424 metro por segundo na diagonal.
Todas as velocidades que o robô pode alcançar, resolvidas direção por direção. Para a frente e para os lados, não há penalidade; a borda diagonal do losango é onde o comando custa 1/√2. Somente um trem de rodas sem 45° obtém o círculo. Baixar SVG

No firmware

Coloque a geometria em um único lugar e nunca a deixe ser digitada duas vezes.

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
  }
};

Meça lx e ly de centro de roda a centro de roda e depois divida por dois — não na placa do chassi, que normalmente é mais larga. Errar k não impede o robô de andar; faz a rotação e a translação se misturarem, de modo que um comando de giro puro também faz o robô avançar e um deslocamento lateral puro faz curva. Se o robô avança enquanto gira no lugar, suspeite de k antes de suspeitar do código.

Solução de problemas

Sintoma Causa provável O que verificar
Para a frente está bom, mas o deslocamento lateral faz curva e rotação Uma roda no canto errado A troca indicada acima; o resíduo será grande e constante
Desliza para o lado oposto ao comando Todas as quatro rodas espelhadas Troque o par esquerdo pelo direito
Girar no lugar também produz translação k errado, ou lx/ly medidos no chassi em vez das rodas Meça de centro de roda a centro de roda novamente
O movimento diagonal é muito mais lento que o para a frente O teto de 1/√2 — não é uma falha Nada a corrigir; projete em torno dele
O robô se inclina para fora das curvas sob um seguidor de caminho Recorte por motor em vez de escala Aplique um fator de escala ao comando inteiro com base na roda mais rápida
A odometria deriva muito para os lados, mas fica boa para a frente Derrapagem dos roletes, funcionando como projetado IMU para a orientação, rodas mortas para a posição
O resíduo dispara apenas em uma superfície A área está escorregadia, ou um rolete está travado Gire todos os roletes à mão

Próximo passo

Execute os números em um robô que possa derrapar: o simulador de tração Mecanum usa exatamente estas equações em um modelo de atrito, para que você possa ver a odometria e o piso discordarem. Depois faça as rodas realmente manterem as velocidades que você calculou — controle de velocidade das rodas em malha fechada — e faça “para a frente” significar para a frente no piso, e não apenas no robô, com tração orientada pelo campo.

Explore o grafo

Faz parte destas montagens

Projetos e caminhos de aprendizagem que incluem este tutorial.

Leitura complementar

Referências