文章目录
-
-
- [阶段一:基础理解 - 学习内容 1:项目概述](#阶段一:基础理解 - 学习内容 1:项目概述)
- [阶段一:基础理解 - 学习内容 2:项目结构详解](#阶段一:基础理解 - 学习内容 2:项目结构详解)
- [阶段一:基础理解 - 学习内容 3:公共数据结构详解](#阶段一:基础理解 - 学习内容 3:公共数据结构详解)
- [阶段一:基础理解 - 学习内容 4:系统入口详解](#阶段一:基础理解 - 学习内容 4:系统入口详解)
- [阶段一:基础理解 - 总结](#阶段一:基础理解 - 总结)
- 下一步学习计划
-
阶段一:基础理解 - 学习内容 1:项目概述
重点理解:
- 项目做什么?
- 激光雷达 SLAM (同时定位与建图)系统
- 可以:建图、定位、回环检测
-
核心特性
这13个特性很重要,先记下来:
-
完整的 3D Lidar SLAM,快速的 LIO 前端(AA-FasterLIO)--- 标配
-
3D 至 2D 地图转换(g2p5)
-
实时回环检测
-
高精度 3D Lidar 定位
-
地图分区动态加载
-
动静态图层分离定位
-
高频 IMU 平滑输出
-
GPS 关联(待完成)
-
里程计输入(待完成)
-
轻量优化库 Miao
-
离线/在线两种模式
-
高频输出(外推器+平滑器)
-
高性能计算(建图1.2核,定位0.8核)
阶段一:基础理解 - 学习内容 2:项目结构详解
项目结构框架
lightning-lm-master/
├── src/ # 核心源码目录
│ ├── app/ # 应用程序入口(main函数)
│ ├── common/ # 公共数据结构和工具
│ ├── core/ # 核心算法模块(最重要!)
│ ├── io/ # 文件读写
│ ├── ui/ # 可视化界面
│ ├── utils/ # 工具函数
│ └── wrapper/ # ROS2封装
├── config/ # 配置文件
├── thirdparty/ # 第三方库
└── README_CN.md
src/core/ 目录详解(核心中的核心)这个目录包含了所有核心算法:
src/core/
├── lio/ # LIO前端(激光雷达里程计)
│ ├── laser_mapping.h/cc # 激光建图主类
│ ├── eskf.hpp/cc # 误差状态卡尔曼滤波
│ ├── imu_processing.hpp # IMU处理
│ └── pointcloud_preprocess.h/cc # 点云预处理
├── loop_closing/ # 回环检测
├── localization/ # 定位模块
│ ├── lidar_loc/ # 激光定位
│ └── pose_graph/ # 位姿图优化
├── maps/ # 地图管理
├── g2p5/ # 3D点云转2D栅格
├── miao/ # 轻量级优化库(自己写的)
├── ivox3d/ # 局部地图空间索引
└── system/ # 系统集成
├── slam.h/cc # SLAM系统主类
└── loc_system.h/cc # 定位系统主类
阶段一:基础理解 - 学习内容 3:公共数据结构详解
- options.h - 全局配置
这个文件定义了所有模块的全局配置参数,使用命名空间来组织:
- debug - 调试相关
- lo - 定位相关
- map - 地图相关
- pgo - 位姿图优化相关
- ui - 可视化相关
- lidar_loc - 激光定位相关
- fasterlio - LIO前端相关
重点理解: 这些参数都是 extern 声明,实际定义在 options.cc 中。
-
keyframe.h - 关键帧
重点看 ,这个类非常重要:class Keyframe {
protected:
unsigned long id_ = 0; // 关键帧ID
double timestamp_ = 0; // 时间戳
CloudPtr cloud_; // 降采样后的点云
SE3 pose_lio_; // 前端LIO的位姿
SE3 pose_opt_; // 后端优化后的位姿
NavState state_; // 卡尔曼滤波器状态
};
为什么有两个位姿?
- pose_lio_ :前端 LIO 实时算出来的位姿(可能有漂移)
- pose_opt_ :后端位姿图优化之后的位姿(更准,可能有跳变)
关键点: 有一个 data_mutex_ 互斥锁,因为关键帧会被多个线程访问!
- nav_state.h - 导航状态
这是系统最核心的数据结构,一定要理解!
状态变量维度:
constexpr static int dim = 12; // 状态变量12维!
12维状态变量:
索引 变量名 维度 说明
0-2 pos_ 3 位置 (x, y, z)
3-5 rot_ 3 旋转 (SO3)
6-8 vel_ 3 速度 (vx, vy, vz)
9-11 bg_ 3 陀螺零偏 (bgx, bgy, bgz)
注意:
-
grav_ 是固定的重力向量, 不参与在线估计
-
ba_ (加计零偏)也不在线估计了
重点理解的几个函数(都很重要!):
-
ToState() - 把状态转成矢量形式
-
FromVectState() - 从矢量恢复状态
-
get_f() - 运动方程
-
df_dx() - 运动方程对状态的雅可比
-
boxminus() / boxplus() - 广义加减运算
阶段一:基础理解 - 学习内容 4:系统入口详解
梳理一下整个流程:
-
程序启动流程 ( run_slam_offline.cc )
流程是这样的:- 初始化日志 (gflags, glog)
- 解析命令行参数 (input_bag, config)
- 创建 RosbagIO 对象(读 rosbag)
- 创建 SlamSystem 对象(设置 online_mode_ = false)
- 调用 slam.Init(config) 初始化
- 调用 slam.StartSLAM("new_map") 开始
- 注册 IMU 和 LiDAR 的回调函数
- 调用 rosbag.Go() 开始跑数据
- 跑完后调用 slam.SaveMap() 保存地图
-
SlamSystem 的成员变量 ( slam.h )
这就是系统的核心组成! 非常重要,一定要记住:std::shared_ptr
lio_ = nullptr; // LIO前端
std::shared_ptrlc_ = nullptr; // 回环检测
std::shared_ptrui::PangolinWindow ui_ = nullptr; // UI可视化
std::shared_ptrg2p5::G2P5 g2p5_ = nullptr; // 栅格地图
系统的核心就是这几个模块的组合!
-
SlamSystem 的初始化( slam.cc)
Init() 函数的流程:
-
第25-29行 :先初始化 LIO 前端( LaserMapping ),这是必须的!
-
第31-36行 :读 yaml 配置文件
-
第38-44行 :如果配置了 with_loop_closing_ ,就初始化回环检测
-
第46-52行 :如果配置了 with_visualization_ ,就初始化 UI
-
第54-79行 :如果配置了 with_gridmap_ ,就初始化 g2p5(栅格地图)
-
第81-121行 :如果是在线模式,就创建 ROS2 node 和 subscriber
-
数据处理流程 - 重点!
看 ProcessLidar() 函数(第241-303行),这是整个系统的数据流向:
ProcessLidar() 被调用
↓
lio_->ProcessPointCloud2(cloud) // 给LIO前端
lio_->Run() // LIO跑起来
↓
检查是否产生了新的关键帧 (cur_kf_ != kf)
↓
如果产生了新关键帧:
├─→ lc_->AddKF(cur_kf_) // 给回环检测
├─→ g2p5_->PushKeyframe(cur_kf_) // 给栅格地图
└─→ ui_->UpdateKF(cur_kf_) // 给UI更新显示
这就是整个 SLAM 系统的核心数据流!
阶段一:基础理解 - 总结
阶段一已经完成!学了什么?
- 项目概况和结构
- 核心数据结构(Keyframe, NavState)
- 系统入口和数据流
应该掌握的重点:
- NavState 的12维状态变量
- Keyframe 为什么有两个位姿(pose_lio_ vs pose_opt_)
- SlamSystem 的4个核心模块成员
- ProcessLidar() 的数据流向
下一步学习计划
阶段一完成! 继续学阶段二(LIO前端)
阶段二会学:
- 点云预处理
- IMU处理
- ESKF滤波器
- 激光匹配(ICP)
- 局部地图管理