一、课程导论与预备知识
1.1 点云与IMU融合定位——到底在解决什么问题?
先聊聊应用场景吧。我做了这么多年定位,发现一个规律:单一传感器永远有短板。
自动驾驶——你想想看,激光雷达在雨雾天性能会下降,IMU却能稳定输出角速度和加速度。我曾在雨天测试过,纯激光雷达定位直接漂移,加上IMU后稳如老狗。
机器人——室内AGV、扫地机器人,这些场景下GPS信号弱甚至没有。IMU提供短时高精度姿态,点云提供环境结构信息,两者互补。我记得有个项目,机器人在走廊里跑,纯靠IMU积分,十分钟后偏了十几度,加上点云匹配后误差控制在厘米级。
AR/VR——这个更讲究实时性。头显设备需要毫秒级的位姿更新,IMU能提供高频(200Hz以上)的预测,点云做低频(10-30Hz)的校正。说白了,IMU负责“快但不准”,点云负责“准但不快”,融合起来就是又快又准。
核心观点:点云与IMU融合定位,本质上是利用IMU的高频特性填补点云匹配的时间间隙,同时利用点云的绝对观测约束IMU的累积漂移。
1.2 课程整体大纲——这30章我们怎么走?
整个课程我设计成了三个递进阶段:
| 阶段 | 章节 | 核心内容 |
|---|---|---|
| 基础篇 | 1-8章 | 数学基础、传感器模型、坐标系变换、点云预处理、IMU预积分 |
| 核心算法篇 | 9-20章 | ICP变种、NDT、ESKF、图优化、因子图、松耦合/紧耦合 |
| 工程实战篇 | 21-30章 | ROS2实现、多传感器标定、回环检测、性能调优、部署落地 |
我个人习惯把课程分成“懂原理”和“能干活”两个维度。前20章让你懂,后10章让你能真正跑起来。
1.3 数学基础——绕不开的四座大山
四元数
为什么不用欧拉角?因为万向锁。我在项目中吃过这个亏——用欧拉角做姿态插值,结果在俯仰90度时直接炸了。四元数没有奇异性,而且插值平滑。
你只需要记住:四元数表示旋转,乘法对应旋转合成。代码里我习惯用Eigen的Quaterniond类:
Eigen::Quaterniond q1(1.0, 0.0, 0.0, 0.0); // 单位四元数
Eigen::Quaterniond q2 = Eigen::AngleAxisd(0.5, Eigen::Vector3d::UnitZ());
Eigen::Quaterniond q_result = q1 * q2; // 旋转合成
李群与李代数
说白了,李群(SO(3)、SE(3))是旋转和变换的集合,李代数(so(3)、se(3))是它们的“切空间”。为什么要学这个?因为优化时需要求导,而旋转矩阵的导数不好算,李代数上的导数就优雅得多。
嗯,这里要注意:李代数到李群的映射是指数映射。我刚开始学的时候总觉得抽象,后来写代码时发现Eigen的Sophus库已经封装好了:
Sophus::SO3d R = Sophus::SO3d::exp(Eigen::Vector3d(0.1, 0.0, 0.0));
Eigen::Vector3d phi = R.log(); // 李代数
卡尔曼滤波简介
卡尔曼滤波的核心思想就一句话:预测 + 观测 = 最优估计。IMU做预测,点云做观测,两者融合就是典型的卡尔曼框架。
我曾经在无人机项目里用扩展卡尔曼滤波(EKF)做姿态估计,发现协方差矩阵的调参特别关键。调大了收敛慢,调小了容易发散。这个坑后面我们会专门讲。
避坑指南:初学者容易把卡尔曼滤波当成黑盒。我建议你至少手写一遍一维卡尔曼滤波的推导,理解“预测-更新”的循环逻辑。这样后面学ESKF(误差状态卡尔曼滤波)时才不会懵。
1.4 编程基础——工具链准备
C++
必须掌握C++11/14,特别是智能指针、模板、STL容器。我见过太多人用裸指针导致内存泄漏,在嵌入式平台上跑几个小时就崩了。
ROS
ROS的消息通信机制、TF变换、bag回放是基本功。我个人习惯用ROS2的Humble版本,实时性更好。但如果你刚入门,ROS1的Noetic也完全够用。
Eigen
Eigen是C++的线性代数库,我们用它做矩阵运算、四元数、李代数。注意:Eigen默认是列优先,而且内存对齐有坑。我曾经在跨动态库传递Eigen对象时踩过对齐的雷,解决方案是加EIGEN_MAKE_ALIGNED_OPERATOR_NEW宏。
PCL库
点云处理离不开PCL。常用的模块:
- pcl::PointCloud:点云数据结构
- pcl::VoxelGrid:体素滤波降采样
- pcl::IterativeClosestPoint:ICP配准
- pcl::visualization:点云可视化
// 一个简单的点云降采样示例
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
pcl::VoxelGrid<pcl::PointXYZ> sor;
sor.setInputCloud(cloud);
sor.setLeafSize(0.05f, 0.05f, 0.05f);
sor.filter(*cloud_filtered);
1.5 本章知识体系总览
下面这张图概括了本章的核心脉络,也是整个课程的知识骨架:
重要提醒:数学基础是后面所有算法的根基。如果你对四元数或李代数不熟,我建议花一周时间专门补一下。不要急着跳代码,基础不牢,后面优化时会一头雾水。
好了,这一章就到这里。记住:融合定位不是把两个传感器数据简单拼在一起,而是从数学上找到最优的估计方式。后面的章节我们会一步步拆解这个过程。
可可精品资料库