1. 先说清楚DynaSLAM是什么,以及为什么这么多人在Ubuntu 18.04上折戟
在动态环境下做视觉SLAM,是所有搞机器人感知的人迟早要面对的坎。静态场景里跑得好好的ORB-SLAM2,一旦有人从镜头前走过,或者有车辆、动物闯入视野,地图点就会被污染,位姿估计开始飘,严重的直接崩溃。DynaSLAM就是针对这个问题的开源项目:它用Mask R-CNN对每一帧做语义分割,把人和车这些动态目标先“抠掉”,再让SLAM只基于静态区域做跟踪和建图,从而在动态场景里保持稳定。
我为什么专门写Ubuntu 18.04?因为这是我在这个系统上从零跑通整个项目之后,被问过最多的问题:Pangolin编译不过、PyTorch路径配不上、权重文件加载崩、运行脚本路径不对……十个人有九个卡在半路。这篇就把我自己的配置全过程、踩过的坑、临时绕路的方案全部记下来,给后来人一个能直接照着走的参考路径。
先说结论:这个项目本身不复杂,复杂的是它把ORB-SLAM2、Mask R-CNN、PyTorch C++ API、Pangolin可视化绑在了一起,任何一环版本不匹配都会连锁报错。接下来我会先讲版本选型,再给逐步编译过程,最后是运行测试和报错速查。如果你只是想要一个“能跑起来的Demo”,照着做就行;如果你想理解为什么这样配置,每一段我也会解释清楚。
1.1 动态环境下的SLAM痛点
传统几何SLAM有个核心假设:场景是静态的。特征点提取完之后,算法假设这些点在三维空间里是固定不动的,然后用它们去估计相机运动。这个假设在办公桌、走廊、户外静态场景下成立,但一旦有人从画面里走过,人的身体上也会提出来一堆特征点,这些点在世界坐标系里的位置是不断变化的——它们本质上是“错误观测”。
正确做法有两个方向:一个是把动态区域检测出来、在特征提取阶段就过滤掉;另一个是只对静态区域的特征做优化,动态区域的特征不参与位姿计算。DynaSLAM选的是用语义分割网络直接生成动态对象的像素级掩码,然后把这些像素对应的特征全部剔除,只保留静态区域。
听起来简单,但要在实际系统里落地,就必须同时处理两件事:一是分割要足够准,漏掉一个行人,特征还是会被污染;二是分割速度要够快,否则SLAM的实时性就没了。DynaSLAM给了一个折中方案:用Mask R-CNN做高精度分割,但允许它跑到较低帧率,SLAM主线程和分割线程并行,不互相阻塞。这种架构也决定了它真正跑起来时的性能瓶颈通常在GPU上,而不在CPU。
1.2 DynaSLAM的工作方式
DynaSLAM不是完全从零写的新系统,它的静态部分基于ORB-SLAM2的框架修改而来。整个项目主要分成两个模块:
SLAM主模块沿用ORB-SLAM2的线程结构——跟踪线程、局部建图线程、回环检测线程。区别在于,每一帧图像在进入特征提取之前,会先被动态掩码处理:掩码覆盖掉的像素区域在特征提取时被直接忽略。Mask R-CNN负责在线生成掩码,同时也保存一份几何分割结果作为补充(基于多视图几何的一致性判断),两条分割路径的输出做融合后使用。
我在实际编译和运行中体会最深的一点是:DynaSLAM对OpenCV、Pangolin、PyTorch C++这三个生态的依赖交织得非常紧,任何一个库的版本换掉,都可能出现诡异的链接错误。比如Pangolin如果用了太新的master版本,ORB-SLAM2里的老代码编译时会直接报API不存在的错。所以配置的开销其实不是某个库本身难装,而是在于你对这一整套生态的版本组合要有整体概念。
1.3 为什么18.04是配置的分水岭
Ubuntu 18.04默认带有GCC 7.3、CMake 3.10、Python 3.6,这些版本单独看都够用,但组合在一起就有意思了:DynaSLAM的老代码里很多是C++11风格,而GCC 7默认编译标准是C++14,虽然大部分代码兼容,但在g2o、DBoW2这些第三方库里偶尔会触发老标准下的编译警告甚至错误。不统一处理,就会在make过程中莫名其妙挂掉。
另外,18.04软件源里的OpenCV是3.2版本,而很多人习惯装新一点的OpenCV 3.4或4.x,一旦apt装的库和自编译的库混在一起,C++头文件冲突的概率会瞬间变大。很多人在这一步卡住,是因为“明明我OpenCV装好了,编译还是说找不到头文件”——其实是有两个OpenCV共存,CMake找到了不是你预期的那一个。
所以后面所有步骤里,我都会强调版本选型,而不是只给一条安装命令。记住这句话:配置DynaSLAM不是装一个库,而是给这一套依赖链锁定一组互不打架的版本。
2. 版本选型与预检:决定你三个小时后是在跑Demo还是在重装系统
在动手敲安装命令之前,我强烈建议先花二十分钟做一轮环境预检。不要急着clone代码,不要急着装库。先搞清楚你手头机器的显卡、驱动、CUDA版本、磁盘空间,再决定依赖怎么装。这样比盲目执行教程里的命令靠谱得多。
2.1 先确认你的显卡、驱动和CUDA
DynaSLAM的动态分割部分有两个选择:完全用CPU跑PyTorch,或者用CUDA加速。CPU版理论上也能编译,但每一帧Mask R-CNN推理可能要好几秒,只适合拿来验证流程,不适合做实时Demo。所以如果你有NVIDIA显卡,我建议优先走CUDA这条路。
预检命令很简单:
nvidia-smi nvcc --versionnvidia-smi能看到你的驱动版本和支持的最高CUDA版本。nvcc是CUDA编译器,如果你装了CUDA toolkit,它会显示具体版本。我的建议是CUDA 10.2或11.x都可以,关键要匹配你后面要装的PyTorch版本。比如你选了PyTorch 1.6的libtorch,它对CUDA 10.2和11.0都有对应包,不要选一个特别新的PyTorch然后配一个很老的CUDA,那样加载时会报CUDA driver version is insufficient之类的问题。
2.2 依赖库版本对照
我把自己最终跑通的版本组合列出来,你可以直接照抄,也可以在这个基础上微调:
| 组件 | 推荐版本 | 说明 |
|---|---|---|
| Ubuntu | 18.04 | 本教程基准系统 |
| GCC/G++ | 7.3.0 | 系统默认即可 |
| CMake | 3.10+ | 系统源里的版本够用 |
| OpenCV | 3.4.x(或直接用apt的3.2) | 建议apt安装,避免混用 |
| Eigen3 | 3.3.7 | apt安装即可 |
| Pangolin | v0.6 | 不要用最新master |
| DBoW2 | 仓库自带 | 随DynaSLAM源码编译 |
| g2o | 仓库自带 | 需显式指定C++11 |
| PyTorch/libtorch | 1.6或1.7 | 需匹配CUDA版本 |
| Python | 3.6 | 系统自带 |
这张表里最需要记住的规则是:Pangolin锁定v0.6,OpenCV用一套就够,libtorch版本必须和你选的CUDA版本对应。
2.3 目录结构和源码版本
我习惯把项目放在一个专门目录下,方便整理,也方便后面写脚本。举例:
mkdir -p ~/Projects/DynaSLAM cd ~/Projects git clone https://github.com/.../DynaSLAM.git源码clone下来之后,建议先看一眼目录结构,找到Thirdparty文件夹。DynaSLAM会把ORB-SLAM2用到的DBoW2和g2o放在这个目录里,不需要你单独去clone一个ORB-SLAM2。如果你之前已经单独配过ORB-SLAM2,也别急着复用,因为DynaSLAM对ORB-SLAM2有定制修改,版本错位会导致符号找不到。
2.4 那个容易被忽略的C++标准问题
这个坑我单独拿出来讲,因为它在编译过程中反复出现。GCC 7默认用-std=gnu++14,但ORB-SLAM2系列的老代码和旧版g2o里,有一些依赖C++11特性的写法,在C++14标准下不是100%兼容。最典型的报错是nullptr未声明、lambda表达式写法不兼容等。
解决办法不是去改源码,而是在编译第三方库时显式传入C++11标准:
cmake -DCMAKE_CXX_FLAGS="-std=c++11" ..这个参数对DBoW2、g2o尤其重要。如果你在编译DynaSLAM主项目时遇到莫名奇妙的模板错误,先检查是不是C++标准导致的。
3. 一步步编译记录:从Pangolin到ORB-SLAM2再到DynaSLAM主工程
这部分的记录按实际安装顺序来,每一步我都写了当时的观察和判断,尽量让你知道为什么要执行这条命令,而不仅是复制粘贴。
3.1 系统依赖与Python环境的准备
先装基础编译工具和OpenCV相关依赖。如果你确定要自己编译OpenCV,可能会多花一两个小时;我实际测试下来,直接用系统源里的OpenCV 3.2也能满足DynaSLAM大部分功能,所以推荐先走apt路线,遇到功能缺失再去补。
sudo apt update sudo apt install -y build-essential git cmake pkg-config \ libgtk2.0-dev libavcodec-dev libavformat-dev libswscale-dev \ libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev \ libeigen3-dev libboost-all-dev libglew-dev \ python3-dev python3-pip这里有一个我踩过的小坑:libglew-dev和libx11-dev一定要装,Pangolin的可视化依赖它们。如果缺了,编译Pangolin时你会看到一个关于GL/gl.h找不到的错误,但错误信息通常不会直接说是缺glew,而是报一堆和OpenGL相关的头文件缺失。
Python方面,DynaSLAM下载权重和生成掩码时会用到Python脚本。18.04自带Python 3.6,够用。再装一下必要的Python包:
pip3 install --user numpy scipy opencv-python如果是国内网络,记得先把pip源换成镜像源,否则下载会非常痛苦。
3.2 Pangolin 0.6的编译与安装
Pangolin是ORB-SLAM2系项目的可视化库。我这里专门强调版本v0.6,是因为新版本Pangolin的接口变化很大,比如pango_display相关API被重构,老代码编译时会出现函数签名不匹配。不要图新,直接按v0.6来。
cd ~/Projects git clone https://github.com/stevenlovegrove/Pangolin.git --branch v0.6 cd Pangolin mkdir build && cd build cmake .. make -j4 sudo make install编译时如果报错说找不到X11/Xlib.h,就是缺libx11-dev。解决办法是:
sudo apt install -y libx11-dev安装完成之后,可以在终端里检查一下头文件是否存在:
ls /usr/local/include/pangolin如果这个目录为空,说明Pangolin没装上,后面的所有编译都会在#include <pangolin/pangolin.h>这一行失败。
3.3 DBoW2和g2o单独编译
这两个库在DynaSLAM的Thirdparty目录里,是ORB-SLAM2跑起来的基础。DBoW2负责词袋模型,g2o负责图优化。这两个库的CMakeLists其实是给顶级项目调用的,但你也可以独立编译一次,提前暴露环境问题。
我的做法是先单独编一遍,确认真没问题,再编主工程,这样可以缩小排错范围:
cd ~/Projects/DynaSLAM/Thirdparty/DBoW2 mkdir build && cd build cmake -DCMAKE_CXX_FLAGS="-std=c++11" .. make -j4然后是g2o:
cd ~/Projects/DynaSLAM/Thirdparty/g2o mkdir build && cd build cmake -DCMAKE_CXX_FLAGS="-std=c++11" .. make -j4g2o编译时间会比较长,建议用-j4不要用-j16,避免同时编译多个目标时内存溢出。有时候用-j参数过多会导致编译进程被系统杀死,不是代码问题,是资源问题。
3.4 ORB-SLAM2部分的编译
DynaSLAM的ORB-SLAM2部分编译方式和原始ORB-SLAM2类似,但不要用原始ORB-SLAM2的build脚本,直接用DynaSLAM自己的CMakeLists。先确认你已经把所有依赖装齐,然后执行:
cd ~/Projects/DynaSLAM mkdir build && cd build cmake .. make -j4这一步可能会遇到两个常见问题,我分别说下怎么处理:
第一个是OpenCV相关错误:error: opencv2/xfeatures2d.hpp: No such file or directory,这是因为你没有安装OpenCV的contrib模块。如果确实需要xfeatures2d,那就只能编译带contrib的OpenCV 3.4;如果不需要,可以考虑检查DynaSLAM源码里是否引用了非必要的头文件。实际中我用apt的OpenCV,这个错误没有出现。
第二个是Eigen3找不到:CMake Error: The following variables are used in this project but set to NOTFOUND: EIGEN3_INCLUDE_DIR。解决办法是确保libeigen3-dev已安装,如果还是找不到,在CMakeLists里手动指定Eigen3目录:
cmake -DEIGEN3_INCLUDE_DIR=/usr/include/eigen3 ..3.5 PyTorch绑定和主CMakeLists的调整
DynaSLAM的动态分割部分需要加载PyTorch模型,所以要用libtorch(PyTorch的C++ API)。这里是整个配置过程最容易翻车的环节,几乎所有人都会在这里卡一轮。
先下载和你CUDA匹配的libtorch版本。例如你选CUDA 10.2,就在PyTorch官网选择对应的libtorch pre-cxx11 ABI版本或默认版本。把压缩包解压到某个固定目录,比如/opt/libtorch,然后修改DynaSLAM主工程的CMakeLists.txt,加上PyTorch的头文件和库路径。
以我当时的修改为例,在CMakeLists.txt里加入类似这样的内容:
set(TORCH_INSTALL_DIR "/opt/libtorch") include_directories(${TORCH_INSTALL_DIR}/include) include_directories(${TORCH_INSTALL_DIR}/include/torch/csrc/api/include) link_directories(${TORCH_INSTALL_DIR}/lib) find_package(CUDA REQUIRED)然后在target_link_libraries部分加入libtorch相关库:
target_link_libraries(DynaSLAM ${TORCH_INSTALL_DIR}/lib/libtorch.so ${TORCH_INSTALL_DIR}/lib/libtorch_cpu.so ${TORCH_INSTALL_DIR}/lib/libc10.so )注意,如果你下载的是GPU版libtorch,还会有一个libtorch_cuda.so,取决于版本名称。链接时如果不确定具体库名,先ls /opt/libtorch/lib看一下。
这里有个关键坑:libtorch有两种ABI版本,一种带了_GLIBCXX_USE_CXX11_ABI=1,另一种是pre-cxx11 ABI。如果DynaSLAM编译时报的错和std::string、std::vector等标准库类型对不上,十有八九是ABI不匹配。解决办法是统一在你编译DynaSLAM时也设置相同的_GLIBCXX_USE_CXX11_ABI值,或者干脆选pre-cxx11版本的libtorch。
3.6 分割权重的下载和放置
编译通过只是第一步,模型权重没放对位置,运行起来照样崩。DynaSLAM需要两个掩码生成相关文件:一个是PyTorch模型权重,一个是Mask R-CNN的Keras/H5权重(用于另一种分割分支)。阻塞的地方在于这些文件体积大,下载容易中断。
项目里通常会有下载脚本,放在scripts目录下。如果没有,你需要手动找到对应下载链接,把权重放到Data/models这样的目录结构下,文件名要和代码里加载的名称完全一致。常见的是mask_rcnn_coco.pth和mask_rcnn_coco.h5。
下载完之后,最好检查一下文件大小是否合理。如果你下到一个几KB的HTML错误页,运行时会报Archive contains no dataset之类的原因,那时就得回头重新下载。
4. 跑起来之后的事:数据集路径、权重加载和第一次运行的真实报错
编译通过不等于立刻能看到运行界面。我第一次编译成功之后,兴冲冲运行,结果在初始化阶段就卡住了,连续蹦出两个问题。这里把运行环节的细节也记录下来。
4.1 数据集准备和配置文件路径修改
DynaSLAM的RGB-D demo需要一个公开的RGB-D benchmark序列。下载时注意序列的命名和压缩包的组织方式:解压之后,序列的根部应该直接是rgbd_dataset_fr1_xxx这样的文件夹,里面包含rgb/、depth/、groundtruth.txt等。如果你解压后发现多了一层嵌套目录,运行时会因为找不到图像而报错。
我的习惯是把数据集放到项目外部的一个独立目录,比如~/Data/RGBD,然后运行前把路径写清楚。避免把数据放到项目目录里,否则后面清理代码仓库时容易误删。
4.2 运行脚本与启动参数
一般运行命令类似:
./Examples/RGB-D/rgbd_tum \ Vocabulary/ORBvoc.txt \ Examples/RGB-D/TUM1.yaml \ ~/Data/RGBD/rgbd_dataset_fr1_deskDynaSLAM还提供了带mask输出的版本,它可能会先生成掩码并写入指定文件夹,再使用掩码进行SLAM。运行前要确保掩码输出目录存在,否则程序会直接退出。
如果你是用GPU跑分割网络,命令行里可能还要指定是否使用几何分割、是否使用Mask R-CNN分割,具体参数在源码的示例配置里有说明。不要看到参数就全开,先把最简路径跑通。
4.3 第一次运行中常见的崩溃点
我的第一次运行崩溃在权重加载阶段,报错是文件路径找不到,最后发现是current working directory不对——我直接在build目录里运行,但它去找的是上一级目录下的Data/models。解决办法是回到项目根目录再运行,或者在命令行里指定绝对路径。
第二个崩溃在分割网络初始化阶段,报错涉及CUDA。原因是我的libtorch编译时选了GPU版本,但运行时没有正确设置LD_LIBRARY_PATH,或者libtorch的CUDA依赖库没被找到。处理方式是在运行前设置环境变量:
export LD_LIBRARY_PATH=/opt/libtorch/lib:$LD_LIBRARY_PATH这两个问题都属于“环境变量和路径”类,解决了之后,项目跑起来的概率就大很多。
5. 我把配置期的错误整理成了一张速查表
为了让后来者不用一条条翻上面的文字,我把这段时间遇到的所有高频错误统一放在这张表里。有类似报错的直接对照查:
| 报错现象 | 根本原因 | 处理方法 |
|---|---|---|
fatal error: pangolin/pangolin.h: No such file | Pangolin未正确安装 | brew/apt或源码安装Pangolin v0.6,确认头文件在/usr/local/include/pangolin |
Eigen3 not found | 缺少libeigen3-dev或CMake路径不对 | 安装libeigen3-dev,或在cmake命令中指定EIGEN3_INCLUDE_DIR=/usr/include/eigen3 |
error: ‘nullptr’ was not declared | 编译标准太低/太高导致旧代码不兼容 | 对第三方库使用-std=c++11,不要用-std=c++17 |
libtorch ... undefined symbol | libtorch ABI不匹配 | 使用相同_GLIBCXX_USE_CXX11_ABI,或换libtorch的pre-cxx11版本 |
CUDA error: driver version is insufficient | CUDA版本和PyTorch版本不匹配 | 降低libtorch版本,或升级显卡驱动 |
Archive contains no dataset | 权重下载不完整或下载到了错误文件 | 重新下载权重,核对文件大小 |
Segmentation fault (core dumped) | 路径配置不对或内存资源不足 | 先检查路径,再检查GPU/内存占用 |
The requested image has no data | 数据集路径错误或嵌套层级不对 | 确认序列文件夹结构是否正确 |
5.1 高频错误速查表(补充)
上面这些错误里,最让我印象深刻的是Segmentation fault。这个报错太笼统了,容易让人摸不着头脑。实际排查时,我建议先用gdb跑一下程序,看崩溃发生在哪个函数,再对照是路径问题还是资源问题,不要盲猜。
另一个高频坑是make -j并发过高导致编译崩溃。很多人一上来就make -j16,然后编译到一半进程被操作系统kill掉。这不是代码问题,而是内存不够。我的经验是:如果内存小于16GB,-j4是最安全的;如果内存充足,再考虑-j8。
5.2 几条配置实操心得
第一条:每次执行cmake之前,如果改了CMakeLists,最好把build目录里的CMakeCache.txt删掉,或者直接删掉build目录重新建。否则CMake会缓存上一次的配置,导致新路径不生效。
第二条:不要把多个版本的OpenCV混在一起。系统里同时存在系统的OpenCV 3.2和你自己编译的OpenCV 4.x时,pkg-config --modversion opencv可能都正常,但CMake的find_package(OpenCV)会随机找其中一个。为了省事,我只保留了apt版本。
第三条:遇到编译错误先去读第一个错误,而不是看最后几行。真实的报错往往在上面,下面一大堆全是连锁反应。这个建议对DynaSLAM这种多层依赖项目尤其适用。
6. 写在最后的一些体会
DynaSLAM整套配置下来,成败关键其实不在某一条命令,而在你对“依赖链整体”的把握。每个库单独装都不难,但组合起来就是另一回事。我之后又在一台干净机器上重新走了一遍流程,把安装命令整理成脚本,半小时内就能跑通,比第一次手动配置快得多。所以如果你想在别的机器上复现,建议也把环境准备这步脚本化,避免重复踩坑。
个人实际体会有两点:一是不要迷信最新的依赖版本,DynaSLAM这种老代码项目,用文档时代对应的版本往往最省事;二是运行阶段一定要养成看程序当前工作目录的习惯,很多路径问题都源于运行目录不对。
如果你配完这个项目还想继续深入,可以试试把mask生成部分替换成更快的分割网络,或者把分割模块和SLAM线程并行化,这些都是很好的扩展方向。至少对我来说,折腾完DynaSLAM之后再去看别的动态SLAM方案,整个思路都清晰了很多。