Skip to Content
BonicBot A2DevelopmentPython ProgrammingLesson 23 - LiDAR Distance Sensing

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

lidar_obstacle_detection.py
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

SensorManager.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 None

It 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

clean_scan.py
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

safety_drive.py
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

MethodReturn TypeDescription
bot.get_lidar_scan()dictRaw sensor_msgs/LaserScan message dictionary
bot.get_min_obstacle_distance()float | NoneDistance 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)?

Last updated on