☰
Fast-LIO 多传感器融合:GPS 融合建图与退化场景优化实战
2026/10/26 15:15:33 网站建设 项目流程

简介:这份文档面向具备机器人学、计算机视觉或SLAM基础的研发人员与工程师,聚焦Fast-LIO激光雷达与IMU融合建图的原理拆解及源码级改进。内容从数据时间对齐、前向与反向传播、KD树建图、观测方程设定到状态优化偏移量逐层展开,并给出位置、旋转矩阵与速度更新的数学推导;针对点云特征不明显时建图易失败的问题,进一步引入GPS数据,通过坐标系对齐标定、姿态矫正与状态优化提升鲁棒性与精度。资源包为1个docx文档,约756KB,结构紧凑,适合作为算法精读与工程改造的参考笔记。目前已有436人学习,读者可据此理解多传感器融合流程、掌握Fast-LIO核心推导,并获得GPS融合改进的落地思路,适用于无人驾驶、无人机导航等场景。

1. 从一次建图翻车说起:Fast-LIO 到底在解决什么问题

去年帮一个做园区巡检机器人的团队看现场,他们用 mid360 跑 Fast-LIO,在走廊里建图一直很稳,结果一进地下车库就崩了——点云稀稀拉拉,墙面特征几乎为零,轨迹直接飘走。这不是参数没调好,而是纯激光惯性里程计在退化场景下的通病:没有绝对参考,误差只能靠 IMU 和点云互相约束,一旦点云约束失效,系统就失去了“后悔药”。Fast-LIO 本身是一套紧耦合的激光惯性里程计,用 IMU 做前向传播、用点云做观测更新,把不同时刻的扫描拼成实时地图。它适合做无人驾驶、无人机导航、机器人定位的开发者,尤其是手里有 mid360 这类固态雷达、想搞明白多传感器融合底层逻辑的人。而这份资源要讲的,不只是 Fast-LIO 怎么跑,更关键的是:当点云特征不明显时,怎么把 GPS 数据接进来,让建图不再玄学。

2. 算法骨架拆解:从数据时间对齐到状态优化的完整链路

2.1 数据时间对齐:IMU 和雷达怎么对上拍子

Fast-LIO 的输入只有两路:IMU 和雷达。以 mid360 为例,IMU 每 0.005 秒出一帧角速度和线加速度,雷达每 0.1 秒出一帧约两万个点的点云。雷达频率低,所以对齐策略是把 IMU 时间往雷达时间上靠:收集一次雷达扫描周期内的所有 IMU 数据,大约 20 帧,然后在这个时间窗口内做前向传播。每次 Fast-LIO 主循环只处理一帧雷达点云,也就是 0.1 秒的数据。这个设计决定了后面所有状态更新的节奏——IMU 负责高频递推,雷达负责低频校正。

常见做法是在代码里维护一个 IMU 队列,收到雷达帧后按时间戳截取对应区间的 IMU 数据。如果时间戳对不齐,比如雷达和 IMU 的时钟源不同步,就会出现点云扭曲。我一般会在初始化阶段检查两路数据的时间差,超过阈值就报警,而不是硬跑。

2.2 前向传播:状态向量里到底装了哪些量

Fast-LIO 的状态向量有 8 个部分,维度是 3×8。源码里定义如下:

// 状态向量 x = [P, R_I, R_L, T_L, v, b_w, b_a, g] // P: IMU 相对第一帧 IMU 坐标系的位置,维度 (1,3) // R_I: IMU 当前坐标系到全局坐标系的旋转矩阵,维度 (3,3) // R_L: 雷达坐标系到 IMU 坐标系的旋转矩阵,刚性连接,固定值,维度 (3,3) // T_L: 雷达坐标系到 IMU 坐标系的位置偏移,固定值,维度 (1,3) // v: IMU 相对全局坐标系的线速度,维度 (1,3) // b_w: 角速度偏置,初始为 0,源码中未实际使用,维度 (1,3) // b_a: 加速度偏置,初始为 0,源码中未实际使用,维度 (1,3) // g: 重力向量,维度 (1,3)

