Tutorial · Intermediário · 20 min de leitura

Odometria de acionamento diferencial a partir de encoders de roda

Calcule a posição de um robô de acionamento diferencial a partir dos encoders, integre movimentos retos e curvas e meça a deriva da odometria.

Um robô de acionamento diferencial tem duas rodas acionadas independentemente, separadas por uma bitola. Quando ambas percorrem a mesma distância, o robô avança em linha reta. Quando uma percorre mais, o chassi descreve um arco. A odometria integra esses pequenos deslocamentos ao longo do tempo para estimar a pose: coordenada x, coordenada y e orientação θ.

A estimativa é local e cumulativa. Começa em uma pose escolhida e não pode se corrigir apenas com encoders de roda. Pequenos erros de diâmetro da roda, bitola, temporização e patinação se acumulam; portanto, o objetivo é uma estimativa útil de curto prazo com limites medidos, não uma verdade de campo perfeita.

Defina uma convenção de coordenadas

Escolha um referencial antes de escrever as equações. Uma convenção bidimensional comum é:

  • x aponta para a frente a partir da pose inicial.
  • y aponta para a esquerda.
  • θ positivo gira no sentido anti-horário.
  • A distância de cada roda, esquerda e direita, é positiva quando o robô avança.

Armazene os ângulos internamente em radianos. Converta para graus apenas para exibição. Normalize a orientação se valores delimitados facilitarem a depuração, mas seno e cosseno também funcionam com ângulos ilimitados.

Sejam dL e dR as distâncias percorridas pelas rodas esquerda e direita desde a atualização anterior, e b a distância efetiva entre as linhas de contato das rodas.

Geometria de um robô de acionamento diferencial girando ao longo de um arco. Um ponto marcado como ICC, o centro instantâneo de curvatura, fica à esquerda, com linhas de raio pontilhadas até o robô no início e no fim da curva. Três arcos concêntricos percorrem da pose inicial à pose final: o caminho da roda interna, o caminho do centro do robô desenhado com tracejado e o caminho mais longo da roda externa. Uma seta curva de dupla ponta entre as duas linhas de raio marca a mudança de orientação, delta theta. As fórmulas informam que delta theta é a diferença entre as duas distâncias das rodas dividida pela separação das rodas, e que a distância do centro é a média delas.
As duas rodas percorrem o mesmo ângulo em torno do mesmo centro, então a diferença entre as distâncias percorridas é a mudança de orientação, e a média é a distância percorrida pelo robô. Baixar SVG

Converta contagens em metros

Tudo acima pressupõe que você já tenha dL e dR em metros. Encoders não produzem metros; produzem contagens. Há uma conversão entre eles, e errá-la escala todos os números que o restante desta página calcula.

countsPerWheelTurn = PPR x edgesDecoded x gearRatio
metresPerCount     = (pi x wheelDiameter) / countsPerWheelTurn

edgesDecoded é 4 somente se você decodificar as duas bordas dos dois canais — a quadratura completa. Decodificar apenas a borda de subida de um canal dá 1 e também descarta a informação de direção, então o robô não consegue distinguir uma reversão de um avanço.

Encoder e redutor Contagens por volta da roda Resolução em uma roda de 65 mm
N20, magnético de 7 PPR, 100:1 2,800 73 um
N20, magnético de 7 PPR, 50:1 1,400 146 um
Magnético de 11 PPR, redutor 30:1 1,320 155 um
Disco óptico de 20 fendas, canal único, na roda 20 10,2 mm

A linha inferior surpreende as pessoas. Um disco com fendas preso à roda com abraçadeiras é barato, mas 10 mm de quantização significa que um deslocamento de 200 mm é estimado com cerca de 5% de precisão, e nenhuma calibração recupera informação que o sensor nunca capturou. O tutorial sobre encoders em quadratura cobre a decodificação completa.

A resolução é um limite inferior da precisão, não uma promessa de exatidão. Uma contagem de 73 um não significa nada se o diâmetro da roda estiver 2% errado.

Calcule o deslocamento linear e o ângulo

