1. 课程导论与预备知识

各位同学好,我是这门课的主讲。在正式开始之前,我想先聊聊——为什么我们要把点云滤波和IMU放在一起讲?

说实话,我刚开始做SLAM那会儿,也踩过不少坑。记得有一次在自动驾驶项目里,激光雷达的数据被雨点打得稀碎,定位直接飘到马路牙子上去了。后来加了IMU做融合,才算稳住。嗯,这就是我们这门课要解决的核心问题。

1.1 点云与IMU融合定位的应用场景

先说说这东西用在哪。你想想看,现在最火的那几个方向,哪个离得开定位?

  • 自动驾驶:车在路上跑,激光雷达扫出点云,IMU提供加速度和角速度。两者一结合,哪怕GPS信号丢了,车也能知道自己在哪。我在做园区无人车时,就靠这套方案扛过了隧道和地下车库。
  • 机器人:不管是扫地机还是仓储AGV,室内没有GPS,全靠点云建图和IMU推算。说白了,这就是机器人的「眼睛」和「小脑」。
  • AR/VR:你戴着头显,头一动,画面就得跟上。IMU负责快速响应,点云负责修正漂移。我试过只用IMU做AR定位,十分钟后虚拟物体就跑到天花板上了——所以必须融合。

核心观点:点云提供「绝对观测」,IMU提供「相对运动」。两者互补,缺一不可。

1.2 课程知识体系概览

这门课一共30章,我把它分成四个模块。先给你画张图,心里有个底。

模块一:基础与工具 第1-5章:坐标系、四元数、李群李代数 开发环境:Ubuntu + ROS + PCL + Eigen 点云滤波基础(体素、统计、半径滤波) 模块二:IMU核心 第6-12章:IMU测量模型与噪声分析 预积分理论(手撕公式) 零偏估计与标定实战 模块三:融合算法 第13-22章:卡尔曼滤波家族 点云-IMU松耦合与紧耦合 因子图优化(iSAM2) 模块四:工程实战 第23-30章:完整SLAM系统搭建 多传感器标定与时间同步 真实场景调试与性能优化

看到没?从基础到实战,层层递进。我个人建议你按顺序学,别跳。尤其是李群李代数那块,很多人觉得抽象就跳过了,后面因子图优化时又回来补课——何必呢?

1.3 所需数学基础

数学这东西,我懂,一提就头疼。但做SLAM绕不开,我尽量用白话给你讲明白。

坐标系变换

说白了就是「把一个点从A坐标系挪到B坐标系」。比如激光雷达扫到一个点,坐标是相对于雷达自己的。但我们要把它放到世界坐标系里,就得做旋转和平移。

我的经验:写代码时最容易搞混的就是坐标系顺序。我曾经在ROS里把base_link和odom搞反了,结果机器人原地转圈跑了十分钟。从那以后,我每次做变换前都会画个坐标系草图。

四元数

旋转矩阵有9个参数,但只有3个自由度,冗余不说还容易产生数值问题。四元数用4个参数表示旋转,紧凑且无奇点。

// 四元数基本形式:q = w + xi + yj + zk
// 单位四元数表示旋转
Eigen::Quaterniond q(1.0, 0.0, 0.0, 0.0);  // 单位四元数,无旋转
// 绕Z轴旋转90度
q = Eigen::Quaterniond(Eigen::AngleAxisd(M_PI/2, Eigen::Vector3d::UnitZ()));

注意:四元数乘法不满足交换律!q1 * q2 和 q2 * q1 结果不同。我见过有人在这上面debug了一整天,最后发现只是乘法的顺序写反了。

李群与李代数简介

嗯,这里要稍微烧脑一点。李群(SO(3)、SE(3))描述的是连续的旋转和变换。李代数则是李群在单位元处的切空间。

为什么要学这个?因为SLAM里要做优化。你想想看,优化需要在流形上求导,但旋转矩阵本身不是向量空间,不能直接加减。李代数把旋转映射到了向量空间,求导就方便了。

概念 李群 李代数
旋转 SO(3) — 3x3旋转矩阵 so(3) — 3维向量(旋转向量)
变换 SE(3) — 4x4齐次矩阵 se(3) — 6维向量(平移+旋转)
核心操作 乘法(复合变换) 加法(优化更新)

我个人习惯用Sophus库,它把李群李代数的运算都封装好了。后面实战章节我们会手写一个简单的李代数求导,到时候你就知道这东西有多好用了。

1.4 开发环境搭建

工欲善其事,必先利其器。环境搭不好,后面全是坑。我直接给你一个经过验证的配置清单。

系统与基础软件

  • Ubuntu 20.04:我推荐这个版本,ROS Noetic原生支持,兼容性好。
  • ROS Noetic:机器人操作系统,负责节点通信、数据录制回放。
  • PCL 1.10:点云库,滤波、分割、配准一条龙。
  • Eigen 3.3:线性代数库,矩阵运算、四元数、几何变换。

一键安装脚本

别一个个去apt-get了,我整理了个脚本,直接跑就行。

#!/bin/bash
# 安装ROS Noetic
sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654
sudo apt update
sudo apt install ros-noetic-desktop-full -y

# 安装PCL
sudo apt install libpcl-dev pcl-tools -y

# 安装Eigen
sudo apt install libeigen3-dev -y

# 安装Sophus(李群李代数库)
cd ~
git clone https://github.com/strasdat/Sophus.git
cd Sophus
mkdir build && cd build
cmake ..
make -j4
sudo make install

避坑指南:我曾经在Ubuntu 22.04上装ROS Noetic,折腾了两天发现不兼容。后来老老实实换回20.04,半小时搞定。所以别跟版本较劲,用推荐的配置最省心。

验证环境

装完后跑个简单的PCL程序,看看能不能正常编译。

# 创建测试文件 test_pcl.cpp
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>

int main() {
    pcl::PointCloud<pcl::PointXYZ> cloud;
    cloud.width = 5;
    cloud.height = 1;
    cloud.points.resize(cloud.width * cloud.height);
    
    for (size_t i = 0; i < cloud.points.size(); ++i) {
        cloud.points[i].x = 1024 * rand() / (RAND_MAX + 1.0f);
        cloud.points[i].y = 1024 * rand() / (RAND_MAX + 1.0f);
        cloud.points[i].z = 1024 * rand() / (RAND_MAX + 1.0f);
    }
    
    pcl::io::savePCDFileASCII("test.pcd", cloud);
    std::cout << "Saved " << cloud.points.size() << " data points to test.pcd." << std::endl;
    return 0;
}

// CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(test_pcl)
find_package(PCL 1.10 REQUIRED)
include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})
add_executable(test_pcl test_pcl.cpp)
target_link_libraries(test_pcl ${PCL_LIBRARIES})

编译通过,生成test.pcd文件,说明环境没问题。如果报错,多半是PCL版本不对或者路径没配好。检查一下/usr/include/pcl-1.10目录是否存在。

最后说一句:数学基础和环境搭建是这门课的「入场券」。别急着往后赶,把这块吃透了,后面30章你会走得很顺。我当年就是基础没打牢,后面反复回头补课,浪费了不少时间。

好,第一章就到这。去把环境搭起来,我们第二章见。


可可精品资料库