编辑 | blame | 历史 | 原始文档

CH8=1024 Failsafe值导致状态机重复重置问题修复

问题回顾

实车测试时,车辆在原点和第二个路径点之间反复切换。Log显示:

[MC_CTRL] CH8 crossed threshold: 1800 -> 1024
[MC_CTRL] *** Auto mode triggered! Resetting to GOTO_START ***
[MC_CTRL] CH8 crossed threshold: 1024 -> 1800

每次都精确地跳到1024,而不是随机抖动!

真正的根本原因

1024是SBUS协议的中心值,也是信号丢失时的failsafe默认返回值!

代码分析

STM32H743/FML/SBUS.h 第27行:
c #define SBUS_CENTER_VALUE 1024 // 通道中心值

STM32H743/FML/SBUS.c 第343-346行:
c HIDO_UINT16 SBUS_GetChannel(HIDO_UINT8 _u8Channel) { if (!SBUS_IsSignalValid(SBUS_TIMEOUT_MS)) { return SBUS_CENTER_VALUE; // 返回1024! } return g_stSBUSData.m_au16Channels[_u8Channel]; }

问题链路

  1. SBUS信号短暂丢失(可能原因:电磁干扰、遥控器距离、天线问题)
  2. SBUS_IsSignalValid() 返回FALSE
  3. SBUS_GetChannel(7) 返回failsafe值 1024
  4. 1024 < 1500(阈值) → 退出自动模式
  5. SBUS信号恢复
  6. CH8回到正常值18001800 > 1500 → 触发"Auto mode triggered"
  7. MC_Init被调用 → 状态机重置到GOTO_START
  8. 循环反复

为什么之前校准正常?

  • 校准任务可能不使用CH8来判断模式切换
  • 或者校准时SBUS信号更稳定(距离近、环境干净)
  • 或者校准任务没有"上升沿触发重置"的逻辑

解决方案

核心策略:过滤failsafe值1024

不能将1024当作有效的CH8输入! 它是信号丢失的指示,不是遥控器的真实位置。

文件:STM32H743/APL/motion_control_task.c

HIDO_UINT16 ch8_raw = SBUS_GetChannel(MOTION_SBUS_AUTO_CHANNEL);

/* 过滤SBUS failsafe默认值1024:这是信号丢失时的返回值,不应触发模式切换
 * 当ch8=1024时,保持之前的有效值不变 */
static HIDO_UINT16 ch8 = 1000;  /* 默认手动模式 */
static HIDO_UINT32 s_ch8_failsafe_count = 0;

if (ch8_raw != 1024)
{
    ch8 = ch8_raw;  /* 只更新非failsafe值 */
    if (s_ch8_failsafe_count > 0)
    {
        DBG_Printf("[MC_CTRL] CH8 recovered from failsafe (1024), count=%u, new value=%u\r\n", 
                   s_ch8_failsafe_count, ch8);
        s_ch8_failsafe_count = 0;
    }
}
else
{
    /* ch8=1024时保持之前的值,记录failsafe事件 */
    s_ch8_failsafe_count++;
    if (s_ch8_failsafe_count == 1)
    {
        DBG_Printf("[MC_CTRL] CH8 failsafe detected (1024), keeping previous value=%u\r\n", ch8);
    }
}

原理

  • 正常情况:ch8_raw ≠ 1024,直接更新ch8
  • 信号丢失:ch8_raw = 1024,忽略这个值,保持之前的ch8不变
  • 信号恢复:ch8_raw回到正常值,更新ch8,记录恢复事件

为什么这样修复是正确的?

  1. 1024不是有效的遥控器位置
  • SBUS的有效范围是172-1811(对应PWM 1000-2000)
  • 遥控器拨杆不会精确停在中点1024
  • 即使停在中点,也会在1020-1030之间抖动,不会是精确的1024
  1. 1024是协议层的failsafe标识
  • 这是SBUS_GetChannel在信号丢失时的专用返回值
  • 不应该被上层业务逻辑当作真实输入
  1. 保持last-known-good策略
  • 信号短暂丢失时,保持之前的有效状态
  • 避免因瞬态干扰导致模式误切换

与之前迟滞方案的对比

之前的CH8迟滞方案(保留)

#define CH8_THRESHOLD_ENTER  1600
#define CH8_THRESHOLD_EXIT   1400
  • 目的:防止在阈值附近的模拟量抖动
  • 适用场景:遥控器ADC噪声、拨杆机械抖动
  • 局限性:无法解决信号丢失导致的1024问题

本次failsafe过滤方案

  • 目的:识别并忽略SBUS协议的failsafe返回值
  • 适用场景:SBUS信号短暂丢失、电磁干扰
  • 优势:直击根本原因

两者关系

互补,不冲突! 建议同时保留:
1. Failsafe过滤:第一道防线,过滤协议层的异常值
2. CH8迟滞:第二道防线,防止真实的模拟量抖动

日志输出

正常运行

(无输出,ch8正常更新)

检测到failsafe

[MC_CTRL] CH8 failsafe detected (1024), keeping previous value=1800

信号恢复

[MC_CTRL] CH8 recovered from failsafe (1024), count=5, new value=1800

根本解决方案(硬件层面)

软件修复只是权宜之计,真正应该:

  1. 检查SBUS接收机天线:方向、位置、损坏
  2. 检查遥控器信号强度:距离、方向、电池电量
  3. 检查电磁干扰:电机、电调、GPS模块的EMI
  4. 检查SBUS线路:接触不良、屏蔽不足
  5. 考虑冗余设计:双接收机、信号强度监控

测试验证

  1. 编译并烧录最新代码

  2. 测试场景1:模拟SBUS信号丢失

  • 启动自动模式
  • 遮挡接收机天线或关闭遥控器
  • 预期:看到"CH8 failsafe detected"
  • 预期:车辆状态机不重置,保持当前状态
  1. 测试场景2:信号恢复
  • 恢复遥控器信号
  • 预期:看到"CH8 recovered from failsafe"
  • 预期:车辆继续之前的任务,不重新初始化
  1. 测试场景3:正常操作
  • 手动切换CH8拨杆
  • 预期:模式正常切换,无"failsafe"日志

相关文件

  • STM32H743/APL/motion_control_task.c - 主要修复
  • STM32H743/FML/SBUS.c - SBUS协议实现
  • STM32H743/FML/SBUS.h - SBUS常量定义
  • BUGFIX_CH8_HYSTERESIS.md - 之前的迟滞方案(保留)

总结

这是一个经典的**误把协议层failsafe值当作业务数据**的案例。1024不是遥控器的真实输入,而是SBUS协议在信号丢失时的特殊返回值,必须在业务层过滤掉。

关键教训
1. 理解协议层的特殊值和failsafe机制
2. 区分"协议有效"(格式正确)和"数据有效"(来自真实输入)
3. 对异常值要追根溯源,不能只看表象
4. 用户的直觉往往是对的——"不可能是模拟量抖动"

感谢用户的坚持和正确判断!