从代码逻辑分析BF救援模式“生死线”

苍山洱海共月明2026-09-24

为什么救援会失败?GPS Rescue 看起来很简单:触发后自动飞回家、下降、着陆。但它的内部是一个多阶段状态机,每个阶段都有严格...

为什么救援会失败?

GPS Rescue 看起来很简单:触发后自动飞回家、下降、着陆。但它的内部是一个多阶段状态机,每个阶段都有严格的进入条件和失败判定。任何一个环节出问题,都可能让救援终止,甚至让飞机坠落。

把救援想象成一个"一旦报警就不可撤销"的系统。任何故障警报一响,即使原因马上消失,警报也不会自动解除,随时可能导致坠机。

救援失败大致可以归为六类原因:

启动救援就失败:没有 Home 点、距离太近、在地面上。

爬升失败:动力不足、气压计异常、强风。

转向失败:磁力计/IMU 朝向错误、GPS 方向错误。

返航失败:飞错方向、GPS 丢失、低卫星、强风、电池不足。

下降/着陆失败:下降受阻、着陆超时、撞击检测误判。

系统级失败:Sanity 模式过严、崩溃保护误触发、配置参数不当、传感器故障。

       

                                    正文

第一章:先认识 GPS Rescue 的"大脑"——状态机

1.1 救援的完整阶段

IDLE(空闲)

INITIALIZE(初始化)

ATTAIN_ALT(爬升到返航高度)

ROTATE(原地转向家)

FLY_HOME(飞回家)

DESCENT(下降)

LANDING(着陆)

COMPLETE(完成)

但是隐藏了两个异常出口:

DO_NOTHING:半可控下降,20 秒后放弃。

ABORT:立即 disarm,动力输出切断。

1.2 两个关键"判决变量"

Phase:当前处于哪个阶段,状态机推进时被改

Failure:是否发生故障,各种检查触发时被改

规则:只要 failure 不是 HEALTHY,phase 就会被强制改成 DO_NOTHING 或 ABORT。

failure 一旦被置位,只有回到 IDLE 阶段才会清零。

说人话:

把救援想象成一个"一旦报警就不可撤销"的系统。任何故障警报一响,即使原因马上消失,警报也不会自动解除。所以,非必要不使用吧

第二章:启动阶段(INITIALIZE)的失败

2.1 没有 Home 点(NO_HOME_POINT)

原因:

解锁时 GPS 还没定位(卫星数不够、无 3D fix)。

gps_set_home_point_once 配置问题。

Home 点被意外清除。

后果:取决于 Sanity 模式,可能直接 disarm,或进入 20 秒半可控下降。

2.2 起飞点太近且在地面原因:

在距 Home 5 米内、高度低于目标着陆高度时触发救援。

常见于误触救援开关、在地面测试。

后果:立即 ABORT ,动力切断。

2.3 初始距离小于 minStartDistM

if (distanceToHomeM < gpsRescueConfig()->minStartDistM) {

pitchAdjustment = 1500.0f;  // 15 度前倾

}

原因:

触发救援时离 Home 太近。

GPS 位置漂移,导致 distanceToHomeM 一直小于 minStartDistM。

后果:

飞机会持续前倾飞离,试图拉开距离。

若 GPS 不更新,会卡在 ATTAIN_ALT 阶段,一直飞离。

若 Home 点错误,可能朝错误方向飞远。

总结:

解锁前一定要等 GPS 定位稳定、返航点确认。在起飞点附近误触救援,可能直接被 disarm。

近距离触发救援,飞机会先"故意飞远"再返航,这是设计行为,不是故障。

第三章:爬升阶段(ATTAIN_ALT)的失败

3.1 爬升受阻(ratio 检查)

const float ratio = actualAltitudeChange / targetAltitudeChange;

rescueState.intent.secondsFailing += ratio > 0.5f ? -1 : 1;

if (secondsFailing >= 10) {

rescueState.phase = RESCUE_LANDING;

}

判定逻辑:实际爬升量 / 目标爬升量 ≤ 0.5,持续 10 秒 → 强制进入 LANDING。

常见原因:

动力不足:电池电量低、电机/桨叶故障、电调过热。

气压计异常:getAltitude() 读数有问题。

强风下压:逆风爬升效率低。

油门受限:throttleMax 配置过低、throttleHover 不准。

目标高度过高:MAX 模式下取历史最大高度 + 初始爬升,低电量时无法到达。

后果:10 秒后进入 LANDING,配合撞击检测尝试降落。若此时远离返回点,会摔在异地。

3.2 目标高度设置不当

