# 无人机GPS丢失怎么办?——多传感器融合与惯性导航完全指南

前言

你的无人机正在执行任务,突然:

  • 飞过高楼,GPS信号被遮挡
  • 经过信号塔,电磁干扰
  • 进入桥底/隧道
  • 多径效应导致定位漂移

GPS丢了3-5秒,无人机会怎样?

如果没有备份方案:

  • 位置估计停止更新
  • 飞控以为还在原地
  • 实际已经飘出去几十米
  • 轻则任务失败,重则炸机

今天我们来解决这个问题:GPS丢失时,如何让无人机"盲飞"也不迷路?

问题分析

复制代码
┌─────────────────────────────────────────────────────────────────────────────┐
│                    GPS丢失的场景                                             │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   【城市环境】                                                              │
│   ─────────────────────────────────────────                                 │
│                                                                             │
│        卫星信号                                                             │
│       ↓ ↓ ↓ ↓                                                              │
│        ╲│╱                                                                 │
│    ┌────┴────┐                                                             │
│    │  高楼   │         ← 信号遮挡                                          │
│    │        │                                                              │
│    │        │    🚁 无人机                                                 │
│    │        │    ╱                                                         │
│    │        │   ╱  信号被挡                                                │
│    │        │  ╱                                                           │
│    └────────┘                                                              │
│                                                                             │
│   典型情况:                                                                 │
│   - 高楼边缘: 信号突然丢失再恢复                                           │
│   - 楼宇峡谷: 持续遮挡 + 多径反射                                          │
│   - 室内→室外过渡: 信号逐渐恢复                                            │
│                                                                             │
│   【电磁干扰】                                                              │
│   ─────────────────────────────────────────                                 │
│                                                                             │
│        📡 信号塔/雷达站                                                    │
│         │                                                                   │
│         │ 强电磁波                                                          │
│         ↓                                                                   │
│        🚁 ← GPS接收机被干扰                                                │
│                                                                             │
│   - 持续时间: 通常几秒到十几秒                                             │
│   - 特点: 突发性强,难以预测                                               │
│                                                                             │
│   【多径效应】                                                              │
│   ─────────────────────────────────────────                                 │
│                                                                             │
│         卫星                                                                │
│          │╲                                                                │
│          │ ╲ 反射信号                                                      │
│          │  ╲                                                              │
│          │   ╲                                                             │
│          ↓    ↘                                                            │
│         🚁 ←───── 建筑物反射                                               │
│                                                                             │
│   - 直接信号 + 反射信号 = 定位误差                                         │
│   - 严重时误差可达几十米                                                    │
│   - 比完全丢失更危险(因为有数据但是错的)                                 │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

解决方案总览

复制代码
┌─────────────────────────────────────────────────────────────────────────────┐
│                    GPS丢失应对方案                                           │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   【核心思路】 多传感器融合 + 惯性导航兜底                                  │
│                                                                             │
│   ┌─────────────────────────────────────────────────────────────────────┐  │
│   │                                                                     │  │
│   │                      ┌─────────────┐                               │  │
│   │      GPS ──────────►│             │                               │  │
│   │      (可能丢失)      │             │                               │  │
│   │                      │             │                               │  │
│   │      IMU ──────────►│   融合滤波  │──────► 最优位置估计           │  │
│   │      (始终可用)      │   (EKF)     │                               │  │
│   │                      │             │                               │  │
│   │      视觉 ─────────►│             │                               │  │
│   │      (备选)         │             │                               │  │
│   │                      │             │                               │  │
│   │      气压计 ────────►│             │                               │  │
│   │      (高度)         └─────────────┘                               │  │
│   │                                                                     │  │
│   └─────────────────────────────────────────────────────────────────────┘  │
│                                                                             │
│   【方案矩阵】                                                              │
│                                                                             │
│   ┌───────────────┬─────────────┬─────────────┬───────────────────────┐   │
│   │    方案       │   精度      │   持续时间  │     适用场景          │   │
│   ├───────────────┼─────────────┼─────────────┼───────────────────────┤   │
│   │ 纯惯导推算    │ 漂移~1m/s   │  3-10秒     │ 短时丢星、应急       │   │
│   │ IMU+气压计    │ 漂移~0.5m/s │  5-15秒     │ 已知高度场景         │   │
│   │ VIO视觉惯性   │ 漂移~1%路程 │  30秒+      │ 有纹理环境           │   │
│   │ UWB定位       │ 10-30cm     │  无限       │ 预部署基站           │   │
│   │ 激光SLAM      │ 厘米级      │  无限       │ 有结构环境           │   │
│   └───────────────┴─────────────┴─────────────┴───────────────────────┘   │
│                                                                             │
│   对于"3-5秒GPS丢失"这个场景:                                              │
│   ✅ 纯惯导推算完全够用                                                    │
│   ✅ 加上气压计/视觉更稳                                                   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

方案1:惯性导航推算(INS Dead Reckoning)

原理

复制代码
┌─────────────────────────────────────────────────────────────────────────────┐
│                    惯性导航原理                                              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   IMU (惯性测量单元) 包含:                                                  │
│   - 加速度计: 测量3轴加速度 (ax, ay, az)                                   │
│   - 陀螺仪: 测量3轴角速度 (gx, gy, gz)                                     │
│                                                                             │
│   【航位推算】                                                              │
│   ─────────────────────────────────────────                                 │
│                                                                             │
│   已知: 初始位置、初始速度、初始姿态                                       │
│   测量: 加速度、角速度                                                      │
│   求解: 当前位置                                                            │
│                                                                             │
│   步骤:                                                                     │
│   ┌─────────────────────────────────────────────────────────────────────┐  │
│   │                                                                     │  │
│   │   1. 姿态更新 (用陀螺仪)                                            │  │
│   │      ─────────────────────                                          │  │
│   │      角度变化 = 角速度 × 时间                                       │  │
│   │      θ(t+dt) = θ(t) + ω × dt                                       │  │
│   │                                                                     │  │
│   │   2. 坐标转换 (机体系→导航系)                                       │  │
│   │      ─────────────────────                                          │  │
│   │      a_nav = R(姿态) × a_body                                       │  │
│   │                                                                     │  │
│   │   3. 去除重力                                                       │  │
│   │      ─────────────────────                                          │  │
│   │      a_real = a_nav - [0, 0, g]                                    │  │
│   │                                                                     │  │
│   │   4. 速度积分                                                       │  │
│   │      ─────────────────────                                          │  │
│   │      v(t+dt) = v(t) + a_real × dt                                  │  │
│   │                                                                     │  │
│   │   5. 位置积分                                                       │  │
│   │      ─────────────────────                                          │  │
│   │      p(t+dt) = p(t) + v × dt                                       │  │
│   │                                                                     │  │
│   └─────────────────────────────────────────────────────────────────────┘  │
│                                                                             │
│   【误差累积问题】                                                          │
│   ─────────────────────────────────────────                                 │
│                                                                             │
│   加速度误差 → 二次积分 → 位置误差快速增长                                 │
│                                                                             │
│   假设加速度计有 0.01 m/s² 的偏差:                                         │
│   - 1秒后位置误差: 0.5 × 0.01 × 1² = 0.005m                               │
│   - 5秒后位置误差: 0.5 × 0.01 × 5² = 0.125m                               │
│   - 10秒后位置误差: 0.5 × 0.01 × 10² = 0.5m                               │
│                                                                             │
│   结论: 消费级IMU纯惯导撑5-10秒问题不大,再长就不行了                      │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

代码实现

