3、传感器仿真基础:激光雷达、摄像头、毫米波雷达、IMU/GNSS 的仿真原理与数据格式

传感器仿真,说白了就是给自动驾驶的车子装上一双“虚拟的眼睛”。

我刚开始做仿真时,总觉得传感器模型差不多就行。后来发现,一个参数没调对,实车测试时直接撞上了路沿。嗯,从那以后我再也不敢小看传感器仿真了。

3.1 激光雷达(LiDAR)仿真

激光雷达的原理很简单:发射激光束,测量反射时间,算出距离。仿真里我们做的就是模拟这个过程。

核心仿真原理:

  • 射线投射(Ray Casting):从激光雷达原点发射射线,检测与场景中物体的交点
  • 光束模型:模拟真实激光束的束散角、能量衰减
  • 噪声模型:加入高斯噪声、多路径反射、雨雾衰减

我个人习惯用 ROS 的 sensor_msgs/PointCloud2 格式。你想想看,这个格式能同时存储点云的 xyz 坐标、反射强度、时间戳,非常方便。

数据格式示例(PointCloud2):

# 点云消息结构
Header header          # 时间戳、坐标系
uint32 height          # 1(无序点云)
uint32 width           # 点云数量
PointField[] fields    # 字段定义(x, y, z, intensity)
  string name          # 字段名
  uint32 offset        # 偏移量
  uint8 datatype       # 数据类型(FLOAT32=7)
  uint32 count         # 元素个数
bool is_bigendian      # 字节序
uint32 point_step      # 每个点的字节数
uint32 row_step        # 每行字节数
uint8[] data           # 点云数据
bool is_dense          # 是否包含无效点

避坑指南: 我曾经在仿真中忽略了激光雷达的“盲区”问题。真实激光雷达在近距离(<0.5m)是无法探测的。仿真里如果不加这个限制,实车部署时就会在近距离出现意外碰撞。

3.2 摄像头仿真

摄像头仿真,说白了就是渲染一张“照片”。但这里有个坑:你不能随便渲染,得模拟真实相机的光学特性。

仿真关键点:

  • 针孔相机模型:内参矩阵(焦距、主点)、畸变系数
  • 光照模型:模拟不同时间、天气的光照条件
  • 运动模糊:车辆高速行驶时,图像会产生拖影
  • 传感器噪声:暗电流噪声、读出噪声、坏点

我建议使用 sensor_msgs/Image 格式。这个格式支持多种编码方式,比如 RGB8、BGR8、MONO8 等。

数据格式示例(Image):

# 图像消息结构
Header header          # 时间戳、坐标系
uint32 height          # 图像高度(像素)
uint32 width           # 图像宽度(像素)
string encoding        # 编码方式(如 "rgb8")
uint8 is_bigendian     # 字节序
uint32 step            # 每行字节数(width * channels)
uint8[] data           # 图像数据

注意: 仿真中的图像太“干净”了。真实摄像头有镜头污渍、眩光、过曝等问题。我建议在仿真中加入随机污点、光晕效果,否则模型在实车上会水土不服。

3.3 毫米波雷达仿真

毫米波雷达和激光雷达不同。它不测精确距离,而是测相对速度和大致方位。仿真时得模拟这种“模糊感”。

仿真原理:

  • FMCW 调制:通过发射频率连续变化的波,测量回波频率差来算距离和速度
  • 多普勒效应:目标运动会导致回波频率偏移,从而算出相对速度
  • 角度测量:通过多天线阵列的相位差估算目标方位角
  • 杂波模型:地面反射、多径效应、雨雪衰减

我记得有一次,仿真中毫米波雷达的检测距离设得太理想了。实车测试时,雷达在雨天根本看不到 200 米外的车。后来我加入了衰减模型,才和实车数据对得上。

数据格式示例(ROS radar_msgs/RadarScan):

# 毫米波雷达扫描消息
Header header
float32 angle_min          # 最小扫描角度
float32 angle_max          # 最大扫描角度
float32 angle_increment    # 角度分辨率
float32 time_increment     # 每帧时间间隔
float32 scan_time          # 扫描周期
float32 range_min          # 最小探测距离
float32 range_max          # 最大探测距离
float32[] ranges           # 距离数组
float32[] intensities      # 回波强度数组
float32[] velocities       # 径向速度数组

