1. 项目概述DSP-SLAM是什么为什么值得折腾一遍先说结论DSP-SLAM是一套把语义级物体先验融进稠密SLAM建图框架里的开源系统说白了就是让机器人在建图的同时不仅知道墙在哪、桌子在哪还能通过预先训练好的3D物体模型把这些物体以“可识别、可操作”的方式直接重建出来。我是在一个室内移动机器人项目里需要语义级障碍物感知时才盯上它的当时在Ubuntu 20.04上折腾了差不多三个整天踩了一堆编译和运行期的坑最后把整个流程跑通之后回头再看这套代码其实它的架构思路非常清晰只要你把依赖环境准备好编译和运行并没有想象中那么劝退。这篇文章就是把我当时在Ubuntu 20.04下配置DSP-SLAM的完整过程、踩坑记录、配置文件修改心得全部整理出来给正在跟这套代码搏斗的人一个可以直接“抄作业”的参考。如果你是做视觉SLAM、语义建图、机器人导航方向的研究生或者工程师又或者你只是对“语义先验如何和传统几何SLAM结合”感兴趣这篇文章都值得往下看。DSP-SLAM的核心创新点在于它没有把物体检测当作一个后处理步骤而是把物体的3D模型通过DeepSDF学出来的隐式曲面直接放进SLAM的优化框架里让这些物体模型反过来约束相机位姿和地图点。这意味着它跑出来的地图不只是“一堆点云”而是“一幅带有物体级语义标签的结构化地图”——比如你在客厅走一圈地图里除了点云墙还有一个单独建模的沙发物体。这种表示对后续的机器人抓取、物体操作、人机交互都非常有价值。我实测下来的总体感受是这套代码对环境的挑剔程度属于“中等偏上”不算是那种开箱即用的项目但只要你的依赖版本卡准按顺序编译基本不会遇到无解的问题。下面我把整个配置过程拆开讲每步都给出我当时为什么这么做、做了什么、遇到了什么问题以及最终怎么解决的。2. 环境准备与依赖选型思路2.1 为什么选Ubuntu 20.04底层依赖怎么对应DSP-SLAM的代码仓库明确支持Ubuntu 20.04官方README里给出的是基于ROS Noetic以及ORB-SLAM3的依赖体系。但注意它其实不强制要求装ROS你完全可以在纯Ubuntu 20.04系统上编译运行只是它内部有一部分代码把ROS的可选依赖包出来了——如果你不打算接机器人平台完全可以关掉ROS相关的宏定义。系统层面的第一件事是确认编译器版本。Ubuntu 20.04默认的GCC是9.xDSP-SLAM要求C17标准用GCC 9完全没问题。不建议你用Ubuntu 22.04去跑因为22.04的GCC是11.xOpenCV版本也更激进编译时会遇到更多ABI兼容问题没必要给自己加戏。然后是关键依赖库的选型我这里直接列一个我当时实测通过的版本组合依赖库推荐版本说明Eigen33.3.7或更高线性代数基础库建议用apt安装OpenCV3.4.x或4.2.0图像处理和相机标定相关4.x也可以Pangolin0.6commit 7b9b3c可视化窗口库建议从源码编译指定版本CUDA11.0/11.1/11.2需要GPU支持用于神经网络推理cuDNN8.0/8.1与CUDA配套即可g2o、DBoW2ORB-SLAM3内置版本不需要单独安装跟着源码编译提示CUDA和cuDNN版本一定要配对不要盲目装最新的。DSP-SLAM里DeepSDF的代码是基于PyTorch的C部署方式编译的PyTorch对CUDA版本非常敏感我用CUDA 11.0 cuDNN 8.0 PyTorch 1.7.1这组组合顺利通过编译目前来看是兼容性比较稳的搭配。2.2 CUDA和cuDNN安装的实操记录如果你机器上已经有NVIDIA驱动可以先在终端里输入nvidia-smi确认驱动支持的CUDA版本。这一步非常关键因为驱动决定的最高CUDA版本是硬上限。比如你的驱动是470.x那它最高支持CUDA 11.4你装CUDA 11.0就完全没问题。安装CUDA 11.0的话我用的是runfile方式建议不要用deb方式因为deb会把驱动也一起装如果不小心覆盖了现有驱动NVIDIA驱动和系统的内核模块一旦对不上重启后会直接黑屏。我当时为了避免麻烦选择把runfile下载到/tmp目录执行并且在安装选项里取消勾选Driver只安装CUDA Toolkit本身。sudo sh cuda_11.0.3_450.51.06_linux.run --toolkit --silent --override装完之后一定要在~/.bashrc里加上环境变量否则编译时找不到nvccexport PATH/usr/local/cuda-11.0/bin:$PATH export LD_LIBRARY_PATH/usr/local/cuda-11.0/lib64:$LD_LIBRARY_PATH export CUDA_HOME/usr/local/cuda-11.0cuDNN就更简单去NVIDIA官网下载对应CUDA 11.0的cuDNN 8.0压缩包然后解压把头文件和库文件拷贝到CUDA目录下即可。我当时下载的是cudnn-11.0-linux-x64-v8.0.5.39.tgz解压后执行sudo cp cuda/include/cudnn.h /usr/local/cuda-11.0/include/ sudo cp cuda/lib64/libcudnn* /usr/local/cuda-11.0/lib64/ sudo chmod ar /usr/local/cuda-11.0/include/cudnn.h /usr/local/cuda-11.0/lib64/libcudnn*验签的方式是直接编译一遍或者很简单地运行一下python3 -c import torch; print(torch.cuda.is_available())如果返回True说明PyTorch已经能调起CUDA了。这个检查动作虽然基础但是非常值得做因为DSP-SLAM的cmake配置会在找PyTorch时顺便检查CUDA能力如果这里失败后面编译必挂。2.3 Python环境和PyTorch版本的重要性DSP-SLAM在运行阶段需要调用一个预训练的DeepSDF物体模型这部分代码是用C接PyTorch的libtorch来实现的但构建和模型加载时会依赖Python侧的PyTorch来生成一些预处理数据。所以你需要保证Python环境里也有一个能和libtorch版本对得上的PyTorch。我当时在系统里装的是Python 3.8Ubuntu 20.04自带用venv创建了一个干净的虚拟环境然后执行pip install torch1.7.1 torchvision0.8.2为什么强调版本一致因为libtorch和torch的版本如果差太多最典型的错误是undefined symbol或者module not found这种问题排查起来很折磨人。你宁可多花二十分钟把版本对齐也别在编译报错时去猜原因。3. 源码获取与整体架构拆解3.1 从GitHub拉取代码后的目录结构分析DSP-SLAM的官方仓库地址在GitHub上clone时记得带--recursive因为它的第三方依赖比如ORB-SLAM3的子模块是通过submodule方式引入的。git clone --recursive https://github.com/JingwenWang95/DSP-SLAM.git cd DSP-SLAM拉完后你会发现代码结构非常典型核心目录大致有这几个src/SLAM主程序源码包含系统初始化、跟踪、局部建图、回环检测等模块这部分代码大量沿用了ORB-SLAM3的结构如果你之前读过ORB-SLAM3的源码看起来会很亲切。src/DeepSDF预训练DeepSDF模型的加载与推理接口包括如何从shape code解码物体曲面、如何把隐式表示转换为点云等。src/object_slamDSP-SLAM特有的模块专门负责物体级地图的表示和更新包括物体检测结果如何关联、物体模型如何与点云对齐等。Vocabulary/ORB词袋模型文件用于回环检测和重定位这个文件比较大如果下载失败或路径不对回环检测一启动就会崩溃。Examples/测试用的配置文件、运行脚本和数据集读取接口。cmake/所有自定义CMake模块包括寻找依赖库的配置文件。当时我第一次读这套代码时最不习惯的是它把物体检测器做成了一个独立模块但又不依赖ROS的感知管线而是把检测结果缓存成obj文件再在SLAM主线程里异步加载。也就是说你可以拿一张RGBD图像作为输入先检测出沙发、椅子、显示器这类物体然后SLAM系统会尝试把这些检测框对应的点云和DeepSDF生成的物体模型匹配起来。这套流程跑通之后地图里不仅有稀疏的路标点和稠密点云还会把匹配好的物体模型直接“附着”在正确的空间位置上所以后期做物体级导航的时候直接查询这个地图就能拿到“物体在哪里”的信息。3.2 编译顺序为什么要严格按依赖来DSP-SLAM的编译顺序非常讲究我强烈建议按以下顺序执行先单独编译Thirdparty/DBoW2和Thirdparty/g2o因为这两个库是ORB-SLAM3的地基如果你跳过直接编译主项目CMake在查找库文件时会报找不到链接目标。编译src/DeepSDF这个模块依赖libtorch和CUDA是整套代码里编译最慢的部分单独编译的好处是出错时定位方便。最后再编译项目主体src/object_slam。在dsp-slam根目录下我最终用的编译命令组是cd Thirdparty/DBoW2 mkdir build cd build cmake .. -DCMAKE_BUILD_TYPERelease make -j4 cd ../../g2o mkdir build cd build cmake .. -DCMAKE_BUILD_TYPERelease make -j4 cd ../../../src/DeepSDF mkdir build cd build cmake .. -DCMAKE_BUILD_TYPERelease make -j8这样一步步来每一步如果失败你都能很快定位是哪一个第三方库的问题。我见过很多人在根目录直接一个cmake ..就开编结果报错了不知道该查哪只能全删了重来。注意make -j8这种并行编译参数要看你CPU核数来定如果内存不够大比如8GB以下建议用make -j4否则编译过程可能直接把内存挤爆导致卡死。4. 编译过程中的核心坑点与解决方案4.1 libtorch的CMake查找路径问题这一节是整篇文章含金量最高的部分因为几乎所有人编译DSP-SLAM都会挂在同一个地方CMake找不到libtorch。DSP-SLAM的CMakeLists里会通过find_package(Torch REQUIRED)来找libtorch但Torch的CMake配置文件默认不会出现在系统路径里。你必须显式指定Torch_DIR例如下载的libtorch解压在~/libtorch目录下那么cd build cmake .. -DCMAKE_BUILD_TYPERelease \ -DTorch_DIR$HOME/libtorch/share/cmake/Torch这里有个细节如果你是用pip install torch装的PyTorch它的C库并不会被完整安装到系统目录只有libtorch这个独立压缩包才会带有完整的share/cmake/Torch目录。所以我的建议是不要只依赖pip安装的torch来编译一定要单独去PyTorch官网下载对应CUDA版本的libtorch包解压到固定目录再让CMake去找它。我当时下载的是libtorch-cxx11-abi-shared-with-deps-1.7.1cu110.zip解压到~/libtorch之后在~/.bashrc里加了一行export Torch_DIR$HOME/libtorch/share/cmake/Torch这样就省得每次cmake都手动传参了。4.2 OpenCV的版本冲突和未定义引用编译到主程序时另一个高频报错是OpenCV相关的“未定义引用”比如cv::Mat的操作、cv::imread这类接口报链接错误。这种情况下八成是因为你系统里同时装了多个OpenCV版本CMake查到了4.x的头文件但链接时却用了3.x的库两者ABI不兼容。解决方法非常直接把所有OpenCV统一到一个版本。我当时是直接把OpenCV 3.4.15从源码编译安装到/usr/local同时把系统里apt装的OpenCV 4.x标记为不需要避免备选路径干扰sudo apt remove libopencv-dev然后编译OpenCV时CMake参数里建议显式关闭不需要的模块减少编译时间cmake .. -DCMAKE_BUILD_TYPERelease \ -DCMAKE_INSTALL_PREFIX/usr/local \ -DBUILD_EXAMPLESOFF \ -DBUILD_TESTSOFF \ -DBUILD_opencv_python3OFF编译安装完之后再回到DSP-SLAM的build目录把CMake缓存清掉重新配置一遍rm -rf CMakeCache.txt CMakeFiles cmake .. make -j4如果你像我一样之前先用apt装过OpenCV那这一步删缓存是必须做的否则CMake缓存里还残留着旧版本的路径信息恶心得很。4.3 关于-marchnative和指令集兼容的提醒还有一个小坑是某些文档会建议你在编译时给编译器加上-marchnative优化参数但这个参数在DSP-SLAM上未必适用。它会让编译器根据当前CPU的指令集生成优化代码但如果你之后把二进制拷到别的机器上运行或者你用的是虚拟机例如在VMware里跑Ubuntu 20.04虚拟化环境下CPU特性检测可能变得不可靠轻则运行崩溃重则直接非法指令。我的建议是保持Release模式不要额外加-marchnative。如果确实想优化可以选-O2或-O3但别为了那一点点性能提升给自己埋一个运行期雷。5. 运行配置、数据集准备与参数调优5.1 数据集准备Replica与ScanNet实测经验DSP-SLAM官方支持的数据集主要是Replica和ScanNet。我用的是Replica的room_0场景因为它的RGBD数据规模和深度噪声都更适合测试SLAM效果。如果你的数据集是ScanNet格式记得先按官方仓库里提供的脚本把sens文件解压成RGB图、深度图和姿势文件。Replica则简单一些直接下载room0相关的压缩包解压后里面是frame000000.jpg、depth000000.png这类文件以及一个traj.txt姿势文件。在Examples/目录下你需要找一个YAML配置文件比如replica.yaml或者scannet.yaml打开后重点修改以下几项Dataset.cfgFile指向数据集的配置文件路径告诉程序去哪找RGB、深度图的文件夹。Dataset.depthPrefix深度图前缀名不要搞错否则程序找不到深度图。Mesh.voxelSize网格化时的体素大小决定了重建的稠密程度和内存占用。Mesh.margin用于网格化的额外边界范围。我当时实际把Mesh.voxelSize从默认的0.01改成了0.02因为我测试场景比较大0.01会让内存占用爆炸跑一会儿就OOM。这里不是说你一定要改成0.02要根据场景大小和机器配置灵活调整。5.2 关键运行参数解析运行DSP-SLAM的命令行和ORB-SLAM3很像基本格式是./Examples/DSP-SLAM-settings Vocabulary/ORBvoc.bin Examples/Replica/room0.yaml但不同之处在于DSP-SLAM启动时会先尝试加载物体检测结果或物体先验模型你需要提前配置好预训练模型路径。这部分配置写在YAML文件的几个关键字段里比如DeepSDF.modelFile指向预训练的DeepSDF权重文件。DeepSDF.codeLengthshape code的维度一般是64或128不要瞎改要和权重匹配。detector.use_cnn如果置为1则使用CNN实时检测物体如果置为0则跳过检测只做几何重建。从实际运行效果看开着物体检测确实会让跟踪线程变慢因为每次关键帧都要跑一次神经网络的物体识别。如果你只是随便跑通流程建议先关掉use_cnn等整个管线能稳定运行了再打开物体检测功能验证地图里的语义物体效果。5.3 可视化与地图输出的正确打开方式DSP-SLAM的可视化依赖Pangolin启动后会有两个Pangolin窗口一个是SLAM主窗口显示相机轨迹和稀疏地图点另一个是稠密地图/网格窗口显示已重建的稠密表面和物体模型。如果你发现第二个窗口一直黑屏大概率是你修改的配置项里**Mesh相关参数没有生效**或者是在数据集帧类型匹配上出了问题。另外地图输出的结果是.ply格式的网格文件程序会在运行结束后自动保存到当前目录文件名类似mesh_output.ply。你可以用MeshLab或CloudCompare打开检查重建效果。如果你想边跑边实时看建议把Mesh.updateIncrement调大一些比如从1改成5这样网格更新的频率低一点CPU压力小很多。提示如果发现地图漂移、相机轨迹明显弯曲最优先排查的不是DSP-SLAM的代码而是你的标定文件。RGB-D相机在跑DSP-SLAM之前一定要确保深度图和彩色图的配准良好两个相机的内参、外参都要填对。我有个同事直接拿未标定的Realsense参数跑结果轨迹和真值差了半米换了一套标定好之后立刻正常了。6. 常见问题与排查技巧实录6.1 编译期的“未定义符号”该怎么快速定位编译时如果报错形如undefined reference to xxx先别急着搜报错信息第一步是确认依赖库的库文件顺序。CMakeLists里如果链接库的书写顺序不对链接器找不到符号是很常见的尤其是在静态库之间互相依赖的场景。DSP-SLAM里object_slam模块依赖了DeepSDF的静态库而DeepSDF又依赖libtorch所以CMakeLists里必须保证库的排列是“被依赖的库放在后面”。如果你是在自己改了CMakeLists之后出现的未定义符号大概率就是这个原因。建议用cmake --build . --verbose查看实际链接命令检查-l参数的先后顺序。如果顺序确实错了把对应库文件调换一下位置重新链接就能解决。6.2 运行时崩溃段错误和内存不足段错误出现最多的场景是在加载预训练权重之前特别是DeepSDF模型文件路径错误时程序会尝试读取一个空指针直接退出。此时先检查DeepSDF.modelFile路径是不是相对路径如果是相对路径一定要在DSP-SLAM根目录下运行程序否则工作目录不一致就会找不到文件。内存不足的问题在跑大场景Replica时尤其常见。解决办法除了调大Mesh.voxelSize之外还可以在程序启动前用ulimit -s unlimited放大概率栈限制避免某些递归函数在初始化时就把栈打爆。另外如果在虚拟机里运行给虚拟机分配的内存建议至少8GB否则开两个Pangolin窗口后系统会非常卡顿甚至直接被杀进程。6.3 相机位姿不稳定、建图漂移的排查如果你跑出来的轨迹在起始阶段就明显漂移先检查是否用了RGBD相机模式。DSP-SLAM对RGBD模式的依赖度很高如果深度图和彩色图时间戳对不上帧间匹配的ICP就全是噪声。ScanNet数据集的RGB和深度图已经对齐但Replica需要确保你下载的是对齐过的版本。另外如果机器人的运动速度快、场景纹理少跟踪丢失是正常现象。这不算是代码bug而是特征点法SLAM的通病。你可以适当减少相机帧率或者把FeatureExtractor.nFeatures从默认值调高比如从1000调到1500这样特征点多了跟踪鲁棒性会好一些。6.4 高频问题速查表问题现象可能原因解决方法CMake找不到Torch未设置Torch_DIR下载libtorch并设置环境变量编译时OpenCV未定义引用多版本OpenCV冲突卸载多余版本重编统一版本启动即崩溃DeepSDF权重路径错误检查modelFile路径和工作目录Pangolin窗口黑屏Mesh参数未生效或数据对齐问题检查Mesh配置确认RGBD时间戳对齐跟踪漂移严重相机标定参数错误重新标定相机内参和外参内存不足被杀死场景大、voxelSize过小调大voxelSize减少网格更新频率模型不显示物体use_cnn为0或未配置检测权重开启CNN检测配置检测模型路径7. 性能调优与运行实测体会在调通基础流程之后我对这套系统的性能特点有了更直观的感受。首先是CPU占用率DSP-SLAM的跟踪线程和局部建图线程都比较吃CPU如果你同时开着Pangolin可视化8核以下的CPU基本会满载。而GPU的占用率反而不是很高DeepSDF推理只在关键帧触发日常跟踪过程的GPU占用大概只有30%左右。如果你最终的目标是把DSP-SLAM搬上机器人有两个调优建议可以参考关闭实时可视化只在调试时打开。Pangolin虽然方便但开销不小尤其是网格实时更新时顶点数和面数一多渲染线程会拖慢整个SLAM的主循环。降低关键帧的插入频率。在YAML配置里找到关键帧插入的条件适当调高最小间隔帧数这样物体检测和DeepSDF匹配触发的频率会降低系统整体会更稳定。我在跑Replica room0的过程中把Mesh.voxelSize设为0.02、关键帧间隔设置为2倍默认值之后整个流程可以在不爆内存的情况下稳定跑到结束生成的稠密地图质量也能满足后续物体级规划的使用需求。最后再分享一个小技巧如果你想测试不同DeepSDF权重对物体重建效果的影响其实不需要重新编译整个项目只需要在YAML配置里换DeepSDF.modelFile的路径即可。但要保证换的新权重文件的codeLength和原来一致否则解码出来的shape code维度不匹配会在运行时直接报维度错误。我当时试过把官方预训练权重换成自己微调过的版本因为维度一致整个过程无缝切换这个设计确实很贴心。