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?
可以保留两个进程的设计,同时增加持续的状态通知和停止确认:
- 只有在飞行状态数据未过期、确认 grounded 且 disarmed,并满足等待时间时,才允许枚举和下载日志。
- 下载期间持续接收状态;出现 armed、离地、状态过期或连接丢失时,撤销下载许可,停止后续请求和重试。
- 通过所用版本支持的方式结束底层传输,确认下载流量已经停止后,再报告任务退出。
- 下一次满足地面条件后重新枚举日志,不默认先前的日志 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 问题。
备注:内容仅供参考。