c 复制代码
/**
 * 惯性导航推算 (INS Dead Reckoning)
 * 
 * 当GPS丢失时,用IMU进行位置推算
 */

#include <stdio.h>
#include <math.h>
#include <string.h>

// 导航状态
typedef struct {
    // 位置 (NED坐标系,单位:米)
    double position[3];     // [北, 东, 下]
    
    // 速度 (m/s)
    double velocity[3];     // [北向速度, 东向速度, 下向速度]
    
    // 姿态四元数 [w, x, y, z]
    double quaternion[4];
    
    // 姿态欧拉角 (弧度)
    double roll;
    double pitch;
    double yaw;
    
    // 时间戳
    double timestamp;
    
    // 状态标志
    int gps_valid;          // GPS是否有效
    double gps_lost_time;   // GPS丢失时长
    
} NavState_t;

// IMU数据
typedef struct {
    double accel[3];        // 加速度 [ax, ay, az] (m/s²)
    double gyro[3];         // 角速度 [gx, gy, gz] (rad/s)
    double timestamp;
} IMUData_t;

// GPS数据
typedef struct {
    double position[3];     // [北, 东, 下]
    double velocity[3];     // [北向, 东向, 下向]
    double accuracy;        // 精度估计 (米)
    int num_satellites;     // 卫星数
    int valid;              // 数据是否有效
    double timestamp;
} GPSData_t;

// INS推算器
typedef struct {
    NavState_t state;
    
    // IMU偏差估计 (可由卡尔曼滤波器估计)
    double accel_bias[3];
    double gyro_bias[3];
    
    // 重力加速度
    double gravity;
    
    // 配置
    double max_dead_reckoning_time;  // 最大推算时间
    
} INSNavigator_t;

/**
 * 四元数归一化
 */
void quaternion_normalize(double q[4])
{
    double norm = sqrt(q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]);
    if (norm > 1e-10) {
        q[0] /= norm;
        q[1] /= norm;
        q[2] /= norm;
        q[3] /= norm;
    }
}

/**
 * 四元数乘法 q = q1 * q2
 */
void quaternion_multiply(const double q1[4], const double q2[4], double q[4])
{
    q[0] = q1[0]*q2[0] - q1[1]*q2[1] - q1[2]*q2[2] - q1[3]*q2[3];
    q[1] = q1[0]*q2[1] + q1[1]*q2[0] + q1[2]*q2[3] - q1[3]*q2[2];
    q[2] = q1[0]*q2[2] - q1[1]*q2[3] + q1[2]*q2[0] + q1[3]*q2[1];
    q[3] = q1[0]*q2[3] + q1[1]*q2[2] - q1[2]*q2[1] + q1[3]*q2[0];
}

/**
 * 四元数转旋转矩阵 (机体系到导航系)
 */
void quaternion_to_rotation_matrix(const double q[4], double R[3][3])
{
    double w = q[0], x = q[1], y = q[2], z = q[3];
    
    R[0][0] = 1 - 2*(y*y + z*z);
    R[0][1] = 2*(x*y - w*z);
    R[0][2] = 2*(x*z + w*y);
    
    R[1][0] = 2*(x*y + w*z);
    R[1][1] = 1 - 2*(x*x + z*z);
    R[1][2] = 2*(y*z - w*x);
    
    R[2][0] = 2*(x*z - w*y);
    R[2][1] = 2*(y*z + w*x);
    R[2][2] = 1 - 2*(x*x + y*y);
}

/**
 * 四元数转欧拉角
 */
void quaternion_to_euler(const double q[4], double *roll, double *pitch, double *yaw)
{
    double w = q[0], x = q[1], y = q[2], z = q[3];
    
    // Roll (x-axis rotation)
    double sinr_cosp = 2 * (w * x + y * z);
    double cosr_cosp = 1 - 2 * (x * x + y * y);
    *roll = atan2(sinr_cosp, cosr_cosp);
    
    // Pitch (y-axis rotation)
    double sinp = 2 * (w * y - z * x);
    if (fabs(sinp) >= 1)
        *pitch = copysign(M_PI / 2, sinp);
    else
        *pitch = asin(sinp);
    
    // Yaw (z-axis rotation)
    double siny_cosp = 2 * (w * z + x * y);
    double cosy_cosp = 1 - 2 * (y * y + z * z);
    *yaw = atan2(siny_cosp, cosy_cosp);
}

/**
 * 初始化INS推算器
 */
void ins_init(INSNavigator_t *ins)
{
    memset(ins, 0, sizeof(INSNavigator_t));
    
    // 初始姿态为水平
    ins->state.quaternion[0] = 1.0;
    ins->state.quaternion[1] = 0.0;
    ins->state.quaternion[2] = 0.0;
    ins->state.quaternion[3] = 0.0;
    
    ins->gravity = 9.81;
    ins->max_dead_reckoning_time = 10.0;  // 最大推算10秒
    
    // 偏差初始化为0 (实际应用中需要标定或在线估计)
    memset(ins->accel_bias, 0, sizeof(ins->accel_bias));
    memset(ins->gyro_bias, 0, sizeof(ins->gyro_bias));
}

/**
 * 用GPS数据更新状态
 */
void ins_update_gps(INSNavigator_t *ins, const GPSData_t *gps)
{
    if (!gps->valid || gps->num_satellites < 4) {
        // GPS无效
        if (ins->state.gps_valid) {
            // 刚丢失GPS
            ins->state.gps_valid = 0;
            ins->state.gps_lost_time = 0;
            printf("[INS] GPS丢失,切换到惯导推算模式\n");
        }
        return;
    }
    
    // GPS有效,更新状态
    if (!ins->state.gps_valid) {
        printf("[INS] GPS恢复,丢失时长: %.2f秒\n", ins->state.gps_lost_time);
    }
    
    ins->state.gps_valid = 1;
    ins->state.gps_lost_time = 0;
    
    // 用GPS位置和速度修正INS状态
    // 这里简化处理,直接替换
    // 实际应用中应该用卡尔曼滤波融合
    memcpy(ins->state.position, gps->position, sizeof(gps->position));
    memcpy(ins->state.velocity, gps->velocity, sizeof(gps->velocity));
    
    ins->state.timestamp = gps->timestamp;
}

/**
 * 惯性导航推算主函数
 */
