ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

GPS/INS松组合导航程序拆包:从惯导数据下载到卡尔曼滤波融合的工程落地

GPS/INS松组合导航程序拆包:从惯导数据下载到卡尔曼滤波融合的工程落地

简介:这份资源是面向导航、测绘及自动驾驶方向学习者的GPS/INS组合导航实践资料,围绕位置组合程序展开,帮助理解松组合模式下惯导与卫星数据的融合流程。压缩包共9个文件,约679KB,包含4个m脚本文件、2个doc文档、1个mat数据文件、1个txt说明及1个dat结果文件,脚本用于实现卡尔曼滤波与组合解算,文档记录程序说明与位置组合结果,mat与dat则提供实验数据与输出,便于直接运行验证。目前已有708人学习下载。资源核心价值在于给出可复现的GPS_INS位置组合代码框架,读者可据此掌握惯导数据下载后的预处理、滤波融合与结果分析思路,对照说明文档快速定位关键模块,并借助实测数据评估不同场景下的导航精度,适合作为课程设计或课题入门的参考范例。

1. GPS/INS 组合导航程序拆包:从松组合到惯导数据下载的落地路径

如果你手头正好有一套惯导设备,却卡在“数据能读出来但不知道怎么和 GPS 融合”这一步,那这个 GPS_INS 位置组合程序包大概率能帮你省掉几周的摸索。它本质上是一个松组合(loosely coupled)架构的组合导航实现,把 GPS 输出的位置、速度与 INS 解算的对应量做卡尔曼滤波融合,输出比纯惯导更稳、比纯 GPS 更连续的位置结果。适合做车载定位、无人机导航、测绘后处理,或者单纯想搞懂组合导航工程实现的开发者。惯导数据下载和组合导航这两个环节,恰恰是大多数人从理论跨到工程时最容易翻车的地方——程序包里给了一条能跑通的路径,但参数和坐标系细节得自己盯紧。

2. 松组合架构拆解:GPS 和 INS 到底怎么“组合”的

2.1 松组合与紧组合的选型逻辑

组合导航按耦合深度分几个层次,这个程序包走的是松组合路线。松组合的做法是:GPS 接收机自己先解算出位置和速度,INS 也独立做机械编排得到位置速度,然后把这两组结果送进卡尔曼滤波器做融合。好处是 GPS 和 INS 各自保持独立,GPS 短时失效时 INS 还能靠惯导递推撑一段时间,工程实现也简单——不需要拿到 GPS 的原始伪距和载波相位。

紧组合则不同,它把 GPS 的伪距、伪距率直接和 INS 预测的对应量做差,作为滤波观测量。紧组合在卫星数少于 4 颗时仍能工作,但实现复杂度高出一大截,需要处理接收机原始观测数据的时间同步和粗差探测。对于大多数做车载或无人机定位的场景,松组合已经够用,这也是为什么这个程序包选了这个架构。

选松组合还有一个现实原因:惯导数据下载之后,你拿到的通常是已经解算好的位置速度信息,而不是原始 IMU 脉冲。松组合正好匹配这种数据形态,不需要额外去接收机里抠原始观测量。

2.2 卡尔曼滤波的状态量与观测方程

程序包里的卡尔曼滤波器,状态量一般取 15 维:位置误差(3)、速度误差(3)、姿态误差(3)、陀螺零偏(3)、加速度计零偏(3)。状态转移矩阵由 INS 的误差传播方程离散化得到,观测方程则用 GPS 位置速度减去 INS 位置速度。

