激光雷达原理与数据解析
各位同学,欢迎来到第二章。上一章我们聊了传感器融合的整体框架,这一章咱们把目光聚焦到最核心的传感器之一——激光雷达上。
说实话,我刚开始接触机器人时,觉得激光雷达就是个“高级转盘”,转一圈就能知道周围有啥。后来踩了不少坑才明白,这里面的门道可不少。今天我就把这些年积累的经验,从原理到实战,一步步拆给你看。
激光雷达工作原理
激光雷达,英文叫 LiDAR(Light Detection And Ranging)。说白了,就是通过发射激光束,测量激光从发射到反射回来的时间差,从而计算出目标物体的距离。
你想想看,这就像你对着山谷喊一声,听回声判断山有多远。只不过激光雷达用的是光速,精度能达到厘米级甚至毫米级。
核心公式:距离 = (光速 × 飞行时间) / 2
除以2是因为激光走了个来回,我们只想要单程距离。
根据扫描方式,常见的激光雷达分这么几类:
- 机械旋转式:通过电机带动激光收发模块旋转,实现360°扫描。Velodyne、禾赛的早期产品都是这种。优点是视野广,缺点是机械结构容易磨损。
- 固态式:没有旋转部件,靠光学相控阵或微振镜来改变激光方向。体积小、寿命长,但视场角通常有限。
- 混合固态式:比如 Livox 的棱镜扫描方案,介于两者之间,算是折中方案。
我个人习惯在室内导航场景用机械旋转式,便宜且成熟。但如果你做的是无人机或者车载,固态式会更合适——毕竟旋转部件在震动环境下容易出问题。
一个小经验:选型时别只看线数(16线、32线、64线),还要关注角分辨率和帧率。角分辨率决定了你能看清多小的物体,帧率决定了动态场景下的数据密度。
点云数据格式
激光雷达采集到的原始数据,经过处理后就是点云(Point Cloud)。每个点包含三维坐标 (x, y, z) 和反射强度 (intensity)。
ROS2 中最常用的点云消息类型是 sensor_msgs/msg/PointCloud2。这个格式比旧版的 PointCloud 更灵活,支持自定义字段。
来看一个典型的点云消息结构:
# sensor_msgs/msg/PointCloud2
std_msgs/Header header # 时间戳和坐标系
uint32 height # 如果是无序点云,height=1
uint32 width # 点的数量
PointField[] fields # 字段定义(x, y, z, intensity等)
bool is_bigendian # 字节序
uint32 point_step # 每个点的字节数
uint32 row_step # 每行的字节数
uint8[] data # 原始二进制数据
bool is_dense # 是否包含无效点(NaN)
这里有个坑,我刚开始用的时候经常搞混:height 和 width 的含义。对于无序点云(大多数单线或机械式雷达),height=1,width 就是点的总数。但对于某些固态雷达,数据可能是按行排列的,这时候 height 就代表行数。
我曾经在解析某款国产雷达的数据时,默认把 height 当成了1,结果点云显示出来全是乱的。后来查文档才发现,这款雷达的数据是按16行排列的。所以,拿到新雷达第一步,先看 height 和 width 的值。
点云数据量通常很大。举个例子,一个32线、10Hz的雷达,每秒产生的点数大约是:
| 参数 | 数值 |
|---|---|
| 线数 | 32 |
| 每线点数 | ~2000 |
| 帧率 | 10 Hz |
| 每秒点数 | 32 × 2000 × 10 = 640,000 |
| 每秒数据量 | ~12 MB(每个点16字节) |
嗯,这里要注意,如果你的机器人主控性能一般,处理这么大数据量可能会卡顿。我建议在发布端就做降采样,或者用 VoxelGrid 滤波器减少点数。
ROS2驱动配置
ROS2 的驱动配置,说白了就是让激光雷达的数据能正确发布到 ROS2 的 topic 上。不同品牌的雷达驱动略有不同,但核心步骤是相通的。
以我常用的思岚 A1 为例,驱动包是 sllidar_ros2。安装和配置步骤如下:
- 安装驱动:
cd ~/ros2_ws/src
git clone https://github.com/Slamtec/sllidar_ros2.git
cd ..
colcon build --packages-select sllidar_ros2
source install/setup.bash
- 配置串口权限:
sudo chmod 666 /dev/ttyUSB0
这一步我经常忘。每次插上雷达发现没数据,第一反应就是检查串口权限。你可以把用户加到 dialout 组,一劳永逸:
sudo usermod -a -G dialout $USER
- 启动驱动节点:
ros2 launch sllidar_ros2 sllidar_a1_launch.py
启动后,你可以用 ros2 topic list 查看是否出现了 /scan 话题。再用 ros2 topic echo /scan 看看有没有数据流。
一个小技巧:如果雷达数据断断续续,多半是 USB 供电不足。我遇到过好几次,换个 USB 口或者用带外接电源的 USB HUB 就能解决。
对于其他品牌的雷达,比如 Velodyne、Ouster,驱动配置思路类似,只是参数文件里需要设置 IP 地址、端口号等网络参数。这里就不一一展开了。
使用rviz2可视化点云
数据有了,怎么看?rviz2 就是我们的眼睛。
启动 rviz2 很简单:
ros2 run rviz2 rviz2
然后在界面里:
- 点击左下角的 "Add" 按钮
- 选择 "By topic" 标签
- 找到
/scan话题,选择 "LaserScan" 显示类型
如果你用的是 3D 激光雷达,话题通常是 /points 或 /velodyne_points,显示类型选择 "PointCloud2"。
这里有个关键设置:Fixed Frame。默认是 map,但如果你没有启动 map 坐标系,需要改成 laser_frame 或 base_link。否则你会看到点云在屏幕上乱飞,或者根本显示不出来。
我曾经在调试时花了半小时找问题,点云就是不出来。后来发现 Fixed Frame 设成了 map,而我的雷达数据是在 laser_frame 坐标系下发布的。坐标系不匹配,rviz2 就没法正确显示。
为了让可视化更清晰,我习惯调整这几个参数:
- Size (m):点的大小,默认 0.01,室内场景可以调到 0.02 或 0.03
- Style:选择 "Points" 或 "Boxes",别选 "Flat Squares",太吃性能
- Decay Time:设为 0.5 秒,可以看到历史轨迹,方便判断动态物体
下面这张图展示了激光雷达数据从采集到可视化的完整流程:
看到这个流程,你应该明白了:激光雷达的数据从硬件出来,经过驱动节点转换成 ROS2 消息,发布到话题上,最后 rviz2 订阅并显示出来。每一步都可能出问题,但只要你按照这个链路去排查,总能找到原因。
好了,这一章的内容就到这里。激光雷达的原理和配置是后续所有传感器融合工作的基础,建议你亲手操作一遍,把雷达跑起来,在 rviz2 里看到点云的那一刻,你会觉得一切都值得。