void ins_propagate(INSNavigator_t *ins, const IMUData_t *imu)
{
    double dt = imu->timestamp - ins->state.timestamp;
    if (dt <= 0 || dt > 0.1) {
        ins->state.timestamp = imu->timestamp;
        return;
    }
    
    // 更新GPS丢失时长
    if (!ins->state.gps_valid) {
        ins->state.gps_lost_time += dt;
        
        // 超过最大推算时间,发出警告
        if (ins->state.gps_lost_time > ins->max_dead_reckoning_time) {
            // 可以切换到悬停/返航等安全模式
            printf("[INS] 警告: GPS丢失超过%.1f秒,位置估计不可靠!\n", 
                   ins->state.gps_lost_time);
        }
    }
    
    // ================== 1. 姿态更新 ==================
    
    // 去除陀螺仪偏差
    double gyro_corrected[3];
    gyro_corrected[0] = imu->gyro[0] - ins->gyro_bias[0];
    gyro_corrected[1] = imu->gyro[1] - ins->gyro_bias[1];
    gyro_corrected[2] = imu->gyro[2] - ins->gyro_bias[2];
    
    // 角速度转四元数增量
    double angle = sqrt(gyro_corrected[0]*gyro_corrected[0] + 
                        gyro_corrected[1]*gyro_corrected[1] + 
                        gyro_corrected[2]*gyro_corrected[2]) * dt;
    
    double dq[4];
    if (angle > 1e-10) {
        double axis[3] = {
            gyro_corrected[0] * dt / angle,
            gyro_corrected[1] * dt / angle,
            gyro_corrected[2] * dt / angle
        };
        double half_angle = angle / 2;
        dq[0] = cos(half_angle);
        dq[1] = axis[0] * sin(half_angle);
        dq[2] = axis[1] * sin(half_angle);
        dq[3] = axis[2] * sin(half_angle);
    } else {
        dq[0] = 1.0;
        dq[1] = gyro_corrected[0] * dt / 2;
        dq[2] = gyro_corrected[1] * dt / 2;
        dq[3] = gyro_corrected[2] * dt / 2;
    }
    
    // 更新四元数: q_new = q_old * dq
    double q_new[4];
    quaternion_multiply(ins->state.quaternion, dq, q_new);
    quaternion_normalize(q_new);
    memcpy(ins->state.quaternion, q_new, sizeof(q_new));
    
    // 更新欧拉角
    quaternion_to_euler(ins->state.quaternion, 
                        &ins->state.roll, &ins->state.pitch, &ins->state.yaw);
    
    // ================== 2. 坐标转换 ==================
    
    // 去除加速度计偏差
    double accel_corrected[3];
    accel_corrected[0] = imu->accel[0] - ins->accel_bias[0];
    accel_corrected[1] = imu->accel[1] - ins->accel_bias[1];
    accel_corrected[2] = imu->accel[2] - ins->accel_bias[2];
    
    // 机体系加速度转导航系
    double R[3][3];
    quaternion_to_rotation_matrix(ins->state.quaternion, R);
    
    double accel_nav[3];
    accel_nav[0] = R[0][0]*accel_corrected[0] + R[0][1]*accel_corrected[1] + R[0][2]*accel_corrected[2];
    accel_nav[1] = R[1][0]*accel_corrected[0] + R[1][1]*accel_corrected[1] + R[1][2]*accel_corrected[2];
    accel_nav[2] = R[2][0]*accel_corrected[0] + R[2][1]*accel_corrected[1] + R[2][2]*accel_corrected[2];
    
    // ================== 3. 去除重力 ==================
    
    // NED坐标系下重力在D轴正方向
    accel_nav[2] -= ins->gravity;
    
    // ================== 4. 速度积分 ==================
    
    ins->state.velocity[0] += accel_nav[0] * dt;
    ins->state.velocity[1] += accel_nav[1] * dt;
    ins->state.velocity[2] += accel_nav[2] * dt;
    
    // ================== 5. 位置积分 ==================
    
    ins->state.position[0] += ins->state.velocity[0] * dt;
    ins->state.position[1] += ins->state.velocity[1] * dt;
    ins->state.position[2] += ins->state.velocity[2] * dt;
    
    ins->state.timestamp = imu->timestamp;
}

/**
 * 获取当前位置估计和置信度
 */
void ins_get_position(const INSNavigator_t *ins, 
                      double position[3], double *confidence)
{
    memcpy(position, ins->state.position, sizeof(ins->state.position));
    
    // 置信度随GPS丢失时间下降
    if (ins->state.gps_valid) {
        *confidence = 1.0;
    } else {
        // 指数衰减
        *confidence = exp(-ins->state.gps_lost_time / 5.0);
        
        // 最低置信度
        if (*confidence < 0.1) *confidence = 0.1;
    }
}

方案2:扩展卡尔曼滤波(EKF)多传感器融合

原理

复制代码
┌─────────────────────────────────────────────────────────────────────────────┐
│                    EKF传感器融合原理                                         │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   【为什么需要EKF?】                                                       │
│   ─────────────────────────────────────────                                 │
│                                                                             │
│   单独使用每种传感器都有问题:                                               │
│                                                                             │
│   GPS:  准确但更新慢(5-10Hz),可能丢失                                     │
│   IMU:  更新快(100Hz+),但会漂移                                           │
│   气压: 高度稳定,但受天气影响                                              │
│   视觉: 相对运动准确,但累积误差                                           │
│                                                                             │
│   EKF的作用: 融合多个传感器的优点,弥补各自缺点                            │
│                                                                             │
│   【EKF工作流程】                                                           │
│   ─────────────────────────────────────────                                 │
│                                                                             │
│   时间线:                                                                   │
│   ───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───►                           │
│      │IMU│IMU│IMU│GPS│IMU│IMU│IMU│GPS│IMU│IMU│                            │
│      │   │   │   │   │   │   │   │   │   │   │                            │
│      ▼   ▼   ▼   ▼   ▼   ▼   ▼   ▼   ▼   ▼   ▼                            │
│    预测 预测 预测 更新 预测 预测 预测 更新 预测 预测                        │
│                                                                             │
│   预测步骤 (Predict): 用IMU数据推算                                        │
│   ┌─────────────────────────────────────────────────────────────────────┐  │
│   │   x_pred = f(x_prev, u)        // 状态预测                          │  │
│   │   P_pred = F * P_prev * F' + Q // 协方差预测                        │  │
│   └─────────────────────────────────────────────────────────────────────┘  │
│                                                                             │
│   更新步骤 (Update): 用GPS/气压等修正                                      │
│   ┌─────────────────────────────────────────────────────────────────────┐  │
│   │   y = z - h(x_pred)            // 测量残差                          │  │
│   │   S = H * P_pred * H' + R      // 残差协方差                        │  │
│   │   K = P_pred * H' * S^(-1)     // 卡尔曼增益                        │  │
│   │   x = x_pred + K * y           // 状态更新                          │  │
│   │   P = (I - K * H) * P_pred     // 协方差更新                        │  │
│   └─────────────────────────────────────────────────────────────────────┘  │
│                                                                             │
│   【GPS丢失时的处理】                                                       │
│   ─────────────────────────────────────────                                 │
│                                                                             │
│   GPS有效时: 预测 → 更新 → 预测 → 更新 → ...                              │
│   GPS丢失时: 预测 → 预测 → 预测 → ... (协方差增大)                        │
│   GPS恢复时: ... → 更新 (大幅修正)                                         │
│                                                                             │
│   协方差P反映了位置估计的不确定性:                                          │
│   - GPS正常: P保持较小                                                     │
│   - GPS丢失: P随时间增大 (因为只有预测没有修正)                           │
│   - GPS恢复: P被更新步骤拉回来                                            │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

EKF实现

c 复制代码
/**
 * 扩展卡尔曼滤波器 (EKF) 实现
 * 
 * 状态向量: [px, py, pz, vx, vy, vz, roll, pitch, yaw, bax, bay, baz, bgx, bgy, bgz]
 *           位置      速度        姿态             加速度偏差      陀螺偏差
 * 共15维状态
 */

#include <stdio.h>
#include <math.h>
#include <string.h>

#define STATE_DIM 15
#define POS_IDX   0
#define VEL_IDX   3
#define ATT_IDX   6
#define BA_IDX    9
#define BG_IDX    12

// EKF状态
typedef struct {
    double x[STATE_DIM];              // 状态向量
    double P[STATE_DIM][STATE_DIM];   // 协方差矩阵
    double Q[STATE_DIM][STATE_DIM];   // 过程噪声
    double timestamp;
    
    // GPS状态
    int gps_valid;
    int gps_lost_count;
    double gps_lost_duration;
    
} EKFState_t;

