4. 传感器数据采集与可视化

各位同学,欢迎来到第四章。

说实话,搞自动驾驶感知,最头疼的往往不是算法本身,而是数据从哪来、能不能看得到。你想想看,算法写得再漂亮,传感器驱动没配好,数据流断在半路上,那一切都是白搭。

这一章,我们就来搞定这件事。我会带你把相机、激光雷达、IMU这三个核心传感器的ROS2驱动跑起来,然后用Rviz2把数据可视化。嗯,这是所有后续感知工作的基础。

4.1 传感器驱动配置:从硬件到ROS2话题

我个人习惯,先把驱动框架理清楚,再动手配参数。ROS2里传感器驱动的本质,就是把硬件数据包解析成ROS2的标准消息类型,然后发布到对应的话题上。

下面这张图,是我自己总结的传感器数据流,你看一眼就明白了。

传感器数据流与ROS2驱动架构 硬件设备 相机 / 激光雷达 / IMU ROS2驱动节点 解析数据 → 生成消息 ROS2话题 /camera/image_raw /scan /imu/data Rviz2可视化 订阅话题 → 渲染显示 订阅/发布 标准消息类型 sensor_msgs/Image sensor_msgs/LaserScan sensor_msgs/Imu

说白了,驱动配置就是三步:找到硬件、启动驱动、看到话题。我刚开始做的时候,经常卡在第一步——硬件权限没给够,驱动死活起不来。

4.2 相机驱动与可视化

相机是感知系统最重要的传感器,没有之一。ROS2里最常用的相机驱动是 usb_cam 和 v4l2_camera。

我个人推荐用 v4l2_camera,因为它对USB相机的兼容性更好。安装很简单:

sudo apt install ros-humble-v4l2-camera

启动驱动,只需要一行命令:

ros2 run v4l2_camera v4l2_camera_node --ros-args -p video_device:="/dev/video0"

嗯,这里要注意。很多同学上来就报错,说找不到设备。为什么?因为默认的 /dev/video0 可能被笔记本内置摄像头占用了。你插的USB摄像头,往往是 /dev/video2 或 /dev/video4。

我的小技巧: 用 ls /dev/video* 查看所有摄像头设备。如果拿不准哪个是外接的,拔掉再插一次,看哪个设备号消失了,那就是它。

驱动启动后,用 ros2 topic list 确认一下,应该能看到 /image_raw 话题。接下来打开Rviz2:

ros2 run rviz2 rviz2

在Rviz2里,点击左下角的「Add」按钮,选择「By topic」,找到 /image_raw,添加「Image」显示类型。瞬间,你就能看到摄像头画面了。

关键参数调整:
  • image_width 和 image_height:分辨率,我一般设640x480,平衡画质和性能
  • framerate:帧率,30fps够用,太高了CPU扛不住
  • pixel_format:像素格式,默认yuyv,如果画面偏色试试mjpeg

我曾经在一个项目里,相机画面全是绿色的噪点,折腾了半天。后来发现是USB线太长,信号衰减了。换了一根短线,问题解决。硬件问题有时候比软件更坑。

4.3 激光雷达驱动与可视化

激光雷达的驱动,不同厂家差别很大。但好消息是,大部分都遵循ROS2的标准接口。我这里以最常见的单线激光雷达为例,比如思岚A1、A2系列。

安装驱动:

sudo apt install ros-humble-slam-toolbox
# 或者从源码编译 rplidar_ros

启动命令:

ros2 launch rplidar_ros rplidar.launch.py

启动后,你会看到 /scan 话题。这是 sensor_msgs/LaserScan 类型的消息,包含距离、角度、强度等信息。

在Rviz2里添加「LaserScan」显示类型,选择 /scan 话题。你会看到一圈点云,这就是激光雷达扫描到的环境轮廓。

避坑指南: 我曾经遇到过激光雷达数据在Rviz2里显示为一条直线,而不是一圈。原因是雷达的串口波特率设置错了。检查一下你的雷达型号对应的波特率,A1是115200,A2是256000。别搞混了。

