4. 激光雷达标定与配置
好,咱们进入第四讲。激光雷达这东西,买回来插上电就能用吗?
说实话,能转、能出数据,但离“好用”还差得远。我见过太多新手,把雷达往车上一装,跑个 Nav2 就抱怨定位不准、地图有重影。其实八成问题出在标定和配置上。
这一讲,咱们就聊聊怎么把雷达“伺候”好。
4.1 帧率与角度分辨率:一对冤家
先问个问题:你希望雷达转得快一点,还是慢一点?
转得快,帧率就高。比如 10Hz,每秒出 10 帧点云。这对动态避障有好处,机器人跑起来反应快。但代价是什么?角度分辨率会下降。
为什么?我解释一下。机械式雷达内部有个电机,带着激光头旋转。如果电机转一圈的时间是 0.1 秒(10Hz),那在这一圈里,激光头能发射的激光脉冲总数是固定的。比如每秒能发 2 万个脉冲,那 10Hz 下,每圈就是 2000 个脉冲。这 2000 个脉冲均匀分布在 360° 上,角度分辨率就是 360/2000 = 0.18°。
如果你把帧率降到 5Hz,电机转一圈要 0.2 秒。同样每秒 2 万个脉冲,每圈就能有 4000 个脉冲。角度分辨率就提升到了 0.09°。
你看,帧率和分辨率,说白了就是鱼和熊掌。
核心结论:
- 高帧率(10Hz+):适合动态场景、快速移动的机器人。角度分辨率会牺牲一些。
- 高分辨率(0.1°以下):适合建图、静态场景扫描。帧率会低一些。
我个人习惯是:做 SLAM 建图时用 5Hz,跑导航时切到 10Hz。当然,这取决于你的雷达型号。有些雷达支持动态切换,有些需要重启驱动。
4.2 畸变校正原理:别让运动毁了你的点云
这是个大坑。我刚开始做机器人时,就栽在这上面。
想象一下:雷达在旋转扫描。它从 0° 扫到 180° 需要 50 毫秒(10Hz 下)。在这 50 毫秒里,你的机器人如果正在转弯,那这帧点云里的每个点,其实是在不同时刻、不同位姿下采集的。
结果就是——一堵笔直的墙,在点云里变成了弯曲的。这就是运动畸变。
注意:运动畸变在低速场景下不明显,但一旦机器人速度超过 0.5m/s 或角速度较大,畸变就会严重影响建图和定位精度。
怎么校正?原理其实不复杂。
核心思路是:把每个激光点的时间戳找出来,然后根据这段时间内机器人的运动(里程计或 IMU 数据),把每个点“反算”到同一个参考时刻(通常是这一帧的起始时刻或中间时刻)。
举个例子:
- 雷达在 t0 时刻发出第一个激光脉冲,测得距离 d0,角度 θ0。
- 在 t1 时刻发出第二个脉冲,测得 d1,角度 θ1。
- 如果机器人在这段时间内移动了 Δx、Δy、Δθ,那第二个点其实是在一个偏移后的坐标系下测得的。
- 校正就是:把第二个点的坐标,通过 Δx、Δy、Δθ 变换回 t0 时刻的坐标系下。
嗯,这里要注意:校正依赖外部里程计数据。如果里程计不准,校正效果反而更差。我曾经在一个项目里,IMU 数据噪声太大,校正后点云比没校正还乱。后来换了更好的 IMU 才解决。
我的经验:如果暂时没有好的里程计,可以先用“匀速模型”做近似校正。假设机器人在一帧时间内匀速运动,用上一帧和当前帧的位姿差来插值。虽然不完美,但比不校正强很多。
4.3 配置参数文件:把一切写进 YAML
好了,理论讲完,咱们来点实际的。在 ROS2 里,激光雷达的配置通常写在一个 YAML 文件里。我拿一个典型的配置举例:
# lidar_config.yaml
laser_frame_id: "laser_link"
# 帧率设置
scan_frequency: 10.0 # Hz,我通常设 10
# 角度分辨率
angle_increment: 0.0174533 # 弧度,约 1 度。如果想更精细,改成 0.0087266(0.5 度)
# 扫描范围
angle_min: -3.14159 # -180°
angle_max: 3.14159 # 180°
# 距离范围
range_min: 0.1 # 米,太近的不要
range_max: 30.0 # 米,太远的不可靠
# 畸变校正开关
enable_motion_distortion_correction: true
# 畸变校正依赖的里程计话题
odom_topic: "/odom"
# 时间戳补偿
time_offset: 0.0 # 秒,如果雷达和主控时间不同步,可以微调
这个文件怎么用?通常在雷达驱动节点的 launch 文件里加载:
# lidar_launch.py
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='sick_scan2', # 以 SICK 雷达为例
executable='sick_generic_can',
name='lidar_node',
parameters=['lidar_config.yaml'],
output='screen'
)
])
你看,就这么简单。但有几个参数我特别想提醒你:
- laser_frame_id:一定要和你的 TF 树对得上。我见过有人写成 "laser",但 TF 里是 "laser_link",结果点云全飞了。
- time_offset:这个参数容易被忽略。如果雷达和主控之间有时延(比如通过 USB 转串口),可以在这里补偿。我曾经调了 0.02 秒,效果立竿见影。
- range_max:别设太大。很多雷达标称 30 米,但实际在室内 10 米外就噪声很大。设小一点,反而能减少误检测。
4.4 知识体系总览
说了这么多,咱们用一张图把这一章的核心逻辑串起来:
4.5 避坑指南
最后,分享几个我踩过的坑:
- 帧率设太高,CPU 扛不住:20Hz 的点云,处理起来 CPU 占用率直接飙到 80%。后来我降到 10Hz,一切正常。别盲目追求高帧率。
- 畸变校正开了,但里程计没发布:驱动会一直等 /odom 话题,导致雷达节点卡死。检查一下你的里程计是否在正常运行。
- 角度分辨率设得太细:比如 0.01°,一帧点云有 36000 个点。传输和处理都慢。除非你有特殊需求,否则 0.5° 到 1° 就够用了。
嗯,这一讲就到这里。配置参数看似琐碎,但每一个参数背后都有它的物理意义和工程权衡。理解了这些,你就能根据实际场景灵活调整,而不是死记硬背。
一句话总结:激光雷达的标定与配置,本质是在帧率、分辨率、计算资源之间找平衡。畸变校正是锦上添花,但前提是里程计要靠谱。