前阵子帮朋友搭了一套移动测量设备,核心就是Livox MID-360配海康工业相机,最后实现的效果是激光雷达实时扫描建图的同时,点云本身带着相机采集的真实颜色,看起来比纯几何点云直观太多了。他发了个朋友圈,评论区一堆人问怎么搞的,我觉得干脆把这套完整流程整理出来,从硬件选型、驱动配置、联合标定到实时彩色点云实现,一次说清楚。
整个过程我踩了不少坑,尤其是海康相机驱动在ROS里的那些历史遗留问题,以及Livox的标定工具对时间同步的苛刻要求,网上资料零零散散,真正能一条龙跑通的教程很少。这篇文章就按照我实际操作的顺序写,把每个环节的坑和注意事项都标出来,新手照着做也能跑通,有经验的朋友可以重点看标定和实时取色那两节,那里面的细节是我实测后总结出来的。
在做这套方案之前,我先想清楚了一件事:为什么选Livox而不是传统机械式雷达,为什么相机用海康而不用RGB-D。机械式雷达精度也不算差,但长期运行有磨损,震动环境下面数据质量衰减很快。Livox MID-360是非重复扫描的固态激光雷达,没有机械旋转电机,靠棱镜折射激光束,扫描pattern是花瓣状的,随着时间累积点云密度会持续增加,这对建图来说非常有利。海康相机选的是工业GigE接口的定焦相机,不带深度,只提供高质量RGB图,好处是曝光可控、硬件触发稳定、驱动成熟,和Livox配合做颜色融合很合适。
整篇文章核心围绕三条主线:第一是ROS环境怎么搭,第二是激光雷达和相机的内外参怎么标定,第三是点云着色的实时管线怎么实现。这三条线缺一不可,任何一个环节出了问题,最后出来的彩色点云都是花的、重影的、或者干脆颜色错位。我会一条条讲清楚。
1. 方案选型与整体架构
先说硬件清单。Livox MID-360,这是整个系统里最重要的传感器,探测范围40米左右,视场角360度水平,垂直方向是-7度到52度,属于宽垂直视场的固态雷达,用在机器人上非常合适。相机我用的是海康MV-CA050-10GC,500万像素GigE接口,配一个6mm定焦镜头,水平视场角大概60度,可以完整覆盖机器人前方主要区域。工控机选的是Intel NUC 11,i7处理器,32G内存,这个配置跑FAST-LIO再加上实时点云着色,CPU占用率大概在65%左右,内存吃了差不多6个G,勉强够用。如果预算充足,建议上i9或者带独立显卡的迷你主机,后续加目标检测什么的会有余量。
整个系统的数据流是这样的:Livox MID-360通过网线直连工控机,跑livox_ros_driver2驱动,发布原始点云话题/livox/lidar;海康相机通过另一个千兆网口连工控机,跑MVS SDK采集图像,通过ROS节点发布为sensor_msgs/Image;然后一个SLAM节点订阅雷达点云和IMU数据,实时输出雷达坐标系下的位姿和局部地图;最后颜色映射节点订阅局部地图和相机图像,利用标定好的外参矩阵把每个点投影到图像平面,取对应像素的RGB,回填到点云里,发布实时彩色点云。
选择这种分离式架构而不是用一体式设备,原因很简单:模块化程度高,传感器坏了单独换,成本也不至于一次性投入太多。而且Livox和Hikvision在各自领域都是非常主流的品牌,遇到问题社区资料多,不会卡死在某个私有坑里。
1.1 为什么不用RGB-D相机或者直接买一体化方案
有人可能会问,直接用RealSense、Azure Kinect这类RGB-D相机不是更省事吗?深度和颜色天然对齐,不用标定,插上就能用。这个说法在室内短距离场景成立,但放到室外或者大范围场景就露馅了。RGB-D的有效深度范围一般只有3到6米,超过10米基本就是噪声,而且强光环境下红外结构光会被环境光淹没,深度图直接花掉。Livox MID-360在阳光下依然能稳定工作,探测距离是RGB-D的好几倍,这是根本性的差别。
也有一些厂商直接卖带相机的激光雷达一体机,比如Livox自己的Mid-360加相机的方案,或者某些安防监控类的融合传感器。这类方案的好处是出厂前已经做好内参标定和硬件同步,拿到手就能用,但代价是价格高,且灵活性差。我想换一个镜头或者换一个安装位置,都要重新考虑结构设计,不如自己搭一套来得自由。而且自己过一遍标定流程,后续如果设备碰撞导致外参偏移,还能自己重新标定恢复,不用返厂,这在工程上是非常重要的能力。
1.2 网口规划与主从机通信
我遇到的一个细节问题是两个传感器各占一个网口,工控机本身的网口数量往往不够用。NUC 11有两个千兆口,一个给了雷达,一个给了相机,外网出口就没有了,调试的时候很不方便。我的解决方法是再接一个USB千兆网卡,专门连路由器或者交换机,用于远程SSH,另外就是在开发机上设置ROS_MASTER_URI,让机器人端的工控机作为ROS master,开发机订阅数据。这就是典型的ROS主从机模式。
主从机配置的时候有几个容易踩坑的点:第一,两台机器的/etc/hosts要把对方的IP和主机名都写上,否则ROS节点发现会超时;第二,ROS_IP和ROS_MASTER_URI必须设置成局域网IP而不是回环地址,否则虽然能连上master,但topic数据发不过来,界面端干干净净什么都收不到,这个问题能卡住很多新手;第三,防火墙要放行对应端口,Ubuntu默认开着ufw的话,SSH和数据端口都容易被拦,建议直接sudo ufw disable或者精确放通。
配置好之后,测试是否正常可以先在工控机上roscore,然后在开发机上rostopic list,能看到话题列表就说明主从机通信没问题。如果看不到,优先检查hosts文件和ROS_IP变量,百分之八十都是这两个地方写错了。
2. ROS环境与驱动安装完整流程
标题里写了“附完整ROS配置流程”,这一节我就把从零开始到两边驱动都能正常出数据的操作步骤完整写出来。系统环境我用的Ubuntu 20.04加ROS Noetic,这对Livox驱动和海康MVS SDK的兼容性都是最优解。如果你用的是Ubuntu 22.04,ROS版本建议选Humble,但海康的ROS wrapper支持度会差一些,编译起来要多花时间折腾。实验验证下来,Ubuntu 20.04加Noetic是当前最稳的组合。
2.1 鱼香ROS一键安装脚本
ROS安装对新手来说第一个拦路虎就是官方源的网络问题,用raw.githubusercontent或者官方apt源经常卡到怀疑人生。我推荐直接用鱼香ROS的一键安装脚本,这个工具在机器人圈子已经很流行了,它本质上是一个交互式shell脚本,可以帮你安装ROS、配置rosdep、安装依赖项,全程自动处理源切换。
wget http://fishros.com/install -O fishros sudo chmod +x fishros ./fishros运行后按提示选择对应版本,比如ROS Noetic桌面版,脚本会自动配置apt源并安装。实测下来,整个安装过程大概20分钟到半小时,取决于网络状况。安装完毕后,记得source一下环境:
echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc source ~/.bashrc鱼香ROS脚本还有一个很实用的功能是rosdepc,是rosdep的国内镜像版本。原生rosdep经常因为需要访问GitHub而失败,rosdepc把数据源缓存到了国内,rosdepc init和rosdepc update基本一两分钟就能完成,这个对后续编译很多功能包来说是救命级别的工具。
2.2 Livox ROS驱动2的编译与配置
Livox官方推出了两代ROS驱动:livox_ros_driver和livox_ros_driver2。MID-360建议直接用livox_ros_driver2,它专门对MID-360做了适配,同时支持Livox SDK2。如果买的是Avia或者Horizon,用第一代驱动也够,不过为了统一管理,我建议新项目一律上driver2。
编译步骤很简单,在src目录下把代码拉下来,然后catkin_make或者catkin build都可以。我习惯用catkin build,因为多包项目增量编译更友好。
mkdir -p ~/lv_cam_ws/src cd ~/lv_cam_ws/src git clone https://github.com/Livox-SDK/livox_ros_driver2.git cd ~/lv_cam_ws catkin_make编译完成后,驱动默认的配置文件在livox_ros_driver2/config目录下,针对MID-360,有MID360_config.json这样的文件。几个关键参数说一下:
lidar_configs里设置了雷达的广播码或者IP。多雷达组网时,每台雷达成独立一行写入,格式有对应模板。publish_freq控制点云发布频率,默认是10Hz,对建图来说够了,不用改。frame_id建议改成livox_frame,方便后面做TF树管理。timestamp_type建议选手表时间还是雷达时间取决于是否做硬件时间同步,这里强烈建议选择“时间同步”相关的选项,稍后详细说明。
启动驱动之前有一个必须检查的项目,就是雷达IP是否和工作站网卡处于同一个网段。MID-360出厂默认IP我遇到过是192.168.1.50,配套的PC网卡要设置成192.168.1.x网段才能发现设备。如果IP不一样,先用Livox Viewer 2把雷达IP改成同网段,再启动ROS驱动,不然驱动会一直报“connection timeout”或者根本发现不了设备。Livox Viewer 2是Livox官方的调试工具,在Windows和Linux都有,修改IP的操作在“Device Manager”界面里完成。记住修改IP时要先把电脑网卡固定到对应网段,否则同样扫不到。
启动方式:
roslaunch livox_ros_driver2 msg_MID360.launch正常启动后,rostopic list里会出现/livox/lidar和/livox/imu两个核心话题。前者是点云,后者是内置IMU数据,类型分别是sensor_msgs/PointCloud2和sensor_msgs/Imu。可以用rqt_image_view或者直接在rviz里添加PointCloud2来验证一下点云是否正常,如果能看到花瓣状扫描点云在旋转,驱动这块就算通了。
2.3 海康相机MVS SDK安装与ROS封装
海康的工业相机没有官方ROS驱动,社区里有好几个封装版本,做得比较完整的是hikrobot_camera这个包,它基于MVS官方SDK封装了ROS节点。安装分两步:先装MVS SDK,再编译ROS封装。
MVS SDK从海康机器人官网下载,选择Linux版本的MVS包,下载下来是个tar.gz压缩包。解压后里面有install.sh,直接运行就会把SDK安装到/opt/MVS目录。装完之后,最好运行一下/opt/MVS/bin/MVS.sh启动MVS客户端,确认相机能正常出图,排除线缆和供电问题。这一步非常重要,如果MVS客户端都连不上相机,后面ROS层怎么改都没用。
然后再编译ROS封装。hikrobot_camera的仓库地址在GitHub上,依赖image_transport和camera_info_manager,这些用apt就能装好。
sudo apt install ros-noetic-image-transport ros-noetic-camera-info-manager cd ~/lv_cam_ws/src git clone https://github.com/Livox-SDK/hikrobot_camera.git cd ~/lv_cam_ws catkin_make这里要提醒的是,海康封装包的启动文件默认参数往往不能直接用,比如相机IP、曝光模式、图像分辨率这些,需要按照你自己的相机实际情况修改。在launch文件里,camera_ip填相机的IP,camera_port一般默认39812,这两个字段必须和设备实际情况一致。图像格式我一般设成BGR8,分辨率设为相机原始分辨率的一半或者原始分辨率,帧率10到15帧就够点云着色用了,太高反而CPU吃紧。
启动相机节点,正常情况能看到/sea_camera/image_raw这个图像话题。如果启动时提示找不到设备,先确认MVS SDK安装路径和相机IP是否可达。ping一下相机IP,通了再看MVS客户端的设备列表是否显示相机为“采流中”。如果MVS里能出图但ROS里不行,大概率是封装包的相机IP写错了。
2.4 Livox与海康相机的时间同步策略
做实时彩色点云,时间同步的重要性不亚于空间标定。空间标定决定了你点投到图像上“投得准不准”,时间同步决定了你采到的图像和点云是不是“同一时刻的世界”。如果时间差太大,车子一动起来,动态物体就会在点云和图像之间出现拖影和错位。
海康相机大部分型号支持PPS和硬件触发,但纯ROS软件方案里,我们更常做的是“软同步”:各自的时间戳都以主机系统时间为基准,系统时间用chrony或者ptp与一个可靠的时间源同步。实际操作中,我用chrony对工控机做了系统时间校准,保证系统时间漂移在毫秒级别。
在ROS层面,点云和图像时间戳虽然都在同一个系统时间里,但各自节点的发布频率不同,雷达10Hz,相机10到15Hz,不可能每一帧都精确对齐。这里我用message_filters的ApproximateTime策略来做时间近似同步,只要两个话题的时间戳差值在设定的slop范围内,就算同步成功,然后同时进入回调函数做取色处理。
message_filters::Subscriber<sensor_msgs::PointCloud2> cloud_sub(nh, "/livox/lidar", 10); message_filters::Subscriber<sensor_msgs::Image> image_sub(nh, "/sea_camera/image_raw", 10); typedef message_filters::sync_policies::ApproximateTime<sensor_msgs::PointCloud2, sensor_msgs::Image> SyncPolicy; message_filters::Synchronizer<SyncPolicy> sync(SyncPolicy(10), cloud_sub, image_sub); sync.registerCallback(boost::bind(&CloudColorizer::cloudImageCallback, this, _1, _2));slop值我一般设到50毫秒,这个范围既能保证大部分帧都能匹配上,又能避免时间差太大引入的错误匹配。如果你的场景中机器人在快速转弯,相机帧率建议提高,同时把slop调小一点,宁可丢帧也不要错配。这个平衡需要通过实际数据观察。
3. 激光雷达与相机联合标定实操
标定是这套方案里技术含量最高、也最容易让人放弃的环节。彩色点云的视觉质量直接取决于外参矩阵准不准。如果外参有1度的偏差,在10米外同一个点的颜色就会偏出半个车身位,图像上的一辆车会被“涂抹”到旁边的墙上。所以这个环节我花了很多篇幅,尽可能把步骤讲细。
3.1 livox_calibration标定工具原理概述
Livox官方在GitHub上开源了一个标定工具,名字叫livox_calibration,仓库地址是livox_calibration,它能够自动计算激光雷达和相机之间的6自由度外参(3旋转加3平移)。基本原理是通过标定板建立3D-2D对应关系:激光雷达扫描标定板上的点云呈现出平面特征,提取出标定板的中心点和法向量;相机图像上通过二维码或棋盘格识别标定板的中心点,也得到一个2D坐标。然后通过多帧观测,最小化重投影误差和点面距离误差,迭代优化外参矩阵。
这里要注意的是,livox_calibration对标定板的要求很高,必须使用带ArUco码和黑白棋盘格混合图案的标定板,官方仓库里提供了PDF文件,直接打印在A2或者A1纸上贴在硬平板上就行。我试过自己画一个草率的棋盘格,结果是优化过程非常不稳定,误差大得离谱,千万不要省这一步。
3.2 标定数据采集流程
具体采集流程是这样的。把标定板放在雷达和相机都能看到的区域,距离在2到6米之间比较合适。太近了雷达点云稀疏,太远了ArUco码识别不出来。标定板要尽量正对相机,但也不要完全平行,稍微倾斜一点效果更好,这样激光雷达的扫描线在标定板上有足够多的点去拟合平面。
然后手动录制一段bag,同时采集点云和图像,时长大概20秒左右,期间缓慢移动标定板位置和姿态,让算法能观测到多种几何关系。推荐的方式是保持机器固定不动,人举着标定板变换位置和角度,这样外参更准。我试过移动底盘、拍静止的板子,效果差很多,因为雷达建图和里程计误差会引入额外噪声。
录制的时候确保图像清晰不要有运动模糊,曝光要合适,标定板的黑白格子要清晰可见。Livox的点云话题和相机图像话题都要同时录进去,用rosbag record一条命令搞定。
rosbag record -O calib.bag /livox/lidar /sea_camera/image_raw采集之后把bag文件放到livox_calibration工具的data路径下,按照README的说明配置好yaml参数,然后运行标定节点。标定过程需要振镜,整个过程也会输出中间可视化结果,可以看到点云投影到图像上的重投影误差在逐步下降,最终的外参矩阵会保存在一个yaml文件里。
3.3 标定结果评估与手工微调
标定完成之后不要急着集成到流程里,必须先做定性验证。最快的方法是把标定得到的变换矩阵写进一个简单的点云投影节点,实时播放一段点云和图像,在rviz里同时显示点云和相机图像,观察远处的物体轮廓是否对齐。注意是“远处”不是“近处”,因为近处的投影误差在视觉上不明显,远处看得最清楚。
如果发现有轻微的整体偏移,可以在外参矩阵的基础上做微调。一个实用的小技巧是只对旋转矩阵的roll、pitch、yaw三个角做小范围搜索,步长0.05度,叠加到你标定的初始值上,用重投影误差最小时的组合作为最终外参。这个搜索过程可以用Python写个脚本自动做,类似一个简单的参数寻优问题。
我自己踩过一个坑:标定板太薄,激光雷达在低角度扫描时会因为板边缘的衍射产生杂点,导致平面拟合误差增大。建议标定板背后垫一块泡沫板,增加厚度,同时用阈值滤掉那些反射强度过低或距离变化异常的点。
标定结果存储成yaml格式,包含三个主要字段:平移向量(x, y, z)单位米,旋转矩阵或四元数,还有一些工具生成的附加字段。在颜色映射节点里直接加载使用即可。
4. 实时彩色点云建图管线实现
说完了标定,终于到最核心的部分:怎么把SLAM建图和颜色映射串成一条实时管线。这一节我先讲整体设计思路,再给每个节点写清楚代码级别的实现细节和参数调优经验。
4.1 SLAM算法选型:FAST-LIO还是Livox-LOAM
我实测过两种主流方案:Livox-LOAM和FAST-LIO。Livox-LOAM是Livox官方基于LOAM框架适配的算法,对MID-360的支持很原生,直接就能跑,但代码结构比较老,对IMU的使用不够充分,在快速运动或者振动环境下容易飘。FAST-LIO是目前使用最广的LiDAR-Inertial里程计方案,融合了雷达点云和IMU数据,建图鲁棒性好,还支持在线标定IMU和雷达的内参,代码质量也高。
两个路线我都跑通之后,我更推荐FAST-LIO作为建图核心,特别是MID-360自带IMU,直接省掉了额外接IMU的麻烦。实测下来,FAST-LIO在楼道、开阔场地、小坡度路面等场景都能保持稳定,建图“飘”的问题基本没有出现。如果你还是遇到建图飘的情况,优先检查IMU话题有没有数据、雷达和IMU之间的外参初始值准不准,以及FAST-LIO的配置参数里是否开了外参在线估计。
FAST-LIO的配置参数里最关键的有三个:一是雷达话题名,改成/livox/lidar;二是IMU话题名,改成/livox/imu;三是雷达和IMU之间的外参,MID-360内置IMU的外参在Livox提供的手册里有参考值,可以先填进去,再让FAST-LIO在线优化。其他参数比如体素分辨率,室外大场景我一般设置成0.3到0.5米,室内精细建图可以调到0.1到0.2米,但要付出CPU升高的代价。
启动FAST-LIO之后,rviz里能看到绿色的点云地图,它会随着机器人移动实时增长。如果发现地图分层、重影或者“拖尾”,大概率是IMU标定有问题或者外参不准,先回到标定步骤排查,不要急着调代码。
4.2 点云着色核心节点实现
这个节点要做的事情很简单:每次收到一组时间同步好的点云和图像,遍历点云里的每个点,用标定好的外参矩阵T_cam_lidar把该点的坐标变换到相机坐标系,然后投影到图像平面得到像素坐标(u,v),检查这个坐标是否落在图像范围内,如果在,就把该像素的RGB赋值给这个点,形成一个新的PointCloud2带字段(x,y,z,r,g,b),发布出去。
旋转矩阵和平移向量组成外参矩阵后,投影公式是:
[u, v, 1]^T = K * T_cam_lidar * [x, y, z, 1]^T其中K是相机内参矩阵,包含了焦距fx、fy和光心cx、cy。这些内参可以通过海康MVS SDK获取,但更稳妥的做法是用棋盘格标定一次相机内参,用OpenCV的calibrateCamera函数,或者用Kalibr工具包。内参不准的话,外参再准也没用,这个顺序不要搞反。
代码实现方面,核心部分大致如下:
void CloudColorizer::cloudImageCallback(const sensor_msgs::PointCloud2ConstPtr& cloud_msg, const sensor_msgs::ImageConstPtr& image_msg) { cv_bridge::CvImagePtr cv_ptr; cv_ptr = cv_bridge::toCvCopy(image_msg, sensor_msgs::image_encodings::BGR8); cv::Mat& image = cv_ptr->image; pcl::PointCloud<pcl::PointXYZI>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZI>); pcl::fromROSMsg(*cloud_msg, *cloud); pcl::PointCloud<pcl::PointXYZRGB>::Ptr color_cloud(new pcl::PointCloud<pcl::PointXYZRGB>); color_cloud->points.reserve(cloud->points.size()); color_cloud->header = cloud->header; for (const auto& point : cloud->points) { Eigen::Vector3d pt_lidar(point.x, point.y, point.z); Eigen::Vector3d pt_cam = ext_R * pt_lidar + ext_t; if (pt_cam.z() <= 0) continue; double u = fx * pt_cam.x() / pt_cam.z() + cx; double v = fy * pt_cam.y() / pt_cam.z() + cy; if (u >= 0 && u < image.cols && v >= 0 && v < image.rows) { pcl::PointXYZRGB p_color; p_color.x = point.x; p_color.y = point.y; p_color.z = point.z; int col = static_cast<int>(u); int row = static_cast<int>(v); cv::Vec3b bgr = image.at<cv::Vec3b>(row, col); p_color.b = bgr[0]; p_color.g = bgr[1]; p_color.r = bgr[2]; color_cloud->points.push_back(p_color); } } sensor_msgs::PointCloud2 out_msg; pcl::toROSMsg(*color_cloud, out_msg); color_pub_.publish(out_msg); }这个节点的时间同步用message_filters做,前面已经写了相关的代码。发布的话题命名成/colored_cloud,发布频率和雷达话题保持一致,大概是10Hz。
在性能方面,遍历10万级别的点云并做矩阵运算,单核CPU基本能跑到20毫秒以内,压力不大。但要注意的是,这个节点会为每个点重新读取一次图像像素,如果图像分辨率很大,比如500万像素,每次点云投影的cache命中率不高,内存带宽会成为瓶颈。一个优化技巧是把图像预取到一个连续数组里,步长是通道数,这样点坐标映射到数组索引的时间会缩短不少。
4.3 用launch一键启动整条管线
所有节点单独跑起来比较麻烦,我写了一个launch文件把这些串起来:
<launch> <node pkg="livox_ros_driver2" type="livox_ros_driver2_node" name="livox_lidar" output="screen"> <param name="config_file" value="$(find livox_ros_driver2)/config/MID360_config.json"/> </node> <node pkg="hikrobot_camera" type="hikrobot_camera_node" name="hik_camera" output="screen"> <param name="camera_ip" value="192.168.2.32"/> <param name="camera_port" value="39812"/> <param name="image_width" value="1920"/> <param name="image_height" value="1080"/> <param name="pixel_format" value="BGR8"/> <param name="frame_rate" value="10"/> </node> <node pkg="fast_lio" type="fastlio_mapping" name="fast_lio" output="screen"> <rosparam file="$(find fast_lio)/config/mid360.yaml"/> </node> <node pkg="cloud_colorizer" type="cloud_colorizer_node" name="cloud_colorizer" output="screen"> <param name="extrinsic_file" value="$(find cloud_colorizer)/config/ext_cam_lidar.yaml"/> <param name="camera_intrinsic_file" value="$(find cloud_colorizer)/config/intrinsic.yaml"/> </node> </launch>这个launch文件的顺序有讲究:先启动雷达和相机,等2秒左右让驱动完成初始化,再启动FAST-LIO,因为FAST-LIO启动时会立刻订阅话题,如果话题还没建立,会有几秒的空窗期。最后启动颜色映射节点。
实际操作中,建议把launch文件按节点拆开,先在终端分别启动雷达和相机,确认话题稳定有数据,再启动FAST-LIO和颜色映射,这样调试时能更精确定位问题是出在哪个环节。等一切都对了,再合并成一个launch文件。
5. 常见问题与排查技巧实录
前面讲了完整流程,这一节把我在实际调试中经常遇到的问题和解决思路汇总一下,方便不同类型的问题快速定位。
5.1 激光雷达建图飘了怎么办
这个问题是所有SLAM方案里最常被问到的。从热搜里也能看到“激光雷达建图飘”是高频词。建图飘的表现是地图分层、点云拖影、或者轨迹在高频抖动。排查思路按优先级排列:先看IMU数据是否正常,转速计的噪声、时间戳是否有跳变。用rostopic echo /livox/imu看一眼加速度和角速度的量级是否合理,如果出现大量离群值,可能是驱动配置里IMU外参初始值不对,也可能是雷达和IMU的时间戳不同步。
第二个可能的原因是雷达本身安装松动。MID-360虽然是固态雷达,但安装支架如果刚度不够,机器人运动时雷达会有微小晃动,这种晃动在IMU里是感知不到的,最终就会表现为建图飘。我的处理办法是检查安装螺丝是否紧固,必要时用胶水或者结构胶加固。
第三个原因是FAST-LIO里点云体素分辨率太高,导致匹配特征不充足。在一个空旷的厂房里,把分辨率设置成0.1米,远处的点太稀疏,帧间匹配容易出错。调成0.3米之后明显好转。这个参数要根据场景动态调整,没有一个万能值。
第四个原因是两种传感器的时间戳不同步。雷达的topic时间戳被驱动设置成了雷达硬件时间,而电脑的ROS时间是系统时间,两者本身有偏移,如果不对齐,点云和IMU数据在时间上就差了一截,里程计自然会抖。解决方法是把驱动配置里的时间戳类型改成系统时间,或者在外部用一个时间同步工具做对齐。Livox驱动2里有个配置项是timestamp_type,建议设成msg.header.stamp基于发布时刻的系统时间。
5.2 海康相机在ROS里无法打开设备
现象是启动相机节点后报错,提示找不到相机或者设备被占用。首先确认MVS客户端是否已经关闭,MVS SDK在Linux下同一时间只允许一个进程独占相机,如果你开了MVS客户端,ROS节点是打不开相机的。这个坑我至少踩了三次,每次都是忘记关MVS。
第二个常见原因是GigE相机的防火墙阻止了发现协议。海康GigE相机使用UDP协议进行设备发现,Linux默认防火墙如果开启,会过滤掉这些广播包。排查方法:ufw status看一下防火墙状态,如果开着就放通对应接口,或者干脆sudo ufw disable在调试阶段省心。
第三个原因是SDK环境变量问题。MVS安装完成后,需要把/opt/MVS/lib加入LD_LIBRARY_PATH,否则ROS节点编译能过但运行时找不到SDK动态库。在~/.bashrc里加上:
export LD_LIBRARY_PATH=/opt/MVS/lib:$LD_LIBRARY_PATH export LD_LIBRARY_PATH=/opt/MVS/lib/64:$LD_LIBRARY_PATH加完之后source ~/.bashrc再重新启动节点,一般就能解决了。
5.3 点云颜色错位或者整体偏色
颜色错位分两种情况:静态错位和动态错位。静态错位就是整个点云投到图像上的位置有偏差,物体边缘和图像轮廓对不上,这是外参标定不准确导致的,需要重新标定。动态错位则是在运动过程中出现“重影”或者“拖色”,比如一个路灯杆在点云上显示了两个不同位置的颜色,这是时间同步没做好,相机的帧率和点云的帧率差太大,或者是slop值设得太大。
整体偏色的问题要检查相机的白平衡设置。海康相机有些型号在MVS里默认是自动白平衡,在室内灯光的暖色调下,图像整体会偏黄,点云着色出来也会偏黄。建议在MVS客户端里手动设置白平衡,或者固定色温到5600K左右,保证颜色还原度稳定。另外,曝光如果太高,高亮区域会过曝,点云的颜色会变成纯白色,细节丢失。我一般把曝光时间控制在5毫秒到15毫秒之间,具体看环境亮度。这里的经验是:宁可画面暗一点,也别过曝,过曝的颜色信息彻底丢失,暗了还能通过后期增益拉回来一部分。
5.4 实时性不够怎么办
如果发现整个管线处理延迟很大,点云发布频率掉到5Hz以下,先看CPU占用在哪些节点。用htop观察,如果FAST-LIO占用了高CPU,可以降低体素分辨率;如果颜色映射节点CPU高,可以考虑限制点云范围,比如只投影retro坐标系前方30米内的点,其他点不处理。还有一个技巧,把图像分辨率从原始500万降低到200万再投点,对边缘精度影响很小,但速度提升明显。
如果工控机有多核,可以考虑给颜色映射节点设定CPU亲和性,让它绑定在某个空闲核上运行,减少上下文切换带来的性能损耗。用taskset命令:
taskset -c 3 rosrun cloud_colorizer cloud_colorizer_node这种优化手段属于锦上添花,先把CPU占用主体优化好再考虑。
说到CPU占用,还有一个隐藏问题:如果rqt和rviz节点同时开着,它们各自订阅彩色点云话题,会拖累系统资源。调试阶段没问题,正式跑任务时尽量关掉可视化工具,或者在另一个不带可视化的电脑上开rviz订阅数据,工控机只做数据采集和处理。这也是前面提到ROS主从机结构的另一个作用。
6. 最终效果与应用扩展
整套流程跑通之后,我在rviz里看到的是一幅活生生的彩色点云地图:墙面上不同颜色的装饰板、地面的停车线、绿色的植物,都能够清晰辨认。相比纯几何点云的灰色世界,彩色点云对后续做语义分割、目标检测、视觉导航都有直接用处。我给朋友的项目里用这个能力做了停车位的语义识别,直接把点云投影到图像上获取颜色特征,再训练一个简单的分类器,就能实现车位占用情况判断,省掉了不少标注成本。
这套方案还可以往几个方向扩展。第一,加入更多相机,比如左右各一个,通过多相机的颜色融合,覆盖雷达360度方向的大视场。第二,把点云颜色和图像语义信息结合,比如把图像的深度学习分割结果映射到点云上,直接输出带语义标签的彩色点云,这对高精地图构建和车路协同场景非常有用。第三,把SLAM的轨迹和彩色点云做批量离线融合,输出更高精度的彩色地图文件,用于三维重建和数字孪生。
如果你也想在自己的机器人或者移动设备上做传感器融合建图,这套“固态雷达加工业相机”的组合是一个投入产出比很高的起点。中间踩过的那些坑,我都已经写在前面了,祝少走弯路,一次跑通。