3_2_lidar.md
April 24, 2026 ยท View on GitHub
3.2 LiDAR Model
This section explains the 2D LiDAR implementation used in the simulation. The LiDAR stack is composed of:
3.2.1 Sensor Parameters
SensorParameters stores installation parameters and LiDAR measurement parameters.
class SensorParameters:
def __init__(self, lon_m=0.0, lat_m=0.0, yaw_deg=0.0, min_m=0.5, max_m=40, reso_deg=2.0,
angle_std_scale=0.01, dist_std_rate=0.005, calibrator=None):
Key parameters:
- Installation pose on the vehicle coordinate system (
lon_m,lat_m,yaw_deg) - Sensing range and angular resolution (
min_m,max_m,reso_deg) - Noise model parameters (
angle_std_scale,dist_std_rate) - Optional calibration module (
calibrator)
Main methods:
calculate_global_pos(state): Converts sensor installation position from vehicle coordinates to global coordinates.calculate_sensor_odometry(state): Stores previous and current sensor poses as homogeneous transforms.calibrate_extrinsic_params(vehicle_state): If a calibrator is attached, estimates extrinsic parameters using sensor and vehicle odometry.draw_pos(axes, elems, state): Draws sensor position, and also draws calibration results when a calibrator exists.
3.2.2 Transformation Utilities
LiDAR point transformation uses homogeneous transformation matrices from:
hom_mat_33(x, y, yaw) is used to convert points from sensor coordinates to vehicle/global coordinates.
3.2.3 ScanPoint
ScanPoint represents one LiDAR return in the point cloud.
- distance and angle in sensor coordinates
- local point coordinates (
x_m,y_m) - transformed global coordinates used for drawing
class ScanPoint:
def __init__(self, distance_m, angle_rad, x_m, y_m):
self.distance_m = distance_m
self.angle_rad = angle_rad
self.point_array = XYArray(np.array([[x_m], [y_m]]))
self.transformed_x = None
self.transformed_y = None
To transform coordinates, ScanPoint chains three transforms:
- Point on sensor coordinates
- Sensor pose on vehicle coordinates
- Vehicle pose on global coordinates
This is implemented in get_transformed_data(...) and calculate_transformed_point(...).
3.2.4 OmniDirectionalLidar
OmniDirectionalLidar generates a 2D point cloud from obstacle contours.
class OmniDirectionalLidar:
def __init__(self, obst_list, params):
self.obst_list = obst_list
self.params = params
self.DIST_DB_SIZE = int(np.floor((np.pi * 2.0) / self.params.RESO_RAD)) + 1
self.MAX_DB_VALUE = float("inf")
self.DELTA_LIST = np.arange(0.0, 1.0, 0.008)
self.latest_point_cloud = []
Main processing flow in update(state):
- Update sensor global position
- Update sensor odometry
- Run optional extrinsic calibration
- Generate contour points for each obstacle
- Convert contour points to range/angle measurements
- Apply ray-casting filter (occlusion handling + nearest point per angle bin)
- Inject distance/angle noise and generate
ScanPointobjects
Current implementation:
def update(self, state):
self.params.calculate_global_pos(state)
self.params.calculate_sensor_odometry(state)
self.params.calibrate_extrinsic_params(state)
distance_list, angle_list = [], []
for obst in self.obst_list.get_list():
vertex_x, vertex_y = obst.vertex_xy()
contour_x, contour_y = self._calculate_contour_xy(vertex_x, vertex_y)
for x, y in zip(contour_x, contour_y):
diff_x = x - self.params.get_global_x_m()
diff_y = y - self.params.get_global_y_m()
distance_m = np.hypot(diff_x, diff_y)
angle_rad = atan2(diff_y, diff_x) - state.get_yaw_rad()
distance_list.append(distance_m)
angle_list.append(angle_rad)
self._ray_casting_filter(distance_list, angle_list, state)
draw(axes, elems, state) draws both LiDAR position and point cloud.
3.2.5 Extrinsic Parameter Auto Calibration (Optional)
UkfExtParamsCalibrator estimates LiDAR extrinsic parameters on the vehicle coordinate system:
- Longitudinal position
- Lateral position
- Yaw angle
Source:
The module uses an Unscented Kalman Filter (UKF):
- Predicts static extrinsic state via sigma points
- Predicts sensor odometry from vehicle odometry and candidate extrinsics
- Updates state using innovation between predicted and measured sensor odometry
When this calibrator is passed into SensorParameters(calibrator=...), the calibration process runs automatically during LiDAR updates and the estimated parameter values are drawn in the simulation.
Example simulation:
- sensor_auto_calibration.py
- Output GIF:
