AGENTS.md 6.4 KB

AGENTS.md

本项目是摩天云 MQTT–MAVLink 串口桥(motian-mavlink-bridge)。它连接飞控串口与摩天云 MQTT Broker:被动解析串口上的 MAVLink 帧,按平台 Base JSON 协议上报遥测,并把平台下行指令翻译成 VKFly MAVLink 帧写回串口。详细协议说明见 README.md,实施方案见 doc/实施方案.md。

技术栈与运行环境

  • Python >= 3.10(代码使用 X | None 等语法),Linux 部署。
  • 运行依赖:paho-mqtt>=2,<3、pyserial>=3.5,<4、pymavlink>=2.4.50,<3(见 pyproject.toml)。
  • MAVLink 方言 VKFly 由 msg_definitions Git 子模块的 XML 生成。
  • 测试用标准库 unittest,不使用 pytest。

目录结构

motian_bridge/
  cli.py          生产入口,创建 paho-mqtt / pyserial 实例并注入 Bridge
  bridge.py       Bridge 核心:MQTT 收发、串口读写线程、Base JSON 编解码、handler 注册、参数表自动同步
  config.py       Config 冻结 dataclass,含校验;密钥从环境变量读取
  aircraft.py     Aircraft:按飞控聚合身份、最新观测、电池与参数表(ParamTable)
  telemetry.py    MAVLink 帧解析与上报节流,内部持有一个 Aircraft(仅串口线程使用)
  commands.py     平台业务指令 -> VKFly MAVLink 帧的 handler
  dialects/v20/VKFly.py   ⚠️ 生成文件,禁止手工修改
tests/            unittest 用例(依赖 FakeMqtt/FakeSerial,test_commands 复用 test_bridge 的辅助函数)
tools/            local_mqtt_broker.py,本地 aMQTT 测试 Broker(非生产依赖)
doc/              平台接口规范、实施方案、qa.md(待平台澄清问题)
config.example.json   配置模板

环境搭建与常用命令

python3 -m venv .venv
.venv/bin/python -m pip install -e .          # 安装(可编辑模式)
cp config.example.json config.local.json      # 再按需修改真实参数

# 跑全部测试(必须是 -s tests,用例间有相互导入)
.venv/bin/python -m unittest discover -s tests -v

# 启动桥接服务
export MOTIAN_MQTT_PASSWORD='由部署环境提供'
.venv/bin/motian-mavlink-bridge --config config.local.json --debug

# 本地联调:先起本地 Broker(需先 pip install "amqtt>=0.12,<0.13")
.venv/bin/python tools/local_mqtt_broker.py

架构与代码约定

  • 依赖注入:Bridge 只接收抽象的 MQTT client 与 serial_factory,具体实现由 cli.py 提供,便于测试用 fake 替换。保持这一模式。
  • 线程边界:串口读取线程(_serial_loop)独占 Telemetry 解析器与其内部的 Aircraft 状态;MQTT 回调线程负责下发。跨线程共享用 threading.Lock / threading.Event,不要引入全局可变状态。Aircraft 的 latest/batteries/params 都只允许串口线程写入,Telemetry 保留 source/latest/params/batteries 兼容属性。
  • 配置:所有配置项加到 Config 冻结 dataclass,并在 __post_init__ 里做校验(非法值直接抛 ValueError)。密钥、密码只从环境变量读取(mqtt_password_env),绝不写进 JSON 或代码。
  • 风格:4 空格缩进、双引号、类型标注、模块级 LOG = logging.getLogger(__name__)。判断类型用 type(x) is int 这类精确判断(避免 bool 被当作 int 接受)。
  • 扩展新平台指令:在 FlightCommandHandlers.install() 里 register_handler(data_type, handler),handler 返回时通过 bridge.publish_report(data_type, data) 上报。未实现/未确认的指令只记日志并丢弃,绝不伪造成功 ACK。
  • 文档、注释用中文;代码标识符和 git 提交信息用英文祈使句(如 Add platform command forwarding callbacks)。

协议约定与红线

  • 上行原始透传固定为 DataType=526 + 大写 HEX Data,发到 /PUBLISH/<SystemID>;结构化上报发到 /RECEIVE/<SystemID>。字段名是 DataType(没有尾随空格)。
  • MQTT 使用 QoS 0、不 retain;收到的 retained 下行一律丢弃;断线不缓存、不重放。
  • 下行报文必须有 DataType/UAVType/Data/SystemID/TimeStamp,且设备标识须与本机配置一致;Data 必须是非空、偶数长度 HEX,不超过 max_command_bytes。
  • 业务指令在尚未收到飞控 HEARTBEAT、未锁定目标 system/component 前禁止下发(_target() 会抛错保护)。
  • 不要修改 motian_bridge/dialects/v20/VKFly.py——它是生成文件。XML 变更后重新生成:

    .venv/bin/python -m pymavlink.tools.mavgen --lang Python --wire-protocol 2.0 \
      --output motian_bridge/dialects/v20/VKFly.py \
      msg_definitions/msg_definitions/VKFly.xml
    
  • Telemetry 中 VKFly.MAVLINK_IGNORE_CRC = 0 是安全底线,不要为调试方便关闭 CRC 校验。

  • 不要提交 config.local.json、.venv/、*.pdf(见 .gitignore);

  • 不要降低 TLS 强度(mqtt_ca_file 校验、证书配置等保持开启)。

测试要求

  • 新增行为必须补 tests/ 下的 unittest 用例;提交前必须通过: .venv/bin/python -m unittest discover -s tests -v
  • 涉及串口/MQTT 的用例用 FakeMqtt / FakeSerial(见 tests/test_bridge.py);涉及真实帧编解码时用 VKFly.MAVLink 构造帧,参照 tests/test_telemetry.py。
  • 涉及配置校验的改动,同步更新 ValidationTests。

常见陷阱

  • 串口重连会重置 Telemetry(可能换了一架飞控),旧状态必须丢弃,不要跨重连复用遥测。
  • Telemetry 逐字节喂给 parse_char,每次只返回一条消息;分块读取不影响帧边界,不要改成整块喂入。
  • STATUSTEXT 的文本需绕过生成的 Python 解码器、手动按 char[50] 读 UTF-8(生成代码按 ASCII 处理会丢字符),改动这里前先看 telemetry.py 注释。
  • 除锁定 HEARTBEAT 后主动同步一次参数表外,桥接程序只被动接收,不主动向飞控请求消息流;缺字段时先确认飞控是否在广播对应消息(--debug 可看到 missing/stale 日志)。参数同步由 request_params_on_start(默认开)控制,超时/重试见 param_request_timeout、param_request_max_attempts;#281 与自动同步共用 commands.py 的 request_params(),改动需同步更新 test_commands.ParameterSyncTests。
  • #274 的 true 表示解锁,不是物理离地;DataType 258 的 IsFlying 也按解锁解释。
  • 部分平台参数映射尚未由飞控协议确认(commands.py 的 TODO_PARAMS)以及 #2050 Data=true 的“接管”语义,均保留 TODO,不要擅自映射或发送;需先澄清可记入 doc/qa.md。