那些让我抓狂的夜晚
说实话,第一次把Sick、HOKUYO或者RPLIDAR这类激光雷达连上Ubuntu然后接上ROS的时候,几乎每个人都会遇到几个让人想摔键盘的问题。我记得有个搞无人车的团队,为了一个/scan数据出不来的问题,整整排查了三天,最后发现竟然是USB 3.0的驱动兼容性问题。今天我把这些年踩过的坑、查过的资料、写过的脚本,全部揉碎了讲给你听。不管你是刚入门的学生,还是正在调试产线的工程师,这篇文章应该能帮你省下不少头发。
第一步:硬件连接的物理层排查
在打开任何终端、安装任何驱动之前,请先做一个动作——看指示灯。
激光雷达的USB接口通常分为两种:一种是纯供电型(比如某些老款RPLIDAR A1),另一种是供电+通信型(大部分SICK、HOKUYO、禾赛、速腾的产品)。当你把USB线插上的时候,雷达内部的小风扇应该会转起来,如果是带激光头的,激光应该会开始扫。如果风扇不转,说明供电不足。
这里有一个很多文档里不提的细节:USB端口的供电能力。
我见过太多人把激光雷达插在笔记本电脑的USB 2.0接口上,然后抱怨数据丢帧。笔记本电脑的USB 2.0端口供电通常只有450mA,而多数工业级激光雷达启动瞬间电流可能达到800mA甚至更高。解决方案很简单,要么用带外接电源的USB Hub,要么直接插到主板后置的USB 3.0接口(那些蓝色的接口)。
另外,USB线的质量也至关重要。市面上那种几块钱的延长线,内阻大、屏蔽差,会导致串口通信出现乱码。我推荐直接用雷达原装线,或者买那种带磁环的屏蔽线。
第二步:Linux USB设备识别
插入雷达后,第一步不是装ROS包,而是确认Linux内核是否识别到了这个设备。打开终端,运行:
lsusb
你会看到类似这样的输出:
Bus 002 Device 003: ID 067b:2303 Prolific Technology, Inc. PL2303 Serial Port
Bus 001 Device 005: ID 1234:5678 Acme Laser Radar Co.
第二行那个Acme Laser Radar Co.就是你的雷达。记录下的ID(比如1234:5678),后面udev规则要用到。
如果lsusb里没看到设备,但你在Windows上能识别,那大概率是Linux内核驱动没加载。运行:
dmesg | tail -n 20
看看最后20行有没有报错信息,比如unable to enumerate USB device或者device descriptor read/64, error -71。这类错误通常是供电问题或线缆问题。
如果看到了设备但名字不对(比如显示成CDC ACU之类的通用名称),也没关系,我们继续往下看权限配置。
第三步:串口权限配置(udev规则)
这是ROS开发中最经典、也最容易被忽视的一个环节。Linux默认把串口设备(如/dev/ttyUSB0)的权限设为root,普通用户没有读写权限。如果你直接运行roslaunch,十有八九会报Permission denied。
解决方式是创建udev规则。假设你的雷达在lsusb里显示为Bus 001 Device 005: ID 1234:5678 Acme Laser Radar Co.,那么:
sudo nano /etc/udev/rules.d/99-joey-radar.rules
写入以下内容(请根据实际VID和PID修改):
SUBSYSTEM=="usb", ATTR{idVendor}=="1234", ATTR{idProduct}=="5678", MODE="0666", GROUP="dialout"
保存后,重新插拔雷达,或者运行:
sudo udevadm control --reload-rules
sudo udevadm trigger
验证权限是否生效:
ls -l /dev/ttyUSB0
你应该看到类似这样的输出:
crw-rw-rw- 1 root dialout 188, 0 ... /dev/ttyUSB0
关键点是rw-rw-rw-(即666权限)和dialout组。如果你的用户不在dialout组,还需要执行:
sudo usermod -a -G dialout $USER
然后注销并重新登录(注意:不是重启终端,是注销账号再登录,否则组变更不会生效)。
第四步:串口参数配置
有些雷达(比如SICK LMS系列)使用标准串口通信,波特率、数据位、停止位需要手动配置。大多数现代雷达通过USB转串口芯片(如FTDI、CP2102、PL2303)连接,Linux内核会自动配置正确的参数,但你最好确认一下。
查看当前串口参数:
stty -F /dev/ttyUSB0 -a
输出中关注这几项:
baud:波特率,常见的是115200、230400、460800cs8:8位数据位cstopb 1:1位停止位parenb:是否有校验位(通常不应有)
如果你的雷达说明书上写的波特率是250000,而系统显示115200,就需要手动修改:
sudo stty -F /dev/ttyUSB0 250000 cs8 -cstopb -parenb
但这只是临时生效,重启后失效。要永久生效,可以写在.bashrc里,或者写一个启动脚本。
第五步:ROS驱动包的选择与安装
这一步因雷达型号而异。市面上主流雷达的ROS驱动大体分三类:官方驱动、社区驱动、通用串口驱动。
5.1 官方驱动
如果你用的是HOKUYO UTM系列,官方包是urg_node:
sudo apt-get install ros-$ROS_DISTRO-urg-node
如果是SICK,官网提供的是sick_tim或sick_ldss包,需要先从官网下载源码编译。
5.2 社区驱动
RPLIDAR是开源社区支持最好的激光雷达之一。安装非常简单:
# 进入ROS工作空间
cd ~/catkin_ws/src
# 克隆驱动
git clone https://github.com/Slamtec/rplidar_ros.git
# 编译
cd ..
catkin_make
source devel/setup.bash
5.3 通用串口驱动
如果你的雷达比较冷门,没有现成的ROS包,可以考虑用serial包自己写一个节点。先安装:
sudo apt-get install ros-$ROS_DISTRO-serial
然后编写一个简单的C++节点来读取串口数据并发布为sensor_msgs/LaserScan消息。
第六步:launch文件配置
驱动装好后,关键在于launch文件怎么写。我们以RPLIDAR为例,常见的rplidar.launch内容如下:
<launch>
<node name="rplidarNode" pkg="rplidar_ros" type="rplidarNode" output="screen">
<param name="serial_port" type="string" value="/dev/ttyUSB0"/>
<param name="serial_baudrate" type="int" value="115200"/>
<param name="frame_id" type="string" value="laser"/>
<param name="inverted" type="bool" value="false"/>
<param name="angle_compensate" type="bool" value="true"/>
</node>
</launch>
参数解释:
serial_port:串口设备路径,根据上一步ls -l /dev/ttyUSB0确认serial_baudrate:波特率,必须与雷达说明书一致frame_id:雷达在TF树中的帧名称,通常是laser或base_linkangle_compensate:角度补偿,开启后可以消除因雷达旋转速度不均匀导致的测量误差
如果你用的是其他雷达,launch文件结构类似,只是参数名可能不同。建议先查看驱动包README里的说明。
第七步:启动节点并查看数据
运行launch文件:
roslaunch rplidar_ros rplidar.launch
如果驱动正常,你应该看到类似这样的输出:
[ INFO] [1690000000.000000000]: RPLIDAR running on ROS package rplidar_ros
[ INFO] [1690000000.001000000]: SDK Version: 1.5.8
[ INFO] [1690000000.002000000]: FIRMWARE RELEASE: 1.17
[ INFO] [1690000000.003000000]: SERIAL PORT BAUDRATE: 115200
[ INFO] [1690000000.100000000]: Laser not starting, trying reconnect...
[ INFO] [1690000000.200000000]: Starting...
[ INFO] [1690000000.500000000]: Scan published, rate: 10.0 Hz
如果看到Scan published,说明驱动已经在工作了。
第八步:数据验证
这是最关键的一步——确认/scan话题真的有数据。
8.1 使用rosrun查看话题
rostopic echo /scan
你应该能看到类似这样的输出:
header:
seq: 123
stamp:
secs: 1690000000
nsecs: 123000000
frame_id: laser
angle_min: -3.14159274101
angle_max: 3.14159274101
angle_increment: 0.00436332344
time_increment: 0.0
scan_time: 0.1
range_min: 0.12
range_max: 8.0
ranges: [1.23, 1.25, 1.27, ..., 1500 more elements...]
intensities: [120, 125, 130, ..., 1500 more elements...]
ranges数组里的每个值代表一个距离读数(单位通常是米),intensities代表反射强度。如果数组全是inf或0,说明雷达没收到有效数据。
8.2 使用rviz可视化
另一个更直观的方法是打开RViz:
rosrun rviz rviz
在RViz里:
- 点击
Add按钮 - 选择
By topic标签 - 找到
/scan话题并添加 - 在左侧
Global Options里,将Fixed Frame设为laser(或你在launch文件里设置的frame_id)
如果一切正常,你应该能看到一条由点组成的弧线,代表雷达扫描的环境。如果点云是断断续续的,或者完全空白,就需要检查驱动输出日志和串口参数。
8.3 检查TF变换
有时候数据其实是有输出的,但你在RViz里看不到,原因是TF树没建好。运行:
rosrun tf tf_monitor
查看laser帧是否被广播。如果没有,可能需要写一个简单的TF broadcaster节点,或者在launch文件里加上static_transform_publisher。
第九步:常见问题排查指南
即使按照上面步骤操作,还是可能遇到问题。以下是我整理的几个高频问题及解法。
问题一:权限错误Permission denied
现象:运行launch文件时报错cannot open port /dev/ttyUSB0: Permission denied
原因:udev规则没生效,或者用户不在dialout组
解决:
# 1. 检查udev规则
cat /etc/udev/rules.d/99-joey-radar.rules
# 2. 重新加载规则
sudo udevadm control --reload-rules
sudo udevadm trigger
# 3. 检查用户组
groups $USER
# 4. 添加用户到dialout组(如果不在)
sudo usermod -a -G dialout $USER
# 5. 注销重新登录
问题二:数据乱码或丢帧
现象:rostopic echo /scan能看到数据,但ranges里大量inf,或者RViz里的点云断断续续
原因:串口波特率不匹配、USB带宽不足、或雷达供电不稳
解决:
- 确认波特率与雷达说明书一致
- 换一个USB端口,优先使用USB 2.0端口(有些雷达在USB 3.0上不稳定)
- 使用带外接电源的USB Hub
- 检查系统负载,运行
top查看CPU是否过高
问题三:雷达能识别但无法扫描
现象:串口能打开,但没有Scan published日志
原因:雷达进入错误状态,需要重启或重置
解决:
# 1. 杀掉可能卡住的节点
pkill -f rplidarNode
# 2. 重新插拔雷达
# 3. 重新启动launch
roslaunch rplidar_ros rplidar.launch
如果还是不行,尝试通过串口发送复位命令(具体命令取决于雷达型号,可查看驱动源码)。
问题四:帧ID错误
现象:RViz里显示No transform from [laser] to [base_link]
解决:在launch文件里确认frame_id参数,并确保TF广播正确。如果是真实机器人,通常需要在机器人描述文件(URDF)里定义雷达的固定位置。
第十步:性能优化建议
当雷达工作稳定后,你可能还会关心性能问题。以下是几个实用技巧。
10.1 提高扫描频率
默认情况下,很多雷达的扫描频率是5Hz或10Hz。如果需要更高频率(比如20Hz),可以在launch文件里调整参数:
<param name="scan_time" type="double" value="0.05"/>
但要注意,频率越高,数据量越大,对CPU和网络带宽的压力也越大。
10.2 降低数据量
如果雷达的扫描范围很大(比如360度,1800个点),但你的应用只需要局部区域(比如前方120度),可以通过过滤来减少数据量。在launch文件里添加:
<param name="angle_min" type="double" value="-1.047"/> <!-- -60度 -->
<param name="angle_max" type="double" value="1.047"/> <!-- 60度 -->
10.3 多雷达同步
如果你需要同时使用多个雷达(比如前后各一个),确保它们的frame_id不同,并且serial_port参数指向不同的USB设备。可以使用usb_modeswitch或手动指定串口路径来避免冲突。
结语:调试是一种心态
写这篇文章的时候,我回想起了自己第一次调试激光雷达的那个下午。从上午9点干到晚上11点,换了三根USB线、重装了两次ROS、改了七次波特率,最后发现是udev规则里的idVendor写错了十六进制位数。那种抓狂又最终解决的感觉,我至今记得很清楚。
激光雷达的ROS接入其实并不复杂,难点在于细节。权限、波特率、帧ID、TF树,每一个环节都可能成为绊脚石。但只要你按部就班地排查,每个问题都有明确的解法。
希望这篇文章能帮你少走弯路。如果还有问题,欢迎在评论区留言,我会尽力帮忙。毕竟,帮后人省点头发,也是我的一点小心意。