☰
GPS/INS松耦合组合导航MATLAB代码实现与调试指南
2026/10/28 12:37:42 网站建设 项目流程

简介:这份资源是面向导航算法学习者与工程研发人员的GPS/INS组合导航仿真代码包,围绕松耦合组合方式展开,重点演示如何用卡尔曼滤波与Mahony AHRS姿态解算融合GPS定位信息与惯性传感器数据,解决单一GPS在遮挡环境下精度下降、纯INS误差随时间累积的问题。压缩包共8个文件,以7个.m脚本和1个.md说明文档为主,整体约8KB,脚本分别承担四元数运算、欧拉角转换、GPS/INS位置速度滤波、Mahony与Madgwick姿态更新及主程序导航解算等职责,README则提供使用说明。已有260人学习。读者可借此理解传感器建模、数据融合接口与仿真流程,掌握滤波器参数调节和结果输出方法,为组合导航系统设计与优化提供可运行的参考范例。

1. 拆开 GPS-INS-Integrated-Navigation-master:一套能跑通松耦合的 MATLAB 组合导航代码

如果你手头只有一段带噪声的加速度计和陀螺仪数据,外加一串稀疏的 GPS 定位点,想验证自己的融合算法到底能不能收敛,这套GPS-INS-Integrated-Navigation-master.zip就是为这个场景准备的。它用 MATLAB 实现了 GPS/INS 松耦合组合导航,核心文件包括main_NAV.m、kalman_GPS_INS_pv.m、madgwickAHRS.m、MahonyAHRSupdate.m、Quaternion_FromEulerAngle.m、quaternProd.m、quaternConj.m。整套代码不依赖任何工具箱,纯脚本加函数,适合做算法验证、课程设计、论文复现。它解决的不是产品级导航,而是让你在桌面上把姿态解算、卡尔曼滤波、GPS 校正这三件事串起来,看清每一步的输入输出。适合已经学过惯性导航基础、能看懂四元数乘法、想动手改参数看结果的人。下面按“资源是什么 → 怎么跑 → 坑在哪 → 怎么改”的顺序拆。

2. 从四元数到卡尔曼:这套代码的模块分工与数据流

2.1 姿态解算层:Mahony 与 Madgwick 两条路

MahonyAHRSupdate.m和madgwickAHRS.m是两个独立的姿态更新函数,输入都是陀螺仪角速度、加速度计比力、磁力计(可选),输出四元数。Mahony 走的是非线性互补滤波,用加速度计修正陀螺仪积分漂移;Madgwick 则是梯度下降加互补滤波,计算量略大但动态响应更平滑。代码里两个都给了,说明作者想让你对比。实际跑的时候,main_NAV.m里默认调用哪一个,取决于你注释掉哪一行。常见做法是先用 Mahony 跑通,因为参数少,主要调Kp和Ki两个增益。

% MahonyAHRSupdate.m 核心片段 function [q] = MahonyAHRSupdate(gx, gy, gz, ax, ay, az, mx, my, mz, q, Kp, Ki) % 归一化加速度计和磁力计 norm_a = sqrt(ax^2 + ay^2 + az^2); ax = ax / norm_a; ay = ay / norm_a; az = az / norm_a; % 估计重力方向与测量重力方向叉积,得到误差 halfvx = q(2)*q(4) - q(1)*q(3); halfvy = q(1)*q(2) + q(3)*q(4); halfvz = q(1)^2 - 0.5 + q(4)^2; halfex = (ay * halfvz - az * halfvy); halfey = (az * halfvx - ax * halfvz); halfez = (ax * halfvy - ay * halfvx); % PI 修正陀螺仪零偏 gx = gx + Kp * halfex; gy = gy + Kp * halfey; gz = gz + Kp * halfez; % 四元数积分 qDot = 0.5 * quaternProd(q, [0 gx gy gz]); q = q + qDot * 0.01; % 0.01 为采样周期,需与数据实际频率一致 q = q / norm(q); end

