Tutorial · Intermedio · 35 min de lectura

LiDAR en robótica: del barrido al mapa de ocupación

Cómo construye un barrido un LiDAR giratorio, por qué más velocidad reduce la resolución angular y cómo el trazado de rayos crea un mapa de ocupación.

Introducción

Un sensor de distancia te dice lo lejos que está una cosa, a lo largo de una línea. Un mapa te dice la forma de una habitación. Todo lo interesante de la navegación vive en el hueco entre esas dos cosas, y de eso trata esta página.

Los dos extremos ya están cubiertos aquí: en un lado el rango de un solo punto, y del otro el SLAM y el A* sobre una rejilla de ocupación. Pero ambos dan por hecha una rejilla que ya existe. Nada dice de dónde salió, y la respuesta —lanzar un barrido por trazado de rayos contra las celdas— es a la vez simple y está llena de trampas.

Un lidar 2D es un sensor ToF sobre una plataforma giratoria

Esto es lo más útil que hay que saber, porque significa que ya entiendes la mitad de la medición.

Dentro de un lidar 2D de hobby hay un único módulo óptico de medición por tiempo de vuelo, exactamente del tipo que hay en un breakout de la serie VL53, montado de lado y girado. Un codificador angular informa de dónde estaba mirando en cada medida. La alimentación y los datos cruzan la frontera giratoria mediante un anillo deslizante o un acoplamiento óptico/inductivo.

Así que un «barrido» no es una fotografía. Es una lista de pares (ángulo, distancia), recopilados de uno en uno, a lo largo de una revolución. Todas las limitaciones que siguen se desprenden de esa frase.

Esto también te dice por qué los sensores ultrasónicos no se giran para convertirse en lidars. Un haz ultrasónico tiene decenas de grados de ancho, así que girarlo no te gana casi nada — estarías difuminando un haz ya ancho por toda la habitación. Un haz óptico estrecho es lo que da sentido a la resolución angular en primer lugar. Barrer un solo sensor ToF con un servomotor, como en el tutorial de barrido con servo, es realmente un lidar lento y de baja resolución.

El presupuesto de muestras es fijo, así que resolución y frescura se tradean

Esta es la parte que sorprende a la gente, y merece entenderse antes de comprar nada.

El módulo de medición tiene un único número de rendimiento: cuántas medidas por segundo puede tomar. En un RPLIDAR A1 eso son unos 8000 muestras por segundo, y no cambia cuando cambias la velocidad de giro. La velocidad de giro la eliges tú, típicamente entre 1 y 10 Hz.

Así que los puntos que obtienes por revolución son sencillamente el presupuesto dividido por la velocidad de giro:

points per revolution = samples per second ÷ spin rate
angular step          = 360° ÷ points per revolution
Velocidad de giro Puntos por revolución Paso angular Periodo de barrido
5.5 Hz 1455 0.25° 182 ms
10 Hz 800 0.45° 100 ms

No puedes tener a la vez barridos frescos y resolución angular fina. Girar a 10 Hz te reduce la latencia a la mitad y casi te reduce a la mitad la resolución angular. Ese único intercambio decide más sobre cómo se comporta un robot que la cifra de alcance de la cabecera, y es lo primero que conviene fijar a conciencia en vez de dejarlo en lo que traiga el driver por defecto.

Robot rápido en un pasillo abierto: gira rápido, necesitas frescura y las paredes son grandes. Robot lento mapeando una habitación desordenada: gira despacio, necesitas el detalle y puedes permitirte la latencia.

Los haces divergen, así que los obstáculos lejanos caen entre ellos

Un paso angular es un ángulo, no una distancia. Dos haces adyacentes se separan según avanzan:

gap between beams ≈ range × angular step (in radians)

A 0,45° eso son 7,9 mm de separación a un metro, y 31 mm a cuatro metros. Nada muestrea el espacio intermedio.

