MULLS 源码架构深度剖析:从 dataio 到 graph_optimizer 的模块化设计阅读指南

MULLS 源码架构深度剖析:从 dataio 到 graph_optimizer 的模块化设计阅读指南

【免费下载链接】MULLS 🤔 MULLS: Versatile LiDAR SLAM via Multi-metric Linear Least Square [ICRA 21] 【免费下载链接】MULLS 项目地址: https://gitcode.com/gh_mirrors/mu/MULLS

MULLS(Multi-metric Linear Least Square LiDAR SLAM)是 ICRA 2021 收录的开源激光雷达 SLAM 系统,以"多度量线性最小二乘"为核心思想,在 KITTI 数据集上实现了低漂移、高效率的建图效果。本文将从源码架构出发,为你完整剖析 MULLS 的模块化设计——从 dataio 数据读取、cfilter 特征提取,到 cregistration 配准、graph_optimizer 图优化,梳理出一条清晰的 LiDAR SLAM 源码阅读路径。无论你是 SLAM 新手还是想研究开源激光里程计实现的开发者,这份 MULLS 源码架构阅读指南都能帮你快速建立全局认知。

MULLS 在 KITTI 数据集上的性能对比

上图是 MULLS 在 KITTI 城市道路与高速公路序列上与主流 LiDAR SLAM 方法的性能对比,可见其在精度与效率上的综合优势。

MULLS 源码整体架构:一张图看懂五大核心模块

MULLS 的源码目录组织得非常清晰,主要分为 include(头文件)、src(实现)、test(可执行程序)、script(运行脚本与配置)和 demo_data(示例数据)几大部分。其中 include 下按功能拆分为四个子目录,构成了整个系统的骨架:

  • include/common/:通用基础模块,包括 dataio.hpp(数据读写)、cfilter.hpp(滤波与特征提取)、cregistration.hpp(配准)、pca.hpp(主成分分析)、utility.hpp(工具函数)以及 map_viewer 可视化模块;
  • include/pgo/:后端优化模块,包含 build_pose_graph.h(位姿图构建)、graph_optimizer.h(图优化)、map_manager.h(地图管理);
  • include/baseline_reg/:用于对比实验的基线配准方法,如 NDT、GICP、VGICP 的 OpenMP 加速实现;
  • include/nav/:导航辅助模块,包含地理坐标转换(geo_tran)与里程计误差计算(odom_error_compute)。

整个系统的主流程入口在 test/mulls_slam.cpp 中,它像一个指挥中心,按顺序调度各个模块完成"读取 → 滤波 → 配准 → 建图 → 闭环 → 优化"的完整 SLAM 闭环。

MULLS SLAM 在 KITTI 00 序列的建图与轨迹演示

上图演示了 MULLS SLAM 在 KITTI 00 序列(城市道路)上的运行效果,包含轨迹、特征点视图与全局地图的实时更新。

dataio 数据读取模块:支持 7 种点云格式的输入输出

阅读 MULLS 源码的第一步,应该从数据入口开始。dataio.hpp 是系统的"咽喉",负责所有点云数据的读写。它的设计亮点在于格式兼容性:除了常见的 .pcd.ply.txt,还支持 .las.csv.h5.bin 等共 7 种格式。

这种灵活性得益于条件编译宏——LIBLAS_ON 控制 LAS 读写(依赖 LibLas),HDF5_ON 控制 H5 读写(依赖 HDF5),对应的头文件 h5_io.hpp 独立成模块。即使你没有安装这些可选库,系统也能正常编译运行,只是对应格式不可用而已。

另外,dataio 中还重载了 Eigen 矩阵的 <<>> 运算符,方便将位姿矩阵直接打印或写入文件——在调试位姿精度时这个小细节非常实用。配套的数据格式转换工具位于 test/format_transformer/,例如 kitti_bin2pcd.cpp 可将 KITTI 原始 .bin 转为 .pcdtxt2pcd.cpp 支持自定义文本点云导入。

cfilter 与 pca 特征提取模块:五类几何特征点是如何产生的

MULLS 能在低算力下实现高精度配准,关键在于它不直接对原始点云做 ICP,而是先提取有意义的几何特征点cfilter.hpp 负责这项工作,它将点云分为五类:

  • 地面点(ground):通过网格高度差分割,配合 PCA 估计法向量;
  • 立面点(facade):墙面、建筑等竖直平面;
  • 柱状点(pillar):路灯、树干等圆柱结构;
  • 梁状点(beam):横梁、杆状结构;
  • 屋顶点(roof):车辆顶棚等水平面。

特征提取的数学基础是 pca.hpp 中的主成分分析。通过对每个点的局部邻域做 PCA,计算线性度(linearity)、平面度(planarity)等几何量,就能判定该点属于哪一类结构。mulls_reg_demo.gif 动画清晰地展示了 NCC(法向量一致性)编码的特征点提取与匹配过程:

MULLS 配准演示:特征点提取与匹配过程

值得一提的是,cfilter 还支持语义掩膜辅助(semantic assist),配合 Semantic KITTI 数据集可以过滤掉动态物体上的特征点,进一步提升鲁棒性。

cregistration 配准核心:mm_lls_icp 多度量线性最小二乘

