实测0x0E停止跟踪后bit2复位(厂商软件锁定框同步消失); --auto-unlock 的触发判据 (表4超时)对本设备存疑(无激光时表4可能根本不发→一锁定就误解锁), 已在代码标注 风险并在部署文档新增§10.1列出待确认项与5种候选判据。全量351条通过
204 lines
11 KiB
Markdown
204 lines
11 KiB
Markdown
# pod_bridge 移交树莓派 4B 部署注意事项
|
|
|
|
> 目标平台:树莓派 4B + **Raspberry Pi OS 官方镜像(64 位,Bookworm / Trixie)**。
|
|
> (2026-09-23 由 Ubuntu 24.04 换回官方镜像:Ubuntu 镜像上串口配置与
|
|
> libstdc++ 符号问题频出,官方镜像对 Pi 串口/固件支持最完整。)
|
|
> 范围:`utils/pod_bridge`(及其依赖的 `visual_track_control` 控制原语库)。
|
|
> 核对日期:2026-09-23,对照规格《光电吊舱控制协议G版-PB.docx》;
|
|
> 依赖轮子已按 PyPI 2026-09-23 上游信息复核。
|
|
|
|
---
|
|
|
|
## 1. 系统与 Python 版本(硬性)
|
|
|
|
- **必须烧录 64 位镜像**(Raspberry Pi Imager 里选 "Raspberry Pi OS (64-bit)"),
|
|
理由见 §3 MAVSDK 对 aarch64 的要求;32 位镜像不要碰。
|
|
- 烧完先确认:`cat /etc/os-release`。**Bookworm 自带 Python 3.11、
|
|
Trixie 自带 Python 3.13**,均满足 PEP 604 标注(`float | None` /
|
|
`FrameParser | None`)要求的 ≥3.10,直接用。
|
|
- Bookworm 起系统 Python 受 PEP 668 保护,**禁止 `pip install` 进系统环境**
|
|
(报 externally-managed-environment),一律建 venv;venv 支持若缺失先 apt 补:
|
|
|
|
```bash
|
|
sudo apt update && sudo apt install -y python3-venv python3-pip
|
|
python3 -m venv ~/venv-pod
|
|
~/venv-pod/bin/pip install -r requirements-pod.txt
|
|
```
|
|
|
|
## 2. 依赖裁剪(树莓派上别全装)
|
|
|
|
`requirements.txt` 是全仓库清单,**吊舱桥接只需要其中两个**,务必裁剪,
|
|
否则 torch/cv2 在 Pi 4B 上是几百 MB 且毫无意义:
|
|
|
|
```text
|
|
# requirements-pod.txt(桥接最小集)
|
|
mavsdk<4 # ⚠ 锁版本,原因见 §3
|
|
pyserial
|
|
pytest # 仅上机自测需要,部署运行可省
|
|
```
|
|
|
|
- `pod_bridge` 本身纯 Python + 惰性导入:`pyserial` 只在 `PodSerial` 实例化时加载,
|
|
`mavsdk` 只在 `Px4Gateway.connect` / 指令发送时加载——单测全绿不需要任何硬件库。
|
|
- **不要**在 Pi 上装 ultralytics/torch/opencv:那是 `stereo_yolo` 检测链的依赖,
|
|
Pi 4B 跑不动实时 YOLO,检测应留在机载算力更强的平台或吊舱内部。
|
|
- 若确实要装 opencv,用 `opencv-python-headless`(无 GUI 依赖),
|
|
并 `sudo apt install libopenblas-dev libatlas-base-dev`。
|
|
|
|
## 3. MAVSDK 在 ARM 上的坑
|
|
|
|
- **mavsdk 4.x 是全新原生 API 重写,与经典 gRPC API 完全不兼容**(2026-09-24
|
|
树莓派实测):没有 `mavsdk.offboard` / `System` / `telemetry`,本仓库全部
|
|
飞控代码(Px4Gateway / MavsdkCommandGateway / test.py)都是经典 API,
|
|
装 4.x 直接 `LegacyModuleError`。**必须锁 `mavsdk<4`**(最新 3.17.4,
|
|
aarch64 官方 wheel `manylinux2014_aarch64`,PyPI 已核对);
|
|
32 位 armv7l 支持不稳定——这是必须 64 位镜像的主因。
|
|
- 3.x 为 gRPC 架构,pip 包内嵌 `mavsdk_server` 可执行文件,**不加载
|
|
libcmavsdk.so,没有 libstdc++ 符号问题**——此前两系统上轮番出现的
|
|
`undefined symbol: ..._M_futex_wait_until...` 是 4.x 原生库专属坑,
|
|
换回 <4 后自然消失。
|
|
- 安装后自检三步(缺一不可;单测全绿**不**证明 mavsdk 已装,测试已打桩脱钩):
|
|
|
|
```bash
|
|
pip list | grep -i mavsdk # 必须显示 3.x(如 3.17.4)
|
|
python -c "from mavsdk import System; print('api OK')"
|
|
find ~/venv-pod -name mavsdk_server # 应有输出;直接执行能起服务更佳
|
|
```
|
|
|
|
- 连接串写法(`pod_bridge.json` 的 `px4.connection_string`):
|
|
- Pi 串口直连飞控 TELEM:`serial:///dev/ttyUSB0:57600`(波特率按飞控侧设置);
|
|
- 经数传/仿真:`udp://:14540`。
|
|
- PX4 侧需确认 TELEM 口已配 MAVLink 且 offboard 心跳未被占用。
|
|
|
|
## 4. 串口硬件(吊舱侧,最容易翻车)
|
|
|
|
- 协议为 **115200 8N1 无校验**(规格 §2.1)。先确认吊舱串口电平:
|
|
- **RS232 → 必须加电平转换或直接用 USB 转串口模块**(FTDI/CH340,推荐,
|
|
免折腾 GPIO UART,设备号 `/dev/ttyUSB0`);
|
|
- TTL 3.3V → 可用 Pi GPIO14/15(`/dev/serial0`)。
|
|
- 用 GPIO UART 时(官方镜像自带 `raspi-config`):
|
|
- `sudo raspi-config` → Interface Options → Serial Port:**控制台选 No、
|
|
串口硬件选 Yes**(等价于 `enable_uart=1` + 关闭 serial-getty 抢占);
|
|
- Pi 4B 上 `/dev/serial0` 默认指向 mini-UART(ttyS0,波特率随主频漂移),
|
|
115200 下不稳——在 `/boot/firmware/config.txt` 加 `dtoverlay=disable-bt`
|
|
把 PL011(ttyAMA0)换回来,`/dev/serial0` 随之改指 ttyAMA0
|
|
(想保留蓝牙改用 `dtoverlay=miniuart-bt`);
|
|
- **必须同时清掉内核控制台**(2026-09-28 实测踩坑):`dmesg` 出现
|
|
`printk: legacy console [ttyS0] enabled` 说明内核 printk 也在往同一个口
|
|
吐日志,与吊舱协议流混在一起(表现为能收几帧后 `OSError errno 5` 或
|
|
持续坏帧)。编辑 `/boot/firmware/cmdline.txt`(**单行文件,务必先备份**)
|
|
删掉 `console=serial0,115200` / `console=ttyS0,115200` 后重启;
|
|
- 串口静默后三连验证(缺一不可):`ls -l /dev/serial0`→ttyAMA0、
|
|
`ps aux | grep "[a]getty"` 无串口 getty、`dmesg | grep -i "console \["`
|
|
不再出现 ttyS0;
|
|
- **Pi 是 3.3V 电平,绝不直连 5V/RS232 电平**,会烧 GPIO。
|
|
- 接线三线:TX/RX **交叉**、**必须共地(GND)**,不共地是通讯乱码的第一大原因。
|
|
- 用户权限:`sudo usermod -aG dialout $USER`,重登录生效,否则 open 串口 Permission denied。
|
|
|
|
## 5. 时钟同步(规格表3 依赖)
|
|
|
|
- `bridge._build_attitude` 用**宿主机 UTC 墙钟**填表3 的年月日时分秒;
|
|
Pi 4B **无 RTC**,断电后时间是错的,吊舱会拿到错误时间戳。
|
|
- 上机后确认 `timedatectl` 显示 `System clock synchronized: yes`;
|
|
无网环境考虑给 Pi 加 RTC 模块,或由飞控 GPS 授时(需改代码,见 §8 已知问题)。
|
|
|
|
## 6. 配置文件(`utils/config/pod_bridge.json`)上机必改两处
|
|
|
|
| 字段 | 改成 |
|
|
|---|---|
|
|
| `pod_serial.port` | 实际设备号,如 `/dev/ttyUSB0`(留空会 fail-fast 报错,这是刻意的) |
|
|
| `px4.connection_string` | 实际飞控连接,如 `serial:///dev/ttyUSB1:57600` |
|
|
|
|
- 引导参数(`guidance.*`)全部是**占位值,未经标定不得用于飞行决策**;
|
|
首次实机只验证通讯收发,速度上限先调小。
|
|
- 配置加载拒绝未知键——改 JSON 时注意拼写,多写的键会直接报错(防呆设计)。
|
|
|
|
## 7. 上机验证顺序(每步过了再下一步)
|
|
|
|
1. **纯软件自测**(无需任何接线):
|
|
`cd utils && ~/venv-pod/bin/python -m pytest tests/pod_bridge -q` → 应 92 全绿
|
|
(单测已打桩 mavsdk 设定点类型,与 libcmavsdk 原生库健康状态无关)。
|
|
2. **串口回环**:USB 转串口模块 TX/RX 短接,跑一个 feed/echo 小脚本验证字节收发。
|
|
3. **只接吊舱**:用仓库自带诊断脚本
|
|
`python utils/pod_bridge/listen_pod.py /dev/ttyUSB0 --seconds 5`
|
|
(加 `--center` 可同时下发归中 0x2B 验证下行);脚本自动统计帧数并判读,
|
|
遥测帧率 ≥48Hz(标称 60Hz 的 80%)退出码为 0 即链路正常。
|
|
4. **只接飞控**:`Px4Gateway.connect` 后确认 `own_state().position_valid` 为 True。
|
|
5. **全链路地面联试**:电机不装桨,观察 offboard 心跳与引导输出。
|
|
6. 最后才考虑带动力测试。
|
|
|
|
## 8. 已知问题处置状态(2026-09-23 更新)
|
|
|
|
代码审查(2026-09-22)发现 4 项,其中 3 项安全相关缺陷**已于 2026-09-23 修复**,
|
|
新增回归测试 8 条(pod_bridge 测试 84 → 92,全量 348 条全绿):
|
|
|
|
1. ~~`Px4Gateway` 四路遥测共用 `OwnState.time_ms`~~ → **已修**:`OwnState` 拆出
|
|
`position_time_ms`(仅 position 流刷新),引导的位置超龄判定改用它;
|
|
2. ~~表2-2 锁定状态(bit2)未参与引导门控~~ → **已修**:`PodBridge._pod_locked`
|
|
要求遥测在 `link.telemetry_timeout_ms` 内且 bit2=锁定,表4 坐标才视为有效
|
|
(该配置项由此从死配置变为生效配置);
|
|
3. ~~`PodBridge.run` 主循环无异常护栏~~ → **已修**:单周期异常按「第 1 次 +
|
|
每满 100 次」告警并补发零速刹车保 offboard 心跳,任务不终止;
|
|
4. 表3 时间戳用宿主机墙钟而非 GPS 时间(见 §5)——**仍未修**,属可接受风险,
|
|
如需精确授时按 §5 对策处理。
|
|
|
|
## 9. 常驻运行(systemd 示例)
|
|
|
|
```ini
|
|
# /etc/systemd/system/pod-bridge.service
|
|
[Unit]
|
|
Description=Pod-PX4 Bridge
|
|
After=network.target
|
|
|
|
[Service]
|
|
ExecStart=/home/<user>/venv-pod/bin/python -m pod_bridge_app
|
|
WorkingDirectory=/home/<user>/code_drone-test/utils
|
|
Restart=always
|
|
RestartSec=3
|
|
StandardOutput=journal
|
|
StandardError=journal
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
```
|
|
|
|
- 热路径不打日志是设计使然(告警走 WarnThrottle),现场排查用
|
|
`journalctl -u pod-bridge -f`。
|
|
- 代码热路径按 10Hz 引导 + 20Hz 姿态下发,Pi 4B 单核占用可忽略,无需实时内核。
|
|
|
|
## 10. 本设备实测特性(2026-09-28,厂商确认)
|
|
|
|
- **本吊舱不含激光测距模块**。后果:
|
|
- 表2-2 激光测距字段恒为 0(无效),不可作为判据;
|
|
- `pod_bridge.json` 的 `link.require_laser_valid` **必须为 false**,否则引导
|
|
永久刹车(该闸门是为"有激光且锁定位置位粘滞"的机型准备的);
|
|
- ⚠ 需向厂商确认:无激光时吊舱如何解算表4 的目标绝对/相对高度
|
|
(是否假设目标在地面),这直接决定引导用的坐标精度。
|
|
- **锁定位置位(表2-2 状态字节1 bit2)在目标丢失后不复位**——实测观察;
|
|
表2-2 脱靶量是定长字段且协议**没有无效标志位**,丢失时表现为 0,
|
|
无法区分"不输出"与"输出 0"。
|
|
→ 单靠 bit2 会在目标丢失后继续朝过期坐标飞,**必须有第二判据**(见 §8/§11)。
|
|
- **主动解除锁定有效**:发 `0x0E 停止跟踪` 后 bit2 复位为未锁定,厂商测试软件的
|
|
锁定框同步消失(2026-09-28 实测)。重新锁定:重发 0x07 或 0x0F+0x10。
|
|
|
|
### 10.1 自动解锁机制(待定,勿贸然启用)
|
|
|
|
`pod_console.py --auto-unlock SEC` 现按「锁定中 + 表4 超过 SEC 秒未更新」触发 0x0E。
|
|
**该判据对本设备存疑**,开箱前需确认:
|
|
|
|
| 待确认项 | 影响 |
|
|
|---|---|
|
|
| 本设备无激光,锁定后**到底发不发 表4** | 若表4 根本不发,`last_tgt_s` 恒空 → 一锁定就被误解锁,机制不可用 |
|
|
| 表4 的实际发送频率(规格 1~60Hz) | SEC 必须远大于实际周期(建议 ≥5s 且 ≥3 倍周期),否则误杀 |
|
|
| 解锁后是否自动重发 0x0F/0x10 重新捕获 | 自动重发可能与"假锁定"形成震荡;建议单次解锁 + 告警,不循环 |
|
|
|
|
候选替代判据(按可靠性排序):
|
|
1. **操作员按键 `u`**(台架阶段推荐,零误杀);
|
|
2. 表4 超时(需先确认表4 存在);
|
|
3. 锁定持续超过 T 秒且**从未**收到表4 → 判为假锁定,解锁一次并告警(不循环);
|
|
4. 脱靶量恒为 0 持续 T 秒 —— 居中跟踪时也会为 0,**误杀风险高**,不推荐;
|
|
5. 由我方视觉链路(stereo_yolo / target_tracker)交叉验证 —— 最可靠,待集成。
|
|
|
|
飞行期的正确行为是**刹车保护**(现有 `target_stale_ms` 已覆盖),与"解锁以便重新
|
|
搜索"是两件事,不要混为一谈。
|
|
|