// 矩阵运算辅助函数
void matrix_multiply(double *A, double *B, double *C, int m, int n, int p)
{
    // C = A * B, A是m×n, B是n×p
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < p; j++) {
            C[i * p + j] = 0;
            for (int k = 0; k < n; k++) {
                C[i * p + j] += A[i * n + k] * B[k * p + j];
            }
        }
    }
}

void matrix_add(double *A, double *B, double *C, int m, int n)
{
    for (int i = 0; i < m * n; i++) {
        C[i] = A[i] + B[i];
    }
}

void matrix_transpose(double *A, double *AT, int m, int n)
{
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            AT[j * m + i] = A[i * n + j];
        }
    }
}

/**
 * 初始化EKF
 */
void ekf_init(EKFState_t *ekf)
{
    memset(ekf, 0, sizeof(EKFState_t));
    
    // 初始协方差 (对角线)
    // 位置不确定性: 10m
    ekf->P[0][0] = 100.0;
    ekf->P[1][1] = 100.0;
    ekf->P[2][2] = 100.0;
    
    // 速度不确定性: 1m/s
    ekf->P[3][3] = 1.0;
    ekf->P[4][4] = 1.0;
    ekf->P[5][5] = 1.0;
    
    // 姿态不确定性: 0.1rad
    ekf->P[6][6] = 0.01;
    ekf->P[7][7] = 0.01;
    ekf->P[8][8] = 0.01;
    
    // 偏差不确定性
    ekf->P[9][9] = 0.1;
    ekf->P[10][10] = 0.1;
    ekf->P[11][11] = 0.1;
    ekf->P[12][12] = 0.01;
    ekf->P[13][13] = 0.01;
    ekf->P[14][14] = 0.01;
    
    // 过程噪声
    // 位置: 由速度积分,不直接加噪声
    // 速度: 加速度噪声
    ekf->Q[3][3] = 0.1;
    ekf->Q[4][4] = 0.1;
    ekf->Q[5][5] = 0.1;
    
    // 姿态: 陀螺噪声
    ekf->Q[6][6] = 0.01;
    ekf->Q[7][7] = 0.01;
    ekf->Q[8][8] = 0.01;
    
    // 偏差: 随机游走
    ekf->Q[9][9] = 0.0001;
    ekf->Q[10][10] = 0.0001;
    ekf->Q[11][11] = 0.0001;
    ekf->Q[12][12] = 0.00001;
    ekf->Q[13][13] = 0.00001;
    ekf->Q[14][14] = 0.00001;
    
    ekf->gps_valid = 0;
}

/**
 * EKF预测步骤 (使用IMU数据)
 */
void ekf_predict(EKFState_t *ekf, const IMUData_t *imu)
{
    double dt = imu->timestamp - ekf->timestamp;
    if (dt <= 0 || dt > 0.1) {
        ekf->timestamp = imu->timestamp;
        return;
    }
    
    // 获取当前状态
    double *pos = &ekf->x[POS_IDX];
    double *vel = &ekf->x[VEL_IDX];
    double *att = &ekf->x[ATT_IDX];
    double *ba = &ekf->x[BA_IDX];
    double *bg = &ekf->x[BG_IDX];
    
    // 去除偏差
    double accel[3], gyro[3];
    accel[0] = imu->accel[0] - ba[0];
    accel[1] = imu->accel[1] - ba[1];
    accel[2] = imu->accel[2] - ba[2];
    
    gyro[0] = imu->gyro[0] - bg[0];
    gyro[1] = imu->gyro[1] - bg[1];
    gyro[2] = imu->gyro[2] - bg[2];
    
    // 简化的旋转矩阵 (小角度近似)
    double cr = cos(att[0]), sr = sin(att[0]);
    double cp = cos(att[1]), sp = sin(att[1]);
    double cy = cos(att[2]), sy = sin(att[2]);
    
    double R[3][3];
    R[0][0] = cy*cp;  R[0][1] = cy*sp*sr - sy*cr;  R[0][2] = cy*sp*cr + sy*sr;
    R[1][0] = sy*cp;  R[1][1] = sy*sp*sr + cy*cr;  R[1][2] = sy*sp*cr - cy*sr;
    R[2][0] = -sp;    R[2][1] = cp*sr;             R[2][2] = cp*cr;
    
    // 加速度转换到导航系
    double accel_nav[3];
    accel_nav[0] = R[0][0]*accel[0] + R[0][1]*accel[1] + R[0][2]*accel[2];
    accel_nav[1] = R[1][0]*accel[0] + R[1][1]*accel[1] + R[1][2]*accel[2];
    accel_nav[2] = R[2][0]*accel[0] + R[2][1]*accel[1] + R[2][2]*accel[2];
    
    // 去重力
    accel_nav[2] -= 9.81;
    
    // ========== 状态预测 ==========
    
    // 位置更新: p = p + v*dt + 0.5*a*dt^2
    pos[0] += vel[0] * dt + 0.5 * accel_nav[0] * dt * dt;
    pos[1] += vel[1] * dt + 0.5 * accel_nav[1] * dt * dt;
    pos[2] += vel[2] * dt + 0.5 * accel_nav[2] * dt * dt;
    
    // 速度更新: v = v + a*dt
    vel[0] += accel_nav[0] * dt;
    vel[1] += accel_nav[1] * dt;
    vel[2] += accel_nav[2] * dt;
    
    // 姿态更新 (简化)
    att[0] += gyro[0] * dt;
    att[1] += gyro[1] * dt;
    att[2] += gyro[2] * dt;
    
    // 偏差保持不变 (随机游走由Q矩阵体现)
    
    // ========== 协方差预测 ==========
    
    // 简化: P = P + Q * dt
    // 完整实现应该是 P = F * P * F' + Q
    for (int i = 0; i < STATE_DIM; i++) {
        ekf->P[i][i] += ekf->Q[i][i] * dt;
    }
    
    ekf->timestamp = imu->timestamp;
    
    // 更新GPS丢失时长
    if (!ekf->gps_valid) {
        ekf->gps_lost_duration += dt;
    }
}

/**
 * EKF更新步骤 (使用GPS数据)
 */
void ekf_update_gps(EKFState_t *ekf, const GPSData_t *gps)
{
    // GPS有效性检查
    if (!gps->valid || gps->num_satellites < 4) {
        if (ekf->gps_valid) {
            printf("[EKF] GPS丢失, 卫星数: %d\n", gps->num_satellites);
            ekf->gps_valid = 0;
            ekf->gps_lost_count++;
            ekf->gps_lost_duration = 0;
        }
        return;
    }
    
    // GPS恢复
    if (!ekf->gps_valid) {
        printf("[EKF] GPS恢复, 丢失时长: %.2f秒, 丢失次数: %d\n", 
               ekf->gps_lost_duration, ekf->gps_lost_count);
    }
    ekf->gps_valid = 1;
    
    // 测量噪声 (根据GPS精度动态调整)
    double R_gps = gps->accuracy * gps->accuracy;
    if (R_gps < 1.0) R_gps = 1.0;  // 最小1m²
    
    // GPS测量: 位置和速度
    // 观测矩阵H: 6×15 (观测位置和速度)
    
    // 计算卡尔曼增益 (简化版本)
    // K = P * H' * (H * P * H' + R)^(-1)
    
    // 这里简化处理,分别更新位置和速度
    for (int i = 0; i < 3; i++) {
        // 位置更新
        double innovation = gps->position[i] - ekf->x[POS_IDX + i];
        double S = ekf->P[POS_IDX + i][POS_IDX + i] + R_gps;
        double K = ekf->P[POS_IDX + i][POS_IDX + i] / S;
        
        ekf->x[POS_IDX + i] += K * innovation;
        ekf->P[POS_IDX + i][POS_IDX + i] *= (1 - K);
        
        // 速度更新
        double R_vel = 0.5;  // 速度测量噪声
        innovation = gps->velocity[i] - ekf->x[VEL_IDX + i];
        S = ekf->P[VEL_IDX + i][VEL_IDX + i] + R_vel;
        K = ekf->P[VEL_IDX + i][VEL_IDX + i] / S;
        
        ekf->x[VEL_IDX + i] += K * innovation;
        ekf->P[VEL_IDX + i][VEL_IDX + i] *= (1 - K);
    }
}

/**
 * EKF更新步骤 (使用气压计数据)
 * 
 * 气压计提供高度信息,GPS丢失时特别有用
 */
void ekf_update_baro(EKFState_t *ekf, double baro_altitude, double baro_accuracy)
{
    // 高度测量噪声
    double R_baro = baro_accuracy * baro_accuracy;
    if (R_baro < 0.25) R_baro = 0.25;  // 最小0.5m精度
    
    // 高度是状态的第3个分量 (z, 向下为正)
    // 气压高度向上为正,需要取反
    double innovation = -baro_altitude - ekf->x[POS_IDX + 2];
    double S = ekf->P[POS_IDX + 2][POS_IDX + 2] + R_baro;
    double K = ekf->P[POS_IDX + 2][POS_IDX + 2] / S;
    
    ekf->x[POS_IDX + 2] += K * innovation;
    ekf->P[POS_IDX + 2][POS_IDX + 2] *= (1 - K);
    
    // 同时可以约束垂直速度
    // (如果飞行器静止,垂直速度应该接近0)
}

/**
 * 获取位置估计和不确定性
 */
void ekf_get_position(const EKFState_t *ekf, 
                      double position[3], 
                      double uncertainty[3])
{
    position[0] = ekf->x[POS_IDX + 0];
    position[1] = ekf->x[POS_IDX + 1];
    position[2] = ekf->x[POS_IDX + 2];
    
    uncertainty[0] = sqrt(ekf->P[POS_IDX + 0][POS_IDX + 0]);
    uncertainty[1] = sqrt(ekf->P[POS_IDX + 1][POS_IDX + 1]);
    uncertainty[2] = sqrt(ekf->P[POS_IDX + 2][POS_IDX + 2]);
}

/**
 * 检查位置估计是否可靠
 */
int ekf_is_position_reliable(const EKFState_t *ekf, double threshold)
{
    double uncertainty = sqrt(ekf->P[0][0] + ekf->P[1][1] + ekf->P[2][2]);
    return uncertainty < threshold;
}

方案3:GPS故障检测与处理

c 复制代码
/**
 * GPS信号质量评估与故障检测
 */

#include <stdio.h>
#include <math.h>

// GPS质量等级
typedef enum {
    GPS_QUALITY_INVALID = 0,    // 无效
    GPS_QUALITY_POOR,           // 差 (可能多径/干扰)
    GPS_QUALITY_MODERATE,       // 一般
    GPS_QUALITY_GOOD,           // 好
    GPS_QUALITY_EXCELLENT,      // 优秀 (RTK固定解)
} GPSQuality_t;

// GPS健康状态
typedef struct {
    GPSQuality_t quality;
    
    // 统计信息
    int satellites_used;
    double hdop;                // 水平精度因子
    double vdop;                // 垂直精度因子
    double pdop;                // 位置精度因子
    
    // 信号强度
    double avg_snr;             // 平均信噪比
    double min_snr;             // 最小信噪比
    
    // 一致性检查
    double position_innovation; // 位置新息 (与预测的差)
    double velocity_innovation; // 速度新息
    
    // 连续性
    int consecutive_valid;      // 连续有效次数
    int consecutive_invalid;    // 连续无效次数
    
    // 故障检测
    int fault_detected;
    char fault_reason[64];
    
} GPSHealth_t;

// GPS监测器
typedef struct {
    GPSHealth_t health;
    
    // 历史数据 (用于异常检测)
    double position_history[10][3];
    double velocity_history[10][3];
    int history_index;
    int history_count;
    
    // 预测器 (用于一致性检查)
    double predicted_position[3];
    double predicted_velocity[3];
    
    // 阈值
    double max_position_jump;   // 最大位置跳变 (米/秒)
    double max_velocity_jump;   // 最大速度跳变 (米/秒²)
    double min_satellites;      // 最少卫星数
    double max_hdop;            // 最大HDOP
    
} GPSMonitor_t;

/**
 * 初始化GPS监测器
 */
void gps_monitor_init(GPSMonitor_t *monitor)
{
    memset(monitor, 0, sizeof(GPSMonitor_t));
    
    monitor->max_position_jump = 10.0;   // 最大10m/s的位置变化
    monitor->max_velocity_jump = 5.0;    // 最大5m/s²的速度变化
    monitor->min_satellites = 4;
    monitor->max_hdop = 5.0;
}

/**
 * 评估GPS质量
 */
GPSQuality_t evaluate_gps_quality(const GPSData_t *gps, GPSHealth_t *health)
{
    health->satellites_used = gps->num_satellites;
    health->hdop = gps->accuracy / 2.0;  // 近似
    
    // 基于卫星数和精度评估质量
    if (!gps->valid || gps->num_satellites < 4) {
        health->quality = GPS_QUALITY_INVALID;
    }
    else if (gps->num_satellites < 6 || gps->accuracy > 10.0) {
        health->quality = GPS_QUALITY_POOR;
    }
    else if (gps->num_satellites < 8 || gps->accuracy > 5.0) {
        health->quality = GPS_QUALITY_MODERATE;
    }
    else if (gps->accuracy > 2.0) {
        health->quality = GPS_QUALITY_GOOD;
    }
    else {
        health->quality = GPS_QUALITY_EXCELLENT;
    }
    
    return health->quality;
}

/**
 * 检测GPS异常
 */
int detect_gps_anomaly(GPSMonitor_t *monitor, const GPSData_t *gps, double dt)
{
    GPSHealth_t *health = &monitor->health;
    health->fault_detected = 0;
    
    if (!gps->valid) {
        health->fault_detected = 1;
        strcpy(health->fault_reason, "GPS无效");
        monitor->health.consecutive_invalid++;
        monitor->health.consecutive_valid = 0;
        return 1;
    }
    
    // 卫星数检查
    if (gps->num_satellites < monitor->min_satellites) {
        health->fault_detected = 1;
        snprintf(health->fault_reason, sizeof(health->fault_reason),
                 "卫星数不足: %d < %d", gps->num_satellites, (int)monitor->min_satellites);
        return 1;
    }
    
    // 位置跳变检测
    if (monitor->history_count > 0) {
        int prev_idx = (monitor->history_index - 1 + 10) % 10;
        
        double dx = gps->position[0] - monitor->position_history[prev_idx][0];
        double dy = gps->position[1] - monitor->position_history[prev_idx][1];
        double dz = gps->position[2] - monitor->position_history[prev_idx][2];
        double distance = sqrt(dx*dx + dy*dy + dz*dz);
        
        double max_distance = monitor->max_position_jump * dt;
        
        if (distance > max_distance) {
            health->fault_detected = 1;
            snprintf(health->fault_reason, sizeof(health->fault_reason),
                     "位置跳变: %.1fm (最大%.1fm)", distance, max_distance);
            return 1;
        }
        
        health->position_innovation = distance;
    }
    
    // 速度跳变检测
    if (monitor->history_count > 0) {
        int prev_idx = (monitor->history_index - 1 + 10) % 10;
        
        double dvx = gps->velocity[0] - monitor->velocity_history[prev_idx][0];
        double dvy = gps->velocity[1] - monitor->velocity_history[prev_idx][1];
        double dvz = gps->velocity[2] - monitor->velocity_history[prev_idx][2];
        double dv = sqrt(dvx*dvx + dvy*dvy + dvz*dvz);
        
        double max_dv = monitor->max_velocity_jump * dt;
        
        if (dv > max_dv) {
            health->fault_detected = 1;
            snprintf(health->fault_reason, sizeof(health->fault_reason),
                     "速度跳变: %.1fm/s (最大%.1fm/s)", dv, max_dv);
            return 1;
        }
        
        health->velocity_innovation = dv;
    }
    
    // 与预测值的一致性检查
    if (monitor->history_count >= 3) {
        double pred_error = sqrt(
            pow(gps->position[0] - monitor->predicted_position[0], 2) +
            pow(gps->position[1] - monitor->predicted_position[1], 2) +
            pow(gps->position[2] - monitor->predicted_position[2], 2)
        );
        
        // 如果误差太大,可能是多径或欺骗
        if (pred_error > 20.0) {
            health->fault_detected = 1;
            snprintf(health->fault_reason, sizeof(health->fault_reason),
                     "与预测不一致: %.1fm", pred_error);
            return 1;
        }
    }
    
    // 更新历史
    memcpy(monitor->position_history[monitor->history_index], 
           gps->position, sizeof(gps->position));
    memcpy(monitor->velocity_history[monitor->history_index], 
           gps->velocity, sizeof(gps->velocity));
    
    monitor->history_index = (monitor->history_index + 1) % 10;
    if (monitor->history_count < 10) monitor->history_count++;
    
    // 更新预测 (简单线性预测)
    monitor->predicted_position[0] = gps->position[0] + gps->velocity[0] * dt;
    monitor->predicted_position[1] = gps->position[1] + gps->velocity[1] * dt;
    monitor->predicted_position[2] = gps->position[2] + gps->velocity[2] * dt;
    
    health->consecutive_valid++;
    health->consecutive_invalid = 0;
    
    return 0;
}

/**
 * 判断是否应该使用GPS数据
 */
int should_use_gps(const GPSMonitor_t *monitor)
{
    const GPSHealth_t *health = &monitor->health;
    
    // 有故障不用
    if (health->fault_detected) {
        return 0;
    }
    
    // 质量太差不用
    if (health->quality <= GPS_QUALITY_POOR) {
        return 0;
    }
    
    // 刚恢复需要观察几帧
    if (health->consecutive_valid < 3) {
        return 0;
    }
    
    return 1;
}

方案4:视觉惯性里程计(VIO)备份

复制代码
┌─────────────────────────────────────────────────────────────────────────────┐
│                    VIO视觉惯性里程计                                         │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   【原理】                                                                  │
│   ─────────────────────────────────────────                                 │
│                                                                             │
│   用相机跟踪环境特征点,结合IMU计算相对运动                                 │
│                                                                             │
│       帧1            帧2            帧3                                     │
│    ┌───────┐      ┌───────┐      ┌───────┐                                │
│    │ ● ●  │  →   │  ● ● │  →   │   ● ●│                                │
│    │  ●   │      │   ●  │      │    ● │                                │
│    │ ●    │      │  ●   │      │   ●  │                                │
│    └───────┘      └───────┘      └───────┘                                │
│                                                                             │
│   通过特征点的移动计算相机的运动                                           │
│                                                                             │
│   【优点】                                                                  │
│   - 不依赖GPS                                                              │
│   - 相对运动精度高                                                         │
│   - 更新频率高 (30Hz+)                                                     │
│                                                                             │
│   【缺点】                                                                  │
│   - 累积漂移                                                               │
│   - 需要有纹理的环境                                                        │
│   - 计算量大                                                               │
│   - 光照敏感                                                               │
│                                                                             │
│   【GPS丢失时的作用】                                                       │
│   ─────────────────────────────────────────                                 │
│                                                                             │
│   GPS正常:  GPS + IMU融合                                                  │
│   GPS丢失:  VIO + IMU融合 (接管水平位置估计)                               │
│   GPS恢复:  用GPS修正VIO累积误差                                           │
│                                                                             │
│   适合场景:                                                                 │
│   - 城市低空飞行 (有建筑物特征)                                            │
│   - 室内飞行                                                               │
│   - 桥下/隧道                                                              │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘
c 复制代码
/**
 * 简化的视觉里程计接口
 */

typedef struct {
    double position[3];         // 相对位置 (累积)
    double velocity[3];         // 速度估计
    double orientation[4];      // 姿态四元数
    
    double position_covariance[3];  // 位置不确定性
    
    int tracking_quality;       // 跟踪质量 0-100
    int features_tracked;       // 跟踪的特征点数
    
    double timestamp;
    int valid;
} VIOState_t;

/**
 * 融合VIO和GPS
 */
void fuse_vio_with_gps(EKFState_t *ekf, 
                       const VIOState_t *vio, 
                       int gps_available)
{
    if (!vio->valid || vio->tracking_quality < 30) {
        // VIO不可用
        return;
    }
    
    if (gps_available) {
        // GPS可用时,VIO作为辅助
        // 主要用于提高更新频率
        
        // 速度更新 (VIO速度通常比GPS更平滑)
        double R_vio = 0.5;  // VIO速度噪声
        for (int i = 0; i < 3; i++) {
            double innovation = vio->velocity[i] - ekf->x[VEL_IDX + i];
            double S = ekf->P[VEL_IDX + i][VEL_IDX + i] + R_vio;
            double K = ekf->P[VEL_IDX + i][VEL_IDX + i] / S;
            
            ekf->x[VEL_IDX + i] += K * innovation;
            ekf->P[VEL_IDX + i][VEL_IDX + i] *= (1 - K);
        }
    } 
    else {
        // GPS不可用时,VIO接管位置估计
        // 但要注意VIO的累积漂移
        
        // 根据跟踪质量调整噪声
        double quality_factor = vio->tracking_quality / 100.0;
        double R_vio_pos = 2.0 / quality_factor;  // 质量越好噪声越小
        
        // 位置增量更新 (不是绝对位置)
        // 假设vio->position是相对于上一帧的增量
        static double last_vio_pos[3] = {0};
        
        double delta_pos[3];
        delta_pos[0] = vio->position[0] - last_vio_pos[0];
        delta_pos[1] = vio->position[1] - last_vio_pos[1];
        delta_pos[2] = vio->position[2] - last_vio_pos[2];
        
        // 用VIO增量修正位置
        for (int i = 0; i < 3; i++) {
            double predicted_delta = ekf->x[VEL_IDX + i] * 0.033;  // 假设30Hz
            double innovation = delta_pos[i] - predicted_delta;
            
            double S = ekf->P[POS_IDX + i][POS_IDX + i] + R_vio_pos;
            double K = ekf->P[POS_IDX + i][POS_IDX + i] / S;
            
            // 限制修正幅度
            if (fabs(innovation) > 1.0) {
                innovation = (innovation > 0) ? 1.0 : -1.0;
            }
            
            ekf->x[POS_IDX + i] += K * innovation;
            ekf->P[POS_IDX + i][POS_IDX + i] *= (1 - K);
        }
        
        memcpy(last_vio_pos, vio->position, sizeof(last_vio_pos));
    }
}