这里有个容易看漏的点:b_w和b_a在源码里其实没起作用,可以删掉。真正参与前向传播的是位置、旋转、速度、重力。旋转矩阵不能直接相加,所以源码里用李代数做统称加号:R + θ = R * exp(θ^),减号则是R1 - R2 = ln(R2^T * R1)。这个细节在推导协方差时非常关键,因为旋转矩阵不满足传统加减法,协方差不能直接按向量算。

前向传播的实际计算公式是不含误差项的版本:

// 位置更新:p_{i+1} = p_i + Δt * v_i // 旋转更新:R_{i+1} = R_i * exp(Δt * (w_m - b_w)^) // 速度更新:v_{i+1} = v_i + Δt * (R_i * (a_m - b_a) + g) // 其中 w_m 和 a_m 是 i 和 i+1 两帧 IMU 的角速度和加速度平均值

速度更新里为什么要加g?因为加速度计测的是比力,静止时它测到的向量和重力方向相反,所以要把重力补偿回去。初始化时设备不动,可以算出重力单位向量和比例系数,把加速度大小对齐到 9.8。

2.3 误差前向传播:协方差矩阵怎么递推

前向传播没考虑噪声,误差会累积,所以要用协方差来描述不确定性。状态误差定义为x = x_true - x_est,协方差P = E[x * x^T]。由于旋转矩阵不能直接算协方差,误差状态里旋转部分用李代数表示:δθ = ln(R_est^T * R_true)。

误差递推公式是一阶泰勒展开:

// x_{i+1} = F_x * x_i + F_w * w_i // P_{i+1} = F_x * P_i * F_x^T + F_w * Q * F_w^T // Q 是测量噪声协方差,对应角速度和加速度的测量误差

F_x是状态转移矩阵,F_w是噪声雅可比。源码里这两个矩阵的推导涉及 BCH 近似和右雅可比矩阵,公式很长,但核心思想是:把旋转部分的扰动用李代数展开,线性化后得到矩阵形式。初始协方差P_0和Q都是预设的对角阵,对应状态的方差和测量方差。调参时如果发现轨迹抖动大,可以适当增大Q里角速度和加速度的方差,让滤波器更相信观测。

2.4 反向传播:把每个点云点拉回同一时刻

前向传播算到的是雷达帧最后一个 IMU 时刻的位姿,但点云里每个点的时间戳不同,需要反向传播把每个点拉回到帧尾时刻的雷达坐标系。流程是:遍历每个点,找到它左侧最近的 IMU 帧,用该帧位姿和 IMU 数据递推到点的时间戳,算出点在全局坐标系的坐标,再转到帧尾雷达坐标系。

// 对每个点 p_j: // 1. 找到左侧最近 IMU 帧 i,姿态为 x_i // 2. 递推到位姿 j:x_j = x_i + Δt * f(x_i, u_i, 0) // 3. 全局坐标:p_G = R_Ij * (R_L * p_j + T_L) + T_Ij // 4. 转到帧尾雷达坐标系:p_k = R_L^T * (R_Ik^T * (p_G - T_Ik) - T_L)

这一步做完,一帧内所有点就统一到了同一时刻,后续 KD 树建图和观测方程才能正确匹配。

2.5 KD 树建图与观测方程:最近邻搜索和平面拟合

处理后的点云转到世界坐标系,生成体素 KD 树,每个体素内只保留离体素中心最近的点,用于最近邻搜索。观测方程的目的是用当前帧点云在前向传播位姿下算出的世界坐标作为估计值,从 KD 树里找近邻平面作为真值,优化状态。

具体流程:对当前帧每个点,在 KD 树里找最近 10 个点,选距离最远的 5 个作为匹配点;用最小二乘法拟合平面;如果存在点到平面距离大于 0.1 米,说明这 5 个点不成平面,跳过;否则计算点到平面距离z_k,如果小于阈值,就构造观测方程0 = h_j(x_k, f_j) = z_k + H_k * x_k + v_j,其中H_k是观测雅可比,v_j是测量噪声。