另外,激光雷达的坐标系也很重要。默认情况下,雷达的frame_id是 laser_frame。如果你在Rviz2里看不到点云,先检查一下「Global Options」里的「Fixed Frame」是不是设成了 laser_frame 或 map。

4.4 IMU驱动与可视化

IMU(惯性测量单元)提供加速度和角速度数据。在感知系统中,IMU主要用于里程计推算和姿态估计。

ROS2里常用的IMU驱动是 imu_tools 和 razor_imu_9dof。我这里以MPU6050为例,通过I2C接口连接。

安装驱动:

sudo apt install ros-humble-imu-tools

启动节点:

ros2 run imu_tools imu_mpu6050_node --ros-args -p port:="/dev/i2c-1"

IMU的数据话题是 /imu/data,消息类型是 sensor_msgs/Imu。这个类型包含三个核心字段:

字段 含义 单位
orientation 四元数表示的姿态 无单位
angular_velocity 角速度 rad/s
linear_acceleration 线加速度 m/s²

在Rviz2里,IMU数据可以用两种方式可视化:

  • 「Imu」显示类型:显示一个三维箭头,表示当前姿态
  • 「Axes」显示类型:显示坐标轴,更直观

我个人习惯用「Axes」,因为一眼就能看出IMU的朝向对不对。如果IMU平放时Z轴朝上,说明安装方向正确。

调试技巧: 把IMU放在桌面上静止,看Rviz2里的箭头是否稳定。如果箭头乱跳,说明数据噪声太大,需要加滤波。我一般用互补滤波或卡尔曼滤波,效果都不错。

4.5 多传感器时间同步

搞定了单个传感器,接下来就是多传感器联调。你想想看,相机、激光雷达、IMU各自有各自的时间戳,如果不做同步,融合出来的数据就是错位的。

ROS2里提供了 message_filters 包来做时间同步。核心思路是:把多个话题的消息按照时间戳对齐,然后一起处理。

示例代码片段:

import message_filters
from sensor_msgs.msg import Image, LaserScan, Imu

# 创建订阅器
image_sub = message_filters.Subscriber(node, Image, '/image_raw')
scan_sub = message_filters.Subscriber(node, LaserScan, '/scan')
imu_sub = message_filters.Subscriber(node, Imu, '/imu/data')

# 时间同步器,容忍50ms的时间差
sync = message_filters.ApproximateTimeSynchronizer(
    [image_sub, scan_sub, imu_sub], 
    queue_size=10, 
    slop=0.05
)
sync.registerCallback(callback)

这里 slop=0.05 表示允许50毫秒的时间误差。我一般设这个值,太大太小都不好。太大会把不同时刻的数据凑在一起,太小又容易丢数据。

我的经验: 时间同步是联调中最容易出问题的地方。我曾经在一个项目中,相机和激光雷达的时间戳差了200多毫秒,导致融合后的点云投影到图像上全是错位的。后来发现是相机驱动里的时间戳用的是系统时间,而激光雷达用的是硬件时间。统一改成系统时间后,问题解决。

4.6 Rviz2配置保存与复用

每次打开Rviz2都要重新添加显示类型,太麻烦了。我建议你把配置保存下来。

操作很简单:

  1. 在Rviz2里配置好所有显示项(相机、激光雷达、IMU)
  2. 点击左上角的「File」→「Save Config As」
  3. 保存为 sensor_demo.rviz 文件

下次启动时,直接加载配置:

ros2 run rviz2 rviz2 -d sensor_demo.rviz

嗯,这个小习惯能帮你省下不少时间。我每次做新项目,都会先配好一套标准的传感器可视化配置,然后复用。

好了,这一章的内容就到这里。传感器驱动配置和可视化,是感知系统的基础设施。基础打牢了,后面的算法才能跑得稳。记住,数据能看得到,问题才能找得到。

可可精品资料库