O centro do eixo se desloca pela distância média das rodas:

dCenter = (dR + dL) / 2

A orientação muda conforme a diferença entre elas:

dTheta = (dR - dL) / b

Distâncias iguais produzem dTheta = 0. Distâncias iguais e opostas produzem dCenter = 0, então o robô gira no lugar em torno do ponto médio do eixo.

Para atualizações pequenas, aplicar a translação na orientação do ponto médio é preciso e evita um caso especial para o movimento em linha reta:

headingMid = theta + dTheta / 2
x = x + dCenter * cos(headingMid)
y = y + dCenter * sin(headingMid)
theta = theta + dTheta

Essa integração no ponto médio é simples o bastante para um controlador embarcado e funciona bem quando o laço é executado com frequência. A integração exata de um arco é útil para passos grandes, mas não corrige medições de roda erradas.

Implemente uma atualização repetível

Mantenha os totais brutos dos encoders e converta suas diferenças para metros. Não zere os contadores do hardware a cada laço; instantâneos facilitam o tratamento de transbordo e o diagnóstico.

struct Pose { float x, y, theta; };

void updateOdometry(Pose& pose, float dLeft, float dRight, float trackWidth) {
  const float dCenter = 0.5f * (dLeft + dRight);
  const float dTheta = (dRight - dLeft) / trackWidth;
  const float headingMid = pose.theta + 0.5f * dTheta;

  pose.x += dCenter * cosf(headingMid);
  pose.y += dCenter * sinf(headingMid);
  pose.theta += dTheta;
}

Chame essa função depois de ler os dois encoders de forma atômica. Os instantâneos esquerdo e direito devem representar quase o mesmo instante; um intervalo longo entre eles produz um desvio aparente durante movimentos rápidos.

Se outro subsistema precisar de velocidade, divida os incrementos pelo tempo decorrido medido. A integração da pose usa distância e, portanto, a oscilação do tempo do laço não altera diretamente a estimativa da distância percorrida.

Leia os dois encoders sem perder contagens

A função acima é aritmética pura. O difícil é fornecer as medições corretamente, e é aí que a odometria embarcada realmente falha. Três detalhes concentram quase todo o risco.

Capture os dois contadores no mesmo instante. As rotinas de interrupção continuam incrementando os contadores enquanto o laço os lê. Ler o esquerdo, executar algum trabalho e depois ler o direito atribui a uma única roda o movimento que ocorreu no intervalo — e as equações interpretam isso fielmente como uma curva.

Nunca zere os contadores do hardware. Totais acumulados continuamente, junto com um valor anterior guardado, fornecem o delta e deixam a contagem bruta disponível para diagnóstico.

Calcule o delta em aritmética sem sinal. O transbordo de um valor com sinal é comportamento indefinido em C++; a sequência de conversões abaixo é definida, não custa nada e permanece correta na virada.

volatile int32_t leftCount = 0, rightCount = 0;   // written only by the ISRs

void isrLeft()  { leftCount  += digitalRead(L_CHAN_B) ? +1 : -1; }
void isrRight() { rightCount += digitalRead(R_CHAN_B) ? +1 : -1; }

constexpr float METRES_PER_COUNT = (3.14159265f * 0.065f) / 2800.0f;   // 72.9 um
constexpr float TRACK_WIDTH      = 0.152f;                             // calibrated, not measured

void odometryTick(Pose& pose) {
  int32_t nowLeft, nowRight;
  noInterrupts();                      // one instant, both wheels
  nowLeft  = leftCount;
  nowRight = rightCount;
  interrupts();

  static int32_t prevLeft = 0, prevRight = 0;
  // Unsigned subtraction wraps in a defined way; the cast back recovers the
  // signed delta even across the 2^32 boundary.
  const int32_t dLeftCounts  = (int32_t)((uint32_t)nowLeft  - (uint32_t)prevLeft);
  const int32_t dRightCounts = (int32_t)((uint32_t)nowRight - (uint32_t)prevRight);
  prevLeft  = nowLeft;
  prevRight = nowRight;

  updateOdometry(pose,
                 dLeftCounts  * METRES_PER_COUNT,
                 dRightCounts * METRES_PER_COUNT,
                 TRACK_WIDTH);
}

