第4章:传感器驱动与数据采集
好,咱们进入实战环节了。这一章我带你搞定三个最常用的传感器:激光雷达、IMU和摄像头。说白了,这就是机器人的「眼睛」和「平衡感」。我在多个项目里都跟它们打过交道,踩过的坑不少,今天一并告诉你。
4.1 激光雷达(RPLIDAR)驱动配置与数据读取
先聊激光雷达。RPLIDAR是思岚科技的明星产品,A1、A2、S1我都用过。我个人习惯用A2,性价比高,室内建图完全够用。
4.1.1 硬件连接与权限设置
拿到雷达后,先接USB。注意,RPLIDAR是串口通信,Linux下需要给权限。我刚开始做的时候,直接插上就跑,结果死活读不到数据。后来才发现是权限问题。
# 查看设备
ls -l /dev/ttyUSB*
# 临时授权
sudo chmod 666 /dev/ttyUSB0
# 永久授权(推荐)
sudo usermod -a -G dialout $USER
# 然后注销重新登录
4.1.2 安装RPLIDAR ROS驱动
官方驱动在GitHub上,直接拉下来编译就行。
cd ~/catkin_ws/src
git clone https://github.com/Slamtec/rplidar_ros.git
cd ..
catkin_make
嗯,这里要注意。如果你用的是ROS Noetic,记得检查一下依赖。我遇到过编译报错,原因是缺少serial库。
sudo apt-get install ros-noetic-serial
4.1.3 启动雷达并读取数据
启动文件很简单,但参数要调对。我一般这样写launch文件:
<launch>
<node name="rplidar_node" pkg="rplidar_ros" type="rplidarNode" output="screen">
<param name="serial_port" value="/dev/ttyUSB0"/>
<param name="serial_baudrate" value="115200"/>
<param name="frame_id" value="laser"/>
<param name="inverted" value="false"/>
<param name="angle_compensate" value="true"/>
</node>
</launch>
启动后,用rostopic看数据:
roslaunch rplidar_ros rplidar.launch
rostopic echo /scan
你会看到一堆角度和距离数据。为什么会有角度补偿?因为雷达旋转时,电机转速会有微小波动。补偿后数据更平滑。
4.2 IMU(MPU6050)驱动配置与数据读取
IMU这东西,说白了就是加速度计+陀螺仪。MPU6050是经典款,便宜又好用。我在做平衡小车时用过它,当时被零漂问题折磨得不轻。
4.2.1 I2C连接与检测
MPU6050走I2C协议。连接很简单:VCC接3.3V,GND接地,SCL和SDA分别接I2C时钟和数据线。在树莓派或Jetson上,通常是引脚3和5。
# 检测I2C设备
sudo i2cdetect -y 1
如果看到0x68,说明连接成功。我遇到过检测不到的情况,十有八九是接线问题。检查一下SCL和SDA有没有接反。
4.2.2 安装MPU6050 ROS驱动
推荐用imu_calib和mpu6050_driver。安装命令:
sudo apt-get install ros-noetic-imu-tools
cd ~/catkin_ws/src
git clone https://github.com/ros-drivers/mpu6050_driver.git
cd ..
catkin_make
4.2.3 数据读取与校准
启动节点后,数据会发布在/imu/data_raw话题上。但原始数据有零漂,必须校准。
roslaunch mpu6050_driver mpu6050.launch
rostopic echo /imu/data_raw
你会看到这样的数据:
orientation:
x: 0.0
y: 0.0
z: 0.0
w: 0.0
angular_velocity:
x: 0.02
y: -0.01
z: 0.03
linear_acceleration:
x: 0.05
y: 0.02
z: 9.81
注意看,静止时角速度不为零。这就是零漂。我曾经用这个数据直接做积分,结果角度越偏越大。后来才学会用互补滤波或卡尔曼滤波。
4.3 摄像头(USB_Cam)驱动配置与图像采集
摄像头这块,我建议用USB摄像头起步。便宜、通用、调试方便。我在做视觉导航时,用的就是普通的罗技C270。
4.3.1 检查摄像头设备
插上摄像头后,先看看系统认不认:
ls /dev/video*
v4l2-ctl --list-devices
如果看到video0,说明驱动加载成功。我遇到过插上没反应的情况,通常是USB口供电不足。换个口试试,或者用带供电的USB Hub。
4.3.2 安装USB_Cam驱动
ROS官方有usb_cam包,直接装:
sudo apt-get install ros-noetic-usb-cam
或者从源码编译:
cd ~/catkin_ws/src
git clone https://github.com/ros-drivers/usb_cam.git
cd ..
catkin_make
4.3.3 配置与启动
usb_cam的launch文件可以自定义参数。我一般这样配:
<launch>
<node name="usb_cam" pkg="usb_cam" type="usb_cam_node" output="screen">
<param name="video_device" value="/dev/video0"/>
<param name="image_width" value="640"/>
<param name="image_height" value="480"/>
<param name="pixel_format" value="yuyv"/>
<param name="camera_frame_id" value="usb_cam"/>
<param name="io_method" value="mmap"/>
</node>
</launch>
启动后,图像数据在/usb_cam/image_raw话题上。用image_view看:
rosrun image_view image_view image:=/usb_cam/image_raw
4.3.4 图像采集与保存
需要保存图像时,可以用image_saver:
rosrun image_view image_saver image:=/usb_cam/image_raw _filename_format:=/home/user/images/frame%04d.jpg _save_all_image:=true
或者自己写个节点订阅话题。我习惯用OpenCV处理:
#include <ros/ros.h>
#include <sensor_msgs/Image.h>
#include <cv_bridge/cv_bridge.h>
void imageCallback(const sensor_msgs::Image::ConstPtr& msg)
{
cv::Mat frame = cv_bridge::toCvCopy(msg, "bgr8")->image;
cv::imshow("Camera", frame);
cv::waitKey(1);
}
int main(int argc, char** argv)
{
ros::init(argc, argv, "image_listener");
ros::NodeHandle nh;
ros::Subscriber sub = nh.subscribe("/usb_cam/image_raw", 10, imageCallback);
ros::spin();
return 0;
}
4.4 多传感器时间同步
最后说个关键问题。三个传感器各自发布数据,时间戳可能对不上。我做融合时,发现激光雷达和摄像头的时间差有50ms,导致建图出现重影。
解决办法是用message_filters做时间同步:
#include <message_filters/subscriber.h>
#include <message_filters/time_synchronizer.h>
#include <sensor_msgs/LaserScan.h>
#include <sensor_msgs/Image.h>
message_filters::Subscriber<sensor_msgs::LaserScan> laser_sub(nh, "/scan", 10);
message_filters::Subscriber<sensor_msgs::Image> image_sub(nh, "/usb_cam/image_raw", 10);
message_filters::TimeSynchronizer<sensor_msgs::LaserScan, sensor_msgs::Image> sync(laser_sub, image_sub, 10);
sync.registerCallback(boost::bind(&callback, _1, _2));
好了,这一章的内容就这些。三种传感器的驱动配置和数据读取,你都应该能上手了。下一章我们聊聊数据预处理,这可是融合前的关键一步。