# 卡尔曼滤波核心步骤(松组合,15维状态) # 状态向量 x = [dpos(3), dvel(3), datt(3), bg(3), ba(3)] # 预测 x_pred = F @ x_prev # F 为状态转移矩阵,由 INS 误差方程离散化 P_pred = F @ P_prev @ F.T + Q # Q 为过程噪声协方差 # 更新(GPS 位置速度到达时) H = np.hstack([np.eye(6), np.zeros((6, 9))]) # 观测矩阵,只观测位置和速度误差 z = gps_pos_vel - ins_pos_vel # 新息:GPS 与 INS 之差 K = P_pred @ H.T @ np.linalg.inv(H @ P_pred @ H.T + R) # 卡尔曼增益 x_update = x_pred + K @ z P_update = (np.eye(15) - K @ H) @ P_pred

这段代码里几个关键参数需要根据实际设备调:Q 矩阵的过程噪声反映 IMU 噪声水平,消费级 MEMS 惯导的陀螺零偏稳定性可能在 10°/h 量级,对应 Q 里的角度随机游走要设大一些;R 矩阵是 GPS 观测噪声,普通单点 GPS 水平位置精度约 2.5m CEP,对应 R 的位置项取 6~10 比较合理。如果 R 设太小,滤波器会过度信任 GPS,GPS 跳点时输出跟着跳;R 设太大,INS 的漂移又压不住。

2.3 惯导数据下载与时间对齐

惯导数据下载这一步,坑往往不在下载本身,而在时间戳对齐。IMU 通常跑 100~200Hz,GPS 只有 1~10Hz,两个数据流的时间戳如果不在同一时间基准上,融合出来的轨迹会有系统性偏差。

常见做法是:先把 IMU 数据按时间戳排序,检查是否有丢帧或重复帧;然后把 GPS 的 UTC 时间转成周内秒,和 IMU 的本地时间做线性插值对齐。如果 IMU 数据里没有绝对时间戳,只有采样计数,那就需要找到第一个 GPS 时间戳对应的 IMU 帧号,往后递推。

# 惯导数据下载后的预处理流程(以常见二进制格式为例) # 1. 检查数据完整性 ls -lh imu_data.bin gps_data.txt # 2. 解析 IMU 二进制,输出 CSV python parse_imu.py --input imu_data.bin --output imu.csv --rate 200 # 3. 检查时间戳单调性 python check_timestamp.py --file imu.csv --column timestamp # 4. GPS 数据转周内秒 python gps_time_convert.py --input gps_data.txt --output gps_sow.csv

参数说明:--rate 200要和实际 IMU 采样率一致,设错了积分出来的速度会差一个比例因子;check_timestamp.py主要看有没有回退的时间戳,有的话说明数据下载过程中出现了缓冲区溢出或串口丢包。

3. 从零跑通组合导航:环境、配置与首次解算

3.1 运行环境与依赖准备

程序包一般给的是源码或可执行文件加配置。如果是源码,先看 README 里的依赖列表。常见的依赖包括 Eigen(矩阵运算)、yaml-cpp(配置文件解析)、以及可选的 Ceres 或 g2o(如果做了图优化)。Windows 下可能给的是 VS 工程,Linux 下是 CMake。

# Linux 下典型编译流程 mkdir build && cd build cmake .. -DCMAKE_BUILD_TYPE=Release make -j4 # 编译完成后检查可执行文件 ls -lh bin/

如果编译报错找不到 Eigen,先确认Eigen3_DIR是否设置正确。CMake 找包失败时,用cmake .. -DEigen3_DIR=/usr/local/share/eigen3/cmake显式指定路径。Release 模式一定要开,Debug 模式下卡尔曼滤波的矩阵运算会慢到无法接受。

3.2 配置文件参数逐项说明

配置文件通常是一个 YAML 或 INI,里面分几块:IMU 参数、GPS 参数、滤波器参数、初始对准参数。IMU 参数里最重要的是零偏和标度因数,如果厂家给了标定文件就直接填,没给的话先用默认值跑一遍看残差。