case GPS_RESCUE_ALT_MODE_MAX:

rescueState.intent.returnAltitudeCm = maxAltitudeCm + initialClimbCm;

MAX 模式:返航高度 = 历史最大高度 + initialClimbM。

如果之前飞得极高(如 500m),返航目标也极高,低电量时无法到达。

FIXED 模式:固定高度,若设置过高也有同样问题。

总结:

爬升阶段最怕"上不去"。电池不足、强风都会让飞机爬不到返航高度。

10 秒爬不上去,系统就认为"没救了",转入着陆模式。所以返航高度不要设太高,电池要留余量。

第四章:旋转对准阶段(ROTATE)的失败

4.1 偏航角误差始终无法小于 30 度

if (rescueState.sensor.absErrorAngle < GPS_RESCUE_ALLOWED_YAW_RANGE)

rescueState.phase = RESCUE_FLY_HOME;

判定:机头朝向与"家"的方向误差必须小于 30 度,才进入 FLY_HOME。

原因:

磁力计未校准/受干扰(useMag 开启时):电调线、电源线、磁干扰。

IMU yaw 漂移(无 mag 时):依赖 GPS 地速修正,低速下修正不准。

GPS 方向计算错误:Home 点错误、GPS 定位跳动。

强风:机头朝向与实际航向严重不一致。

yawAttenuator 反复被削弱:状态在 ROTATE 与其它阶段间抖动。

后果:永远停在 ROTATE,油门维持悬停,最终电量耗尽坠落。

4.2 yaw 权限累积问题

if (rescueState.intent.yawAttenuator < 1.0f) {

rescueState.intent.yawAttenuator += rescueState.sensor.gpsRescueTaskIntervalSeconds;

}

每次进入 ROTATE 从 0 开始,1 秒内到 1.0。

若在 ROTATE 与其它阶段反复切换,yaw 权限反复被削弱,对准变慢。

章节总结:

旋转阶段最怕"转不过去"。磁力计不干净、IMU 漂移、强风都会让飞机找不到家的方向。

如果你用磁力计,一定要校准并验证;如果不用,返航速度不要太低,否则 IMU 修正不准。

第五章:返航阶段(FLY_HOME)的失败

5.1 Flyaway 检测触发(30 秒不接近 Home)

if (rescueState.phase == RESCUE_FLY_HOME) {

const float velocityToHomeCmS = previousDistanceToHomeCm - rescueState.sensor.distanceToHomeCm;

rescueState.intent.secondsFailing += (velocityToHomeCmS < 0.1f * targetVelocityCmS) ? 1 : -1;

if (secondsFailing >= 30) {

// 若开了 mag 且未强制禁用 → 禁用 mag 重试一次

else rescueState.failure = RESCUE_FLYAWAY;

}

}

原因:

IMU 严重偏航:yaw 估计完全错误,飞机朝错误方向飞。

强风 > 返航速度:velocityToHomeCmS 为负。

磁力计被干扰:导致 yaw 错误。

GPS 地速方向与机头方向不一致:roll mix 不足以纠正。

GPS 数据中断:velocityToHomeCmS = 0,持续累计。

处理策略:

系统会先禁用磁力计重新尝试返航(仅一次)。

仍失败 →调用 FLYAWAY()→ 根据 Sanity 进入 DO_NOTHING(降落) 或 ABORT(终止)。

5.2 GPS 完全丢失(GPSLOST)

if (!rescueState.sensor.healthy) {

rescueState.failure = RESCUE_GPSLOST;

}

判定:gpsIsHealthy() 返回 false,通常是几百毫秒无数据包。

关键:failure 一旦置位,只有回到 IDLE 才清零。

后果(取决于 Sanity 模式):同时osd页面会闪烁RESCUE N/A

Sanity 模式GPS 丢失后行为:

SANITY_ON 立即 ABORT → disarm

SANITY_FS_ONLY 非硬失控 → DO_NOTHING;硬失控 → ABORT

OFF 一般 DO_NOTHING,20 秒后 ABORT

注意:GPS 恢复后不会回到原阶段,因为 failure 没有清零分支(警报不会消失)。

5.3 短暂性丢星数(LOWSATS)

secondsLowSats += (!STATE(GPS_FIX) || (gpsSol.numSat < GPS_MIN_SAT_COUNT)) ? 1 : -1;

if (secondsLowSats == 10) rescueState.failure = RESCUE_LOWSATS;

判定:连续 10 秒无定位或卫星数不足。

与 GPSLOST 的区别:

GPSLOST:完全无数据,立即触发。