观测雅可比的推导里,只有旋转δθ_Ik和位置p_Ik可导,外参R_L和T_L固定。最终形式是:

// H_k = [n_j^T, -n_j^T * (R_Ik * (R_L * p_kj + T_L))^, 0, 0, 0, 0, 0, 0] // n_j 是平面法向量

2.6 状态优化:卡尔曼滤波和 SMW 恒等式

优化时除了观测方程,还要约束状态偏移量尽量小。用贝叶斯卡尔曼滤波融合运动方程和观测方程,增益矩阵K = P_AB * P_B^{-1},其中P_AB = (P_A^{-1} + P_B^{-1})^{-1}。源码里用了 Sherman-Morrison-Woodbury 恒等式来避免直接求大矩阵逆,提高计算效率。

// 卡尔曼增益:K = (P_A^{-1} + P_B^{-1})^{-1} * P_B^{-1} // 状态更新:x_AB = (I - K) * μ_A + K * μ_B // 协方差更新:P_AB = (I - K) * P_A

这部分是 Fast-LIO 计算量最大的环节,但也是保证实时性的关键。如果发现建图延迟高,可以检查 KD 树体素大小和最近邻搜索点数,适当降低搜索范围。

3. GPS 融合改进:从坐标系对齐到状态增广的落地步骤

3.1 为什么纯 Fast-LIO 在退化场景会崩

纯激光惯性里程计没有绝对参考,所有位姿都是相对第一帧 IMU 坐标系推算的。在长走廊、地下车库、隧道这类几何特征重复或缺失的场景,点云匹配会失效,观测方程约束变弱,误差累积后轨迹直接飘走。GPS 提供绝对位置,虽然频率低、精度受环境影响,但可以作为全局约束把轨迹拉回来。改进的核心思路是:把 GPS 的经纬度坐标转换到局部 ENU 坐标系,然后作为观测方程的一部分加入优化。

3.2 坐标系对齐标定:GPS 和雷达怎么统一

GPS 输出的是经纬度和海拔,需要先转成局部 ENU 坐标。常见做法是选第一帧 GPS 位置作为原点,用墨卡托投影或简单的经纬度转平面公式:

import math def gps_to_enu(lat, lon, alt, lat0, lon0, alt0): # 简化处理:小范围内用线性近似 R = 6378137.0 # 地球半径,米 dlat = math.radians(lat - lat0) dlon = math.radians(lon - lon0) x = dlon * R * math.cos(math.radians(lat0)) y = dlat * R z = alt - alt0 return x, y, z

参数说明:lat0, lon0, alt0是原点经纬度和海拔,x, y, z是 ENU 坐标。小范围内这个近似够用,如果范围大,建议用 UTM 投影。标定时要确保 GPS 天线和雷达之间的外参已知,否则融合会引入系统偏差。

3.3 姿态矫正:GPS 观测方程怎么构造

GPS 提供的是位置观测,观测方程可以写成:

// z_gps = h_gps(x_k) + v_gps // h_gps(x_k) = P_Ik + R_Ik * T_gps // T_gps 是 GPS 天线在 IMU 坐标系下的位置偏移

其中P_Ik是 IMU 在全局坐标系的位置,R_Ik是旋转,T_gps是外参。观测雅可比只对位置和旋转有非零项:

// H_gps = [I, -R_Ik * T_gps^, 0, 0, 0, 0, 0, 0]

把 GPS 观测方程和激光观测方程一起加入卡尔曼滤波,增益矩阵和状态更新公式不变,只是观测维度增加。注意 GPS 的测量噪声协方差R_gps要根据实际精度设置,通常比激光观测大,避免 GPS 跳变带偏轨迹。

3.4 状态增广:把 GPS 外参也放进优化

如果 GPS 天线和 IMU 的外参标定不准,可以把T_gps也作为状态量加入优化。状态向量从 8 部分扩到 9 部分,前向传播时T_gps不变,观测方程里对T_gps求导得到新的雅可比列。这样系统能在线估计外参,减少标定误差影响。代价是计算量增加,但现代处理器上跑 mid360 加 GPS 融合,实时性通常没问题。

4. 避坑与排查:GPS 融合建图常见的五个翻车点

4.1 现象:轨迹在 GPS 信号跳变时突然抖动

原因:GPS 测量噪声协方差R_gps设得太小,滤波器过度相信 GPS,信号一跳变就把状态拉偏。解决:把R_gps调大,或者对 GPS 做滑动平均滤波,剔除明显跳变的点。我一般会先录一段静态数据,看 GPS 的方差,再设R_gps为方差的 2 到 3 倍。

4.2 现象:建图整体偏移,和实际环境对不上

原因:GPS 原点和雷达第一帧坐标系没对齐,或者外参T_gps标定错误。解决:检查gps_to_enu的原点是否和 Fast-LIO 初始化时的第一帧 IMU 位置一致。如果不一致,要么改原点,要么在观测方程里加一个固定的平移补偿。外参可以用卷尺量,或者用标定工具算。

4.3 现象:加入 GPS 后计算延迟明显增加

原因:观测维度增加,卡尔曼滤波的矩阵运算量变大,或者 KD 树搜索范围没变但点云数量多了。解决:降低 KD 树最近邻搜索点数,从 10 降到 5;或者对 GPS 观测做降频,比如每 10 帧雷达才用一次 GPS 更新。实测这样能把延迟压回实时范围。

4.4 现象:GPS 信号丢失后轨迹直接飘走

原因:GPS 丢失时观测方程只剩激光,如果场景退化,系统没有后备约束。解决:在 GPS 丢失时增大激光观测的权重,或者临时增大过程噪声Q,让滤波器更依赖 IMU 递推。更稳妥的做法是加一个失效检测,GPS 丢失超过阈值就切换到纯激光惯性模式,并记录状态,等 GPS 恢复后再平滑融合。

4.5 现象:建图出现重影,点云分层

原因:时间对齐没做好,GPS 时间戳和雷达、IMU 时间戳不同步。解决:检查三路数据的时间戳来源,确保都在同一时钟域。如果 GPS 走串口,延迟可能达到几十毫秒,需要在代码里做时间补偿。我一般会在初始化阶段打印三路数据的时间差,超过 10 毫秒就手动调偏移量。

5. 二次开发上手:从改参数到换传感器的验证方法

拿到这份源码后,我建议先别急着改代码,而是跑一遍原始 Fast-LIO,用 mid360 录一段数据,确认建图正常。然后按这个顺序做二次开发:第一步,把 GPS 数据接进来,只做坐标系转换和观测方程构造,先不优化外参,看轨迹能不能被 GPS 拉回。第二步,调R_gps和Q,用静态和动态两段数据对比,找到不抖动又不飘的平衡点。第三步,如果外参不准,再把T_gps加入状态增广,观察在线估计的收敛情况。

验证方法上,我习惯用 evo 工具算轨迹的绝对位姿误差,对比纯 Fast-LIO 和 GPS 融合版本的 RMSE。如果融合后 RMSE 下降超过 30%,说明改进有效;如果反而变大,优先检查时间对齐和外参。另一个技巧是录一段 GPS 信号故意遮挡的数据,看系统能不能平滑切换,而不是直接崩掉。

代码改造时,注意 Fast-LIO 的状态向量维度是固定的,加 GPS 观测不用改状态维度,只改观测方程和雅可比。如果要把 GPS 外参加入优化,才需要扩状态。源码里b_w和b_a没用到,可以删掉腾出计算资源。最后,别忘了在配置文件里把 GPS 开关做成可配置项,方便对比实验。

从那以后我每次做多传感器融合,都强制先跑一遍时间对齐检查,再跑静态标定,最后才上动态场景。这个习惯帮我省了至少三次通宵排查。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询