参数项典型值说明
imu_rate200 HzIMU 采样率,必须和实际数据一致
gps_rate1 HzGPS 输出率,常见 1/5/10 Hz
gyro_bias[0.01, 0.01, 0.01] rad/s陀螺零偏初值,有标定用标定值
accel_bias[0.05, 0.05, 0.05] m/s²加速度计零偏初值
pos_noise5.0 mGPS 位置观测噪声标准差
vel_noise0.5 m/sGPS 速度观测噪声标准差
init_align_time60 s初始对准时长,静态对准用

初始对准这块,程序包一般支持静态对准。把设备静置 60 秒,程序采集陀螺和加速度计数据,用加速度计测重力方向确定水平姿态,用陀螺测地球自转角速度确定航向。如果陀螺精度不够(消费级 MEMS 测不到地球自转),航向就得靠 GPS 运动轨迹来初始化,或者外部给一个磁力计航向。

3.3 首次解算与结果检查

配置填好后,跑一次完整解算。输入是 IMU 数据文件和 GPS 数据文件,输出通常是轨迹文件(位置、速度、姿态)和一个日志文件。

# 运行组合导航解算 ./bin/gps_ins_fusion --config config/params.yaml \ --imu data/imu.csv \ --gps data/gps.csv \ --output result/trajectory.csv # 检查输出 head -5 result/trajectory.csv # 列:time, lat, lon, alt, vn, ve, vd, roll, pitch, yaw

跑完之后先看日志里的新息序列。新息是 GPS 观测减去 INS 预测的差值,正常情况下应该在零附近波动,标准差和 R 矩阵设的量级一致。如果新息持续偏大或者有趋势,说明初始对准有问题或者 IMU 零偏没标定好。再看轨迹文件,把 GPS 原始轨迹和组合导航轨迹画在一起,组合导航的轨迹应该比纯 GPS 平滑,且在 GPS 信号遮挡段有连续输出。

4. 避坑与排查:组合导航跑不通时先查这几处

4.1 轨迹发散或跳变

现象:解算出来的轨迹在某个时间段突然飞掉,位置跳出去几百米甚至更远。

原因:最常见的是 GPS 数据里混入了粗差,比如多路径效应导致的位置跳点,而 R 矩阵设得偏小,滤波器把跳点当成真实观测拉过去了。另一个可能是 IMU 数据在某个时刻出现了丢帧,积分速度时用了错误的时间间隔。

解决:在观测更新前加一个新息卡方检验,新息超过阈值就跳过这次 GPS 更新。阈值一般取 3~5 倍观测噪声标准差。同时检查 IMU 时间戳的差分,如果相邻两帧时间差超过标称采样周期的 1.5 倍,标记为丢帧并做补偿或跳过。

4.2 初始对准航向偏差大

现象:静态对准 60 秒后,输出的航向和实际朝向差几十度,跑起来轨迹整体旋转。

原因:消费级 MEMS 陀螺的零偏稳定性不足以敏感地球自转角速度(约 15°/h),静态对准算出来的航向基本是噪声。另一个原因是对准期间设备有轻微晃动,加速度计测到的重力方向不准。

解决:如果陀螺精度不够,改用双天线 GPS 测向或者磁力计辅助航向初始化。对准期间确保设备放在稳固平面上,远离振动源。对准时间可以适当延长到 120 秒,取平均降低噪声。

4.3 GPS 和 IMU 时间戳不同步

现象:组合导航轨迹和纯 GPS 轨迹整体错开一个固定时间量,速度曲线有相位差。

原因:GPS 的 UTC 时间和 IMU 的本地时间没有对齐,或者 GPS 的周内秒跳变(跨周)没处理。

解决:在数据预处理阶段做时间对齐,用第一个 GPS 时间戳对应的 IMU 帧号作为基准,往后按采样率递推。跨周问题需要在周内秒上加 604800 秒的整数倍修正。对齐之后画一下 GPS 速度大小和 IMU 积分速度大小的对比曲线,两条线应该基本重合。

4.4 滤波器参数不匹配导致精度差

