PAYATHON 2026

MAVSDK 串口下载 PX4 日志时再次起飞触发 failsafe,如何排查?

数据小许

结论

现有信息不足以认定“PX4 在日志下载期间 arming 就必然触发 failsafe”,也不能仅凭两条下载超时日志判定是 MAVSDK 缺陷。应先确认 PX4 实际触发了哪一种 failsafe,再核对下载流量、链路状态和进程生命周期。

这套系统已经出现实际飞行异常,应先确保日志下载与下一次飞行互斥。启动下载前等待 disarmed/grounded,只能确认下载开始时满足条件,不能保证整个下载期间都满足条件。

下载重试说明了什么?

Timeout! 和 Requesting missing chunk 表示下载端等待日志数据超时后,请求缺失部分。MAVSDK 的 LogFiles 实现中有超时补取逻辑,因此即使下载最终成功,也可能出现这些输出。它们本身不能解释 PX4 的 failsafe 原因。MAVSDK LogFiles 实现

需要分别查清日志为何需要重传,以及再次起飞时哪项飞行安全条件失效。两者可能有关,也可能只是同时发生。

先确认 failsafe 的具体原因

保留故障前后的 PX4 Events、STATUSTEXT 和飞行 .ulg,对齐下载开始、arming、起飞、通信异常和 failsafe 触发的时间。具体可用的日志字段取决于固件版本。

根据实际事件检查:

  • Data Link Loss:确认 PX4 监测哪个组件的连接、相关 HEARTBEAT 是否中断,以及 downloader 启停是否改变连接状态。PX4 对这类 failsafe 有独立配置,不能将其与所有 MAVLink 通信异常混为一谈。PX4 failsafe 配置
  • Offboard Loss:仅在使用 Offboard 时检查,核对控制消息的到达间隔,以及控制进程是否受阻。
  • 其他原因:如果事件指向位置、RC、电池或系统故障,应沿该方向继续排查,不要预先归因于日志下载。

同时记录 PX4 固件版本或 commit、MAVSDK-Python 版本,以及实际运行的 mavsdk_server 版本。仅凭问题中的源码行号无法唯一确定版本。

两个进程为何仍可能相互影响?

watcher 与 downloader 分开运行,便于分别管理任务,底层资源却未必独立。如果两者最终经过同一个 UART、PX4 MAVLink instance 或路由队列,下载流量可能与遥测、心跳或控制流量竞争资源,需要通过测量验证。

先梳理完整的连接关系,尤其要确认 downloader 实际连接的地址。watcher 使用本机 TCP,不能证明 downloader 使用独立的物理链路。

如果 mavlink-router 已经打开某个串口,应用应通过其配置的端点通信,避免 downloader 再直接打开同一个串口。只有确认两个进程确实打开了同一设备,才能将串口争用列为本次故障原因。

在地面测试中,可通过 PX4 控制台观察:

mavlink status
logger status

比较有无下载时的链路速率、发送错误、消息间隔和 logger 状态。如果增加带宽或降低下载流量后现象消失,这只能支持资源竞争的判断,还需结合 failsafe 事件确认因果关系。

如何协调 watcher 与 downloader?

可以保留两个进程的设计,同时增加持续的状态通知和停止确认:

  1. 只有在飞行状态数据未过期、确认 grounded 且 disarmed,并满足等待时间时,才允许枚举和下载日志。
  2. 下载期间持续接收状态;出现 armed、离地、状态过期或连接丢失时,撤销下载许可,停止后续请求和重试。
  3. 通过所用版本支持的方式结束底层传输,确认下载流量已经停止后,再报告任务退出。
  4. 下一次满足地面条件后重新枚举日志,不默认先前的日志 ID 和文件状态仍然有效。

下面是协调逻辑的伪代码,函数名表示需要实现的行为,不是 MAVSDK API:

on flight_state_update(state):
    allowed = state.fresh and state.grounded and not state.armed

    if not allowed:
        revoke_download_permission()
        notify_downloader_to_stop()

on download_start_request():
    if ground_delay_satisfied() and download_permission_valid():
        start_single_downloader()

on downloader_stop_request():
    stop_new_log_requests_and_retries()
    end_underlying_log_transfer()
    confirm_transfer_stopped()

MAVLink 定义了用于结束日志传输的 LOG_REQUEST_END。取消 Python task、关闭 gRPC 流或退出 Python 进程,是否会让底层发送该消息,需要核对实际版本,不能直接假定传输已经停止。MAVLink 日志消息定义

发送结束消息前,还要确保 downloader 不再发起重试,否则后续请求可能重新启动传输。当前 PX4 main 分支中,LOG_REQUEST_END 会将日志传输处理器置为 Idle。这只是该源码分支的行为,仍需检查已部署的固件。PX4 日志传输实现

如果系统能够协调 arming,应在 arming 前完成停止下载并确认的流程。收到 armed 遥测后才停止,仍存在状态传播和取消延迟。若 arming 来自独立 RC,无法通过该服务协调,应安排明确的地面维护窗口。

停止 downloader 时,也要保留飞行所依赖的通信组件。先确认 downloader 是否承担心跳或控制职责,避免停止操作本身造成连接丢失。

如何缩小到具体原因?

先在 SITL 验证状态协调,再在拆桨的地面环境中检查实际串口和存储负载。依次比较:

  • 不启动 downloader。
  • 只连接 downloader,不枚举或下载。
  • 只枚举日志。
  • 持续下载历史日志。
  • 在 arming 前停止下载并确认流量结束。

如果只连接就触发异常,优先检查组件身份、心跳和连接生命周期。如果只有大量下载时才出现异常,优先检查共享链路和资源负载。若有明确的 logger 或存储错误,再调查相应固件与存储设备。

不要通过关闭 failsafe 来验证下载是否正常。提交缺陷报告时,应附上确切版本、完整连接拓扑、首次 failsafe 事件和最小复现步骤。现有材料尚不足以将其归类为某个已知 MAVSDK 问题。

备注:内容仅供参考。