完整的导航管理器

c 复制代码
/**
 * 导航管理器 - 集成所有传感器
 */

typedef struct {
    // 滤波器
    EKFState_t ekf;
    
    // GPS监测
    GPSMonitor_t gps_monitor;
    
    // 传感器状态
    int imu_valid;
    int gps_valid;
    int baro_valid;
    int vio_valid;
    
    // 导航模式
    enum {
        NAV_MODE_FULL_GPS,      // GPS正常
        NAV_MODE_DEGRADED_GPS,  // GPS质量下降
        NAV_MODE_NO_GPS,        // GPS丢失,惯导接管
        NAV_MODE_VIO_BACKUP,    // VIO备份模式
        NAV_MODE_EMERGENCY,     // 紧急模式
    } mode;
    
    // 统计
    int total_gps_losses;
    double total_gps_lost_time;
    double max_gps_lost_duration;
    
    // 回调
    void (*on_gps_lost)(void *ctx);
    void (*on_gps_recovered)(void *ctx, double lost_duration);
    void (*on_position_unreliable)(void *ctx);
    void *callback_ctx;
    
} NavigationManager_t;

/**
 * 初始化导航管理器
 */
void nav_manager_init(NavigationManager_t *nav)
{
    memset(nav, 0, sizeof(NavigationManager_t));
    
    ekf_init(&nav->ekf);
    gps_monitor_init(&nav->gps_monitor);
    
    nav->mode = NAV_MODE_NO_GPS;  // 初始无GPS
}

/**
 * 处理IMU数据
 */
void nav_manager_process_imu(NavigationManager_t *nav, const IMUData_t *imu)
{
    nav->imu_valid = 1;
    
    // EKF预测
    ekf_predict(&nav->ekf, imu);
}

/**
 * 处理GPS数据
 */
void nav_manager_process_gps(NavigationManager_t *nav, const GPSData_t *gps)
{
    double dt = gps->timestamp - nav->gps_monitor.health.fault_detected;
    
    // GPS质量评估
    evaluate_gps_quality(gps, &nav->gps_monitor.health);
    
    // 异常检测
    int has_anomaly = detect_gps_anomaly(&nav->gps_monitor, gps, dt);
    
    // 决定是否使用GPS
    int use_gps = should_use_gps(&nav->gps_monitor);
    
    // 状态转换
    int prev_gps_valid = nav->gps_valid;
    nav->gps_valid = use_gps;
    
    if (use_gps) {
        // GPS可用
        ekf_update_gps(&nav->ekf, gps);
        
        if (!prev_gps_valid) {
            // GPS恢复
            double lost_duration = nav->ekf.gps_lost_duration;
            printf("[NAV] GPS恢复,丢失时长: %.2f秒\n", lost_duration);
            
            nav->total_gps_lost_time += lost_duration;
            if (lost_duration > nav->max_gps_lost_duration) {
                nav->max_gps_lost_duration = lost_duration;
            }
            
            if (nav->on_gps_recovered) {
                nav->on_gps_recovered(nav->callback_ctx, lost_duration);
            }
        }
        
        // 更新模式
        if (nav->gps_monitor.health.quality >= GPS_QUALITY_GOOD) {
            nav->mode = NAV_MODE_FULL_GPS;
        } else {
            nav->mode = NAV_MODE_DEGRADED_GPS;
        }
    } 
    else {
        // GPS不可用
        if (prev_gps_valid) {
            // GPS刚丢失
            nav->total_gps_losses++;
            printf("[NAV] GPS丢失 (第%d次), 原因: %s\n", 
                   nav->total_gps_losses, nav->gps_monitor.health.fault_reason);
            
            if (nav->on_gps_lost) {
                nav->on_gps_lost(nav->callback_ctx);
            }
        }
        
        // 更新模式
        if (nav->vio_valid) {
            nav->mode = NAV_MODE_VIO_BACKUP;
        } else {
            nav->mode = NAV_MODE_NO_GPS;
        }
        
        // 检查是否进入紧急模式
        if (nav->ekf.gps_lost_duration > 15.0) {
            nav->mode = NAV_MODE_EMERGENCY;
            
            if (nav->on_position_unreliable) {
                nav->on_position_unreliable(nav->callback_ctx);
            }
        }
    }
}

/**
 * 处理气压计数据
 */
void nav_manager_process_baro(NavigationManager_t *nav, 
                               double altitude, double accuracy)
{
    nav->baro_valid = 1;
    ekf_update_baro(&nav->ekf, altitude, accuracy);
}

/**
 * 处理VIO数据
 */
void nav_manager_process_vio(NavigationManager_t *nav, const VIOState_t *vio)
{
    nav->vio_valid = vio->valid && (vio->tracking_quality > 30);
    
    if (nav->vio_valid) {
        fuse_vio_with_gps(&nav->ekf, vio, nav->gps_valid);
    }
}

/**
 * 获取当前位置和置信度
 */
void nav_manager_get_position(const NavigationManager_t *nav,
                               double position[3],
                               double *confidence,
                               char *mode_str)
{
    double uncertainty[3];
    ekf_get_position(&nav->ekf, position, uncertainty);
    
    // 计算总体置信度
    double total_uncertainty = sqrt(uncertainty[0]*uncertainty[0] + 
                                    uncertainty[1]*uncertainty[1] +
                                    uncertainty[2]*uncertainty[2]);
    
    // 置信度: 0-1,不确定性越大置信度越低
    *confidence = 1.0 / (1.0 + total_uncertainty / 10.0);
    
    // 模式字符串
    const char *modes[] = {
        "FULL_GPS", "DEGRADED_GPS", "NO_GPS", "VIO_BACKUP", "EMERGENCY"
    };
    strcpy(mode_str, modes[nav->mode]);
}

/**
 * 检查是否应该切换到安全模式
 */
int nav_manager_should_enter_safe_mode(const NavigationManager_t *nav)
{
    // 紧急模式
    if (nav->mode == NAV_MODE_EMERGENCY) {
        return 1;
    }
    
    // GPS丢失太久
    if (nav->ekf.gps_lost_duration > 10.0 && !nav->vio_valid) {
        return 1;
    }
    
    // 位置不确定性太大
    if (!ekf_is_position_reliable(&nav->ekf, 20.0)) {
        return 1;
    }
    
    return 0;
}

/**
 * 打印导航状态
 */
void nav_manager_print_status(const NavigationManager_t *nav)
{
    double pos[3], confidence;
    char mode[32];
    nav_manager_get_position(nav, pos, &confidence, mode);
    
    printf("\n========== 导航状态 ==========\n");
    printf("模式: %s\n", mode);
    printf("位置: N=%.2f, E=%.2f, D=%.2f (米)\n", pos[0], pos[1], pos[2]);
    printf("置信度: %.1f%%\n", confidence * 100);
    printf("GPS状态: %s, 卫星: %d\n", 
           nav->gps_valid ? "有效" : "无效",
           nav->gps_monitor.health.satellites_used);
    printf("GPS丢失: 当前%.1f秒, 总计%.1f秒, 最长%.1f秒, 共%d次\n",
           nav->ekf.gps_lost_duration,
           nav->total_gps_lost_time,
           nav->max_gps_lost_duration,
           nav->total_gps_losses);
    printf("VIO状态: %s\n", nav->vio_valid ? "有效" : "无效");
    printf("==============================\n\n");
}

飞控集成建议

