Tutorial · Intermediário · 35 min
LiDAR para robôs: da varredura ao mapa de ocupação
Entenda como um LiDAR giratório constrói uma varredura, por que girar mais rápido reduz a resolução angular e como os raios atualizam uma grade de ocupação.
Introdução
Um sensor de distância informa a distância de um objeto, ao longo de uma linha. Um mapa informa a forma de uma sala. Tudo o que é interessante na navegação está no intervalo entre essas duas coisas, que é o assunto desta página.
Os dois extremos já foram tratados aqui: medição de um único ponto, de um lado, e SLAM e A* em uma grade de ocupação, do outro. Mas ambos pressupõem que uma grade já exista. Nada explica de onde ela veio, e a resposta — projetar uma varredura em células — é simultaneamente simples e cheia de armadilhas.
Um LiDAR 2D é um sensor ToF sobre uma base giratória
Este é o conceito mais útil que você pode conhecer, porque significa que já entende a metade da medição.
Dentro de um LiDAR 2D de hobby há um módulo óptico de medição de tempo de voo, exatamente como o de uma placa de desenvolvimento da série VL53, apontado lateralmente e montado sobre uma base giratória. Um encoder angular informa para onde o módulo estava orientado a cada medição. A alimentação e os dados atravessam a fronteira entre as partes fixa e giratória por meio de um anel deslizante ou de um acoplamento óptico/indutivo.
Portanto, uma “varredura” não é uma fotografia. É uma lista de pares (angle, range), coletados um de cada vez ao longo de uma volta completa. Todas as limitações abaixo decorrem dessa frase.
Isso também explica por que sensores ultrassônicos não são simplesmente girados para virar LiDARs. Um feixe ultrassônico tem dezenas de graus de abertura angular, portanto girá-lo quase não agrega nada — você apenas espalharia um feixe já largo pelo ambiente. Um feixe óptico estreito é o que torna a resolução angular significativa. Fazer um único sensor ToF varrer com um servo, como no tutorial de ultrassônico com varredura, de fato produz um LiDAR lento e de baixa resolução.
O orçamento de amostras é fixo, então atualização e resolução trocam
Esta é a parte que surpreende as pessoas e vale entender antes de comprar qualquer coisa.
O módulo de medição tem um único valor de vazão: quantas medições por segundo ele consegue fazer. Em um RPLIDAR A1, esse valor é de cerca de 8000 amostras por segundo e não muda quando você altera a taxa de rotação. Você escolhe a taxa de rotação, normalmente entre 1–10 Hz.
Assim, os pontos obtidos por volta completa são simplesmente o orçamento dividido pela taxa de rotação:
points per revolution = samples per second ÷ spin rate
angular step = 360° ÷ points per revolution
| Taxa de rotação | Pontos por volta | Passo angular | Período da varredura |
|---|---|---|---|
| 5,5 Hz | 1455 | 0,25° | 182 ms |
| 10 Hz | 800 | 0,45° | 100 ms |
Você não pode obter varreduras recentes e boa resolução angular ao mesmo tempo. Girar a 10 Hz reduz pela metade a latência e quase pela metade a resolução angular. Essa única troca influencia mais o comportamento do robô do que o alcance anunciado no produto, e é a primeira configuração que deve ser escolhida deliberadamente, em vez de deixar no padrão do software do sensor.
Para um robô que se move rapidamente em um corredor aberto: gire rápido, porque você precisa de informações recentes e as paredes são grandes. Para um robô lento que mapeia uma sala cheia de objetos: gire lentamente, porque você precisa de detalhe e pode permitir mais latência.
Os feixes divergem, então obstáculos distantes ficam entre eles
Um passo angular é um ângulo, não uma distância. Dois feixes adjacentes se afastam à medida que se propagam:
gap between beams ≈ range × angular step (in radians)
Com 0,45°, isso corresponde a uma lacuna de 7,9 mm a um metro e de 31 mm a quatro metros. Nada amostra o espaço entre eles.
Considere uma perna de cadeira de 20 mm. Girando a 10 Hz, a lacuna entre feixes ultrapassa 20 mm em cerca de 2,5 m — além disso, a perna pode ficar inteiramente entre dois feixes e não produzir nenhum retorno. A 5,5 Hz, você chega a cerca de 4,6 m antes de a mesma coisa acontecer.
Isso explica um comportamento que, de outro modo, parece um sensor quebrado: obstáculos finos aparecem quando o robô se aproxima e entram no mapa a um ou dois metros de distância. O LiDAR não estava falhando. A perna nunca havia sido amostrada.
Ao orientar o projeto, leve em conta duas consequências:
- Não confie em uma única varredura para detectar obstáculos finos. Acumular várias varreduras em uma grade, como veremos adiante, é o que realmente encontra pernas de mesa — cada varredura amostra ângulos ligeiramente diferentes.
- Pernas de cadeira e mesa são uma falha clássica de robôs domésticos, porque são finas, ficam exatamente na altura do LiDAR e o robô só as descobre tarde.
Uma varredura não é uma fotografia
Os pontos de uma volta completa não foram medidos no mesmo instante. A 5,5 Hz, a varredura leva 182 ms, e o robô não espera educadamente.
- A 0,5 m/s, o robô percorre 91 mm durante uma volta completa.
- A 1 rad/s, a varredura é borrada ao longo de 10,4°.
Tratar essa lista de pontos como uma única fotografia rígida, tirada em uma única pose, deforma a representação do mundo. Paredes retas ficam curvas ou duplicadas, e a correspondência de varreduras passa a lutar contra correções que são realmente consequência do movimento do próprio robô.
É por isso que sensor_msgs/LaserScan transporta scan_time e time_increment junto com as distâncias: eles permitem ao consumidor determinar quando cada feixe foi medido. A correção — transformar cada ponto pela pose que o robô tinha no carimbo de data/hora daquele feixe — chama-se compensação de movimento, e boas camadas de processamento de SLAM fazem isso automaticamente.
Na prática, se seus mapas ficam limpos com o robô parado e borrados durante o movimento, suspeite da compensação de movimento e dos carimbos de data/hora muito antes de suspeitar do sensor. E diminua a velocidade durante o mapeamento. Metade da velocidade significa metade da distorção, sem custo adicional.
Você só obtém um plano horizontal
Um LiDAR 2D mede um plano. Tudo o que fica acima ou abaixo desse plano não existe para ele.
As três falhas clássicas são:
- Saliências. Um tampo de mesa a 700 mm é invisível para um LiDAR a 150 mm. O robô passa confiante por baixo e fica preso.
- Obstáculos baixos. Uma soleira, um cabo, uma meia. Todos abaixo do plano.
- Quedas de nível. Uma escada descendente é espaço vazio em todas as direções que o LiDAR consegue ver. Ela parece um piso perfeitamente livre.
Nenhum processamento de varredura corrige isso, porque a informação nunca foi capturada. Robôs reais mantêm um sensor de contato, sensores de borda e muitas vezes um sensor apontado para baixo ou para a frente junto com o LiDAR — não porque o LiDAR seja ruim, mas porque um plano é um plano. Quando você lê que um robô aspirador “tem LiDAR e ainda tem sensores de contato”, esta é a razão.
Da varredura à grade: projeção de raios
Agora, a metade de mapeamento. Uma grade de ocupação divide o mundo em células quadradas e armazena, para cada uma, o grau de crença de que esteja ocupada.
A ideia que faz esse processo funcionar é simples: uma leitura de distância informa sobre todas as células ao longo do raio, não apenas sobre a célula em sua extremidade. Se um feixe percorreu 3 m antes de atingir algo, todo o espaço que ele cruzou deve estar vazio — caso contrário, teria sido interrompido antes.
Portanto, cada feixe produz três atualizações:
- Células atravessadas pelo raio → evidência de estarem livres. Percorra a linha do sensor até o impacto e atualize cada célula no sentido de vazio.
- Célula na qual a leitura terminou → evidência de estar ocupada. Atualize-a no sentido de ocupada.
- Células além do impacto → nenhuma informação. O feixe foi interrompido. Você não aprendeu nada sobre o que está atrás daquela parede e, portanto, deve deixar essas células intactas.
Percorrer a linha é apenas rasterização de linha — o algoritmo de Bresenham, o mesmo que desenha uma linha em uma tela.
Uma leitura no alcance máximo exige tratamento próprio. Muitos controladores de sensor informam o valor máximo, ou infinito, quando nenhum retorno foi obtido. Isso não significa “há uma parede a 12 m” — significa “não foi encontrado nada”. Marque o trajeto do raio como livre e não marque nenhuma célula ocupada no final.
Log-odds: por que somar em vez de multiplicar
Você poderia armazenar uma probabilidade por célula e multiplicar as atualizações de Bayes. Na prática, todos armazenam log-odds:
l = ln( p / (1 - p) ) p = 1 / (1 + e^(-l) )
Há dois motivos. Multiplicar muitas probabilidades pequenas causa subfluxo numérico; somar logs não. Além disso, isso reduz a atualização a uma única adição, barata o suficiente para ser realizada em cada célula de cada feixe de cada varredura.
Com p = 0.5 (nenhuma informação) mapeando para l = 0, escolha um valor para um impacto e outro para um feixe que passou sem encontrar um obstáculo — digamos p_occ = 0.7 (l = +0.847) e p_free = 0.4 (l = −0.405) — e a atualização é:
l_cell += l_occ # this beam hit this cell
l_cell -= 0.405 # this beam passed through this cell
Uma célula começando em l = 0 após três impactos:
| Observação | Log-odds | Probabilidade |
|---|---|---|
| início (desconhecida) | 0.000 | 0.500 |
| impacto | +0.847 | 0.700 |
| impacto | +1.695 | 0.845 |
| impacto | +2.542 | 0.927 |
| atravessada | +2.136 | 0.894 |
| atravessada | +1.731 | 0.850 |
As evidências se acumulam, e a discordância puxa a estimativa de volta. Esse é todo o algoritmo.
Limite os totais. Isso importa mais do que parece. Vinte impactos consecutivos sem limite colocam uma célula em l = 16.9, correspondente a p = 0.999999. Agora alguém move a cadeira. Desfazer essa certeza exige 42 observações livres. A cadeira deixa um fantasma permanente, e o planejador continua contornando nada.
Limitar l a algo como ±3,5 resolve o problema: uma crença forte continua forte, mas algumas varreduras contraditórias podem revertê-la. Se seus mapas acumulam fantasmas de objetos que já saíram, essa é quase sempre a razão.
Desconhecido é um terceiro estado, não sinônimo de livre
Este é o erro que produz planos confiantes e perigosos.
Uma grade recém-inicializada é inteiramente desconhecida. Se seu planejador tratar o estado desconhecido como atravessável, ele traçará uma rota diretamente pelas regiões do mundo que você nunca observou — e essas regiões, por serem inexploradas, são exatamente onde as surpresas se escondem. Se tratar o estado desconhecido como bloqueado, o robô recusará se mover no início, porque tudo é desconhecido.
As duas abordagens estão erradas; mantenha os três estados distintos e decida deliberadamente:
- Ocupada — não planeje através dela.
- Livre — planeje através dela.
- Desconhecida — planeje através dela apenas com um custo, ou apenas durante uma exploração deliberada.
A exploração de fronteira, que é como um robô escolhe onde procurar em seguida, baseia-se inteiramente na fronteira entre células livres e desconhecidas. Colapsar os dois estados descarta essa capacidade.
Escolhendo o tamanho da célula
A resposta usual é 5 cm para robôs internos, e há uma razão para não usar células menores só porque é possível.
Uma célula menor que o espaçamento dos feixes na distância típica está inventando uma precisão que você não tem — a 4 m, os feixes estão separados por 31 mm; portanto, células de 1 cm deixam buracos permanentes entre raios que nunca se preenchem. Células muito maiores que a margem de folga do seu robô, por outro lado, fazem portas parecerem intransponíveis, porque uma única célula ocupada pode engolir a abertura.
Regra prática: use células um pouco menores que a passagem mais estreita pela qual você precisa passar e nem menores que o espaçamento dos feixes na região em que realmente opera. Depois infle os obstáculos pelo raio do robô no momento do planejamento, em vez de diminuir as células para compensar.
Quando dá errado
| Sintoma | Normalmente |
|---|---|
| Obstáculos finos aparecem somente quando estão próximos | O espaçamento dos feixes superou a largura deles na distância — comportamento esperado, não uma falha |
| Paredes curvam ou duplicam durante o movimento | Varredura sem compensação de movimento; pontos tratados como pertencentes a um único instante |
| Mapa limpo quando parado, mas borrado durante o movimento | Mesma causa; também tente mapear mais devagar |
| Robô passa sob uma mesa e fica preso | O plano 2D não vê saliências; é preciso um segundo sensor |
| Escadas parecem piso aberto | Quedas de nível são invisíveis a um plano horizontal; use sensores de borda |
| Obstáculos removidos continuam no mapa | Log-odds não foram limitados, então a certeza não pode ser desfeita |
| O mapa inteiro se enche de obstáculos nas bordas | Leituras de alcance máximo “sem retorno” marcadas como impactos |
| O planejador traça uma rota pelo espaço inexplorado | Estado desconhecido confundido com livre |
| Grade fina cheia de pequenos buracos | Células menores que o espaçamento dos feixes; nada amostra entre os raios |
| Paredes de vidro desaparecem completamente | Retornos ópticos passam diretamente — o único caso em que o ultrassônico vence |
A última linha é a ressalva honesta para toda a página. O LiDAR supera o sonar em resolução, taxa e alcance e depois perde completamente para ele em uma porta de vidro, que o som reflete e a luz não. É o argumento mais claro para não escolher apenas um sensor e considerar o problema resolvido.
Explore o grafo
Faz parte destas montagens
Projetos e caminhos de aprendizagem que incluem este tutorial.
Leitura complementar