2021年11月底我把 Covins 这套多机器人单目协同建图方案在 Euroc 数据集上完整跑通了一遍中间踩了不少坑也把整个系统的设计逻辑捋了一遍。今天这篇就把当时的实操过程、关键参数、避坑点全部分享出来给想入门多机器人 SLAM 协同建图的朋友一条能抄的作业。Covins 这个名字我第一次看到是在一次组会上一句话概括就是把 VINS-Fusion 从单机 SLAM 扩展成支持多机器人协同建图的方案每个机器人只带一个单目相机加 IMU通过共享视觉信息完成多机的地图融合与回环修正。它解决的问题很直接——多台机器人要在未知环境里各跑各的最后拼出一张全局一致的地图不做事先标定也不依赖外部定位设施。适合研究多机器人协同、分布式 SLAM、或者做多机探索任务的同学参考。1. 项目背景与设计思路多机器人协同建图到底难在哪先说清楚一个问题单机 SLAM 这些年已经非常成熟了ORB-SLAM、VINS-Mono、VINS-Fusion、LIO-SAM 这些都做得很好。单机的问题是你背着相机走一圈地图出来完事。但一旦把一台机器人换成多台机器人情况就完全变了。1.1 多机协同的三大核心难题第一个难题是坐标系统一。每台机器人都在自己的坐标系里建立地图如果初始位置不同大家的地图坐标系天然就是错开的。怎么把多张局部地图对齐到同一个世界坐标系这是协同建图绕不开的第一关。传统做法是靠 RTK、UWB 或者预先布置的标记点来做初始对齐但室内、地下、无 GPS 的环境里这些手段全部失效。第二个难题是通信带宽与算力有限。多机器人系统通常是靠无线网络通信的如果像集中式 SLAM 那样把所有机器人的原始图像、激光数据全部传给一个中央服务器处理无线带宽和服务器算力很快就撑不住了。一个 VGA 分辨率的灰度图30fps 就是 30MB/s 左右三台机器同时传就是 90MB/s一般的无线局域网根本扛不住。第三个难题是地图不一致与回环冲突。不同机器人各自建立的地图中同一个物理位置可能有不同的特征描述。当一个机器人走到另一个机器人已经探索过的区域时系统需要识别出这是同一个地方否则地图会出现重叠、错位甚至分叉。而回环检测在多机场景下不仅是单机的全局优化问题还牵扯到跨机位姿约束。1.2 Covins 给出的答案分布式协作而非集中式融合Covins 的思路和集中式融合最大的不同在于它让每台机器人保持独立的局部建图能力只共享小体积的视觉描述子信息和关键帧位姿而不是共享原始图像或者稠密点云。每个机器人继续用自己那份 VINS-Fusion 做视觉惯性里程计和局部地图维护同时通过一个共享描述子池去检测跨机器的回环。我在实操中体会最深的一点是这种设计极大地降低了通信负载。跑 Euroc MH01 序列时单台机器人传输的共享描述子数据量大约只有原始图像流的 5% 左右三台机器人协同建图所占用的带宽基本稳定在 1-2MB/s 量级。这个设计决策直接决定了系统在现实部署中的可行性——无线环境再差这点数据量也都是能撑住的。2. 核心原理拆解Covins 如何实现单目协同建图要理解 Covins必须理解它从 VINS-Fusion 继承了什么、改了什么。VINS-Fusion 本身是一个基于滑动窗口优化的紧耦合视觉惯性里程计支持单目IMU、双目IMU等多种传感器配置。它有两套东西对后来者极其友好一是鲁棒的 IMU 预积分和边缘化策略二是完整的关键帧管理和回环检测模块回环模块用的是 DBOW2 词袋模型。2.1 共享描述子与跨机回环检测Covins 最核心的改动在回环检测层面。单机 VINS-Fusion 里回环只在当前帧和自身历史关键帧之间进行。Covins 则把这个范围扩展到了整个机器人集群每台机器人定期把自己的关键帧描述子广播出去同时接收其他机器人的描述子构建一个跨机描述子库。当某台机器人在当前图像中提取到的特征点描述子能在其他机器人的历史关键帧里匹配上系统就会构建一个跨机回环约束。这个约束会被送入位姿图优化器中参与全局位姿修正。因为每个关键帧还保存着对应的 3D 特征点位置、IMU 位姿等信息跨机回环产生后系统就能利用这些共同的 3D 观测去估计两台机器人之间的相对位姿。提示这里有个非常关键的细节——描述子的匹配不是简单的最近邻。Covins 在 DBOW2 词袋匹配之后还会做几何一致性验证也就是用 RANSAC 配合基础矩阵或单应矩阵去剔除误匹配。这个步骤必须有词袋匹配只是候选框选几何验证才是最后的把关者。2.2 坐标框架对齐策略跨机回环检测成功之后接下来就是坐标对齐。这里又分两种情况情况一A 机器人和 B 机器人在地图的某个区域相遇检测到足够多的共同特征后系统可以通过 PnP 求解出 A 坐标系到 B 坐标系的相对变换。这个变换一旦建立A 机器人的轨迹和地图点就全部变换到 B 的坐标系下两机地图合并为一个整体。情况二A 机器人和 B 机器人从未直接相遇但它们各自都和 C 机器人有共视区域。这时系统通过 A-C、B-C 两段相对变换做传递解算出 A 到 B 的间接变换。这个链条可以继续延长形成一个多机位姿图。所有相对变换的边和单机内部的里程计约束一起送入全局图优化最终得到整体一致的地图。我实测下来传递变换的误差会随链路长度累积两跳以内结果还算可靠三跳以上就需要比较强的回环约束来约束漂移。这也是为什么 Covins 的论文里强调多机系统中共同出现的重要性。2.3 为什么要选单目方案既然用单目为什么不直接用双目或者 RGB-D 相机呢部署成本和标定难度是主要原因。双目相机需要基线标定和高精度的同步RGB-D 在室外强光下基本失效在大型场景下测量范围也很有限。单目相机配合 IMU 是成本最低、适用范围最广的方案。代价是单目初始化比较敏感对运动激励有要求纯旋转无法初始化。跑数据时也需要注意启动阶段要避免静止或纯旋转。在实际实验中我的经验是单目IMU 这套组合在 Euroc 这种带 IMU 的数据集上表现很好因为 VINS-Fusion 本身就是为这个传感器配置设计的IMU 预积分能很好地补偿单目尺度不可观测的问题。Euroc 数据集自带高精度 IMU 数据频率 200Hz这对视觉惯性紧耦合来说是非常理想的输入条件。3. Euroc 数据集实操从数据准备到系统跑通Euroc 数据集是苏黎世联邦理工用微型飞行器采集的视觉惯性数据集包含机器大厅MH01-MH05、室外V101-V103和房间V201-V203三个场景序列。数据集提供左右目灰度图像、IMU 数据加速度和角速度以及动作捕捉系统提供的轨迹真值。对跑 VINS 系算法的人来说这是最标准的评测数据集。3.1 数据集下载与格式说明Euroc 官方提供的是 ASL 格式的文件夹内部结构和文件内容是这样的mav0/cam0/data/左目灰度图像以时间戳命名的 png 文件mav0/cam0/sensor.yaml左目相机内参、畸变系数mav0/imu0/data.csvIMU 数据包含 timestamp、角速度、加速度mav0/imu0/imu.yamlIMU 内参、噪声密度、随机游走mav0/state_groundtruth_estimate0/data.csv轨迹真值mav0/body.yamlIMU 到机体的外参mav0/cam0/下的 cam0 到 IMU 的外参在 sensor.yaml 中跑 VINS 系算法前需要把 ASL 格式转为 rosbag。官方提供了转换脚本但我更推荐直接用开源的转换工具把图像和 IMU 数据封装成 ROS 消息并保持时间戳完整。如果你不想自己转Euroc 官方也提供了转换好的 bag 文件下载。注意转换时要确认图像消息是sensor_msgs/Image而不是sensor_msgs/CompressedImage。VINS 系列的相机订阅读的是原始图像压缩流会导致帧率下降和解码延迟直接影响里程计精度。MH01 序列大约 182 秒VGA 分辨率752x480图像频率 20HzIMU 频率 200Hzbag 体积在 800MB 左右。跑起来对磁盘 IO 和 CPU 都有一定要求建议用固态硬盘存放 bag 文件避免 IO 瓶颈导致丢帧。3.2 编译 Covins 与依赖环境我跑 Covins 时的环境是 Ubuntu 18.04 ROS MelodicCeres Solver 1.14 或者 1.13 均可OpenCV 3.3.1。如果你用的 Ubuntu 20.04 ROS Noetic需要注意 Ceres 和 OpenCV 的版本兼容尤其是 OpenCV 4 带来的描述子接口变化可能导致编译报错。整体编译步骤分为四步# 1. 创建并初始化 catkin 工作空间 mkdir -p ~/covins_ws/src cd ~/covins_ws catkin_init_workspace src # 2. 拉取 Covins 及其依赖vision_opencv、geometry 等按需安装 cd ~/covins_ws/src git clone https://github.com/HKUST-Aerial-Robotics/Covins.git # 3. 确认依赖项已安装 sudo apt-get install ros-melodic-cv-bridge ros-melodic-image-transport ros-melodic-tf # 4. 编译 cd ~/covins_ws catkin_make source devel/setup.bash实际编译过程中最常见的问题是cv_bridge和 OpenCV 版本冲突。如果你系统里的 OpenCV 是 4.x 而 cv_bridge 是依赖 3.x 的就会出现链接错误。我的解决办法是先用roscd cv_bridge查看当前 cv_bridge 使用的 OpenCV 版本再决定是否需要从源码重新编译 cv_bridge。实操心得如果编译报错信息里出现fatal error: opencv2/xfeatures2d.hpp或者opencv2/features2d.hpp找不到大概率是 OpenCV 版本问题。在 Ubuntu 18.04 上最简单的方式是把系统的 libopencv-dev 控制在 3.2并用源码编译 Ceres 和 DBoW2。3.3 配置 launch 文件与参数Covins 启动时需要为每台机器人指定一个独立 ID 和名字空间。配置文件在Covins/estimator/config/下核心参数包括robot_id当前机器人的编号从 0 开始robot_nameROS 名字空间如 robot0、robot1imu_topicIMU 订阅话题名image_topic图像话题名这里用的是单目需要指定/cam0/image_rawshare_descriptor_topic共享描述子的发布订阅话题use_shared_loop_closure是否开启共享回环检测必须为 trueEuroc 数据集的相机内参和 IMU 参数在euroc_config.yaml中已经给出了模板直接填入 MH01 的标定值即可。以 MH01 为例左目相机焦距约 458.654主点坐标约 (367.215, 248.375)畸变系数为 [-0.28340811, 0.07395907, 0.00019359, 1.76187114e-05]。这些数据在sensor.yaml里都有替换即可。如果要在同一台电脑上模拟多机器人协同我的做法是给每个 Covins 实例设置不同的 ROS 名字空间并分别订阅不同的图像话题比如将 MH01 的左右目做色彩反转后模拟不同机器人的视角同时共享描述子话题放在全局命名空间下这样三台虚拟机器人就能实现跨机回环检测。3.4 单机与多机运行命令单机验证跑通是整个流程的第一步。做这个的意义在于确认数据集、相机参数、IMU 参数都没有问题系统能正常输出轨迹和地图再进行多机扩展。单机运行典型命令# 终端 1启动 Covins 单机节点 roslaunch covins covins_euroc.launch robot_id:0 # 终端 2回放数据集 rosbag play MH_01_easy.bag /cam0/image_raw:/robot0/cam0/image_raw /imu0:/robot0/imu0多机模式下的启动差异在于每台机器人需要独立的名字空间和话题重映射。模拟多机协同的命令大致如下# 终端 1机器人 0 roslaunch covins covins_euroc.launch robot_id:0 robot_name:robot0 # 终端 2机器人 1 roslaunch covins covins_euroc.launch robot_id:1 robot_name:robot1 # 终端 3回放 MH01 作为 robot0 的数据 rosbag play MH_01_easy.bag /cam0/image_raw:/robot0/cam0/image_raw /imu0:/robot0/imu0 # 终端 4回放 MH02 作为 robot1 的数据 rosbag play MH_02_difficult.bag /cam0/image_raw:/robot1/cam0/image_raw /imu0:/robot1/imu0这样跑的关键在于MH01 和 MH02 都位于机器大厅两者参观的区域有部分重叠重叠区域一旦被描述子匹配命中就能触发跨机回环。我当时观察到的现象是在开始阶段两机各自的轨迹独立运行当 robot1 运行到 robot0 已经探过的区域后RVIZ 里两张地图的漂移误差会突然被拉齐整个全局地图出现一次明显的收紧这就是跨机回环优化的效果。3.5 如何判断协同是否生效协同算法跑起来后别只看 RVIZ 里地图好不好看要用数据说话。我一般会验证三点第一检查是否产生跨机回环约束。在 Covins 日志中搜索shared loop found或cross robot loop等关键词。如果跑完整个 bag 一条跨机回环都没有地图肯定是拼不到一起的。第二对比单机轨迹精度和协同轨迹精度。分别保存两次运行后的位姿结果用evo工具对比轨迹和真值的 ATE绝对轨迹误差。协同模式下因为加入了跨机约束正常情况下两机的轨迹误差都会比单机模式更低尤其是在重叠区域附近。第三检查共享描述子通信量。用rostopic hz /shared_descriptors查看消息频率用rostopic bw查看带宽占用。如果频率长期为零说明描述子共享链路没建立起来需要检查网络配置或者话题名是否统一。Euroc MH01 序列我在单机 VINS-Fusion 下能跑到大约 0.06-0.09m 的 RMSE 误差Covins 协同后单机轨迹 RMSE 同样能维持在这个水平而全局地图的一致性因为有了跨机约束视觉上一眼就能看出明显提升。4. 常见问题与排查技巧实录这些年帮周围同学解决过不少 Covins 的运行问题大部分都集中在编译、时间戳和数据格式这几类上。以下是我实际踩过、也帮别人排查过的典型问题整理成速查表供参考。4.1 编译与依赖问题现象可能原因解决办法编译报错找不到features2d.hppOpenCV 版本过高或路径不对安装 libopencv-dev 3.2或调整 CMakeLists 中的 OpenCV 路径Ceres 版本不兼容Ceres 1.14 接口变化编译安装 1.13 或 1.14确认FindCeres.cmake能正确找到cv_bridge 链接失败cv_bridge 依赖的 OpenCV 版本与系统不一致从源码编译 vision_opencv指定 OpenCV 3.2DBoW2 描述子类型不匹配原始 DBoW2 与修改版接口差异使用 Covins 仓库自带的三方库版本实操心得最容易让人崩溃的是 cv_bridge 问题。你系统里dpkg -l | grep opencv能看到装了一堆 OpenCV 4 的库但 cv_bridge 是 Melodic 自带、编译时依赖 OpenCV 3.2 的。两个版本混在一起链接器随机选择报错千奇百怪。最终极的办法是把系统里的 OpenCV 4 卸载干净只留 3.2然后重新编译 cv_bridge。这一招能解决 90% 的编译难题。4.2 运行期问题现象可能原因解决办法启动后地图长时间不初始化单目初始化需要足够平移运动或 IMU 数据质量差检查启动时是否静止或纯旋转给机器人加平移激励轨迹发散、地图飞了IMU 外参或噪声参数设置错误重新检查imu.yaml中的噪声密度与随机游走核对body.yaml外参跨机回环从未触发描述子话题不匹配、通信链路不通、两机器人没有共视区域用rostopic list确认共享描述子话题存在用rostopic echo查看消息内容确认数据序列有重叠场景地图融合后出现错位跨机回环数量不足或几何验证失败增加共享描述子频率放宽候选帧数量重建词袋回放 bag 时掉帧严重磁盘 IO 或 CPU 过载换 SSD降低回放速率为 0.5-0.8 倍跑 Euroc 时最有意思的问题是MH01 和 MH02 明明都是机器大厅但直接把两个 bag 同时回放给两台机器人跨机回环却迟迟不来。后来排查发现MH02 的运动速度比 MH01 快不少回环触发需要关键帧之间的共视足够充分。解决办法是把loop_closure_frequency这个参数调大让系统更频繁地检测跨机回环。这个参数在配置文件中的单位是秒表示每隔多少秒进行一次回环检测我最终从默认值 0.5 调到了 0.2。4.3 精度与参数调优心得Covins 的参数大约有三类单机 VIO 参数、回环检测参数、全局图优化参数。单机参数直接用 VINS-Fusion 的 Euroc 配置就行回环检测参数重点调的是match_image_global和feature_invite相关的阈值。过高的阈值会漏检回环过低的阈值会引入大量误匹配。我调参时遇到过系统把两个相似但并非同一位置的场景误判成回环的情况。这个问题的根源是词袋的视觉词汇表在光照变化下不够鲁棒。解决办法并不是简单降低匹配阈值而是增大 RANSAC 几何验证的迭代次数并提高内点比例的门限。关键经验协同建图的精度上限取决于单机里程计质量。如果单机 VIO 就开始飘协同算法再先进也救不回来。所以我的建议是先把单机数据跑到满意再开启共享描述子的开关。一上来就同时调单机和协同参数出现问题时很难定位。5. 后续扩展与实际应用展望Covins 跑通只是第一步多机器人单目协同建图真正的价值在于它能作为上层规划系统的基础。这也是我在研究中最感兴趣的部分。构建出全局一致的地图后接下来就可以做多机器人路径规划、任务分配和协同探索。5.1 从协同建图到协同规划在多机器人探索任务中机器人需要知道哪块区域已经被探过了哪块还没探。有了 Covins 输出的全局地图每个机器人都能获取其他机器的已探索区域信息。规划层就可以据此生成无碰撞的目标点分配避免多台机器人反复扫描同一块区域。一种常见的设计是把 Covins 的全局地图输出给中央规划器由中央规划器做全局路径规划和任务分配。另一种更去中心化的方式是每台机器人运行自己的本地规划器通过共享的地图信息判断其他机器的位置用优先级或拍卖机制解决任务冲突。这两种我在仿真里都试过后者对通信更敏感但系统鲁棒性更强。5.2 传感器与场景扩展Covins 目前固定用的是单目IMU 输入。如果要扩展到更多传感器配置比如双目改动量主要集中在里程计前端和初始化模块。回环检测和跨机协同的框架是传感器无关的因为共享的始终是视觉描述子而描述子的提取不依赖于相机是单目还是双目。另一个很实用的扩展方向是融合 GPS 先验。在室外部分开放环境下GPS 可以提供大致的初始位置估测加速坐标对齐和回环搜索。但要注意一旦场景过渡到室内或地下GPS 信号丢失系统仍需退回到纯视觉惯性模式。这种有 GPS 用 GPS没 GPS 退回纯视觉的平滑切换机制需要在状态估计层面做仔细设计。5.3 性能调优方向从我实际跑数据的感受看Covins 代码仍然有进一步优化的空间。首先是描述子共享策略目前是定期广播所有新关键帧的描述子其实可以基于信息增益做筛选只分享那些对未来回环检测最有价值的关键帧。这个方向在学术论文中已经有相关探讨也适合拿来当作优化课业或者工程落地项目。其次是图优化频率的可调节性。全局位姿图优化在机器人数量增加时计算量上得非常快。实际部署中可以将优化频率降低或者只对跟当前机器人位姿相关的子图做增量优化这样能在精度牺牲有限的情况下换到更平滑的实时性能。最后分享一个我在多个多机 SLAM 项目里用到的通用技巧一定要先把单机数据跑得非常熟再开协同功能。每个机器人单独工作正常了再怀疑描述子共享、通信、同步等问题。协同 SLAM 的问题排查难度是叠加的不先把地基打好排查起来会非常痛苦。我当时花了不少时间在调试单机和协同之间的衔接最终发现大部分问题都出在单机参数没调好或者数据播放时序不对而不是协同算法本身的缺陷。如果你正在研究多机器人协同建图或者刚接触 Covins希望这篇实操记录能帮你少走一些弯路。多机协同是个系统工程从数据、通信到优化每一环都踩过坑但跑通之后那份多张地图拼成一张全局图的成就感确实值得。