3 · 传感器驱动与数据读取

写ROS节点驱动激光雷达、IMU、相机,再把数据流可视化出来——这是SLAM流水线的“第一公里”。我见过太多同学在算法上花大把时间,结果一跑数据发现时间戳是乱的,或者点云畸变到没法看。说白了,驱动写不好,后面全是白搭。

ROS 驱动节点 激光雷达 driver sensor_msgs/LaserScan IMU 驱动 sensor_msgs/Imu 相机驱动 sensor_msgs/Image rviz / rqt_image_view 可视化 话题发布

3.1 激光雷达驱动:从串口到点云

我早期做机器人时,用的还是单线雷达,串口数据一包一包读,校验和算错一个位,整个点云就飞了。现在ROS里大部分激光雷达都有现成驱动包,比如 rplidar_ros、urg_node。但核心逻辑你得懂:

  • 串口/网络配置:波特率、设备权限(chmod 666 /dev/ttyUSB0)
  • 数据帧解析:起始位、角度、距离、强度
  • 发布话题:sensor_msgs/LaserScan 或 PointCloud2

我个人习惯:写一个launch文件,把串口参数和frame_id都暴露出来。这样换雷达型号时,改个参数就行,不用动代码。

<launch>
  <node name="lidar_driver" pkg="rplidar_ros" type="rplidarNode" output="screen">
    <param name="serial_port" value="/dev/ttyUSB0"/>
    <param name="frame_id" value="laser_frame"/>
    <param name="angle_compensate" value="true"/>
  </node>
</launch>

3.2 IMU驱动:加速度+角速度的原始味道

IMU数据看着简单,但坑特别多。我遇到过最离谱的一次——IMU的坐标系和机器人坐标系差了90度,结果融合出来的姿态直接翻车。驱动节点里至少要做这几件事:

  1. 读取原始寄存器或串口数据
  2. 转换到ROS坐标系(ENU或NED,务必和你的其他传感器统一)
  3. 填充协方差矩阵(很多人直接填0,后面优化会出问题)

💡 避坑指南:我曾经在IMU驱动里忘了设置orientation_covariance,结果EKF一直警告协方差奇异。后来老老实实根据手册填了噪声密度,世界清净了。

# Python 示例:发布IMU消息
import rospy
from sensor_msgs.msg import Imu

pub = rospy.Publisher('/imu/data_raw', Imu, queue_size=10)
imu_msg = Imu()
imu_msg.header.frame_id = 'imu_link'
imu_msg.linear_acceleration.x = ax
imu_msg.angular_velocity.z = wz
# 别忘了时间戳
imu_msg.header.stamp = rospy.Time.now()
pub.publish(imu_msg)

3.3 相机驱动:图像与相机信息

相机驱动相对成熟,usb_cam、uvc_camera 或者 realsense2_camera 都能直接出图。但有个细节——相机内参必须通过 CameraInfo 话题发布,否则后面的图像矫正、V-SLAM全得崩。

话题消息类型说明
/camera/image_rawsensor_msgs/Image原始图像数据
/camera/camera_infosensor_msgs/CameraInfo内参矩阵、畸变系数

你想想看,如果内参给错了,后面特征点投影到3D时就会歪掉。我一般会在驱动里加一个camera_info_url参数,从YAML文件加载内参,这样标定一次,到处使用。

3.4 可视化:让数据“说话”

驱动写完了,怎么知道数据对不对?别只靠打印。用 rviz 看激光点云和图像,用 rqt_image_view 看实时画面。我习惯在rviz里同时显示TF树和传感器数据,一眼就能看出frame_id有没有配错。

⚠️ 注意:可视化节点会占用不少CPU。如果你在嵌入式平台(比如Jetson Nano)上调试,建议降低点云显示频率,或者只显示降采样后的数据。我曾经在Nano上同时开3个可视化窗口,直接把GUI卡死……

# 启动可视化(终端)
rosrun rviz rviz -d my_slam.rviz
# 或者直接看图像
rosrun rqt_image_view rqt_image_view /camera/image_raw

3.5 驱动节点的时间同步陷阱

三个传感器各自发布话题,但时间戳可能来自不同时钟源。激光雷达用电脑时间,IMU用板载时钟,相机用硬件触发——这就乱了。我建议在驱动节点里统一使用 ros::Time::now() 打时间戳,或者用 message_filters 做近似同步。后面第4章会细讲,但驱动阶段就要有这个意识。

一句话总结:驱动节点是SLAM的“地基”。地基歪了,后面算法再牛也救不回来。写驱动时多花10分钟检查坐标系、时间戳、协方差,后面能省10小时调bug的时间。