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

参数不是普通全局变量¶
一个可维护参数至少需要定义:
- 稳定名称或标识;
- 数据类型;
- 单位;
- 默认值;
- 最小值和最大值;
- 枚举或位掩码含义;
- 是否需要重启;
- 适用机型或功能;
- 持久化方式;
- 版本迁移规则;
- 地面工具说明。
参数能够被写入,不代表当前值安全或会立即生效。
编译期配置与运行时参数¶
| 类型 | 适合内容 | 主要风险 |
|---|---|---|
| 编译期配置 | 板级资源、驱动裁剪、内存布局 | 改变产物,必须重新构建 |
| 启动期参数 | 端口、传感器方向、机型 | 错误值可能阻止启动或解锁 |
| 运行时参数 | 可安全在线调整的目标和限制 | 并发更新、瞬态和范围 |
| 只读状态 | 版本、健康、统计和诊断 | 不能被误当成可写配置 |
不要为了方便把所有设置都做成可实时写入参数。修改时钟、总线、内存和关键输出映射通常需要重新初始化,甚至只能在构建阶段决定。
参数写入需要事务语义¶
高风险参数更新不能简单执行“修改运行值,再尝试保存”。否则持久化失败时,随机存取存储器中的运行配置与非易失存储中的启动配置会分裂。
共同前置步骤是:
- 把候选值写入暂存区,不直接覆盖当前配置;
- 解析类型、单位和枚举;
- 检查单项范围和跨参数约束;
- 检查当前飞行、解锁和设备状态;
- 记录旧配置和变更来源。
需要重启的参数可以采用:
支持在线修改的参数可以采用:
应用失败时恢复旧运行快照,旧持久化记录仍保持活动;活动标记提交失败时也必须恢复旧运行快照并废弃候选记录。只有能够证明运行态切换及其外部副作用可逆时,才允许使用这条在线路径。会重配时钟、总线、执行器、传感器或其他不可逆状态的高风险参数必须拒绝在线修改,改用重启后生效路径。
具体实现还要定义断电原子性、双槽或日志式存储、校验和启动恢复规则。任何阶段都不能先向用户返回成功再异步尝试完成关键持久化。
逐项写入一组相互依赖的参数,可能在中间状态产生无效配置。必要时应使用事务、配置版本或启动后整体校验。
参数迁移¶
固件升级后,参数可能:
- 新增;
- 删除;
- 改名;
- 改单位;
- 改范围;
- 改默认值;
- 改枚举含义;
- 拆分或合并。
迁移代码必须知道旧版本和新版本,不能只判断“存储中有一个同名数字”。单位或枚举语义变化时,即使二进制类型相同也需要迁移。
升级测试至少覆盖:
- 全新空白配置;
- 上一受支持版本;
- 较旧但声明可升级的版本;
- 中途断电;
- 校验失败;
- 超范围旧值;
- 降级或回滚。
通信协议先定义契约¶
协议字段至少说明:
- 消息标识;
- 方向;
- 数据类型和字节序;
- 单位和比例;
- 坐标系;
- 时间戳;
- 有效标志;
- 序号;
- 长度;
- 版本;
- 校验;
- 超时;
- 权限;
- 错误响应。
只有“发送三个浮点数”无法说明接收方应该如何解释。
常见协议角色¶
- 多旋翼串行协议(MSP,MultiWii Serial Protocol)常用于配置器与部分飞控固件之间的参数、状态和命令交互;
- 微型飞行器链路协议(MAVLink,Micro Air Vehicle Link)常用于飞控、地面站和伴随计算机之间的遥测、任务与命令;
- 项目内部消息总线用于模块之间交换状态和事件;
- 启动加载协议用于固件识别、擦除、写入和校验。
协议名称相同不代表全部消息、扩展、版本和权限策略一致。
控制命令需要权限与状态门禁¶
能够到达通信端口的消息,不应自动获得以下能力:
- 解锁;
- 切换飞行模式;
- 修改安全参数;
- 写入任务;
- 控制执行器;
- 重启;
- 刷写固件;
- 清除日志或配置。
设计时应明确身份、链路来源、签名或认证能力、重放风险、物理接入假设和当前状态。没有加密或认证的传统协议不能靠“消息格式复杂”获得安全性。
日志是测量系统¶
日志字段至少定义:
- 名称;
- 单位;
- 坐标系;
- 采样或发布时间;
- 来源模块;
- 更新率;
- 有效状态;
- 缩放和量化;
- 丢样行为;
- 版本。
记录值本身会消耗CPU、内存、总线和存储带宽。高频记录过多可能改变被测系统的时序,这属于观察者效应。
日志带宽估算¶
假设一个记录包含32字节有效数据,附加8字节时间和封装开销,以500赫兹记录:
多个主题叠加后还要考虑缓冲区峰值、存储卡延迟和日志丢弃策略。平均写入带宽足够,不代表最坏写入延迟可接受。
地面工具必须与固件配套¶
记录:
| 项目 | 需要核对 |
|---|---|
| 固件 | 项目、版本、提交和板级目标 |
| 配置器或地面站 | 版本和支持范围 |
| 参数元数据 | 名称、类型、单位、范围和说明 |
| 消息定义 | 方言、版本和扩展 |
| 升级器 | 设备识别、镜像格式和校验 |
| 日志工具 | 文件格式和字段版本 |
新版工具连接旧固件,或者旧工具连接新版固件,都可能隐藏字段、错误解释枚举或写入不支持的设置。
PX4 v1.17.0的只读追踪示例¶
参数:SYS_AUTOSTART¶
src/lib/systemlib/system_params.c中定义:
其相邻元数据说明它选择系统启动脚本、范围为0至9999999,并且修改后需要重启。由此可以追踪:
在SITL中只读检查:
源码中的PARAM_DEFINE_INT32(SYS_AUTOSTART, 0)证明源码默认值为0;param show只用于核对运行时类型和当前值,不能独立证明源码默认值。本专题不执行param set SYS_AUTOSTART ...,因为错误机型会改变启动模块和控制分配。该例不要求安装地面站。
消息:vehicle_status¶
消息定义位于msg/versioned/VehicleStatus.msg。构建系统由消息定义生成C/C++类型,commander等模块发布,其他模块和地面接口按需订阅。
SITL只读检查:
至少核对:
timestamp;- 解锁状态;
- 导航状态;
- 失效保护和系统类型字段;
- 当前源码中的消息版本。
字段名不能脱离固定消息版本解释。新增、删除或改变字段语义时,还需处理消息版本、桥接代码、日志解析器和地面工具。
日志¶
ULog是PX4二进制日志格式的专名,不按普通英文首字母缩写展开。文件通常使用.ulg扩展名。
执行:
参数元数据中的SDLOG_MODE默认值为0,但PX4 v1.17.0的SITL启动脚本会通过param set-default SDLOG_MODE 1覆盖为“从启动开始记录”。因此不能只根据元数据推断运行状态:
logger help确认该固定版本支持的命令;param show SDLOG_MODE读取本次SITL实际值;logger status确认是否正在记录;- 若没有记录,执行
logger on后再次检查状态; - 读取一个
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宣称目标主题已经记录。
兼容性测试¶
- 未知消息应被安全忽略或明确拒绝;
- 长度不足和超长消息不得越界访问;
- 非数值、无穷大和非法枚举不得进入控制逻辑;
- 重复、乱序和延迟消息按契约处理;
- 参数写入在不允许状态下被拒绝;
- 中途断电不留下半写配置;
- 日志字段新增不破坏旧解析器的既有字段;
- 地面工具显示值与飞控内部单位一致;
- 所有拒绝和迁移结果可记录。
检查理解¶
- 为什么参数不能只定义名称和默认值?
- 哪些设置不适合在飞行中动态修改?
- 参数类型相同为什么仍可能需要版本迁移?
- 通信协议为什么必须定义时间戳和有效状态?
- 增加日志字段为什么可能改变实时行为?