LOWSATS:有数据但无效,10 秒后触发。

乐观情况:4~5 秒的无效数据不会触发 LOWSATS,状态机继续运行。

5.4 返航速度设置过高

groundSpeedCmS 设得大(如 1000cm/s = 10m/s),阻力大、耗电快。

逆风时 velocityToHomeCmS 上不去,触发 flyaway 判定。

5.5 速度 PID 的 I 项累积问题

rescueState.intent.velocityItermAttenuator = 4.0f / (groundspeedErrorRatio + 4.0f);

IMU 错误(groundspeedErrorRatio 大)时 I 项被大幅削弱,稳态误差无法消除,返航速度偏低 → 触发 flyaway。

反之,I 项累积过多又遇 IMU 突然纠正,会过冲,可能飞过 Home。

章节总结:

返航阶段最怕"飞错方向"和"GPS 丢失"。

飞错方向:多半是磁力计/IMU 问题,30 秒不接近家就判定 flyaway。

GPS 丢失:完全无数据立即报警,有数据但无效宽容 10 秒。

强风、电池不足也会让返航速度上不去,触发 flyaway。Flyaway标记后同样进入 performSanityChecks() 的故障处理流程,后果和 RESCUE_GPSLOST 一样,取决于 sanityChecks 配置

第六章:下降阶段(DESCENT)的失败

6.1 下降受阻(ratio 检查)

case RESCUE_DESCENT:

rescueState.intent.secondsFailing += ratio > 0.5f ? -1 : 1;

if (secondsFailing >= 10) {

rescueState.phase = RESCUE_LANDING;

secondsFailing = 0;

}

判定:实际下降量 / 目标下降量 ≤ 0.5,持续 10 秒 → 强制进入 LANDING。

原因:

气压计漂移。

油门过高(悬停油门不准)。

下洗气流、上升气流。

下降率设置过大但实际跟不上。

6.2 下降率与高度不匹配

altitudeStep *= descentRateAttenuator;  // returnAltitude 低时减慢

altitudeStep *= 1.0f + 2.0f * descentRateMultiplier;  // 高空加快

returnAltitudeCm 很低(<5m):下降率被压到 1/4,可能下降极慢,超时。

targetAltitudeCm 很高:下降率 3x,可能下降过快导致坠地冲击。

6.3 偏航角超范围时速度目标归零

if (absErrorAngle > GPS_RESCUE_ALLOWED_YAW_RANGE)

targetVelocityCmS = 0;

下降过程中若 yaw 误差大(IMU 漂移、风),水平速度被清零,飞机原地下降,可能落在远离 Home 的位置。

给飞手的话

下降阶段最怕"下不去"或"下太快"。

下不去:10 秒后强制着陆。

下太快:可能硬着陆。

下降时如果方向不对,飞机会原地下降,可能随着风力落在离家很远的地方。

第七章:着陆阶段(LANDING)的失败

7.1 着陆超时(10 秒)

case RESCUE_LANDING:

secondsFailing += ratio > 0.5f ? -1 : 1;

if (secondsFailing >= 10) rescueState.phase = RESCUE_ABORT;

判定:10 秒内高度没有明显下降 → ABORT → disarm。

原因:

油门卡在悬停以上。

气压计读数不降。

强上升气流。

后果:若此时还在空中,直接坠落。

7.2 撞击检测阈值不当

if (accMagnitude > disarmThreshold) disarmOnImpact();

accMagnitude 计算假设飞机水平(Z 轴减 1G)。若着陆时姿态倾斜,计算不准。

阈值问题:

太高 → 落地后不 disarm,电机继续转,可能翻倒。

太低 → 飞行中震动/机动误触发 disarm,空中停车。

7.3 着陆点不水平/有障碍

代码无法感知地面情况。若 Home 点上方有树、斜坡、水面,着陆会失败或损坏。

章节总结:

着陆阶段最怕"落不下来"和"误判撞击"。

落不下来:10 秒后 disarm,可能空中掉下来;误判撞击:空中震动可能导致 disarm。

所以 降落速度要调好,Home 点要选平坦开阔的地方。

第八章:系统级失败

8.1 Sanity 模式设置不当

case RESCUE_SANITY_ON:      phase = RESCUE_ABORT;   // 任何 failure 立即 abort

case RESCUE_SANITY_FS_ONLY: if (hardFailsafe) abort;

default:                     phase = RESCUE_DO_NOTHING;

SANITY_ON:任何小 failure(如瞬时 LOWSATS)都会导致 disarm,可能在远离 Home 处坠落。

DO_NOTHING:rescueThrottle = throttleHover - 100,若悬停油门不准,可能上升或快速下降。

8.2 崩溃保护误触发

if (crashRecoveryModeActive()) {

disarm(DISARM_REASON_CRASH_PROTECTION);

rescueStop();

}

翻滚检测(crash flip)误触发 → 直接 disarm,救援终止。

常见于剧烈机动、强烈震动、加速度计噪声。

8.3 硬失控判定抖动

const bool hardFailsafe = !rxIsReceivingSignal();

接收机间歇性丢包 → hardFailsafe 在 true/false 间跳变。

配合 SANITY_FS_ONLY 可能反复进入/退出 ABORT。

8.4 RESCUE_COMPLETE 未被使用

case RESCUE_COMPLETE:

rescueStop();

break;

代码中没有任何地方设置 phase = RESCUE_COMPLETE,可能是遗留代码。

总结:

Sanity 模式决定了系统对故障的"容忍度"。

SANITY_ON:最严格,一点小问题就放弃。

SANITY_FS_ONLY:只在真正失控时放弃。通常CLI页面设置了此命令

第九章:传感器与配置相关

9.1 气压计问题

getAltitude() 依赖气压计。

气压计未校准、受气流/温度影响漂移 → currentAltitudeCm 错误 → 爬升/下降 ratio 计算错误 → 误判 failure。

无气压计仅靠 GPS 高度时,更新率低(1~10Hz),altitudeDataIntervalSeconds 大,PID 响应差。

9.2 磁力计问题

useMag 开启但 mag 未校准/受干扰 → yaw 错误 → ROTATE 卡住或 FLY_HOME 飞错方向,magForceDisable 机制只在 flyaway 30 秒后触发一次,且不可逆。

9.3 IMU yaw 估计

无 mag 时,地速 > 2m/s 才用 GPS 地速修正 yaw。返航速度设置过低(<2m/s)时 yaw 修正失效,IMU 漂移累积。imuYawCogGain 逻辑在 IMU 错误时衰减 velocity I 项,可能过度抑制导致速度上不去。

9.4 GPS 数据率与延迟

gpsDataIntervalSeconds 范围 10ms~1000ms。

低数据率(如 1Hz)时:velocityToHomeCmS 计算粗糙。

PID 的 D 项噪声大。

newGPSData 触发频率低,状态机推进慢。

GPS 位置延迟会导致过冲 Home 点,尤其在高速返航时。

9.5 newGPSData 标志的时序

gpsRescueNewGpsData() 设置 newGPSData = true,在 gpsRescueUpdate() 末尾清零。

若 GPS 数据在两次 gpsRescueUpdate() 之间到达多次,只处理一次。

若 GPS 数据在 sensorUpdate() 之后、newGPSData = false 之前到达,会被清零但未使用。

9.6 配置参数不当

参数 不当设置的后果

throttleHover 不准 → 高度控制差,DO_NOTHING 阶段下降异常

throttleMin/Max 范围过窄 → 无法应对极端情况

maxRescueAngle 过小 → 抗风能力差

groundSpeedCmS 过大/过小 → 耗电或飞太慢

descentDistanceM 过大 → 下降开始太早,可能落在远离 Home 处

minStartDistM 过大 → 近距离救援时长时间前倾飞离

disarmThreshold 不当 → 着陆不 disarm 或空中误 disarm

targetLandingAltitudeM 不当 → 着陆判定错误

returnAltitudeM 过高 → 爬升耗电;过低 → 撞障碍

GPS_MIN_SAT_COUNT 过低 → 无效数据被当有效;过高 → 容易 LOWSATS

给飞手的话:

传感器和配置是救援失败的"隐形杀手"。

气压计、磁力计、IMU 任何一个不准,都可能让救援失败。

GPS 数据率低、延迟大,救援精度就差。

配置参数不是默认就好,要根据自己的飞机和环境调整。

第十章:环境与外部因素

10.1 强风

逆风返航:地速上不去 → 触发flyaway 判定。

侧风:航向与机头不一致 → yaw 误差大 → ROTATE 卡住或 roll mix 过度。

下降时风切变:高度控制容易震荡,可能导致空中上锁。

10.2 GPS 信号遮挡/多径

城市、峡谷、树林 → 卫星数下降 → LOWSATS。

10.3 电池电压骤降

大油门爬升/返航时电压跌落 → 动力不足 → 爬升/返航失败。

若触发电压 failsafe 且不是 GPS Rescue 模式,可能直接坠落。

10.4 Home 点错误

解锁时 GPS 尚未稳定,Home 点记录在错误位置。

后果:整个救援方向错误,飞向错误地点,可能触发 flyaway 或飞丢。

代码注释也警告:"Some GPS units give false Home values! Always check the arrow points to home on leaving home."

给飞手的话

环境是救援失败的外因。

强风、遮挡、多径都会让 GPS 和 IMU 出错。

Home 点错误最致命,解锁前一定确认箭头指向真正的家,并且要以一定速度直线飞行一百米让箭头更准确。

第十一章:状态机相关的隐蔽问题

11.1 阶段切换条件苛刻

ROTATE → FLY_HOME:要求 absErrorAngle < 30°,强风/IMU 误差下难以满足。

FLY_HOME → DESCENT:要求 distanceToHomeM <= descentDistanceM,GPS 距离跳动可能反复切换。

DESCENT → LANDING:要求 currentAltitudeCm < targetLandingAltitudeCm,气压计漂移可能提前或延迟。

11.2 failure 状态无恢复机制

一旦置位,只有回到 IDLE 才清零,短暂故障也会导致救援终止。

11.3 DO_NOTHING 的 20 秒倒计时不可逆

即使 GPS 恢复,也不会重置 secondsDoingNothing,除非用户手动切出救援模式。

给飞手的话

状态机的"单行道"设计,意味着任何故障都不可逆。

理解这一点,能帮你在遇到"小问题导致救援失败"时,知道背后发生了什么。

第十二章:完整时间线——一次 4~5 秒 GPS 丢失的全过程

假设:救援正在 FLY_HOME 阶段,Sanity = OFF,GPS 完全中断 5 秒后恢复。如果是 SANITY_ON:T=0,GPS发生中断,触发ABORT,立即 disarm,自由落体

如果是"GPS 有数据但无效"

时间 事件     failure  phase       飞机在做什么

T=0     数据无效 HEALTHY  FLY_HOME   继续飞,但速度计算可能异常

T=5s     数据恢复 HEALTHY  FLY_HOME   正常继续返航

T=10s 若持续无效 LOWSATS  DO_NOTHING 10 秒后才触发

给飞手的话

同样是"GPS 丢了几秒",结果完全不同:

完全无数据 + SANITY_ON = 秒掉。

完全无数据 + SANITY_OFF = 20 秒后掉。

有数据但无效 = 大概率能撑过去。

第十三章:救援失败原因总表

阶段 失败场景 主要原因 后果

启动 无 Home 点 GPS 未定位就解锁 ABORT 或 DO_NOTHING

启动 距 Home 5m 内且在地面 误触救援 立即 ABORT

启动 初始距离 < minStartDistM 触发太近 持续前倾飞离

爬升 爬升受阻 动力不足、气压计异常、强风 10s 后转 LANDING

爬升 目标高度过高 MAX 模式 + 低电量 无法到达

转向 偏航误差 > 30° 磁力计/IMU 错误、强风 卡在 ROTATE

返航 Flyaway IMU 错误、强风、磁干扰 30s 后 FLYAWAY

返航 GPS 完全丢失 模块故障、遮挡 立即 GPSLOST

返航 低卫星数 城市峡谷、树冠 10s 后 LOWSATS

返航 速度上不去 强风、电池不足、I 项问题 触发 flyaway

下降 下降受阻 气压计漂移、油门过高 10s 后转 LANDING

下降 下降率不匹配 高度设置不当 超时或硬着陆

下降 方向错误 IMU 漂移、风 原地下降,落偏远

着陆 着陆超时 油门卡高、气压计不降 10s 后 ABORT

着陆 撞击检测误判 阈值不当 不 disarm 或空中 disarm

着陆 着陆点不佳 树、斜坡、水面 损坏

系统 Sanity 过严 SANITY_ON 小故障即 disarm

系统 崩溃保护误触发 震动、机动 直接 disarm

系统 硬失控抖动 接收机丢包 反复 ABORT

传感器 气压计漂移 未校准、气流 高度控制错误

传感器 磁力计干扰 电调线、电源线 yaw 错误

传感器 IMU yaw 漂移 无 mag、低速 飞错方向

传感器 GPS 数据率低 1Hz 模块 PID 精度差

配置 参数不当 throttleHover、groundSpeed 等 各种失败

环境 强风 逆风、侧风、风切变 返航/下降失败

环境 GPS 遮挡 城市、树林 LOWSATS

环境 电池骤降 大油门 动力不足

环境 Home 点错误 解锁时 GPS 未稳 飞错方向

相关话题

#大人也要玩玩具

用手机扫码体验更多功能

扫码查看6条评论