Lesson 23 - LiDAR Distance Sensing
Learning Objective
- Access raw 360-degree 2D LiDAR range arrays using
bot.get_lidar_scan(). - Retrieve instant closest obstacle distances in meters using
bot.get_min_obstacle_distance(). - Filter invalid range readings (
NaN,Inf, out-of-bounds) to build collision-prevention safety loops.
Introduction
LiDAR (Light Detection and Ranging) sensors measure distance by pulsing laser light against surrounding obstacles. The robot’s LiDAR streams continuous 360-degree distance arrays over ROS 2 topics.
This lesson covers querying raw LiDAR arrays and using get_min_obstacle_distance() for collision prevention.
Code
import time
from bonicbot_bridge import BonicBot
with BonicBot(host="192.168.0.188") as bot:
print("Waiting for LiDAR stream...")
bot.wait_for_data(timeout=5.0, require_lidar=True)
# 1. Reading closest obstacle distance
closest_m = bot.get_min_obstacle_distance()
print("Closest obstacle distance:", closest_m, "meters")
# 2. Accessing raw LiDAR scan dictionary
scan_data = bot.get_lidar_scan()
if scan_data:
ranges = scan_data.get("ranges", [])
range_min = scan_data.get("range_min", 0.0)
range_max = scan_data.get("range_max", float("inf"))
print(f"Total range beams: {len(ranges)} | Min/Max limits: [{range_min}m, {range_max}m]")
# 3. Simple safety check loop before moving
if closest_m is not None and closest_m < 0.3:
print("⚠️ Warning: Obstacle too close! Aborting motion.")
else:
print("✅ Path clear. Proceeding forward...")
bot.move_forward(speed=0.2, duration=1.0)Expected Output
Click to see expected output
🤖 Connected to BonicBot at 192.168.0.188:9090
Waiting for LiDAR stream...
Closest obstacle distance: 1.42 meters
Total range beams: 360 | Min/Max limits: [0.15m, 12.0m]
✅ Path clear. Proceeding forward...
🔌 Disconnected from BonicBot🔧 Under the Hood
How get_min_obstacle_distance() filters scans in sensors.py
get_min_obstacle_distance() filters scans in sensors.pySensorManager.get_min_obstacle_distance() parses the latest sensor_msgs/LaserScan dictionary:
valid = [
r for r in ranges
if isinstance(r, (int, float))
and not math.isnan(r)
and not math.isinf(r)
and range_min <= r <= range_max
]
return min(valid) if valid else NoneIt removes NaN / Inf noise readings before computing the mathematical minimum.
Student Challenge
Challenge 1 — Python Only
Write a filtering function clean_scan_ranges(ranges_list, min_val=0.15, max_val=10.0) that removes float('nan') and float('inf') values, returning only valid float distances.
Click to see solution
import math
def clean_scan_ranges(ranges_list, min_val=0.15, max_val=10.0):
return [
r for r in ranges_list
if isinstance(r, (int, float))
and not math.isnan(r)
and not math.isinf(r)
and min_val <= r <= max_val
]
raw_test = [1.2, float('nan'), float('inf'), 0.05, 3.4]
print("Cleaned ranges:", clean_scan_ranges(raw_test))Challenge 2 — Robot
Build a safety drive loop: drive forward continuously until bot.get_min_obstacle_distance() drops below 0.4 meters, then stop immediately.
Click to see solution
import time
from bonicbot_bridge import BonicBot
with BonicBot(host="192.168.0.188") as bot:
bot.wait_for_data(timeout=3.0, require_lidar=True)
print("Starting forward safety drive...")
bot.move_forward(speed=0.2)
while True:
dist = bot.get_min_obstacle_distance()
if dist is not None and dist <= 0.4:
print(f"🛑 Obstacle detected at {dist:.2f}m! Stopping.")
bot.stop()
break
time.sleep(0.05)Quick Reference
LiDAR Methods
| Method | Return Type | Description |
|---|---|---|
bot.get_lidar_scan() | dict | Raw sensor_msgs/LaserScan message dictionary |
bot.get_min_obstacle_distance() | float | None | Distance in meters to closest valid obstacle |
Reflection Questions
Why must LiDAR range arrays be explicitly filtered for math.isnan() and math.isinf() before passing them to min()?
What should a robot do if get_min_obstacle_distance() returns None (e.g. all LiDAR beams are out of range)?