实战技巧: 毫米波雷达的“多目标检测”在仿真中很容易被忽略。真实场景中,一个目标可能产生多个反射点。我建议在仿真中为每个目标生成 2-3 个散射点,更贴近真实情况。

3.4 IMU/GNSS 仿真

IMU 和 GNSS 是定位的“黄金搭档”。IMU 提供高频的加速度和角速度,GNSS 提供低频的位置。仿真时得把两者结合起来。

IMU 仿真原理:

  • 加速度计模型:模拟三轴加速度,加入零偏、比例因子、随机游走噪声
  • 陀螺仪模型:模拟三轴角速度,同样加入零偏和噪声
  • 重力补偿:仿真中需要减去重力加速度分量

GNSS 仿真原理:

  • 卫星几何分布:模拟可见卫星数量、DOP 值
  • 误差模型:电离层延迟、对流层延迟、多路径效应
  • 更新频率:通常 10Hz,比 IMU 的 100-200Hz 低很多

你想想看,为什么 IMU 需要高频?因为车辆在颠簸路面上的姿态变化很快,低频的 GNSS 根本跟不上。仿真中如果 IMU 频率设低了,定位结果会严重失真。

数据格式示例:

# IMU 消息(sensor_msgs/Imu)
Header header
geometry_msgs/Quaternion orientation     # 四元数姿态
float64[9] orientation_covariance        # 姿态协方差
geometry_msgs/Vector3 angular_velocity   # 角速度 (rad/s)
float64[9] angular_velocity_covariance   # 角速度协方差
geometry_msgs/Vector3 linear_acceleration # 线加速度 (m/s²)
float64[9] linear_acceleration_covariance # 线加速度协方差

# GNSS 消息(sensor_msgs/NavSatFix)
Header header
float64 latitude          # 纬度 (度)
float64 longitude         # 经度 (度)
float64 altitude          # 海拔 (米)
uint8 status              # 状态(0=无解, 1=单点, 2=差分, 4=RTK固定)
float64 position_covariance[9]  # 位置协方差

重要提醒: 我曾经在仿真中把 IMU 的零偏设为零,结果实车测试时定位漂移得一塌糊涂。真实 IMU 一定有零偏,而且会随温度变化。仿真中一定要加入零偏稳定性模型,否则你的定位算法在实车上根本跑不起来。

3.5 传感器仿真知识体系

下面这张图是我自己整理的传感器仿真知识体系。它把四种传感器的仿真原理、数据格式、关键参数都串起来了。

传感器仿真知识体系 传感器仿真 激光雷达 LiDAR 摄像头 Camera 毫米波雷达 Radar IMU / GNSS 射线投射 光束模型 噪声模型 格式: PointCloud2 针孔相机模型 光照/天气模拟 运动模糊 格式: Image FMCW 调制 多普勒效应 杂波/衰减模型 格式: RadarScan 加速度/角速度 零偏/噪声模型 卫星几何分布 格式: Imu/NavSatFix 核心目标:模拟真实传感器特性,缩小仿真与实车的差距 关键仿真参数对比 传感器 更新频率 主要噪声源 激光雷达 10-20 Hz 高斯噪声、多路径 摄像头 15-30 Hz 暗电流、运动模糊 毫米波雷达 10-20 Hz 杂波、多径衰减 IMU/GNSS 100-200 Hz / 10 Hz 零偏、随机游走

这张图把四种传感器的核心要素都列出来了。我建议你把它打印出来贴在工位上,做仿真时随时对照。

我的个人经验: 传感器仿真不是越复杂越好。刚开始做时,先用简单的射线投射模型跑通流程。等算法稳定了,再逐步加入噪声、衰减等细节。一步到位反而容易出问题。

好了,传感器仿真的基础就讲到这里。记住一句话:仿真做得越真实,实车部署就越顺利。别偷懒,把每个传感器的特性都模拟到位。

可可精品资料库