现象:轨迹能跑通,但组合导航精度还不如纯 GPS,或者 INS 漂移压不住。

原因:Q 和 R 的比例失调。Q 太小表示过度信任 INS 预测,GPS 观测被忽略;Q 太大表示不信任 INS,组合导航退化成 GPS 平滑。

解决:先用 Allan 方差分析 IMU 静态数据,得到角度随机游走和速度随机游走的实际值,填进 Q 矩阵。R 矩阵用 GPS 静态数据的标准差来定。调参时先固定 R 调 Q,看新息序列是否白噪声;再固定 Q 微调 R,看轨迹平滑度和跟随性的平衡。

4.5 坐标系不一致导致位置偏移

现象:组合导航输出的经纬度和 GPS 原始经纬度差一个固定偏移,或者高度差几十米。

原因:GPS 输出可能是 WGS84 椭球高,而 INS 解算用的是当地水平坐标系,高度基准不一致。或者程序内部用了不同的地球模型参数。

解决:确认程序用的椭球参数(长半轴、扁率)和 GPS 数据一致。高度方面,如果需要海拔高,得做大地水准面精化,把椭球高转成正高。平面位置偏移检查一下投影方式,高斯投影和 UTM 的中央经线不同会导致偏移。

5. 进阶技巧:用轨迹闭合差和 Allan 方差验证组合导航质量

跑通只是第一步,怎么判断结果可信才是关键。我一般用两个手段:轨迹闭合差和 Allan 方差。

轨迹闭合差适合有往返或闭环路线的场景。把起点和终点的组合导航输出位置做差,如果闭合差在分米级,说明整体解算没有系统性漂移。如果闭合差到了米级甚至更大,回去查 IMU 零偏估计是否收敛、GPS 观测有没有被粗差污染。具体做法是:解算完整条轨迹后,取起点和终点各 10 个历元的位置平均值做差,再除以轨迹总长度,得到相对闭合差。相对闭合差优于 1/1000 算合格,优于 1/5000 算不错。

# 轨迹闭合差计算 import numpy as np start_pos = np.mean(traj[:10, 1:4], axis=0) # 前10个历元平均位置 end_pos = np.mean(traj[-10:, 1:4], axis=0) # 后10个历元平均位置 closure = np.linalg.norm(end_pos - start_pos) # 闭合差(米) total_dist = np.sum(np.linalg.norm(np.diff(traj[:, 1:4], axis=0), axis=1)) relative = closure / total_dist print(f"闭合差: {closure:.3f} m, 相对闭合差: 1/{1/relative:.0f}")

Allan 方差用来验证 IMU 数据的噪声特性,同时也能反推 Q 矩阵该设多少。把 IMU 静态采集 1~2 小时的数据,按不同时间簇长计算 Allan 方差,画双对数曲线。曲线在斜率 -1/2 段对应角度随机游走,斜率 +1/2 段对应零偏不稳定性。把角度随机游走的数值填进 Q 矩阵的角度项,零偏不稳定性用来判断陀螺零偏估计的收敛速度。

# 用 Allan 方差工具分析静态 IMU 数据 python allan_variance.py --input imu_static.csv --rate 200 --output allan.png # 输出:allan.png 包含陀螺和加速度计的 Allan 方差曲线 # 从曲线上读取 ARW 和 BI 值,填入滤波器 Q 矩阵

还有一个习惯:每次换设备或换数据,先跑一遍纯 INS 递推,看 1 分钟漂多少。如果纯 INS 1 分钟位置漂移超过 100 米,说明 IMU 零偏太大或者标定有问题,这时候组合导航的融合效果也会受限。纯 INS 漂移在几十米量级时,松组合通常能把精度拉到 GPS 水平附近。

从那以后我每次拿到新的惯导数据,都强制走一遍“纯 INS 递推 → Allan 方差 → 组合导航 → 闭合差检查”这个流程,不跳过任何一步。希望帮到你。

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

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进