Roomba 40k

July 27, 2026

Roomba preto com um Raspberry Pi e uma câmera parafusados por cima, fiação aparente, num piso de cerâmica

Um iRobot compatível com Create2 dirigido pelo navegador em tempo real, com Raspberry Pi 3B+ a bordo, ligado ao robô por um conversor USB-TTL. Celular ou desktop abrem a página e dirigem, com vídeo ao vivo da câmera CSI.

A decisão que sustenta o projeto é de arquitetura: uma única thread de controle é dona da serial, e a camada web nunca a toca. O handler HTTP escreve o estado desejado num objeto compartilhado sob lock, e o laço de controle drena isso a ~50 Hz. Serial é bloqueante, asyncio não é, e misturar os dois é como se ganha travamento intermitente impossível de reproduzir. Toda ação de hardware nova, incluindo música e wake, segue o mesmo caminho.

A pegada é de carrinho de controle remoto, não de fila de comandos: o último comando vence e nada é enfileirado. Tem heartbeat de 300 ms, então perder o wifi ou fechar a aba para o robô em vez de deixar ele seguir com a última ordem. Só um cliente dirige por vez; os outros entram como espectadores e podem pedir o controle.

A interface tem D-pad com slider de velocidade de 50 a 500 mm/s, joystick analógico com mistura arcade, e modo teclado. O HUD mostra os sensores de bump e os quatro de cliff, empurrados por WebSocket quando mudam.

O vídeo foi o problema difícil

Câmera CSI com libcamera, codificada em H.264 por hardware e servida por MediaMTX via WebRTC sobre UDP. A política é explícita: imagem atual vale mais que imagem contínua. Engasgo visível é aceitável, vídeo bufferizado e velho não é, porque dirigir com meio segundo de atraso é dirigir no passado.

Duas descobertas que só aparecem medindo:

O MediaMTX enfileira fragmento RTP, não quadro exibido. O aviso de “descartando 35 frames” não significa 35 quadros perdidos. Com a fila padrão a latência crescia; com fila pequena demais, todo keyframe estourava a fila sozinho, porque o encoder emite o IDR como uma rajada de 38 a 47 pacotes. O valor certo é o menor que ainda cabe a rajada inteira.

E o bug que parecia regressão de software: o encoder de hardware falhava com ioctl(VIDIOC_QBUF) failed porque o padrão do sistema reservava 76 MB de memória de GPU. Abaixo de 128 MB o H.264 por hardware não sobe. Nada no código tinha mudado.

Stack: Python, aiohttp, WebSocket, pycreate2, pyserial, MediaMTX, WebRTC, Raspberry Pi 3B+.

Repositório no GitHub

Tecnologias: Python, aiohttp, WebSocket, pycreate2, pyserial, MediaMTX, WebRTC, Raspberry Pi

← Voltar para todos os projetos