逻辑说明:先归一化加速度计,消除量纲影响;再用当前四元数推算理论重力方向,与实测重力方向做叉积得到姿态误差;误差乘以Kp直接补偿陀螺仪,Ki用于补偿陀螺仪零偏。参数Kp典型值 0.5~2.0,Ki取 0.001~0.01。Kp太大姿态会抖,太小收敛慢。采样周期 0.01 对应 100Hz,如果你的 IMU 是 200Hz,这里必须改成 0.005,否则四元数积分会翻车。

2.2 组合导航层:松耦合卡尔曼滤波怎么接

kalman_GPS_INS_pv.m是位置-速度卡尔曼滤波器,状态量是[px, py, pz, vx, vy, vz],观测量是 GPS 的位置和速度。INS 通过加速度计积分得到预测位置和速度,GPS 到来时做量测更新。代码里没有做姿态与位置的联合滤波,姿态只用于把机体加速度转到导航系,所以是典型的松耦合。main_NAV.m负责读数据、循环调用姿态更新和卡尔曼更新、画图。

% kalman_GPS_INS_pv.m 预测步核心 function [x_pred, P_pred] = kalman_predict(x, P, acc_nav, dt, Q) % 状态转移矩阵 F F = [1 0 0 dt 0 0; 0 1 0 0 dt 0; 0 0 1 0 0 dt; 0 0 0 1 0 0; 0 0 0 0 1 0; 0 0 0 0 0 1]; % 控制输入矩阵 B,把导航系加速度映射到位置和速度 B = [0.5*dt^2 0 0; 0 0.5*dt^2 0; 0 0 0.5*dt^2; dt 0 0; 0 dt 0; 0 0 dt]; x_pred = F * x + B * acc_nav; P_pred = F * P * F' + Q; end

逻辑说明:dt是 IMU 采样周期,acc_nav是去掉重力后的导航系加速度。Q是过程噪声协方差,反映你对 INS 积分结果的信任程度。Q越大,滤波器越相信 GPS;Q越小,越相信 INS 短期推算。常见做法是Q取对角阵,位置项 1e-4,速度项 1e-2,具体看你的 IMU 噪声密度。量测更新部分用 GPS 位置和速度构造H矩阵,计算卡尔曼增益,更新状态和协方差。注意 GPS 速度不是所有模块都输出,如果你的数据只有位置,把H和R的对应行去掉即可。

2.3 数据流与文件依赖关系

main_NAV.m是入口,先加载数据,再初始化四元数和卡尔曼状态,然后进入主循环。每个循环里:读一帧 IMU → 调用MahonyAHRSupdate或madgwickAHRS更新姿态 → 用quaternConj和quaternProd把机体加速度转到导航系 → 调用kalman_GPS_INS_pv做预测 → 如果当前时刻有 GPS,做量测更新 → 保存结果。Quaternion_FromEulerAngle.m用于初始化姿态,如果你知道初始欧拉角,用它转成四元数。quaternProd.m和quaternConj.m是四元数乘法和共轭,姿态更新和坐标变换都依赖它们。整个数据流没有闭环控制,纯开环仿真,所以你可以随意替换数据源。

3. 跑通 main_NAV.m:数据准备、参数配置与结果验证

3.1 数据格式与加载方式

代码没有附带真实数据集,main_NAV.m里通常用load读一个.mat文件,变量名可能是imu_data和gps_data。IMU 数据一般包含时间戳、三轴陀螺仪(rad/s)、三轴加速度计(m/s²)。GPS 数据包含时间戳、经纬高或局部坐标、速度。如果你手头是neo-m8n gps模块输出的 NMEA 语句,需要先转成局部坐标。常见做法是用geodetic2ned或自己写墨卡托投影,把经纬高转成东北天坐标。注意 GPS 时间戳和 IMU 时间戳要对齐,代码里一般用interp1插值到 IMU 时刻。

