实测记录: 无激光时吊舱不输出表4(目标经纬度)

20Hz喂伪造表3(lat39.9042/lon116.4074/rel_alt50m),只收到约60Hz表2-2,
表4一帧都没有。判读: 吊舱目标地理解算依赖激光测距,无斜距即不解算。

架构影响:
- guidance.py 引导律在本设备上永久刹车(bridge.py:169 target_valid 依赖表4),
  安全方向正确但吊舱侧不再提供目标坐标
- 目标距离/坐标必须改由自有链路 stereo_yolo -> stereo_ranger 提供
- --auto-unlock 实测禁用: pod_console.py:232 把 last_tgt_s is None 当超时,
  会一锁定就误解锁并与 0x0F 常驻自动重锁循环震荡
- 阶段2/阶段3 精度实验取消(前提不成立)

保留两种待排除可能: 未真锁定、表3时戳/有效性要求,给出复测命令。
This commit is contained in:
keita
2026-10-08 10:04:04 +08:00
parent e1dbf081ab
commit 257721e035
3 changed files with 91 additions and 18 deletions
@@ -1,8 +1,50 @@
# 用「模拟飞控」喂表3 验证吊舱目标解算能力的实验方案
> 状态:**代码已实现**(`sim_fc.py` 已落地,配套 21 个纯软单测),
> 参数已敲定见 §7,**待上机实跑**得到 Q1/Q2/Q3 的实测答案。
> 日期:2026-09-29 关联:`docs/树莓派4B部署注意事项.md` §10 / §10.1
> 状态:**Q1 已有实测答案 —— 无激光时吊舱不输出 表4**(2026-10-08,见 §0.1)。
> 工具 `sim_fc.py` 已落地并配套 21 个纯软单测,参数已敲定见 §7。
> 日期:2026-09-29 立项 / 2026-10-08 实测收敛 关联:`docs/树莓派4B部署注意事项.md` §10.0
---
## 0.1 🔴 实测结论(2026-10-08):Q1 = 否,无激光 → 表4 不输出
**实验**:`sim_fc.py` 以 20Hz 持续喂伪造 表3(lat 39.9042 / lon 116.4074 /
rel_alt 50m,真实 UTC 递增时戳),同时观测下行。
**结果**:只收到 表2-2 遥测(≈60Hz),**表4 一帧都没有**(退出码 1)。
**判读**:吊舱的目标地理解算**依赖激光测距**——没有斜距就无法把视场角换算成
地面坐标,于是它**根本不发 表4**(不是发 0,也不是吐旧值)。原先设想的
"是否假设目标贴地"随之作废:**它压根没解算**。
**三个问题的答案**:
| 问题 | 实测答案 |
|---|---|
| **Q1** 无激光时是否输出表4 | ❌ **否**。表4 路径在本设备上不存在 |
| **Q2** 表4 频率 | ❌ 无从谈起(无输出)。`target_stale_ms` 对表4 无意义 |
| **Q3** 目标丢失后表4 行为 | ❌ 无法观测。目标丢失判据**不能**依赖表4(这与 §10.1 的预判一致) |
**架构影响(分叉已选边)**:
1. `guidance.py` 地理位置引导律在本设备上**永久刹车**——`bridge.py:169` 的
`target_valid` 依赖表4,表4 恒缺则每周期走 `_brake()`。安全方向正确(不会乱飞),
但**功能上等于吊舱侧不提供目标坐标**;
2. 目标距离与坐标**必须改由我方自有链路提供**:`stereo_yolo` 检测 →
`stereo_ranger` 双目视距。吊舱退化为"伺服稳定指向 + 表2-2 脱靶量"传感器;
3. 若要保留吊舱侧目标定位,只能换**带激光测距的吊舱型号**或外挂测距模块;
4. `--auto-unlock` **已实测禁用**(`pod_console.py:232` 把 `last_tgt_s is None`
当成超时,会一锁定就误解锁并循环震荡)。
**尚未完全排除的两种可能**(值得再花 10 分钟钉死,钉死前不要把结论当成绝对):
1. 本次测试**未必真的锁定成功**(bit2 未置位)→ 吊舱可能要求先锁定才解算。
复测加 `--detect person --auto-lock`,看汇总里"首次锁定"是否有值;
若**锁定后仍无表4**,结论才完全坐实。
2. 吊舱可能对 表3 的**时戳/位置有效性**有额外要求 → 用 `--freeze-time` 做一次对照。
**阶段2 / 阶段3 处置**:**取消**(精度比对与高度敏感性扫描都以表4 存在为前提)。
除非上面第 1 条复测翻盘,否则不要再往这条路上投时间。
---
+42 -12
View File
@@ -171,17 +171,15 @@ WantedBy=multi-user.target
`journalctl -u pod-bridge -f`。
- 代码热路径按 10Hz 引导 + 20Hz 姿态下发,Pi 4B 单核占用可忽略,无需实时内核。
## 10. 本设备实测特性(2026-09-28,厂商确认)
## 10. 本设备实测特性(2026-09-28 厂商确认 + 2026-10-08 实测)
- **本吊舱不含激光测距模块**。后果:
- 表2-2 激光测距字段恒为 0(无效),不可作为判据;
- `pod_bridge.json` 的 `link.require_laser_valid` **必须为 false**,否则引导
永久刹车(该闸门是为"有激光且锁定位置位粘滞"的机型准备的);
- ⚠ 需向厂商确认:无激光时吊舱如何解算表4 的目标绝对/相对高度
(是否假设目标在地面),这直接决定引导用的坐标精度。
→ 已给出**不依赖厂商答复的自测方案**:用树莓派伪造飞控数据喂 表3,
逼吊舱吐 表4,见 `docs/吊舱解算验证方案-模拟飞控喂表3.md`。
该实验还顺带回答 §10.1 悬着的两个前置问题(表4 是否存在、实际频率)。
- 🔴 **无激光时吊舱不输出 表4(目标经纬度)** —— **实测确认,2026-10-08**。
详见 §10.0,这是本项目迄今最重要的架构性结论。
- **锁定位置位(表2-2 状态字节1 bit2)在目标丢失后不复位**——实测观察;
表2-2 脱靶量是定长字段且协议**没有无效标志位**,丢失时表现为 0,
无法区分"不输出"与"输出 0"。
@@ -193,16 +191,48 @@ WantedBy=multi-user.target
0x07 / 0x0F / 0x10(实测结论,2026-09-28 纠正)。只有发了 `0x08 目标识别关`
才真正退出识别,此时才需要按 `d` / `a` 重新开启。
### 10.1 自动解锁机制(待定,勿贸然启用)
### 10.0 实测结论:无激光 → 表4 不输出(2026-10-08)
**实验**:用 `sim_fc.py` 以 20Hz 持续喂伪造 表3(lat 39.9042 / lon 116.4074 /
rel_alt 50m,真实 UTC 递增时戳),同时观测下行。
**结果**:只收到 表2-2 遥测(约 60Hz),**表4 一帧都没有**。
**判读**:吊舱的目标地理解算**依赖激光测距**。没有距离输入时,它拿不到目标的
斜距,无法把视场角换算成地面坐标,于是**根本不发 表4**(不是发 0、不是发旧值)。
此前"无激光时如何解算高度/是否假设目标贴地"的问题随之作废——**根本没解算**。
**直接后果(务必读完再决定下一步)**:
| 受影响项 | 后果 |
|---|---|
| `guidance.py` 地理位置引导律 | **永久刹车**。桥接层 `bridge.py:169` 的 `target_valid` 依赖表4;表4 恒缺 → `_latest_target` 恒 None → `GuidanceLaw.update()` 每周期走 `_brake("载机位置或目标不可用/超龄")`。安全方向正确(降级刹车、不会乱飞),但**吊舱表4 这条引导路径在本设备上等于不存在** |
| 目标距离/坐标来源 | 必须改由**我方自有链路**提供:`stereo_yolo` 检测 → `stereo_ranger` 双目视距。吊舱只当作"稳定指向 + 表2-2 脱靶量"的伺服/传感器用 |
| `--auto-unlock`(§10.1) | **必然误触发,已实测禁用**。见 §10.1 |
| 后续选型 | 若要保留吊舱侧目标定位,只能换**带激光测距的吊舱型号**,或外挂测距模块 |
**尚未排除的两种可能(值得再花 10 分钟钉死)**:
1. 吊舱需要**先真正锁定**才解算,而本次测试未必锁定成功(bit2 未置位)。
→ 复测时加 `--detect person --auto-lock`,并在汇总里确认"首次锁定"有值;
若锁定后仍无表4,结论才完全坐实。
2. 吊舱要求 表3 的**时戳/位置有效性**满足某种条件(例如 GPS 有效标志)。
→ 可用 `--freeze-time` 做一次对照。
> 复测命令:`python -m pod_bridge.sim_fc /dev/ttyAMA0 --detect person --auto-lock
> --seconds 60 --json phase1.json`,退出码 1 = 仍无表4。
### 10.1 自动解锁机制(🔴 本设备实测禁用,2026-10-08)
`pod_console.py --auto-unlock SEC` 现按「锁定中 + 表4 超过 SEC 秒未更新」触发 0x0E。
**该判据对本设备存疑**,开箱前需确认:
**该判据在本设备上 100% 误触发,不要用**:因为 §10.0 实测确认表4 根本不发,
`last_tgt_s` 恒为 None,而 `pod_console.py:232` 的条件把
`last_tgt_s is None` **直接当成超时** → 一旦锁定满 SEC 秒就发 0x0E,并且每
SEC 秒重复一次(与"假锁定"形成持续震荡:解锁 → 自动锁定 → 解锁 → …)。
| 待确认项 | 影响 |
| 待确认项 | 现状(2026-10-08 更新) |
|---|---|
| 本设备无激光,锁定后**到底发不发 表4** | 若表4 根本不发,`last_tgt_s` 恒空 → 一锁定就被误解锁,机制不可用 |
| 表4 的实际发送频率(规格 1~60Hz) | SEC 必须远大于实际周期(建议 ≥5s 且 ≥3 倍周期),否则误杀 |
| 解锁后是否自动重发 0x0F/0x10 重新捕获 | **不需要**:0x0F 是常驻模式,0x0E 后目标重新入画会自动锁定;自动重发反而可能与"假锁定"形成震荡 |
| 本设备无激光,锁定后到底发不发 表4 | ✅ **已实测:不发**。判据前提不成立 |
| 表4 的实际发送频率 | ❌ 无从谈起(无输出) |
| 解锁后是否自动重发 0x0F/0x10 重新捕获 | 不需要(0x0F 常驻),但**这反而让误解锁的震荡可以一直循环**,所以更不能用 |
候选替代判据(按可靠性排序):
1. **操作员按键 `u`**(台架阶段推荐,零误杀);
+4 -3
View File
@@ -224,9 +224,10 @@ def main() -> int:
latest_tgt = frame
# ---- 自动解除锁定:锁定中但表4 长时间不更新 ----
# ⚠ 本设备无激光测距,表4(目标经纬度)可能始终不发 → last_tgt_s 恒为
# None,此判据会一锁定就误解锁。启用前先用控制台观察「目标帧 距今」,
# 确认锁定后表4 真的在发。触发判据的替代方案见部署文档 §10。
# 🔴 本设备已实测(2026-10-08):无激光测距时吊舱**根本不发表4** →
# last_tgt_s 恒为 None,而下方条件把 None 当成超时,故本设备上
# --auto-unlock 会一锁定就误解锁,并每 SEC 秒与「0x0F 常驻自动重锁」
# 循环震荡。**不要再启用**,判据改用按键 u。详见部署文档 §10.0/§10.1。
if (args.auto_unlock > 0 and latest is not None
and latest.is_target_locked
and (last_tgt_s is None or now_s - last_tgt_s > args.auto_unlock)