Gráfico de la separación entre haces de lidar adyacentes frente a la distancia al objetivo, para 5.5 Hz (1455 puntos por revolución, 0.25 grados) y 10 Hz (800 puntos por revolución, 0.45 grados). Ambas líneas suben linealmente desde cero, la de 10 Hz con el doble de pendiente. Una línea discontinua horizontal marca una pata de silla de 20 mm, y los marcadores muestran que la separación de haces a 10 Hz supera ese ancho más allá de 2.5 metros y la de 5.5 Hz más allá de 4.6 metros.
La separación de muestreo crece linealmente con la distancia, y el doble de rápido a 10 Hz que a 5.5 Hz. Donde cada línea cruza el ancho de la pata de silla es donde esa pata deja de ser detectable. Descargar SVG

Toma una pata de silla de 20 mm. Girando a 10 Hz, la separación entre haces pasa de 20 mm a unos 2,5 m — más allá de eso la pata puede quedarse enteramente entre dos haces y no devolver nada. A 5,5 Hz llegas hasta unos 4,6 m antes de que ocurra lo mismo.

La misma pata de silla de 20 mm dibujada frente a dos haces adyacentes a dos distancias. A 2 metros los haces están separados 16 mm y la pata es más ancha que la separación, así que un haz cae sobre ella y se detecta. A 5 metros los haces están separados 39 mm y la pata es más estrecha que la separación, así que queda entre los haces y no vuelve nada.
El mismo objeto y el mismo sensor, dos veces. Nada de la pata cambió — solo si un haz casual apuntaba a ella. Descargar SVG

Esto explica un comportamiento que si no parece un sensor roto: los obstáculos finos parecen aparecer a medida que el robot se acerca, asomando en el mapa a un metro o dos. El lidar no estaba fallando. La pata nunca se muestreó.

Dos consecuencias que merece la pena diseñar alrededor:

  • No confíes en un solo barrido para obstáculos finos. Acumular varios barridos en una rejilla, como se explica más abajo, es lo que realmente encuentra las patas de las mesas — cada barrido muestrea ángulos ligeramente distintos.
  • Las patas de silla y de mesa son el fallo doméstico clásico del robot, porque son finas, están exactamente a la altura del lidar, y el robot se entera de ellas tarde.

Un barrido no es una instantánea

Los puntos de una revolución no se midieron en el mismo instante. A 5,5 Hz el barrido dura 182 ms, y el robot no espera educadamente.

  • Conduciendo a 0,5 m/s, el robot recorre 91 mm durante una revolución.
  • Girando a 1 rad/s, el barrido queda difuminado a lo largo de 10,4°.

Tratar esa lista de puntos como una única instantánea rígida tomada en una pose deforma el mundo. Las paredes rectas salen curvadas o duplicadas, y el emparejamiento de barridos lucha contra correcciones que en realidad son tu propio movimiento.

Por eso sensor_msgs/LaserScan lleva scan_time y time_increment junto a las distancias: le permiten a quien las consume averiguar cuándo se tomó cada haz. Corregirlo —transformar cada punto por la pose que el robot tenía en la marca de tiempo de ese haz— se llama deskewing o compensación de movimiento, y los buenos front-ends de SLAM lo hacen por ti.

Qué significa esto en la práctica: si tus mapas están limpios estando quieto y difuminados en movimiento, sospecha del deskewing y de las marcas de tiempo mucho antes que del sensor. Y frena mientras mapeas. La mitad de velocidad es la mitad de distorsión, gratis.

Solo obtienes una rebanada horizontal

Un lidar 2D mide un plano. Lo que quede por encima o por debajo de ese plano no existe.

Los tres clásicos:

  • Voladizos. Un tablero a 700 mm es invisible para un lidar a 150 mm. El robot pasa por debajo con confianza y se queda encajado.
  • Obstáculos bajos. Un umbral de puerta, un cable, un calcetín. Todos por debajo del plano.
  • Desniveles. Una escalera que baja es espacio vacío en todas las direcciones que el lidar puede ver. Se lee como un suelo perfectamente despejado.