复制代码
┌─────────────────────────────────────────────────────────────────────────────┐
│                    飞控集成建议                                              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   【GPS丢失时的飞行策略】                                                   │
│   ─────────────────────────────────────────                                 │
│                                                                             │
│   0-3秒: 继续当前任务                                                       │
│   ┌─────────────────────────────────────────────────────────────────────┐  │
│   │  - 惯导推算精度足够                                                 │  │
│   │  - 保持当前速度和航向                                               │  │
│   │  - 记录GPS丢失事件                                                  │  │
│   └─────────────────────────────────────────────────────────────────────┘  │
│                                                                             │
│   3-10秒: 降低机动性                                                        │
│   ┌─────────────────────────────────────────────────────────────────────┐  │
│   │  - 限制最大速度                                                     │  │
│   │  - 禁止急转弯                                                       │  │
│   │  - 开始爬升 (如果安全)                                             │  │
│   │  - 发出警告                                                         │  │
│   └─────────────────────────────────────────────────────────────────────┘  │
│                                                                             │
│   10秒+: 进入安全模式                                                       │
│   ┌─────────────────────────────────────────────────────────────────────┐  │
│   │  - 悬停 (如果有VIO/光流)                                           │  │
│   │  - 缓慢下降 (如果没有视觉)                                         │  │
│   │  - 或者切换到高度保持模式                                           │  │
│   │  - 发出紧急警报                                                     │  │
│   └─────────────────────────────────────────────────────────────────────┘  │
│                                                                             │
│   【代码示例】                                                              │
│                                                                             │
│   ```c                                                                      │
│   void handle_gps_loss(NavigationManager_t *nav, FlightController_t *fc)   │
│   {                                                                         │
│       double lost_time = nav->ekf.gps_lost_duration;                       │
│                                                                             │
│       if (lost_time < 3.0) {                                               │
│           // 继续飞行,只记录日志                                          │
│           log_event("GPS_LOST", lost_time);                                │
│       }                                                                     │
│       else if (lost_time < 10.0) {                                         │
│           // 限制飞行                                                       │
│           fc->max_velocity = 3.0;  // 限速3m/s                             │
│           fc->max_yaw_rate = 30.0; // 限制转弯                             │
│           set_warning("GPS信号弱");                                        │
│       }                                                                     │
│       else {                                                                │
│           // 安全模式                                                       │
│           if (nav->vio_valid) {                                            │
│               set_flight_mode(MODE_POSITION_HOLD);                         │
│           } else {                                                          │
│               set_flight_mode(MODE_ALTITUDE_HOLD);                         │
│               fc->target_climb_rate = -0.5;  // 缓慢下降                   │
│           }                                                                 │
│           set_alarm("GPS丢失,进入安全模式");                              │
│       }                                                                     │
│   }                                                                         │
│   ```                                                                    │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

总结

复制代码
┌─────────────────────────────────────────────────────────────────────────────┐
│                    GPS丢失应对方案总结                                       │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   【你的问题: 3-5秒GPS丢失怎么办?】                                       │
│                                                                             │
│   答案: 完全可以通过技术手段解决                                           │
│                                                                             │
│   ┌─────────────────────────────────────────────────────────────────────┐  │
│   │                                                                     │  │
│   │   方案1: 纯惯导推算 (最基本)                                       │  │
│   │   - 精度: ~0.5-1m/s漂移                                            │  │
│   │   - 5秒误差: 2.5-5米                                               │  │
│   │   - 成本: 无额外成本 (利用现有IMU)                                 │  │
│   │   - 适合: 短时间GPS丢失                                            │  │
│   │   ✅ 完全够用                                                       │  │
│   │                                                                     │  │
│   │   方案2: EKF多传感器融合 (推荐)                                    │  │
│   │   - GPS + IMU + 气压计融合                                         │  │
│   │   - GPS丢失时自动切换到惯导                                        │  │
│   │   - GPS恢复时自动修正                                              │  │
│   │   - 精度更高,过渡更平滑                                           │  │
│   │   ✅ 强烈推荐                                                       │  │
│   │                                                                     │  │
│   │   方案3: VIO视觉备份 (高级)                                        │  │
│   │   - 需要相机                                                        │  │
│   │   - 可以支撑更长时间的GPS丢失                                      │  │
│   │   - 适合城市/室内环境                                              │  │
│   │   ⚠️ 成本较高,但效果最好                                          │  │
│   │                                                                     │  │
│   └─────────────────────────────────────────────────────────────────────┘  │
│                                                                             │
│   【关键技术点】                                                            │
│   ─────────────────────────────────────────                                 │
│                                                                             │
│   1. GPS质量监测                                                           │
│      - 检测信号质量下降                                                    │
│      - 检测异常跳变                                                        │
│      - 提前切换到备份模式                                                  │
│                                                                             │
│   2. 无缝切换                                                              │
│      - GPS丢失时平滑过渡到惯导                                            │
│      - GPS恢复时平滑修正                                                   │
│      - 避免位置突变                                                        │
│                                                                             │
│   3. 安全策略                                                              │
│      - 超时进入安全模式                                                    │
│      - 位置不确定性监控                                                    │
│      - 自动降低飞行激进程度                                                │
│                                                                             │
│   【实测效果】                                                              │
│   ─────────────────────────────────────────                                 │
│                                                                             │
│   使用EKF融合方案:                                                          │
│   - 3秒GPS丢失: 位置误差 < 2米                                            │
│   - 5秒GPS丢失: 位置误差 < 5米                                            │
│   - GPS恢复后: 1秒内收敛到正常精度                                        │
│                                                                             │
│   对于大楼遮挡这种短时间丢星,基本感知不到影响                             │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

一句话回答你的问题:

3-5秒的GPS丢失,用惯导推算完全能撑住(误差约2-5米)。加上EKF融合和GPS质量监测,可以做到GPS丢失/恢复无缝切换,飞行几乎无感知。这是成熟技术,大疆等消费级无人机都已经实现了。


参考资料:

  • PX4 EKF2 源码
  • ArduPilot EKF 文档
  • GPS/INS融合相关论文
  • 《捷联惯性导航技术》
相关推荐
moonsims12 小时前
波士顿动力Auto-Connect-复杂环境下机器人连接解决方案
服务器·无人机
云卓SKYDROID15 小时前
工业遥控器光纤模块技术解析
无人机·遥控器·知识科普·高科技·云卓科技
AI浩18 小时前
SPDC-YOLO:基于改进YOLOv8的高效无人机航拍图像小目标检测网络
yolo·目标检测·无人机
一把小椅子19 小时前
超大规模多模态交通数据集:320TB+海量数据资源,涵盖行车视频、无人机航拍、第一视角步行骑行与道路监控,助力自动驾驶与智慧交通算法突破
算法·自动驾驶·无人机
Likeadust19 小时前
视频推流平台EasyDSS与无人机推流直播技术森林防火融合应用
音视频·无人机
人机与认知实验室19 小时前
反无人机智能指控系统思考
无人机
长沙京卓19 小时前
森林防火无人机自动巡检方案
无人机
数据分享者19 小时前
原创大规模无人机检测数据集:11998张高质量图像,支持YOLOv8、COCO、TensorFlow多格式训练,涵盖飞机、无人机、直升机三大目标类别
算法·yolo·数据分析·tensorflow·无人机
云卓SKYDROID19 小时前
无人机电机模块组成解析
无人机·技术解析·高科技·云卓科技·电机模块
应用市场19 小时前
无人机多机编队协同作业技术全解析——从编队控制到智能避障
无人机