配准是 MULLS 的灵魂模块。cregistration.hpp 中封装了核心算法 mm_lls_icp(Multi-metric Linear Least Square ICP),它针对不同类型的特征点,设计了多种残差度量:

  • 点到点(pt2pt):用于柱状点等点状特征;
  • 点到面(pt2pl):用于地面、立面等面状特征;
  • 点到线(pt2li):用于梁状、边缘特征。

不同度量的残差被组合成一个线性最小二乘问题,从而避免了传统 ICP 中非线性优化的复杂迭代,这也是 MULLS 速度快、且能用线性求解器直接解算位姿的原因。源码中通过 used_feature_type 字符串(如 "111110")灵活控制启用哪几类特征参与配准。

baseline_reg 目录下的 NDT、GICP 实现则用于对比实验——当 mm_lls_icp 判定配准失败时,系统会退回到基线方法,保证系统的稳定性,这是一个很实用的工程兜底设计。

MapManager 地图管理模块:局部地图更新与动态物体剔除

建图质量直接决定配准精度,map_manager.h 中的 MapManager 类负责维护用于配准的局部地图。它的核心功能包括:

  • update_local_map:以当前位姿为中心,在指定半径内截取局部地图并做体素降采样,控制地图规模;
  • map_based_dynamic_close_removal:基于距离阈值剔除近处的动态物体点,减少配准干扰;
  • judge_new_submap:根据累计位移、旋转和帧数判断何时开启新的子图,为后端闭环做准备。

这套"局部地图 + 子图划分"的设计,让前端配准始终保持在小规模数据上运行,是 MULLS 实时性的重要保障。

build_pose_graph 位姿图构建:相邻约束与闭环约束的生成

进入后端,首先看到的是 build_pose_graph.cpp 中的 Constraint_Finder 类,它负责生成位姿图的两类边:

  1. 相邻约束(ADJACENT):相邻两帧之间的相对位姿,直接来自前端里程计输出,信息矩阵由配准质量决定;
  2. 重叠配准约束(overlap registration constraint):通过 KD 树在子图间搜索空间相邻的候选节点,计算包围盒 IoU 判断重叠程度,再对重叠子图重新配准生成闭环边。

double_check_tran 函数还会用里程计预测位姿对闭环结果做二次校验,过滤误匹配——这种"先粗筛、再精配、后校验"的策略能有效防止错误回环污染整个位姿图。

graph_optimizer 图优化模块:g2o / ceres / gtsam 三后端自由切换

位姿图构建完成后,就轮到整个系统的"大脑"——graph_optimizer.cpp 出场。这个模块的设计非常开放:同一套代码同时支持 g2o、Ceres、GTSAM 三种主流非线性优化库,通过编译宏(G2O_ONCERES_ONGTSAM_ON)和命令行参数(pose_graph_optimization_method)自由切换,无需修改任何业务代码。

这一设计在 CMakeLists.txt 中也有对应体现,你可以通过 BUILD_WITH_CERESBUILD_WITH_G2OBUILD_WITH_GTSAM 三个开关选择安装哪个优化后端(作者推荐 Ceres)。优化完成后,update_optimized_nodes 会把优化后的位姿回传给前端,实现全局一致性修正,显著降低累积漂移。

MULLS 在 KITTI 01 高速公路序列的建图效果

上图展示了 MULLS 在 KITTI 01(高速公路)序列上的结果,可见其在长直道、弯道场景下仍能保持稳定的轨迹估计。

零基础实战:如何快速跑通并阅读 MULLS 源码

想亲手验证上面的架构分析,只需三步:

  1. 克隆代码git clone https://gitcode.com/gh_mirrors/mu/MULLS
  2. 编译运行:项目自带 16 帧示例数据(demo_data/pcd/),安装 PCL、glog、gflags 等依赖后执行 sh script/run_mulls_slam.sh 即可一键运行,无需任何数据准备;
  3. 对照阅读:以 test/mulls_slam.cpp 为线索,按"dataio → cfilter → cregistration → map_manager → build_pose_graph → graph_optimizer"的顺序逐模块追踪调用关系,配合 script/config/ 下的 gflags 配置文件理解各参数作用,你会发现整条代码链路一目了然。

如果只想单独测试配准效果,可以运行 sh script/run_mulls_reg.sh,它基于 test/mulls_reg.cpp 提供独立的点云配准演示,非常适合初学者先理解前端核心再深入后端。

总结:MULLS 源码架构带给我们的设计启示

回顾整个 MULLS 源码架构,最值得学习的不仅是"多度量线性最小二乘"这个算法创新,更是它高度模块化、松耦合的工程组织方式:数据 IO 与算法解耦、前端配准与后端优化解耦、可选依赖全部用编译宏隔离。这种设计让新手可以按模块逐个攻破,也让研究者能轻松替换任意环节做实验。

从 dataio 到 graph_optimizer,MULLS 用不到十个核心类就完成了一套完整的 LiDAR SLAM 系统,这份源码阅读指南希望能成为你探索激光 SLAM 世界的良好起点。🧭

【免费下载链接】MULLS 🤔 MULLS: Versatile LiDAR SLAM via Multi-metric Linear Least Square [ICRA 21] 【免费下载链接】MULLS 项目地址: https://gitcode.com/gh_mirrors/mu/MULLS

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值