Ningún procesado de barrido lo arregla, porque la información nunca se capturó. Los robots reales mantienen un bumper, sensores de precipicio y a menudo un ranger mirando hacia abajo o inclinado hacia delante junto al lidar — no porque el lidar sea malo, sino porque un plano es un plano. Cuando leas que un robot aspiradora «tiene lidar y además bumpers», esta es la razón.

Del barrido a la rejilla: trazado de rayos

Ahora la mitad de mapeo. Una rejilla de ocupación divide el mundo en celdas cuadradas y guarda, para cada una, con qué fuerza crees que está ocupada.

La idea que lo hace funcionar: una lectura de distancia te informa de todas las celdas a lo largo del rayo, no solo de la celda del final. Si un haz recorrió 3 m antes de golpear algo, entonces todo el espacio que cruzó tuvo que estar vacío — si no, se habría detenido antes.

Así que cada haz produce tres veredictos:

Rejilla de celdas cuadradas con un sensor a la izquierda y un rayo dibujado hacia una celda arriba a la derecha. Las celdas por las que pasa el rayo están sombreadas como libres, la celda donde aterriza la lectura de distancia está sombreada como ocupada, y las celdas que continúan por la misma dirección más allá de ese impacto están sombreadas como desconocidas. Una leyenda indica que las celdas atravesadas pasan a ser libres y su log-odds baja, el impacto pasa a ser ocupado y su log-odds sube, y las celdas tras el impacto siguen desconocidas y se dejan intactas en vez de marcarse como libres.
Un haz actualiza toda una línea de celdas. Las celdas tras el impacto quedan en sombra — el haz nunca llegó a ellas, así que siguen desconocidas, que es una cosa distinta de libres. Descargar SVG
  1. Las celdas por las que pasó el rayo → evidencia de libre. Recorre la línea del sensor al impacto y empuja cada celda hacia vacío.
  2. La celda en la que aterrizó la lectura → evidencia de ocupada. Empújala hacia llena.
  3. Las celdas más allá del impacto → nada. El haz se detuvo. No aprendiste nada sobre lo que hay detrás de ese muro, así que debes dejar esas celdas intactas.

Recorrer la línea es simplemente rasterizado de línea — el algoritmo de Bresenham, el mismo que dibuja una línea en una pantalla.

Una lectura a distancia máxima necesita su propio tratamiento. Muchos drivers informan del máximo, o de infinito, cuando no volvió nada. Eso no es «hay un muro a 12 m» — es «no se encontró nada». Marca el rayo como libre y marca ninguna celda ocupada al final.

Log-odds: por qué sumas en vez de multiplicar

Podrías guardar una probabilidad por celda y multiplicar actualizaciones de Bayes. En la práctica todo el mundo guarda log-odds:

l = ln( p / (1 - p) )          p = 1 / (1 + e^(-l) )

Dos razones. Multiplicar muchas probabilidades pequeñas se desborda hacia cero; sumar logaritmos no. Y convierte la actualización en una única suma, lo bastante barata para hacer en cada celda de cada haz de cada barrido.

Con p = 0.5 (sin idea) correspondiendo a l = 0, elige un valor para un impacto y otro para un fallo — digamos p_occ = 0.7 (l = +0.847) y p_free = 0.4 (l = −0.405)— y la actualización es:

l_cell += l_occ     # this beam hit this cell
l_cell -= 0.405     # this beam passed through this cell

Una celda que empieza en l = 0 después de tres impactos:

Observación Log-odds Probabilidad
inicio (desconocida) 0.000 0.500
impacto +0.847 0.700
impacto +1.695 0.845
impacto +2.542 0.927
atravesada +2.136 0.894
atravesada +1.731 0.850

La evidencia se acumula, y el desacuerdo la devuelve. Ese es todo el algoritmo.

