跳转至

参数、协议、日志与地面工具

参数、通信协议和日志共同构成飞控的外部接口。修改其中任何一个,都可能影响配置兼容、地面工具、自动化脚本、升级和故障分析。

参数协议日志数据边界

参数不是普通全局变量

一个可维护参数至少需要定义:

  • 稳定名称或标识;
  • 数据类型;
  • 单位;
  • 默认值;
  • 最小值和最大值;
  • 枚举或位掩码含义;
  • 是否需要重启;
  • 适用机型或功能;
  • 持久化方式;
  • 版本迁移规则;
  • 地面工具说明。

参数能够被写入,不代表当前值安全或会立即生效。

编译期配置与运行时参数

类型 适合内容 主要风险
编译期配置 板级资源、驱动裁剪、内存布局 改变产物,必须重新构建
启动期参数 端口、传感器方向、机型 错误值可能阻止启动或解锁
运行时参数 可安全在线调整的目标和限制 并发更新、瞬态和范围
只读状态 版本、健康、统计和诊断 不能被误当成可写配置

不要为了方便把所有设置都做成可实时写入参数。修改时钟、总线、内存和关键输出映射通常需要重新初始化,甚至只能在构建阶段决定。

参数写入需要事务语义

高风险参数更新不能简单执行“修改运行值,再尝试保存”。否则持久化失败时,随机存取存储器中的运行配置与非易失存储中的启动配置会分裂。

共同前置步骤是:

  1. 把候选值写入暂存区,不直接覆盖当前配置;
  2. 解析类型、单位和枚举;
  3. 检查单项范围和跨参数约束;
  4. 检查当前飞行、解锁和设备状态;
  5. 记录旧配置和变更来源。

需要重启的参数可以采用:

暂存候选
→ 整体校验
→ 写入非活动配置槽
→ 回读并校验
→ 原子切换活动版本或提交标记
→ 重启后加载

支持在线修改的参数可以采用:

暂存候选
→ 整体校验
→ 写入非活动持久化记录并回读校验
→ 在安全调度点切换可逆的运行快照
→ 验证运行态应用成功
→ 原子切换持久化活动标记
→ 成功后报告“已应用并保存”

应用失败时恢复旧运行快照,旧持久化记录仍保持活动;活动标记提交失败时也必须恢复旧运行快照并废弃候选记录。只有能够证明运行态切换及其外部副作用可逆时,才允许使用这条在线路径。会重配时钟、总线、执行器、传感器或其他不可逆状态的高风险参数必须拒绝在线修改,改用重启后生效路径。

具体实现还要定义断电原子性、双槽或日志式存储、校验和启动恢复规则。任何阶段都不能先向用户返回成功再异步尝试完成关键持久化。

逐项写入一组相互依赖的参数,可能在中间状态产生无效配置。必要时应使用事务、配置版本或启动后整体校验。

参数迁移

固件升级后,参数可能:

  • 新增;
  • 删除;
  • 改名;
  • 改单位;
  • 改范围;
  • 改默认值;
  • 改枚举含义;
  • 拆分或合并。

迁移代码必须知道旧版本和新版本,不能只判断“存储中有一个同名数字”。单位或枚举语义变化时,即使二进制类型相同也需要迁移。

升级测试至少覆盖:

  • 全新空白配置;
  • 上一受支持版本;
  • 较旧但声明可升级的版本;
  • 中途断电;
  • 校验失败;
  • 超范围旧值;
  • 降级或回滚。

通信协议先定义契约

协议字段至少说明:

  • 消息标识;
  • 方向;
  • 数据类型和字节序;
  • 单位和比例;
  • 坐标系;
  • 时间戳;
  • 有效标志;
  • 序号;
  • 长度;
  • 版本;
  • 校验;
  • 超时;
  • 权限;
  • 错误响应。

只有“发送三个浮点数”无法说明接收方应该如何解释。

常见协议角色

  • 多旋翼串行协议(MSP,MultiWii Serial Protocol)常用于配置器与部分飞控固件之间的参数、状态和命令交互;
  • 微型飞行器链路协议(MAVLink,Micro Air Vehicle Link)常用于飞控、地面站和伴随计算机之间的遥测、任务与命令;
  • 项目内部消息总线用于模块之间交换状态和事件;
  • 启动加载协议用于固件识别、擦除、写入和校验。

协议名称相同不代表全部消息、扩展、版本和权限策略一致。

控制命令需要权限与状态门禁

能够到达通信端口的消息,不应自动获得以下能力:

  • 解锁;
  • 切换飞行模式;
  • 修改安全参数;
  • 写入任务;
  • 控制执行器;
  • 重启;
  • 刷写固件;
  • 清除日志或配置。

设计时应明确身份、链路来源、签名或认证能力、重放风险、物理接入假设和当前状态。没有加密或认证的传统协议不能靠“消息格式复杂”获得安全性。

日志是测量系统

日志字段至少定义:

  • 名称;
  • 单位;
  • 坐标系;
  • 采样或发布时间;
  • 来源模块;
  • 更新率;
  • 有效状态;
  • 缩放和量化;
  • 丢样行为;
  • 版本。

