最近在给项目里的巡检机器人升级感知系统,手里正好有一台 Livox 的 MID360 和一台 Intel RealSense D435i,目标很明确:把激光雷达、相机、IMU 三条数据链路组合起来跑 R3LIVE,实现实时定位和彩色点云建图。折腾完这套"MID360 + D435i + R3LIVE"从标定到部署的全流程之后,最大的感受是:单看每个环节的教程都不算少,但能把这几个传感器真正串在一起、把标定关系捋顺、把 R3LIVE 跑稳定,中间其实藏着不少文档里不会明写的坑。
这篇文章不是概念介绍,而是我实际把整套系统推上线之后整理的完整链路,包括为什么选这两个传感器、驱动和话题怎么打通、相机内参和雷达相机外参怎么标、外参怎么填进 R3LIVE 的 launch 文件、部署时有哪些参数值得调,以及我在现场踩过的几个典型问题。不管是实验室里做多传感器融合课题的学生,还是准备把 R3LIVE 用在实际机器人平台上的工程师,照着这条链路走一遍,应该能省下不少乱试的时间。
1. 项目概述与传感器选型思路
1.1 这套组合能解决什么问题
先说结论:MID360 负责提供激光雷达点云,D435i 提供彩色图像和内置 IMU,R3LIVE 把这三路数据紧耦合在一起,实时输出带 RGB 颜色的高密度彩色点云地图,同时给出机器人自身的位姿估计。和单纯跑 FAST-LIO、LIO-SAM 这类纯激光惯导方案相比,R3LIVE 最大的差异点是加入了视觉信息,能利用图像中的纹理信息去修正激光里程计累积的漂移,在建图效果上,尤其是场景特征相对稀疏的走廊、厂房里,地图的细节和稳定性会好很多。
另一个实际价值是它能把定位和建图放到一个系统里做,不需要先跑一个建图、再单独跑一个定位模块。对于巡检机器人、仓储 AGV、校园配送车这种项目,这是很常见的需求:白天跑一圈,地图带颜色,后续做导航的时候可以直接用彩色点云做语义观察,这会省掉很多后端处理的功夫。
1.2 为什么选 MID360 和 D435i
MID360 是 Livox 的 360 度非重复扫描固态激光雷达,体积小、重量轻,适合装在巡检机器人和无人机上,水平视角 360 度、垂直视角大概 59 度,最近探测距离能做到 0.1 米左右,这意味着机器人附近的点云不会因为近距盲区而缺失。它不像传统机械式雷达那样转着圈扫描,而是用非重复扫描的方式在视场里不断填充点云密度,对 SLAM 来说点云覆盖率和均匀性更好。
D435i 选择它主要看中三点:RGB 图像分辨率可以调到 640x480 甚至更高,帧率能跑到 30fps,满足 R3LIVE 对图像频率的要求;它自带 IMU,虽然精度比不上独立的高性能 IMU,但省去了额外接线和标定 IMU 到相机外参的麻烦;驱动成熟,realsense-ros 在 ROS 生态里很稳定,话题输出非常规整。
这套组合还有个好处:D435i 是双目结构光深度相机,但 R3LIVE 并不依赖它的深度图,主要用彩色图像做视觉约束,深度图可以留给其他模块使用。这样一来同一个相机承担了两个任务,硬件成本没有增加,系统集成度反而更高。不过要注意,如果项目对 IMU 的零偏稳定性要求很高,比如长时间在剧烈振动环境下工作,D435i 内置的消费级 IMU 可能会成为精度瓶颈,到时候建议外加一个独立 IMU,并把 IMU 和激光雷达的外参单独标定。
2. 前期准备:驱动安装与数据链路打通
2.1 MID360 驱动与话题验证
MID360 必须使用 livox_ros_driver2,而不是老的 livox_ros_driver,这一点很多人一上来就踩坑。老驱动主要适配的是 Horizon、HAP 这类一代雷达,MID360 的消息定义和接口都不完全兼容,直接用老驱动编译没问题但就是不出点云,或者点云形状明显不对。
安装方式是把它放进工作空间的 src 目录,比如:
cd ~/catkin_ws/src git clone https://github.com/Livox-SDK/livox_ros_driver2.git cd ~/catkin_ws catkin_make source devel/setup.bash连接雷达后,通过 udp 方式启动:
roslaunch livox_ros_driver2 msg_MID360.launch启动后可以用 rostopic list 确认话题,重点看/livox/lidar是否在输出。默认情况下这个 launch 输出的是 livox_ros_driver2/CustomMsg 类型的点云话题,R3LIVE 默认订阅的就是这个类型,所以这里保持默认即可。如果你在其他项目里需要标准 sensor_msgs/PointCloud2 类型,可以在 launch 里把pointcloud_type参数改成 1,但跑 R3LIVE 时建议不要改,否则后续话题类型不匹配,还得在 R3LIVE 里改订阅接口。
确认点云数据正常,可以用 rviz 订阅/livox/lidar,能看到实时扫描的点云。这里有一个细节:MID360 的雷达数据里包含反射强度和点的时间戳偏移,CustomMsg 类型会比 PointCloud2 多携带每点的时间偏移字段,R3LIVE 做去畸变时会用到这个信息,所以尽量保持 CustomMsg 不变。
2.2 D435i 驱动与图像/IMU 话题验证
D435i 的驱动是 realsense-ros,官方维护得比较勤,直接源码编译或者 apt 安装都行。我用的是源码编译方式:
cd ~/catkin_ws/src git clone https://github.com/IntelRealSense/realsense-ros.git cd ~/catkin_ws catkin_make source devel/setup.bash启动的时候建议直接用带 IMU 的 launch:
roslaunch realsense2_camera rs_camera.launch unite_imu_method:=linear_interpolation这里unite_imu_method:=linear_interpolation是把加速度计和陀螺仪的数据在时间上对齐合并成一个 IMU 消息输出。R3LIVE 需要 IMU 频率和加速度、角速度数据,一般会订阅/camera/imu话题。如果这里不加这个参数,IMU 会分成/camera/accel/imu_info和/camera/gyro/imu_info之类多个话题,配置起来更麻烦。
启动之后留意几个话题:
/camera/color/image_raw:彩色图像,R3LIVE 的主输入之一/camera/imu:加速度计和陀螺仪合并后的 IMU 数据/camera/color/camera_info:相机内参信息
因为 D435i 出厂默认内参会写入相机本身,realsense-ros 会直接把这些内参放到 camera_info 话题里。这对 R3LIVE 是好事,它启动时会从/camera/color/camera_info读取内参,不需要手动填。但如果后续用 Kalibr 重标过相机内参,记得要么在 realsense-ros 里覆盖内参文件,要么直接在 R3LIVE 的配置里手动填入标定后的内参,否则两个内参不一致会直接影响视觉约束的效果。
在跑 R3LIVE 之前,我建议先录一段数据看看话题时间戳和帧率。一个很常见的坑是:realsense-ros 默认输出的图像是 1280x720 或者更高分辨率,帧率有时候会掉到 15fps 甚至更低,而 R3LIVE 对图像帧率比较敏感,频率太低会导致视觉帧间隔过大。所以在配置里提前把彩色流分辨率设为 640x480、帧率设为 30fps,能避免后期很多麻烦。
3. 标定流程:从相机内参到全局外参
3.1 内参标定:D435i 彩色相机
虽然 D435i 出厂带了内参,但我还是建议实际标一次。原因很简单:出厂内参在个体之间存在差异,尤其是相机被摔过、温度变化大、或者换了镜头模组之后,出厂值可能偏得比较明显。对于 R3LIVE 这种紧耦合系统,内参错了,视觉投影误差会慢慢累积成地图重影,且极难排查。
标定内参我用的是 Kalibr,因为后面标相机到 IMU 外参也需要 Kalibr,一套工具链用到底,不用在中途切换。准备工作是打印一张 kalibr 支持的目标板,我常用 apirlgrid 6x6 型号,打印后贴在平整硬板上,注意不要让纸张有褶皱,否则角点提取精度会受影响。
标定过程大致是:
rosbag record -O camera_calib.bag /camera/color/image_raw录制时拿着标定板在相机前慢慢移动,覆盖画面中心和边缘,尽量让标定板在画面中处于不同角度和距离,大概录 60 到 90 秒。然后运行:
kalibr_calibrate_cameras --bag camera_calib.bag --topics /camera/color/image_raw --models pinhole-equi --target aprilgrid_6x6.yamlpinhole-equi 模型是 Kalibr 里对旋转对称畸变的常见选择。运行完会得到一个camchain-xxx.yaml文件,里面就是 fx、fy、cx、cy 和畸变系数。拿到之后可以先把这些值记下来,后面 R3LIVE 的外参计算和 launch 配置都会用到。
这里要多说一句:相机标定不要只标一次就完事。我在项目里有一个习惯,每次更换相机固定座、拆装镜头之后都会重标一遍内参。内参和外参是强耦合的,内参偏一点,你后面就算把外参调到最优,视觉重投影误差还是达不到理想值。
3.2 IMU 标定与相机-IMU 外参
D435i 内置 IMU 不是专门为高精度 SLAM 设计的,所以出厂数据里的噪声密度和随机游走参数不一定能直接满足 R3LIVE 的需求。虽然 R3LIVE 本身能在线估计 IMU 零偏,但提前获取一份 IMU 的 noise density 和随机游走值,写进配置里,能明显减少系统启动初期的收敛时间。
IMU 的标定工具我推荐 imu_utils,这个包需要配合一个静止放置的 IMU 数据包使用。操作方法是把 D435i 平放在桌面上静置两小时以上?其实 imu_utils 官方推荐至少静止录两个小时,这个时间有点长,但实际录一两个小时并不算夸张。录制命令:
rosbag record -O imu_static.bag /camera/imu然后用 imu_utils 处理,得到imu_imu.yaml文件,里面包含加速度计和陀螺仪的噪声密度及随机游走。对于 D435i 这种消费级 IMU,数据一般差强人意,但至少比没有强。
接下来是相机到 IMU 的外参标定。这一步在 Kalibr 里是一套完整流程:先准备好 IMU 数据话题和图像话题,然后执行:
kalibr_calibrate_imu_camera --bag camera_imu_calib.bag --cam camchain.yaml --imu imu_imu.yaml --target aprilgrid_6x6.yaml跑完之后会输出相机坐标系到 IMU 坐标系的旋转和平移,以及时间延迟。这里的输出,就是后面计算"雷达到 IMU 外参"的中间量。需要留意的是,Kalibr 计算出的外参定义是 IMU 到相机还是相机到 IMU,不同版本的文档注释有差异,拿到结果后建议先在 rviz 里做一次投影验证,确认旋转方向是对的,再往下走。
3.3 激光雷达-相机外参标定
MID360 到 D435i 彩色相机的外参,可以通过 Livox 官方开源的livox_camera_lidar_calibration工具来标,也可以用其他通用标定方案。这个工具的原理是利用一块已知尺寸的标定板,同时提取点云中的平面约束和图像中的棋盘格角点,通过非线性优化求出雷达坐标系到相机坐标系的变换。
标定操作大概分几步:
- 准备一块足够大的标定板,推荐棋盘格边长至少 5cm 以上的型号,因为 MID360 是非重复扫描,点云比较稀疏,标定板太小了,点云落到板面上的点太少,平面拟合精度会差。
- 启动 MID360 和 D435i,让雷达和相机同时看到标定板,板子距离传感器 1 到 3 米之间,姿态倾斜一些,不要正对。
- 采集一段数据,用工具自带的点选界面在图像上选棋盘格角点,在点云上选标定板边缘点,自动拟合平面。
- 优化输出外参,通常会给出旋转矩阵和平移向量,保存下来。
这个环节容易出问题的地方是点云里的标定板很难选准。MID360 在近距离上的点云密度并不高,尤其如果标定板是黑色边框、表面不太反光,点云返回的反射强度很弱,平面拟合出来会偏。我的建议是:在采集数据之前先用抹布把标定板表面擦干净,保证漫反射,板子尽量选哑光材质,不要用玻璃或者高反光表面。另外,标定过程中让标定板在整个视场里保持静止至少 2 到 3 秒,不要一直晃,否则点云叠加后平面会模糊。
拿到激光雷达到相机的外参之后,再结合 Kalibr 输出的相机到 IMU 外参,就能算出激光雷达到 IMU 的外参。计算公式很简单:
T_lidar_to_imu = T_camera_to_imu * T_lidar_to_cameraT 代表 4x4 齐次变换矩阵,顺序不能反,实际编程时建议用 Eigen 或者 tf2 把每一步都打出来核对。
3.4 外参串联与 launch 配置
R3LIVE 的 launch 文件里需要填写两个参数:extrinsic_R和extrinsic_T,一般表示从雷达坐标系到 IMU 坐标系的外参。extrinsic_R是一个 9 元素的旋转矩阵字符串,按行优先写入;extrinsic_T是 3 元素的平移向量字符串。
比如标定得到旋转矩阵的 9 个数值是r00, r01, r02, r10, r11, r12, r20, r21, r22,平移是tx, ty, tz,那么在 launch 里填:
<arg name="extrinsic_R" default="r00,r01,r02,r10,r11,r12,r20,r21,r22" /> <arg name="extrinsic_T" default="tx,ty,tz" />填写前一定要确认坐标系方向。R3LIVE 源码注释里对"extrinsic 表示哪个坐标系到哪个坐标系"在不同版本里写得不完全一样,我的做法是先用标定结果直接填,然后在 rviz 里叠加显示相机图像投影和雷达点云,如果彩色点云边缘和图像边缘明显错开,就交换旋转方向再试。这个方法虽然朴素,但比盯着矩阵判断哪个是 R 哪个是 R 的转置可靠得多。
外参填完也别急着跑真机,可以先找一个有丰富几何特征的场景,反复走几遍,观察彩色地图里墙面、门框的线条是否干净。如果地图边缘重影明显,大概率是外参平移量有偏差;如果整体旋转导致地图歪斜,大概率是旋转矩阵方向反了。标定不是一次性的,我实际调这一套外参就花了大概一个下午,反复标定、反复进 rviz 看,才把重投影误差控制在可接受范围。
4. R3LIVE 编译部署与 launch 参数详解
4.1 环境与依赖
R3LIVE 主要在 ROS 1 环境下运行,我用的系统是 Ubuntu 20.04 + ROS Noetic。依赖不算复杂,但建议按顺序装齐,避免编译到一半缺库:
sudo apt install libgoogle-glog-dev libgflags-dev libeigen3-dev libpcl-dev libopencv-dev ros-noetic-pcl-ros ros-noetic-cv-bridge ros-noetic-image-transport然后是 R3LIVE 本体:
mkdir -p ~/r3live_ws/src cd ~/r3live_ws/src git clone https://github.com/hku-mars/r3live.git cd ~/r3live_ws catkin_make source devel/setup.bash如果前面已经在 catkin_ws 里编译过 livox_ros_driver2 和 realsense-ros,也可以直接把 r3live 放进同一个工作空间,编译时一起 catkin_make,这样后续启动时环境变量不用切来切去。需要注意,R3LIVE 编译时对 Eigen 和 OpenCV 的版本有要求,不要图省事装太新的 OpenCV,4.2 以下通常没问题,太新的版本偶尔会编译报错。
4.2 launch 配置与外参填入
R3LIVE 的 launch 文件一般在r3live/r3live/launch/r3live.launch。打开之后需要重点改三处:雷达话题名、图像话题名、外参。
雷达话题默认是/livox/lidar,这个对应 MID360 驱动默认输出,不用改。图像话题默认可能是/camera/color/image_raw,和 realsense-ros 默认输出一致,也不用改。IMU 话题默认应该是/imu/data或者/camera/imu一类的名字,如果你的 D435i 是直接启动驱动,IMU 话题大概率是/camera/imu,那就在 launch 里把 IMU 话题参数改成/camera/imu。
外参填法在 3.4 节说过,这里不再重复。剩下一个比较隐蔽的参数是图像分辨率。R3LIVE 默认可能期望 640x480 的输入,如果你在 D435i 驱动里把分辨率设置成了 1280x720,可能也能跑,但每帧的图像处理时间会明显增加,导致实时性下降。建议在 realsense 的 launch 里提前固定彩色流参数:
<arg name="color_width" default="640"/> <arg name="color_height" default="480"/> <arg name="color_fps" default="30"/>这样 R3LIVE 收到的图像尺寸就是它最熟悉的形态,处理速度和视觉特征提取效果都比较均衡。
4.3 启动与初始化注意事项
所有配置完成后,启动顺序建议如下:
# 终端1:启动 MID360 驱动 roslaunch livox_ros_driver2 msg_MID360.launch # 终端2:启动 D435i 驱动 roslaunch realsense2_camera rs_camera.launch unite_imu_method:=linear_interpolation # 终端3:启动 R3LIVE roslaunch r3live r3live.launchR3LIVE 启动时会有一段初始化过程,这个过程非常关键。很多人启动后看到点云没有立刻变彩色,就以为系统没跑起来,其实是因为初始化阶段激光雷达和相机的数据还没有对齐。我的经验是:启动前先把机器人放置在静止状态,等 R3LIVE 的日志里出现初始化完成的提示之后,再缓慢移动机器人。如果一启动就大力晃动,初始化期的视觉和激光匹配很容易发散,表现为位姿突然跳变、地图飘飞。
初次运行建议开着 rviz,加载 R3LIVE 提供的r3live.rviz配置文件,重点观察三个东西:/laser_cloud_vis实时点云、/rgb_cloud_vis彩色点云、以及/path_vis轨迹。彩色点云正常出现后,说明视觉约束已经参与优化,整套系统基本跑通了。
5. 运行调优与常见问题排查
5.1 实时运行效果与参数调优
R3LIVE 跑起来是一回事,跑得稳是另一回事。我在实际项目中主要调过几个参数,位置在r3live/r3live/config/r3live_config.yaml里。
第一个是图像分辨率相关的视觉处理参数。如果 CPU 负载过高,可以适当降低图像金字塔层数,或者减少每帧提取的特征点数量。这个要看你电脑的算力来权衡,我的建议是先保持默认跑一版,用top观察 CPU 占用,如果某个核长期占满,再考虑降参数。
第二个是点云体素滤波参数。R3LIVE 会把地图维护成体素结构,体素大小直接决定地图细节度和内存占用。默认值在室内场景表现不错,但如果在户外或者面积很大的厂房,体素可以适当调大一点,减少地图点数量,防止内存爆炸。体素太小会导致地图点太多,体素太大则地图细节丢失,这个参数需要根据场景反复试。
第三个是 IMU 相关参数。如果你从 imu_utils 拿到了 D435i 的噪声密度和随机游走,记得填进配置里。不少人忽略这一步,系统也能跑,但初始化阶段会多花几秒甚至十几秒去估计 IMU 零偏,而且在运动激励不足的场景里容易初始化失败。
调参没有万能公式,我个人的建议是每次只改一个参数,记录修改前后的地图重影和轨迹漂移情况。多传感器融合系统的参数是强耦合的,一次改好几个参数,出了问题很难定位是哪一项导致的。
5.2 常见问题速查表
我把这次部署中遇到的典型问题整理成了一张表,方便快速对照。
| 现象 | 可能原因 | 排查与解决办法 |
|---|---|---|
| 启动后一直没有彩色点云 | 图像话题没有数据,或 R3LIVE 订阅的话题名和驱动输出不一致 | 用rostopic hz /camera/color/image_raw检查图像频率,用rostopic info确认话题类型 |
| 点云整体抖动或地图重影 | 外参不准确,尤其是旋转矩阵方向错误 | 回到 rviz 做投影对齐检查,调整 extrinsic_R 旋转方向 |
| 初始化阶段系统发散 | 启动时机器人移动太快,或外参误差过大 | 静止放置 3 到 5 秒后再移动,重新检查外参精度 |
| CPU 占用过高,实时性差 | 图像分辨率过高,特征提取数量过大 | 把彩色图像降到 640x480,减少视觉特征数量 |
| 地图颜色和实际场景对不上 | 相机曝光时间设置不当或自动曝光开启 | 固定曝光时间,避免图像亮度剧烈变化影响视觉匹配 |
| 长时间运行后轨迹漂移明显 | IMU 数据质量差,或时间戳同步不严格 | 检查 IMU 话题频率,必要时换独立 IMU,或者用硬件同步线缆 |
关于时间戳同步,这个值得单独说。D435i 和 MID360 是两套独立设备,时间戳来自各自驱动,在没有硬件同步信号的情况下,两者之间存在几毫秒到几十毫秒的偏差。R3LIVE 对这种偏差有一定容忍度,但如果偏差过大,系统会表现为初始化困难或者运行中位姿跳变。如果项目对精度要求高,建议给两套设备接同一个外部时钟源,或者在录制 rosbag 时使用rosparam set /use_sim_time true配合时钟源做离线对齐。对于原型验证阶段,软件时间同步基本够用,但要心里有数:没有硬件同步,系统长期运行的稳定性上限会降低。
还有一个小坑:D435i 内置 IMU 的坐标系方向和相机彩色图坐标系方向并不完全一致,realsense-ros 会做一部分转换,但如果你在 Kalibr 标定时把 IMU 话题直接给进去,一定要确认 IMU 数据的加速度方向。有些数据集里加速度方向反了,会导致 R3LIVE 的重力估计完全相反,表现为点云地图翻转,非常难排查。
5.3 关于 FAST-LIO 建图的横向对比
很多人在部署完 MID360 之后会顺手用 FAST-LIO 做一版建图,我也这么干过。FAST-LIO 是纯激光惯导融合方案,既不需要相机标定,也不需要视觉处理,启动非常简单,适应性强,在没有纹理的场景里也能稳定运行。但它输出的是不带颜色的雷达点云图,而且因为没有视觉修正,在长走廊、大平面这类退化场景里,激光里程计仍然会有累积漂移,只是漂移速度比纯雷达方案慢一些。
R3LIVE 的优势在环境有足够纹理信息时体现得最明显。比如室内办公区、仓库货架区,墙面上的标识、货架上的标签都能提供很丰富的视觉约束,地图明显更"紧实",颜色信息也能直接用于后续分割。反过来,如果环境是纯白色墙面或者空旷的地下停车场,视觉约束很少,R3LIVE 的表现就会退化到接近纯激光惯导的水平,但还多了相机标定的复杂度。
所以我的建议是:如果项目只要求几何定位,不要求颜色地图,MID360 + FAST-LIO 是更省事的组合;如果要做彩色地图、要带视觉回环或者需要给后续感知模块提供纹理信息,那才值得上 R3LIVE。前期多花在标定上的功夫,在后期建图质量和系统稳定性上都会赚回来。
6. 一些实操体会与扩展方向
整套系统从零开始配置到稳定运行,我大概花了两个工作日。如果只算纯跑通流程,可能半天就够,但真正把地图质量调到满意的状态,时间基本都耗在标定和参数微调上。尤其是激光雷达到相机外参,我反复标了三次才让自己满意。第一次标完直接跑,彩色地图边缘发虚,第二次发现是标定板在点云里提取的平面不够准,第三次换了更大的标定板、放慢采集动作,效果才明显好起来。
我的经验是:多传感器融合项目的坑,九成在数据质量,不在算法本身。传感器时间戳对不对、话题频率稳不稳、标定板干不干净、启动时机器人动不动,这些细节决定了 R3LIVE 能不能发挥出论文里的效果。与其迷信参数调优,不如先花时间把数据链路检查干净,很多看似玄学的漂移问题,最后发现都是时间戳偏差导致。
后续如果要在真机上长跑,我建议在这个方案之外加两个模块:一是保存 rosbag,定期回放做离线标定复核;二是引入回环检测,R3LIVE 本身不内置全局回环,长时间大范围运行时累积漂移会成为主要矛盾,外部再接一个回环模块,或者定期用其他建图方法做闭环修正,整套系统才更接近可交付状态。