Recorta los totales. Esto importa más de lo que parece. Veinte impactos seguidos sin recortar ponen una celda en l = 16.9, que es p = 0.999999. Ahora alguien mueve la silla. Deshacer esa certeza requiere 42 observaciones de libre. La silla deja un fantasma permanente, y tu planificador sigue esquivando la nada.

Recortar l a algo como ±3.5 lo arregla: la creencia fuerte sigue siendo fuerte, pero un puñado de barridos contradictorios puede tumbarla. Si tus mapas acumulan fantasmas de objetos que ya no están, casi siempre es por esto.

Desconocido es un tercer estado, no un sinónimo de libre

Este es el error que produce trayectorias seguras y peligrosas.

Una rejilla recién inicializada está enteramente desconocida. Si tu planificador trata lo desconocido como transitable, trazará una ruta recta a través de las partes del mundo que nunca has mirado — y, por no exploradas, son justo donde viven las sorpresas. Si lo trata como bloqueado, el robot se niega a moverse al principio, porque todo está desconocido.

Ambos están mal; mantén los tres estados distintos y decide a conciencia:

  • Ocupada — no planifiques a través de ella.
  • Libre — planifica a través de ella.
  • Desconocida — planifica a través de ella solo con un coste, o solo cuando explores deliberadamente.

La exploración de frontera, que es como un robot decide dónde mirar después, se construye enteramente sobre la frontera libre/desconocido. Colapsar los dos es tirar eso por la ventana.

Elegir el tamaño de celda

La respuesta habitual es 5 cm para robots de interior, y hay una razón para no afinar solo porque puedas.

Una celda más pequeña que tu separación de haces al alcance típico está inventando precisión que no tienes — a 4 m los haces están separados 31 mm, así que celdas de 1 cm dejan agujeros permanentes entre rayos que nunca se rellenan. Celdas mucho mayores que el margen de holgura de tu robot, por su parte, hacen que las puertas parezcan impasables, porque una única celda ocupada puede tragarse el hueco.

Regla práctica: un tamaño de celda algo menor que el hueco más estrecho por el que debas pasar, y no menor que tu separación de haces donde realmente operas. Después infla los obstáculos por el radio del robot en el momento de planificar, en vez de encoger las celdas para compensarlo.

Cuando va mal

Síntoma Normalmente
Los obstáculos finos solo aparecen de cerca La separación de haces superó su ancho a esa distancia — esperado, no un fallo
Las paredes se curvan o se duplican al conducir Barrido sin deskew; puntos tratados como un único instante
Mapa limpio quieto, difuminado en movimiento Misma causa; prueba además a mapear más despacio
El robot pasa bajo una mesa y se encaja El plano 2D no ve voladizos; hace falta un segundo sensor
Las escaleras se leen como suelo abierto Los desniveles son invisibles para un plano horizontal; sensores de precipicio
Los obstáculos que se retiraron siguen en el mapa Log-odds sin recortar, así que la certeza no se puede deshacer
El mapa entero se llena de obstáculos en los bordes Lecturas de distancia máxima «sin retorno» marcadas como impactos
El planificador traza rutas por espacio inexplorado Desconocido confundido con libre
Rejilla fina llena de agujeros de moteado Celdas más pequeñas que la separación de haces; nada muestrea entre rayos
Las paredes de cristal desaparecen por completo Los retornos ópticos pasan de largo — el único caso donde gana el ultrasónico

Esa última fila es la salvedad honesta de toda la página. El lidar gana al sonar en resolución, frecuencia y alcance, y luego pierde por goleada ante una puerta de cristal, contra la que el sonido rebota y la luz no. Es el argumento más claro para no elegir un solo sensor y dar el problema por resuelto.

Explora el grafo

Forma parte de estos montajes

Proyectos y rutas de aprendizaje que incluyen este tutorial.

Lecturas adicionales

Referencias