记录值本身会消耗CPU、内存、总线和存储带宽。高频记录过多可能改变被测系统的时序,这属于观察者效应。

日志带宽估算

假设一个记录包含32字节有效数据,附加8字节时间和封装开销,以500赫兹记录:

单条记录 = 32 + 8 = 40字节
每秒数据量 = 40 × 500 = 20000字节
约为20千字节每秒,不含文件系统和块写入额外开销

多个主题叠加后还要考虑缓冲区峰值、存储卡延迟和日志丢弃策略。平均写入带宽足够,不代表最坏写入延迟可接受。

地面工具必须与固件配套

记录:

项目 需要核对
固件 项目、版本、提交和板级目标
配置器或地面站 版本和支持范围
参数元数据 名称、类型、单位、范围和说明
消息定义 方言、版本和扩展
升级器 设备识别、镜像格式和校验
日志工具 文件格式和字段版本

新版工具连接旧固件,或者旧工具连接新版固件,都可能隐藏字段、错误解释枚举或写入不支持的设置。

PX4 v1.17.0的只读追踪示例

参数:SYS_AUTOSTART

src/lib/systemlib/system_params.c中定义:

PARAM_DEFINE_INT32(SYS_AUTOSTART, 0);

其相邻元数据说明它选择系统启动脚本、范围为0至9999999,并且修改后需要重启。由此可以追踪:

C源码注释和PARAM_DEFINE
→ 构建时参数元数据
→ 固件参数表
→ 控制台与地面站参数界面
→ 启动脚本读取

在SITL中只读检查:

param show SYS_AUTOSTART

源码中的PARAM_DEFINE_INT32(SYS_AUTOSTART, 0)证明源码默认值为0;param show只用于核对运行时类型和当前值,不能独立证明源码默认值。本专题不执行param set SYS_AUTOSTART ...,因为错误机型会改变启动模块和控制分配。该例不要求安装地面站。

消息:vehicle_status

消息定义位于msg/versioned/VehicleStatus.msg。构建系统由消息定义生成C/C++类型,commander等模块发布,其他模块和地面接口按需订阅。

SITL只读检查:

listener vehicle_status 1

至少核对:

  • timestamp
  • 解锁状态;
  • 导航状态;
  • 失效保护和系统类型字段;
  • 当前源码中的消息版本。

字段名不能脱离固定消息版本解释。新增、删除或改变字段语义时,还需处理消息版本、桥接代码、日志解析器和地面工具。

日志

ULog是PX4二进制日志格式的专名,不按普通英文首字母缩写展开。文件通常使用.ulg扩展名。

执行:

logger help
param show SDLOG_MODE
logger status
listener vehicle_status 1
shutdown

参数元数据中的SDLOG_MODE默认值为0,但PX4 v1.17.0的SITL启动脚本会通过param set-default SDLOG_MODE 1覆盖为“从启动开始记录”。因此不能只根据元数据推断运行状态:

  1. logger help确认该固定版本支持的命令;
  2. param show SDLOG_MODE读取本次SITL实际值;
  3. logger status确认是否正在记录;
  4. 若没有记录,执行logger on后再次检查状态;
  5. 读取一个vehicle_status样本,正常shutdown并刷新日志。

正常shutdown并返回主机终端后,在PX4源码根目录运行:

LOG_FILE=$(find build/px4_sitl_default/rootfs/log \
  -type f -name '*.ulg' -print | sort | tail -n 1)
test -n "$LOG_FILE" || exit 1
printf 'log=%s\n' "$LOG_FILE"
command -v ulog_info
ulog_info "$LOG_FILE"

ulog_info不存在,可把Python虚拟环境创建在源码目录外,再回到源码根目录解析:

python3 -m venv ../px4-log-tools
. ../px4-log-tools/bin/activate
python3 -m pip install pyulog
LOG_FILE=$(find build/px4_sitl_default/rootfs/log \
  -type f -name '*.ulg' -print | sort | tail -n 1)
ulog_info "$LOG_FILE"

通过标准:

  • 找到非空.ulg文件;
  • ulog_info能够解析文件头、版本和时间信息;
  • 解析器没有报告文件截断或格式错误;
  • 记录了固件提交和msg/versioned/VehicleStatus.msg版本。

某个uORB主题能够被listener读取,不代表它一定进入当前日志配置。还要检查src/modules/logger、日志配置和实际ULog字段列表,不能仅凭logger status宣称目标主题已经记录。

兼容性测试

  • 未知消息应被安全忽略或明确拒绝;
  • 长度不足和超长消息不得越界访问;
  • 非数值、无穷大和非法枚举不得进入控制逻辑;
  • 重复、乱序和延迟消息按契约处理;
  • 参数写入在不允许状态下被拒绝;
  • 中途断电不留下半写配置;
  • 日志字段新增不破坏旧解析器的既有字段;
  • 地面工具显示值与飞控内部单位一致;
  • 所有拒绝和迁移结果可记录。

检查理解

  1. 为什么参数不能只定义名称和默认值?
  2. 哪些设置不适合在飞行中动态修改?
  3. 参数类型相同为什么仍可能需要版本迁移?
  4. 通信协议为什么必须定义时间戳和有效状态?
  5. 增加日志字段为什么可能改变实时行为?

主要参考