A 73 um por contagem, um contador com sinal de 32 bits transborda depois de cerca de 157 km; portanto, em um robô de mesa, o transbordo é apenas teórico. Ainda assim, vale gastar duas conversões para tratá-lo corretamente. O mesmo padrão é obrigatório em um contador de 16 bits, que transborda depois de 2,4 m.

Faça o cálculo de uma curva

Suponha que a roda esquerda percorra 0,20 m, a direita percorra 0,30 m e a bitola seja 0,25 m:

  • dCenter = 0.25 m
  • dTheta = (0.30 - 0.20) / 0.25 = 0.4 rad
  • a partir da orientação zero, a orientação do ponto médio é 0.2 rad
  • dx ≈ 0.25 cos(0.2) = 0.245 m
  • dy ≈ 0.25 sin(0.2) = 0.050 m

O robô termina um pouco à esquerda de seu eixo frontal original e girado cerca de 22,9°. Verificar um cálculo manual como esse captura erros de sinal e unidade antes de o código chegar ao hardware.

Calibre os dois parâmetros dominantes

O diâmetro efetivo da roda controla a escala da distância. Percorra uma linha reta longa, de comprimento medido, compare a distância informada com a real e multiplique a escala do diâmetro por actual / reported. Calibre cada lado se o robô curvar apesar de comandos iguais.

A bitola efetiva controla a escala da rotação. Comande várias rotações completas no lugar, meça a mudança real de orientação com uma referência externa e ajuste a bitola. Várias rotações amplificam o erro e facilitam a medição. O arrastamento dos pneus faz com que o valor efetivo possa diferir da distância entre as rodas medida com uma régua.

Mantenha os dois parâmetros configuráveis. A superfície, a compressão dos pneus, a carga e o desgaste podem alterá-los; modelos de hardware precisam de parâmetros ajustáveis para a calibração.

Saiba como rápido o erro cresce

A calibração não elimina o erro, ela reduz o coeficiente. Conhecer o tamanho do que resta diz por quanto tempo você pode confiar na estimativa antes que uma referência externa precise corrigi-la.

Fonte de erro Tamanho de um erro realista O que ele custa
Escala do diâmetro da roda 1% 10 cm em um percurso reto de 10 m
Escala da bitola 2% 7,2° após uma volta completa
Escala da bitola 2% 8,7 cm de erro de fechamento em um quadrado de 1 m
Arrastamento sistemático das rodas 2% por giro no lugar 0,9° por curva de 90°, 45° após 50 curvas
Arrastamento aleatório das rodas 2% por giro no lugar cerca de 6° após 50 curvas, crescendo com a raiz quadrada
Integração no ponto médio a 50 Hz 0,04 rad por passo a 2 rad/s 0,007%, aproximadamente 0,07 mm por metro

O resultado do quadrado vem da integração de um quadrado de 1 m com quatro curvas de 90° no lugar e nada errado, exceto a bitola. Todo o restante é exato, e o robô ainda termina 8,7 cm longe de onde começou.

Compare a última linha com as duas primeiras. A matemática da integração nunca é seu erro dominante. Ela está três ordens de grandeza abaixo dos termos de calibração e quatro abaixo da patinação. Por isso, aumentar a frequência do laço para perseguir precisão é a otimização errada — e é por isso que a página sobre patinação das rodas importa mais para sua pose final do que qualquer coisa desta página.

Observe também que os erros sistemáticos e aleatórios se comportam de maneiras completamente diferentes. O arrastamento sistemático se acumula linearmente e vale eliminar por calibração. O aleatório cresce com a raiz quadrada do número de curvas; portanto, 50 curvas custam cerca de 6°, não 45° — inconveniente, mas não corrigível por qualquer ajuste de parâmetro.

Escolha uma taxa de atualização

O arco entre duas amostras é aproximado por uma corda reta na orientação do ponto médio, então o erro depende de quanto a orientação muda por passo. Para um passo de dTheta radianos, a corda é curta em aproximadamente dTheta^2 / 24:

Taxa de atualização dTheta a 2 rad/s Erro da corda Na prática
200 Hz 0,010 rad 0,0004% Inútil para esta matemática
100 Hz 0,020 rad 0,002% Gratuito se o laço já roda nessa frequência
50 Hz 0,040 rad 0,007% Padrão confortável
20 Hz 0,100 rad 0,04% Adequado para um robô interno lento
10 Hz 0,200 rad 0,17% Visível em uma rotação rápida
5 Hz 0,400 rad 0,67% Lento demais para confiar durante uma curva

Escolha 50 Hz e não se preocupe com isso. Use a atenção economizada para sincronizar as duas leituras dos encoders, o que, de qualquer forma, importa mais que a própria taxa: um desvio de 1 ms entre os instantâneos esquerdo e direito, enquanto as rodas diferem em 0,5 m/s, cria 0,5 mm de diferença entre rodas do nada a cada laço.

Adicione um giroscópio sem confundir os referenciais

Um giroscópio costuma fornecer uma mudança de orientação de curto prazo melhor do que a diferença entre os encoders das rodas. Você pode usar a orientação do giroscópio para theta e continuar usando a distância média das rodas para a translação. Aplique a translação na média das orientações antiga e nova do giroscópio.

Isso não torna a posição absoluta. Giroscópios têm viés, e a odometria baseada na distância das rodas ainda sofre patinação. É necessário um sensor que forneça uma referência global — pontos de referência da câmera, localização com LiDAR ou outra referência externa — para corrigir a pose acumulada.

Na terminologia ROS, uma estimativa local contínua pertence naturalmente ao referencial odom. Um sistema de localização pode atualizar map → odom sem forçar a transformação local e suave odom → base_link a dar um salto.

Meça a deriva em vez de escondê-la

Execute três testes repetíveis:

  1. Avance e recue até retornar ao ponto inicial.
  2. Execute várias voltas e retorne à orientação original.
  3. Percorra um quadrado grande e compare a pose final com a marca inicial.

Registre os deltas dos encoders, a pose calculada, a tensão da bateria e a superfície. Repita cada teste nos dois sentidos. Erro de escala consistente sugere calibração; erro que muda com o sentido sugere folga ou assimetria; erro que muda com a superfície sugere patinação.

Solução de problemas

Sintoma Normalmente Solução
O robô vira à esquerda e a orientação diminui Sinal invertido ou ordem das rodas invertida Inverta uma vez, no ponto em que as contagens entram
O movimento reto muda a orientação Escalas das rodas diferentes, contagens perdidas ou leituras não sincronizadas Calibre cada lado e capture os dois contadores juntos
A rotação é consistentemente grande demais Bitola efetiva pequena demais Multiplique a bitola pelo valor real dividido pelo comandado
A orientação deriva somente em alta velocidade Interrupções perdidas sob carga Encurte as ISRs ou mova a decodificação para o hardware
O quadrado nunca fecha apesar da calibração Patinação e erro de integração se acumulando Adicione uma correção externa; nenhum parâmetro resolve isso
A posição salta após percursos longos Transbordo do contador tratado com aritmética com sinal Calcule o delta sem sinal e converta de volta
A distância está certa, mas a orientação errada Bitola não calibrada ou giroscópio em conflito com os encoders Calibre somente nas rotações, com a distância já correta
Perfeito na simulação, errado no chão Modelo sem deformação dos pneus, folga ou temporização de sensores Confie nos testes de bancada, não no simulador

Experimente as consequências da esteratação no Simulador de Seguidor de Linha e compare as estimativas locais de movimento com os conceitos de mapeamento em fundamentos de SLAM. Para a tarefa que depende diretamente dessa estimativa — percorrer fileiras paralelas em todo um piso — veja planejamento de caminhos de cobertura e o simulador de cobertura.

Explore o grafo

Faz parte destas montagens

Projetos e caminhos de aprendizagem que incluem este tutorial.

Leitura complementar

Referências