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 é:
xaponta para a frente a partir da pose inicial.yaponta 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.
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 mdTheta = (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 mdy ≈ 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:
- Avance e recue até retornar ao ponto inicial.
- Execute várias voltas e retorne à orientação original.
- 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.
- ProjetoConstrua um micromouse para resolver labirintos
- ProjetoConstrua um robô com desvio de obstáculos
- ProjetoConstrua um robô de cobertura que percorre todo o ambiente
- ProjetoConstrua um robô seguidor de linha: do simulador à pista real
- ProjetoConstrua um rover GPS de pontos de passagem que dirige sozinho
- Caminho de aprendizagemControle de motores para robôs: roteiro de aprendizagem
- Caminho de aprendizagemSeguimento de caminhos para robôs: roteiro de aprendizagem
Leitura complementar