% 数据加载与时间对齐示例 load('imu_data.mat'); % 包含 t_imu, gyro, accel load('gps_data.mat'); % 包含 t_gps, pos_gps, vel_gps % 把 GPS 位置插值到 IMU 时间轴 pos_gps_interp = interp1(t_gps, pos_gps, t_imu, 'linear', 'extrap'); vel_gps_interp = interp1(t_gps, vel_gps, t_imu, 'linear', 'extrap'); % 标记哪些 IMU 时刻有 GPS 观测 has_gps = ~isnan(pos_gps_interp(:,1));

逻辑说明:interp1的extrap选项允许外推,但 GPS 缺失段外推会引入虚假观测,建议把外推部分置NaN,在卡尔曼更新时用has_gps判断是否执行量测更新。参数t_imu和t_gps单位要一致,通常用秒。如果你的 GPS 是 1Hz,IMU 是 100Hz,插值后大部分时刻没有 GPS,这是正常的,滤波器靠 INS 递推。

3.2 关键参数配置表

参数含义典型值调整影响
KpMahony 比例增益0.5~2.0越大姿态收敛快,但噪声放大
KiMahony 积分增益0.001~0.01补偿陀螺零偏,太大会缓慢振荡
dtIMU 采样周期0.01s (100Hz)必须与实际数据频率一致
Q_pos位置过程噪声1e-4越大越信 GPS
Q_vel速度过程噪声1e-2越大越信 GPS
R_posGPS 位置观测噪声1~10根据 GPS 精度设,单位 m²
R_velGPS 速度观测噪声0.1~1根据 GPS 速度精度设

这些参数没有万能值,我一般先让Q和R保持默认,跑一遍看位置误差曲线,如果 INS 发散太快就增大Q,如果 GPS 跳变被过度平滑就减小R。注意R的单位要和状态量一致,位置用 m²,速度用 (m/s)²。

3.3 运行与结果验证

直接运行main_NAV.m,正常会弹出三个图:姿态角、位置、速度。姿态角看横滚和俯仰是否收敛到合理范围,位置看组合结果是否比纯 INS 更贴近 GPS。验证方法:把 GPS 量测更新关掉,只跑 INS 积分,位置会在几十秒内漂出几百米;打开更新后,位置应被拉回 GPS 附近。如果姿态角一直发散,先检查加速度计符号和坐标系定义,常见错误是加速度计正方向搞反,导致重力估计错误。

% 关闭 GPS 更新的对比测试 if has_gps(k) [x, P] = kalman_update(x, P, pos_gps_interp(k,:), vel_gps_interp(k,:), R); end % 注释掉上面 if 块,只保留预测,观察纯 INS 漂移

逻辑说明:通过条件开关可以快速对比松耦合和纯 INS 的效果。kalman_update内部计算增益K = P_pred * H' / (H * P_pred * H' + R),然后更新x = x_pred + K * (z - H * x_pred)。如果R设得过大,K趋近 0,GPS 几乎不起作用,结果和纯 INS 一样。

4. 避坑与排查:四元数、坐标系、时间同步的五个血泪经验

4.1 现象:姿态角在静止时缓慢旋转 → 原因:陀螺仪零偏未补偿 → 解决:增大Ki或先做静态零偏校准

Mahony 的积分项就是干这个的,但Ki太小时补偿速度跟不上零偏。我一般先让 IMU 静止采 30 秒,求陀螺仪均值作为零偏,在进入滤波器前减掉。如果代码里没有这一步,Ki设到 0.01 以上,但会引入低频振荡。注意静态校准要在恒温下做,温度变化后零偏会变。

4.2 现象:位置在 GPS 更新时跳变 → 原因:GPS 坐标系与 INS 导航系不一致 → 解决:统一到东北天或北东地

常见错误是 GPS 给的是经纬高,直接当米用。必须先转局部坐标。另外注意 INS 导航系是东北天还是北东地,kalman_GPS_INS_pv.m里状态量顺序要和 GPS 转换后的顺序一致。如果 GPS 是北东地,INS 是东北天,更新时 y 和 z 会反号,位置曲线会出现锯齿。

