Construa um robô ROS 2 que vê e segue até um marcador
Um robô que localiza um marcador do outro lado de uma sala, descobre onde ele está em relação a si mesmo e chega de frente — estruturado como um grafo real de nós ROS 2.
O que você está construindo
Um robô colocado em algum lugar de uma sala que gira até encontrar um marcador impresso em uma parede e dirige até ele — parando a meio metro de distância, em ângulo reto com a face do marcador, e não apenas perto.
Todas as outras construções deste site executam um programa em um microcontrolador. Esta é um computador com rodas, e isso muda o assunto do projeto. As partes difíceis não são mais temporização e fiação; são saber onde as coisas estão em relação umas às outras e manter várias partes do software honestas entre si enquanto todas executam ao mesmo tempo.
Por que este robô precisa de um computador
Um Arduino não consegue fazer isso, e vale ser preciso sobre o motivo. Não é a velocidade bruta — é que um quadro de câmera ocupa um quarto de megabyte, a detecção ArUco exige álgebra linear com ponto flutuante e tudo isso precisa acontecer enquanto as rodas ainda estão sendo comandadas a 50 Hz. Esse é um trabalho para um sistema operacional com memória e agendamento reais.
O que você ganha em troca dessa máquina Linux é a capacidade de olhar para dentro de um robô em execução. Cada mensagem entre cada parte é um tópico que você pode assinar de um notebook. Quando o robô passa pelo marcador em vez de ir até ele, você não adiciona mensagens de impressão nem regrava o software — executa ros2 topic echo na pose e a vê errada em tempo real.
A forma do grafo de nós
Cinco responsabilidades, um nó para cada uma:
| Nó | Publica | Tarefa |
|---|---|---|
camera |
/image_raw, /camera_info |
Retira quadros do barramento CSI |
aruco_detector |
TF camera_link → marker_7 |
Encontra o marcador e resolve sua pose |
docking_controller |
/cmd_vel |
Decide para onde dirigir |
diff_drive |
porta serial para o Arduino | Conversão de Twist em velocidades das rodas |
odometry |
TF odom → base_link |
Integra as contagens dos encoders |
As interfaces são o que torna isso valer a pena. O controlador nunca toca em uma câmera ou em um motor — consome uma transformação e produz um Twist. Isso permite dirigir o mesmo robô por teleoperação com teclado, testar o controlador contra uma transformação falsa sem componentes e, depois, inserir uma pilha de navegação que publique exatamente o mesmo tópico.
Leia nós, tópicos, serviços e ações antes de desenhar sua própria versão dessa tabela. O erro mais comum nesta etapa é transformar o controlador de acoplamento em um serviço — ele é um objetivo de longa duração que precisa poder ser cancelado, e é exatamente para isso que serve uma ação.
Lista de materiais
Este é o robô com dois cérebros, e a lista de peças reflete isso: um computador para percepção e um microcontrolador para as coisas que um computador não faz de forma confiável.
| Peça | Qtd. | Custo aproximado | Observações |
|---|---|---|---|
| Raspberry Pi 4, 4 GB | 1 | US$ 55 | 4 GB é o mínimo prático para ROS 2 mais visão. 1 GB faz troca de memória e morre |
| Módulo de câmera Pi 3 | 1 | US$ 25 | A versão Wide é melhor para navegação — 102° em vez de 66° |
| microSD classe A2, 32 GB | 1 | US$ 8 | Ou inicialize por um SSD USB, que é realmente mais rápido |
| Dissipador ou ventilador | 1 | US$ 5 | Um Pi 4 reduz a frequência a 80 °C, e um Pi limitado perde quadros |
| Arduino Uno ou Nano | 1 | US$ 5 | Encoders e controle de motores — a metade em tempo real |
| Motores N20 com encoder | 2 | US$ 16 | |
| TB6612FNG | 1 | US$ 3 | |
| Chassi 2WD | 1 | US$ 12 | Espaço para um Pi, uma haste de câmera e uma bateria |
| Pacote de bateria | 1 | US$ 15 | 3S com regulador chaveado de 5 V dimensionado para 3 A |
| Marcadores ArUco impressos | — | US$ 0 | Imprima, meça o tamanho impresso e use a medida |
Total: aproximadamente US$ 145–175. Este é o projeto mais caro do site por uma margem larga, e a maior parte do custo é o Pi.
A alimentação é onde esses robôs falham, e a falha é cara. Uma queda de tensão durante uma escrita no cartão SD corrompe toda a imagem do sistema. Use um regulador chaveado dimensionado bem acima do consumo do Pi, nunca compartilhe o trilho com os motores e verifique vcgencmd get_throttled — qualquer valor diferente de zero significa que a fonte é inadequada e que um cartão corrompido está a caminho.
Meça seus marcadores impressos. A solução da pose ArUco escala diretamente com o tamanho do marcador que você declara. Um marcador impresso a 95% pelo “ajustar à página” de uma impressora produz poses 5% erradas em todas as distâncias, e nada no fluxo de processamento informará isso.
Ordem de construção
1 — Faça o ROS 2 funcionar e prove a rede. Siga instalar o ROS 2 em um Raspberry Pi. Não avance até ros2 topic echo no notebook mostrar um tópico publicado no robô. A descoberta por Wi-Fi é a coisa mais provável de consumir uma noite, e você quer que ela aconteça agora, e não enquanto depura visão.
2 — Faça as rodas obedecerem a um Twist. Conecte o Arduino, os encoders e o TB6612FNG, e construa a ponte cmd_vel. Marco: a teleoperação por teclado do notebook dirige o robô real. Calibre aqui a separação entre rodas — tudo abaixo herda esse valor.
3 — Calibre a câmera. Corretamente, com um alvo real, seguindo calibração de câmera e pose ArUco. Uma câmera não calibrada produz poses que parecem plausíveis e estão erradas dezenas de pontos percentuais nas bordas do quadro, o pior modo de falha possível.
4 — Publique o marcador como uma transformação. Não como uma mensagem personalizada com x e y. Publicar camera_link → marker_7 no TF2 permite que o controlador pergunte “onde está o marcador, em base_link?”, e a resposta considera exatamente como a câmera está montada — inclusive o fato de ela estar inclinada, como está.
5 — Dirija até o marcador. Um controlador proporcional com base na direção medida em relação ao robô: vire em direção a ele, avance e pare na distância de aproximação. Isso funciona, mas chega em ângulo, que é o ponto da próxima etapa.
6 — Aproxime-se ao longo da normal. Em vez de dirigir diretamente ao marcador, calcule um ponto de passagem afastado da face do marcador ao longo de sua normal, vá até ele e só então dirija em linha reta. Esta é a diferença entre alcançar o acoplador e acoplar. É também onde a orientação do marcador — a parte da pose que você não precisava até agora — começa a importar, e onde encontrará a ambiguidade de pose.
7 — Coloque tudo em uma máquina de estados. Procurar, aproximar, alinhar, final, concluído, além das transições de saída de cada estado quando o marcador é perdido. Máquinas de estados finitas para comportamento de robôs cobre a estrutura; o que este robô precisa especificamente é um tempo limite de marcador perdido que volte à busca em vez de continuar pela última pose conhecida.
Observações dos componentes que importam
Monte a câmera rigidamente e meça como ela está. Toda pose que o robô calcula é relativa à câmera, e TF2 a transforma em uma pose relativa ao robô usando a transformação que você declara de base_link a camera_link. Uma câmera em suporte flexível torna essa transformação declarada uma mentira que varia com a aceleração.
Incline a câmera para baixo e registre isso. Uma câmera apontada para o horizonte perde o marcador exatamente quando o robô fica perto. De dez a quinze graus para baixo a mantém no quadro durante a aproximação final — e essa inclinação vai para a transformação estática, não para um fator de correção improvisado no controlador.
Meça o marcador com paquímetro. A escala da pose é diretamente proporcional ao tamanho do marcador que você informa ao solucionador. Imprimir a 96% porque a impressora ajustou à página torna cada distância 4% errada, de forma silenciosa e consistente.
Alimente o Pi separadamente dos motores. Um motor travado derruba o trilho, e onde um Arduino apenas reiniciaria sem dano, um Pi corrompe o sistema de arquivos. Use um regulador separado ou outra bateria — este não é o lugar de economizar uma peça.
Mantenha o cabo da câmera longe dos fios dos motores. É uma ligação de alta velocidade sem blindagem. Ruído dos motores acoplado a ela aparece como quadros corrompidos, que aparecem como detecções piscando sem nenhuma razão visível.
Como fica um bom resultado
| Medição | Típico em um Pi 4 |
|---|---|
| Captura da câmera a 640×480 | 30 fps |
| Detecção ArUco, 640×480 | 25–30 fps, usando 40–60% de um núcleo |
| Detecção ArUco, 1920×1080 | 5–8 fps — e cada quadro está desatualizado |
| Alcance de detecção do marcador (marcador de 100 mm, 640×480) | 1,5–2,5 m |
| Precisão da pose a 1 m | ±2–5 cm de posição, ±3–5° de orientação |
| Latência total de imagem à decisão | 60–120 ms |
| Laço de controle de motores, no Arduino | 100–200 Hz |
| Latência de tópico ROS 2, do Pi ao Arduino pela porta serial | 5–15 ms |
Duas linhas carregam a lição do projeto inteiro.
Resolução não é gratuita, e uma resolução maior costuma ser pior. Ir de 640×480 para 1080p custa 4–6× o processamento para cerca de 1,7× o alcance de detecção. A menos que você realmente precise ver um marcador mais distante, o quadro menor oferece uma resposta mais rápida e atual — e atualidade importa mais que precisão em um laço de controle.
A linha de latência explica por que existe a divisão em dois cérebros. A 0,3 m/s, 100 ms de latência de visão são 3 cm de deslocamento; girando a 90°/s, são 9° de rotação. Toda medição de visão descreve onde o robô estava. Feche um laço rápido diretamente nela e ele oscilará. A estrutura que funciona é a que este robô usa: o Arduino executa o laço rápido com encoders, e a visão o corrige lentamente — exatamente a mesma forma de fundir GPS com odometria no rover de pontos de passagem, e pelo mesmo motivo.
Obturador rolante, se o robô se mover enquanto olha
Os módulos de câmera padrão do Pi têm obturador rolante: as linhas são expostas uma após outra, então o topo de um quadro é capturado alguns milissegundos antes da parte inferior. Parado, isso é invisível. Girando a 90°/s, os quatro cantos de um marcador ArUco são capturados em quatro orientações diferentes do robô — e a pose resolvida a partir deles está errada de uma maneira que a calibração não consegue corrigir.
Se o robô precisa fazer visão em movimento, é para isso que existe o módulo Global Shutter. Se ele pode parar, olhar e depois se mover, o módulo mais barato é perfeitamente suficiente — e parar para olhar é uma escolha legítima de projeto, não uma solução improvisada.
Quando algo dá errado
| Sintoma | Geralmente |
|---|---|
| O notebook não vê tópicos | Tráfego multicast bloqueado pelo ponto de acesso, ou ROS_DOMAIN_ID diferente |
| Marcador detectado, robô não se move | Twist publicado para um assinante de TwistStamped |
| Distância sistematicamente errada em alguns pontos percentuais | Tamanho do marcador errado ou página escalada pela impressora |
| Pose oscila muito à distância | Marcador pequeno demais no quadro — aproxime-se ou imprima maior |
| A normal do marcador alterna | Ambiguidade de pose — aproxime-se fora do eixo ou use uma placa ChArUco |
| Robô chega perto do marcador, mas torto | Está orientando para o marcador em vez de seguir sua normal |
| Passa do ponto na aproximação final | Pilotando por uma pose que tem 50–100 ms — reduza a velocidade perto do final |
| Continua dirigindo depois de o marcador sair do quadro | Não há tempo limite de marcador perdido na máquina de estados |
Vale perceber essa distribuição antes de começar: quase nada nela é visão computacional. É rede, referenciais, unidades e controle — é isso que construir um robô ROS 2 realmente ensina, e é por isso que o caminho dos fundamentos do ROS 2 passa o tempo em padrões de comunicação e referenciais, e não em OpenCV.
Se este passo for demais, o micromouse ensina mapeamento e planejamento em um microcontrolador sem Linux envolvido, e o robô controlado por celular cobre a metade de “comandos chegam por uma rede” desse problema com uma fração das peças.
Roteiro do projeto
O caminho de construção
Siga a árvore tecnológica das peças até um robô funcionando. Cada nó é desbloqueado quando seus pré-requisitos são concluídos, e seu progresso fica salvo neste dispositivo.
0 / 19 concluídos
Componentes
- ControladorRaspberry PiUm computador Linux completo do tamanho de um cartão—o cérebro para robôs com visão e ROS.
- SensorCâmera Raspberry PiUma câmera em seu próprio canal de dados, para a visão não disputar o barramento USB.
- ControladorArduino UnoA placa de 8 bits que tolera erros de ligação, pela qual a maioria das pessoas começa na robótica.
- DriverDriver de motor TB6612FNGUma ponte H com MOSFET que preserva a tensão que você realmente pagou.
- AtuadorMotorredutor com encoder N20Micro motorredutor de engrenagens metálicas com encoder traseiro, para o robô saber até onde foi.
- ChassiChassi de robô 2WDA plataforma onde se fixam dois motores, uma rodinha livre e toda a eletrônica.
- AlimentaçãoBateria e fonte de alimentação do robôA diferença entre um robô que funciona e outro que fica reiniciando.
Tutoriais deste caminho
- Iniciante · 1 horaInstalar o ROS 2 em um Raspberry Pi e criar um espaço de trabalhoEscolha o sistema operacional, instale o ROS 2 com apt, compile um workspace com colcon e conecte o computador ao robô.
- Iniciante · 19 min de leituraNós, tópicos, serviços e ações no ROS 2Escolha o padrão de comunicação adequado do ROS 2 e inspecione como os nós trocam dados e comandos do robô.
- Intermediário · 20 min de leituraFrames de coordenadas TF2 do ROS 2 para robôs móveisConstrua e depure uma árvore de frames TF2, de map e odom passando pela base do robô até cada sensor.
- Intermediário · 22 min de leituraCalibração da câmera e pose de ArUco com OpenCVCalibre os parâmetros intrínsecos da câmera, valide o erro de reprojeção e estime a pose 3D de um marcador ArUco.
- Intermediário · 45 minDe cmd_vel às rodas no acionamento diferencial ROS 2Converta um Twist em velocidades das rodas esquerda e direita — cinemática, saturação, zona morta e watchdog.
- Iniciante · 17 min de leituraLeia encoders de quadratura para medir distância e velocidadeTransforme pulsos de encoder de quadratura em medições confiáveis do sentido de rotação, da distância e da velocidade das rodas.
- Iniciante · 17 min de leituraMáquinas de estados finitas para o comportamento de robôsSubstitua condicionais entrelaçadas de robôs por estados, eventos, transições, tempos limite e recuperação explícitos.
Perguntas frequentes
Por que usar ROS 2 neste projeto em vez de um único script Python?
Para este robô sozinho, um único script funcionaria e seria mais curto. O que ele não suportaria é a segunda funcionalidade. No momento em que o laço da câmera, o laço de tração e a lógica de decisão precisam rodar em taxas diferentes e continuar funcionando quando um deles trava, um único script se transforma em um problema de agendamento que você mesmo precisa resolver. O ROS 2 oferece separação de processos, um formato de comunicação entre as partes e — a parte que você sente imediatamente — a possibilidade de inspecionar qualquer tópico de um notebook enquanto o robô está rodando. O projeto vale ser feito porque ensina essa estrutura em um problema pequeno o bastante para ainda ser compreendido.
Preciso de um Arduino além do Raspberry Pi?
Não estritamente, mas o robô fica muito melhor com um. O Pi executa Linux, o que significa que seu laço de motores é agendado junto com tudo o mais e ocasionalmente atrasa alguns milissegundos. Isso é invisível para visão e fatal para um PID de roda. Dividir o robô — Pi para percepção e decisões, microcontrolador para os laços que não podem sofrer variação no intervalo de execução — é a arquitetura padrão por um motivo, e é exatamente a divisão que o ROS 2 encoraja.
Por que um marcador ArUco em vez de detectar um objeto real?
Porque o marcador fornece uma pose completa de 6 DOF a partir de um único quadro, sem dados de treinamento e sem ambiguidade sobre qual objeto foi encontrado. Detectar uma cadeira informa aproximadamente onde está uma cadeira; detectar um marcador ArUco informa posição e orientação em metros, que é o que um controlador realmente precisa. É também um ponto de partida honesto — estações de acoplamento reais, robôs de armazém e plataformas de pouso de drones usam marcadores fiduciais pelo mesmo motivo.
Por que a orientação do marcador fica alternando?
Isso é ambiguidade de pose, uma propriedade da geometria e não um erro no código. Um quadrado plano visto quase de frente tem duas orientações 3D que projetam quase os mesmos pixels, então pequenas quantidades de ruído fazem o solucionador alternar entre elas. A distância permanece estável enquanto a normal estimada salta. Use um marcador fisicamente maior, faça a abordagem com um pequeno desvio do eixo para que as duas soluções se separem, ou migre para uma placa ChArUco ou vários marcadores no acoplador — todas opções que dão ao solucionador mais geometria para distinguir as soluções.
Quão preciso é o acoplamento?
Com uma câmera calibrada e um marcador medido até o milímetro, um ou dois centímetros a uma distância de meio metro é realista. Os erros que dominam não são os que as pessoas esperam: um tamanho de marcador inserido errado escala proporcionalmente todas as estimativas de distância, e a latência da cadeia de processamento da câmera significa que a pose usada para dirigir descreve onde o marcador estava 50 a 100 milissegundos antes. Reduzir a velocidade nos últimos 30 cm elimina a maior parte do segundo problema sem custo adicional.
Posso fazer isso em um Raspberry Pi Zero?
Neste projeto, não — ou não com conforto. Um Zero 2 W pode executar ROS 2 e decodificar um fluxo de câmera, mas a detecção ArUco em uma taxa útil sobrecarrega tudo, e criar um espaço de trabalho nele é doloroso. Use um Pi 4 com 4 GB ou um Pi 5. O Zero é uma boa placa para um robô cujo Pi apenas retransmite comandos.