
搞ORB-SLAM3部署这事最气人的往往不是算法本身而是环境、依赖、版本、数据格式这些琐碎问题。我最近在Ubuntu 20.04上把ORB-SLAM3从源码完整编译了一遍用EuRoC数据集跑通了单目IMUMono-Inertial模式期间踩了不少坑——有编译期的有参数配置的也有对IMU初始化机理理解不到位导致的误操作。这篇记录把整个过程完整复盘一遍包括环境搭建、build.sh编译流程、配置参数改动、运行命令、日志输出解读以及我在yaw慢漂和IMU初始化上的一些实际观察希望能帮后来的人少走点弯路。不管你是在校学生、刚入门SLAM的工程师还是准备用ORB-SLAM3做视觉惯性里程计验证的开发者这篇都值得收藏。1. 项目复盘我为什么要写这篇运行记录1.1 看似简单的部署其实暗坑不少ORB-SLAM3开源四年多网上教程一搜一大把看起来无非就是克隆、装依赖、跑build.sh三步。但真动手实操版本不匹配、依赖库冲突、数据集路径错误、yaml参数格式问题随便一个都能让你卡上好几天。我自己就在Pangolin和OpenCV的兼容性上浪费了差不多一个下午在IMU初始化失败的问题上又反复折腾了很久。所以这篇记录的价值在于把我在Ubuntu 20.04上从零到一跑通ORB-SLAM3单目IMU模式的完整路径复现出来包含我踩过的坑和对应的解决办法。读者照着走一遍基本能在一两个小时内部署完成剩下时间可以专心研究算法和改进实验而不是跟CmakeLists.txt较劲。1.2 单目IMU到底能解决什么场景问题纯单目SLAM有个天生的短板——尺度不可观测。相机在移动过程中我们无法仅凭单帧图像判断物体到底离我们多远场景是“放大”还是“靠近”了。这个问题在地图构建、机器人导航、AR叠加这些实际场景中非常致命因为你需要真实的物理尺度来做路径规划和碰撞检测。而单目IMU的方案恰恰是用IMU的加速度计和陀螺仪数据弥补单目视觉在尺度上的缺失。IMU能测量真实的加速度和角速度这些是物理量、有绝对尺度所以视觉惯性融合之后系统能估计出真实的轨迹尺度同时还能在视觉短暂丢失或者快速运动导致图像模糊的时候用IMU的预测结果顶上去。这也是ORB-SLAM3中Monocular-Inertial模式存在的意义——它比纯单目更鲁棒又比双目和RGB-D在硬件上更轻量、更省成本特别适合无人机、手持设备、车载前视摄像头这类场景。2. 环境准备与核心依赖版本解析2.1 系统、硬件与基础工具我用的系统是Ubuntu 20.04.6 LTS内核5.15这算是ORB-SLAM3比较主流的部署环境。官方推荐Ubuntu 18.04或20.0420.04的优势是OpenCV 4.2可以直接用apt安装不用自己从源码编译OpenCV省事很多。硬件方面我用的是一台普通台式机CPU是i5-10400内存16GB无独立显卡也能跑——ORB-SLAM3的视觉前端主要吃CPU大多数环节对GPU没有硬性要求。基础工具链直接一条命令装齐sudo apt update sudo apt install -y build-essential cmake git pkg-configcmake版本在20.04上是3.16完全够用。gcc默认是9.4编译ORB-SLAM3也没有问题。2.2 四大依赖库的选型与避坑ORB-SLAM3的核心依赖是Pangolin、OpenCV、Eigen3以及仓库自带的DBoW2、g2o、Sophus在Thirdparty目录下。前三个需要自己装后三个在编译时由build.sh自动顺带编译。先说Eigen3。Ubuntu 20.04的apt源里默认是Eigen 3.3.7这个版本和ORB-SLAM3是兼容的。如果从源码装了Eigen 3.4以上版本g2o编译时会出现模板匹配错误常见报错形如“static assertion failed”。所以我的建议很简单直接用apt装Eigen别折腾。sudo apt install -y libeigen3-dev然后是OpenCV。20.04默认是4.2.0ORB-SLAM3官方支持OpenCV 3.x和4.x4.2用下来没有任何问题。这里有个容易踩的坑如果你之前装了OpenCV 4.5或4.6编译时可能会遇到cv::bow::Dictionary之类的符号问题因为ORB-SLAM3的DBoW2第三方库对OpenCV的接口依赖比较老。建议先检查系统里OpenCV版本pkg-config --modversion opencv4如果是4.2.0直接往下走就行。如果你系统里已经装过别的版本可以开个干净的虚拟环境或者干脆卸载重装别硬凑。Pangolin是用来做界面可视化的也是整套依赖里最容易出问题的。我用的版本是Pangolin v0.8官方仓库master分支在2023年之后做了一次比较大的重构接口变化不小直接编最新版可能会和ORB-SLAM3源码不兼容。安装命令如下git clone https://github.com/stevenlovegrove/Pangolin.git cd Pangolin git checkout v0.8 ./scripts/install_prerequisites.sh --dry-run mkdir build cd build cmake .. make -j8 sudo make installinstall_prerequisites.sh脚本主要是安装一些系统级依赖比如libglew-dev、libgl1-mesa-dev、libegl1-mesa-dev、libxkbcommon-dev这些如果网络不好可以手动apt安装。如果你不需要可视化比如在服务器上跑也可以在CMake时加-D BUILD_EXAMPLESOFF或者干脆不装Pangolin、改掉ORB-SLAM3里的相关头文件但这样操作风险大不推荐新手尝试。2.3 库的安装顺序为什么重要很多教程会忽略构建顺序但这其实是编译成败的关键细节之一。ORB-SLAM3的编译链路是这样的先编Thirdparty里的DBoW2再编g2o然后编Sophus最后才编译Examples里的可执行文件。build.sh脚本内部默认按这个顺序执行而它假设Pangolin和OpenCV已经提前装好并能被Cmake找到。所以实际操作顺序是先装Eigen和OpenCV再编Pangolin并install最后进入ORB-SLAM3目录执行build.sh。如果你把顺序反过来比如先跑build.sh再装Pangolincmake阶段就会报Could not find Pangolin白白等半天。提示Pangolin编译完成后一定要sudo make install否则ORB-SLAM3的CMakeLists.txt里find_package(Pangolin)会找不到库。装完可以用这个命令验证ls /usr/local/lib/libpangolin*。3. 编译ORB-SLAM3全过程从克隆到build.sh3.1 获取源码与目录结构源码从官方GitHub仓库拉取git clone https://github.com/UZ-SLAMLab/ORB_SLAM3.git cd ORB_SLAM3拉下来之后目录里的关键结构大概是这样的Examples/存放各个模式下的运行程序源码和配置文件比如Monocular、Stereo、RGB-D、Monocular-Inertial等子目录Vocabulary/ORB词典文件可以用工具生成仓库里也直接提供了训练好的ORBvoc.txtThirdparty/DBoW2、g2o、Sophus三个第三方库的源码build.sh一键编译脚本值得说明的是ORB-SLAM3的源码仓库已经比较稳定大部分文件不会频繁变动所以不需要锁定特定commit直接pull最新master即可。唯一需要注意的是仓库比较大里面有EuRoC的配置文件和一些测试数据克隆时如果网络慢可以加--depth 1只拉取最新一次提交。3.2 编译过程中的验收点执行编译chmod x build.sh ./build.sh这里建议你观察编译输出不要干等。整个编译链路有五个主要编译目标DBoW2、g2o、Sophus、ORB_SLAM3主库、可执行程序。每编译完一个目标屏幕上会出现对应的marker。关键点是编译到Sophus时编译器会报一些warning这很正常别慌。Sophus是一个比较老的李代数库在gcc 9下会有一堆未使用变量和隐式类型转换的warning只要不是error就能继续跑。整个编译过程视机器性能大概需要10到20分钟。结束后Examples/Monocular-Inertial/下应该生成mono_inertial_euroc和mono_inertial_tum_vi两个可执行文件。前者用于EuRoC数据集的单目IMU模式后者用于TUM-VI数据集。3.3 我在编译时实际碰到的三个问题第一个问题是Pangolin的版本兼容。我最初直接clone了Pangolin的master分支编译ORB-SLAM3时在Viewer.cc报了一堆setWindowTitle相关的错误。后来发现是Pangolin v0.9把接口改了。解决办法是切回v0.8 tag重新编译安装立马就过。第二个问题是OpenCV的cv::Mat和cv::FileStorage头文件冲突。这个主要出现在同时装了多个OpenCV版本的系统里。我检查发现系统里既有OpenCV 4.2又有ROS自带的OpenCV 4.5CMake优先找到了4.5结果DBoW2编译时报了找不到cv::FileNodeIterator的错误。处理方法是把/usr/local/lib/cmake/opencv4临时移到别处强制CMake使用系统的/usr/lib/x86_64-linux-gnu/cmake/opencv4编完再移回来。第三个问题是内存不足。编译g2o时很多模板实例化非常吃内存。我的16GB内存机器上只开make -j8会偶发内存不足导致编译器崩溃。后来改成make -j4就稳定多了。如果你的机器内存只有8GB建议直接make -j2慢一点但是不会崩。3.4 单目IMU模式的可执行程序清单编译完成后我习惯先打个表确认一下生成的可执行文件方便后续对号入座模式可执行文件路径适用数据集Monocular-InertialExamples/Monocular-Inertial/mono_inertial_eurocEuRoC MAV数据集Monocular-InertialExamples/Monocular-Inertial/mono_inertial_tum_viTUM-VI数据集Stereo-InertialExamples/Stereo-Inertial/stereo_inertial_eurocEuRoC MAV数据集MonocularExamples/Monocular/mono_eurocEuRoC MAV数据集纯视觉如果编译完这些文件都在说明主程序编译成功可以进入下一步。4. 单目IMU的核心原理为什么系统能工作4.1 视觉惯性融合的底层逻辑在正式跑数据之前我花了不少时间重新梳理ORB-SLAM3单目IMU的数学原理。理解原理不是为了发论文而是为了在实际问题中定位故障。IMU和视觉的融合本质上是一个状态估计问题。系统状态包括相机位姿位置和姿态、速度、IMU零偏bias、以及当前地图点的逆深度或三维坐标。视觉部分提供重投影误差约束IMU部分提供预积分约束二者通过因子图Factor Graph或滑动窗口优化联合求解。IMU的数据频率高通常是100Hz到200Hz视觉帧率低通常是20Hz到30Hz。两者融合的直观好处是在两次视觉帧之间IMU可以频繁积分给出短时间内的相对运动预测而视觉观测则周期性地修正IMU积分带来的累积漂移。反过来当相机快速旋转或者运动模糊导致视觉失配时IMU依然能维持一段时间的合理位姿估计。4.2 初始化阶段尺度、重力、速度与零偏的估计单目IMU模式对初始化极其敏感我实际测试中至少有一半的失败都发生在初始化阶段。ORB-SLAM3的初始化主要做了这么几件事视觉初始化利用基础矩阵或者单应矩阵恢复初始的稀疏特征点深度和初始帧间运动这个阶段得到一个无尺度的相机轨迹。IMU联合初始化利用视觉给出的帧间相对位姿和IMU的角速度/加速度测量估计出一个真实的尺度因子、重力方向相对于相机坐标系的朝向以及每一帧的速度。这一步的核心思路是构建一个线性最小二乘问题将IMU预积分项和视觉相对运动之间的残差最小化。零偏初始化对加速度计和陀螺仪的零偏做初始估计这一步在后续优化中会不断细化。这个过程要求IMU有充分的激励。什么叫充分的激励就是IMU在初始化阶段必须经历足够的加速度变化和角速度变化。如果你把设备放在桌上静止不动或者用极其缓慢均匀的速度平移IMU无法观测到重力之外的其他加速度信息线性化系统会退化初始化就会失败或者给出一个离谱的尺度。这在我实际操作中体会特别深——我一开始用一段很“温和”的手持数据去跑结果初始化花了很长时间而且尺度偏差巨大。换上一段有加速、有转弯的数据之后系统几乎在1秒内就完成了初始化。4.3 相机-IMU外参标定值的准确度决定上限ORB-SLAM3的配置文件中需要给定相机到IMU的外参即IMU坐标系在相机坐标系下的位置平移向量和姿态旋转四元数。这个外参的重要性常常被忽略。如果你用的数据集是EuRoC官方文档里给出了精确的外参直接用即可。但是如果你使用自己采集的数据这个外参必须经过标定。外参不准有什么后果最典型的表现是初始化阶段即使成功了优化后的轨迹会呈现出系统性的漂移特别是旋转部分。因为视觉和IMU两个传感器对同一个运动的观测视角不同如果外参错误残差计算从一开始就是错的优化器只能通过调节其他状态变量比如零偏来“硬凑”长期下来零偏估计也会有偏最终位姿精度大幅下降。我自己在测试时故意把旋转外参的一个分量改错5度结果轨迹的终点误差从0.3米变成了1.8米差距非常明显。所以如果你用的是自采数据建议先用Kalibr或imu_utils做一次完整的相机内参、IMU内参和相机-IMU外参标定再进ORB-SLAM3。4.4 yaw方向的慢漂移为什么会有、能不能消除在实际测试EuRoC序列的时候我注意到一个现象即使整个SLAM过程没有丢帧、没有重定位轨迹的yaw角偏航角依然会存在一个非常慢的漂移。这其实是单目IMU模式下的一个共性问题。原因要从可观测性角度去理解。IMU的重力向量在观测方程中扮演了“绝对参考”的角色它决定了roll横滚和pitch俯仰两个方向的可观性也就是说这两个方向的角度误差会被重力观测持续修正。但是yaw方向呢重力向量是一个平行于竖直方向的向量绕竖直方向的旋转不会改变重力向量所以IMU无法提供yaw方向的绝对参考。yaw的收敛只能依赖视觉观测而纯单目视觉本身也没有绝对的yaw参考单目无法感受绝对的偏航角只能通过特征点的三角化和连续帧匹配来慢慢积累。这带来的直观结果就是yaw必然存在慢漂移这是系统固有属性不是Bug。解决方案通常是引入额外的绝对观测比如磁力计提供地磁航向角、GPS航向、或者地图中的已知方向特征。如果你的应用对航向角精度要求比较高单靠单目IMU是做不到长期无漂移的。理解了这一点你在看轨迹误差的时候就不会过度惊慌。4.5 配置文件中的IMU噪声参数ORB-SLAM3给出的EuRoC yaml配置文件里有一组和IMU相关的参数关键项是Tbc相机到IMU的外参平移和旋转RateIMU数据频率NoiseGyro陀螺仪噪声密度rad/s/sqrt(Hz)NoiseAcc加速度计噪声密度m/s^2/sqrt(Hz)Gravity重力加速度大小这些噪声参数是IMU预积分和滤波器协方差矩阵的基础。如果你的IMU和EuRoC上的IMUADIS16448差异较大务必替换成自己标定的噪声参数。否则可能出现两种典型症状噪声参数设置过小优化器过分信任IMU视觉偏差被忽略轨迹平滑但精度差噪声参数设置过大优化器几乎只信任视觉IMU的作用被削弱初始化容易失败。我在测试中用的是一颗消费级IMUMPU6050和EuRoC的IMU噪声水平差了不止一个数量级。所以我直接把噪声密度调大了一倍左右再结合视觉初始化效果会好很多。但这只是一个经验性的调参方向具体数值还是要依靠Allan方差标定。5. EuRoC数据集实测跑通第一个单目IMU序列5.1 数据集下载与目录整理EuRoC MAV数据集是苏黎世联邦理工ETH发布的无人机视觉惯性数据集里面有双目灰度图像和IMU数据并提供了Vicon和Leica的ground truth轨迹。我们用它的MH_01到MH_05序列测试单目IMU模式。下载时要注意版本。EuRoC提供ASL格式和ROS bag两种格式ORB-SLAM3官方示例使用的是ASL格式目录结构是MH_01/ ├── mav0/ │ ├── cam0/ │ ├── cam1/ │ ├── imu0/ │ ├── leica0/ │ └── state_groundtruth_estimate0/下载解压后MH_01目录下的路径就是这个结构。ORB-SLAM3运行程序接收的第二个参数就是指向这个mav0目录的路径所以解压之后别擅自改动目录结构。下载建议用官网的网盘或者学术镜像文件比较大MH序列每个大约2到4GB注意预留磁盘空间。我通常是放在/data/euroc/MH_01/mav0这种路径下。5.2 配置文件参数解读运行单目IMU模式的EuRoC程序需要显式指定三个内容ORB词表文件、配置文件、时间戳文件。其中配置文件是关键路径是Examples/Monocular-Inertial/EuRoC.yaml。这个文件是ORB-SLAM3对EuRoC数据集预先标定好的参数文件。打开这个yaml能看到几个关键参数Camera.fx/fy/cx/cy相机内参EuRoC的MH序列用的是全局快门相机内参基本一致Camera.k1/k2/p1/p2畸变系数Camera.width/height图像尺寸EuRoC左目是752x480Camera.fps视觉帧率EuRoC是20fpsIMU.Tbc相机到IMU的外参这里是四元数平移的写法IMU.NoiseGyro/NoiseAccIMU噪声参数ORBextractor.nFeatures每帧提取的特征点数量默认1000Viewer和System相关参数线程数、可视化开关等这里特别提醒一个细节Camera.fps参数不仅影响时间戳读取还影响ORBextractor中特征点金字塔层数和关键帧判定。如果你用的是自采数据这里必须改成你相机实际帧率不能照抄EuRoC的20。还有IMU.Rate它定义的是IMU传感器数据频率。ORB-SLAM3的IMU预积分代码会用这个频率来计算相邻IMU测量之间的时间间隔。如果实际IMU数据频率和配置不一致预积分的时间间隔就会出错位姿估计会快速发散。5.3 运行命令与日志关键输出运行命令如下./Examples/Monocular-Inertial/mono_inertial_euroc \ Vocabulary/ORBvoc.txt \ Examples/Monocular-Inertial/EuRoC.yaml \ /data/euroc/MH_01 \ Examples/Monocular-Inertial/EuRoC_TimeStamps/MH01.txt这里的第四个参数是时间戳文件ORB-SLAM3会根据这个文件去数据集中读取对应的图像。时间戳文件每一行是一个时间戳必须和cam0目录中的图像文件名对应。EuRoC自带的时间戳文件在Examples/Monocular-Inertial/EuRoC_TimeStamps/目录下文件名类似MH01.txt。运行之后终端会有大量输出。关键看几行初始化相关程序会在视觉初始化完成后开始联合初始化IMU。如果看到类似Initialization from IMU has been completed的日志说明IMU初始化成功这是整个过程中最关键的节点。Tracking跟踪状态实时输出当前图像帧的编号、关键帧数量、局部地图点数量、相机位姿等。在运行结束时会输出统计信息包含平均跟踪时间、关键帧数量、局部地图优化次数等。如果你的终端没有出现初始化完成的日志而是一直在Attempting initialization循环说明IMU初始化失败。这时候不要急着改代码先回忆一下我前面说的IMU激励条件大概率是数据太温和或者IMU噪声设置不合理。5.4 轨迹输出与精度评估ORB-SLAM3在运行结束后会生成一个以f开头的轨迹文件比如f_vio_estimated.txt或者KeyFrameTrajectory_TUM_Format.txt位置一般在可执行文件所在的目录下。如果你没有显式关闭保存默认就会生成。这个轨迹文件主要记录的是每一帧相机在世界坐标系下的位姿位置和四元数。要和EuRoC的ground truth做对比可以用evo工具pip install evo evo_ape tum groundtruth.txt estimated.txt -a-a参数表示先做一次Umeyama对齐因为单目IMU虽然恢复了尺度但和ground truth的坐标系定义可能没有完全对齐。对齐后的ATEAbsolute Trajectory Error是你的SLAM系统精度的直接体现。我在MH_01上跑出来的ATE大概是0.4到0.6米左右的误差水平具体数值取决于运行次数和初始化质量。值得注意的是ORB-SLAM3在多次运行时结果并不完全一致因为ORB特征提取、RANSAC、以及线程调度都存在随机性这是很正常的现象评估时应取多次运行的平均值。6. 高频问题与排查速查表6.1 编译期问题问题症状解决办法Pangolin版本不兼容Viewer.cc报大量接口错误切换到Pangolin v0.8 tag重新编译多个OpenCV版本冲突DBoW2或ORB_SLAM3主库报cv符号错误指定/usr目录下的OpenCV4.2或临时移除冲突cmake文件Eigen版本过新g2o编译报模板断言失败卸载Eigen 3.4apt安装libeigen3-dev3.3.7内存不足make过程编译器崩溃或OOM降低并行编译数make -j4找不到PangolinCMake阶段报Could not find Pangolin确认执行过sudo make install并检查环境变量缺少系统依赖编译过程中报缺少头文件对照install_prerequisites.sh安装X11、GL、GLEW等依赖6.2 运行期问题问题症状解决办法初始化一直不成功日志反复出现Attempting initialization检查IMU激励是否充分、IMU噪声参数是否合理尺度因子异常轨迹尺度偏离ground truth很大检查是否成功完成联合初始化检查IMU外参是否正确运行中途跟踪丢失Tracking lost频繁出现检查相机帧率配置、ORB特征点数量、数据质量yaw漂移轨迹整体朝向逐渐偏移这是单目IMU的固有特性非Bug可加磁力计或GPS外源修正轨迹文件没生成运行结束后找不到f_vio_estimated.txt检查系统设置里是否关闭了保存轨迹的选项6.3 我的调参经验在调参上我最深的体会是不要一开始就动ORB特征点数量先检查输入的IMU信息是否正确。很多初始化问题其实不是特征点数量不够而是IMU数据的频率、时间戳、外参这些底层的“物理参数”不对。如果说有一点实用的调参技巧那就是在拿到一个完全陌生的数据集时先把视觉跟踪跑起来只跑纯单目模式不启用IMU确认视觉本身没问题再加上IMU做联合初始化。这样能精准定位问题出在视觉环节还是惯导环节避免一次改一堆参数导致问题更难排查。我在调试自采数据时基本都是这个套路。最后再分享一个小技巧在调试IMU相关问题时把ORB-SLAM3的轨迹输出和IMU原始数据一起画出对比图。在evo里跑一个evo_traj对比能让漂移问题看得一清二楚。纸上分析数据永远比盯着终端日志更高效。这也是我个人在整个运行记录中最受益的操作方式。