4.3 现象:四元数模长逐渐偏离 1 → 原因:积分后未归一化或dt错误 → 解决:每步强制归一化,核对dt

MahonyAHRSupdate末尾有q = q / norm(q),但如果你自己改了代码忘了加,四元数会漂。另外dt写错会导致积分步长不对,比如实际 200Hz 写成 0.01,四元数旋转速度会慢一倍,姿态跟踪不上。检查方法:静止时四元数应保持常数,旋转时模长始终为 1。

4.4 现象:卡尔曼滤波结果比纯 INS 还差 → 原因:Q和R量级不匹配 → 解决:先调R再调Q

如果R设得太小,GPS 噪声被完全信任,位置会跟着 GPS 跳。如果Q设得太大,预测步几乎不起作用,滤波器退化成 GPS 平滑。我一般先把R设为 GPS 标称精度的平方,比如 GPS 水平精度 2m,R_pos设 4,然后微调Q让曲线在 GPS 缺失段漂移可接受。

4.5 现象:quaternProd报维度错误 → 原因:四元数行向量与列向量混用 → 解决:统一为行向量或列向量

代码里quaternProd(q, [0 gx gy gz])要求两个输入维度一致。如果你从别处拷来的四元数是列向量,这里会报错。打开quaternProd.m看第一行,如果是function ab = quaternProd(a, b),检查a和b的size。统一用行向量最省事,MATLAB 默认也是行向量。

5. 进阶改法:把 Mahony 换成 Madgwick,再给卡尔曼加零偏状态

5.1 切换姿态算法并对比动态响应

main_NAV.m里把MahonyAHRSupdate替换成madgwickAHRS,注意 Madgwick 的输入参数是Beta而不是Kp/Ki。Beta典型值 0.01~0.1,越大越信加速度计,越小越信陀螺仪。切换后跑同一段数据,看横滚角在快速机动时的滞后。Mahony 在低频振动下更稳,Madgwick 在加减速剧烈时收敛更快。我一般两个都跑,取曲线重合度高的那个。

% 切换为 Madgwick % [q] = MahonyAHRSupdate(gx, gy, gz, ax, ay, az, mx, my, mz, q, Kp, Ki); [q] = madgwickAHRS(gx, gy, gz, ax, ay, az, mx, my, mz, q, Beta);

逻辑说明:Madgwick 内部用梯度下降求姿态误差梯度,再与陀螺仪积分融合。Beta相当于梯度下降步长,太大姿态会抖,太小漂移抑制弱。建议从 0.03 开始试。

5.2 给卡尔曼加陀螺仪零偏状态

松耦合的kalman_GPS_INS_pv.m只估计位置和速度,陀螺零偏靠 Mahony 的Ki补偿。如果你想更精确,可以把状态扩到 9 维,加入三轴陀螺零偏,观测量不变。这样 GPS 位置误差会间接修正零偏。改法:状态转移矩阵加零偏项(零偏随机游走),Q加零偏过程噪声。代码改动量不大,但需要重新调Q。我试过在低精度 IMU 上扩维,位置误差能降 20% 左右,代价是收敛变慢。

5.3 用真实 GPS 数据替换仿真数据

如果你有neo-m8n gps模块的实测数据,先解析 NMEA 的GPGGA和GPRMC,提取经纬高、速度、时间。用geodetic2ned转局部坐标,参考点取第一条 GPS 的经纬高。IMU 数据如果是gps 数据里常见的 MPU6050 输出,注意量程和单位,陀螺仪可能是 °/s,要转 rad/s。时间同步用 GPS 的 PPS 或串口时间戳对齐。替换后先跑纯 INS 看漂移速率,再开组合看修正效果。从那以后我每次拿到新数据,都先画一遍原始加速度计和陀螺仪曲线,确认没有截断和符号错误,再进滤波器。希望帮到你。

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

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

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

立即咨询