实现预定流程全链路: 任务状态机 + 编排器 + 地面站 + 真机/SITL入口

- utils/task_runner: 6态状态机(WAIT→ARM_TAKEOFF→GOTO(L2)→TRACK(L1)→APPROACH→RTL)
  + 编排器(快照采集/状态动作) + 双层日志(事件JSONL/遥测CSV) + 吊舱控制指令(0x07/0x0F/0x0E/0x08)
- pod_bridge: ground_link 地面坐标UDP注入(超龄判无效,无激光替代表4);
  set_heading_servo_enabled() 运行时L1/L2切换(切换即reset清积分防输出跳变);
  pod_locked 提为公共门控; config 新增 ground_inject 段
- virtual_pod 模拟吊舱(无电机语义) + verify_px4 增量④仅飞控验证 +
  pod_sitl_test L1 SITL全流程(飞行编排不塞进 run_bridge, 保持纯offboard闭环入口)
- 入口: task_runner_sitl(VirtualPod+虚拟目标, SITL端到端跑通约1m24s) /
  task_runner_real(真串口+UDP注入+吊舱控制)
- 地面站 ground_station: 坐标注入 + 状态可视化(Flask)
- S1标定回填(2026-10-09): beta_sign=+1 / alpha_sign=-1, 加标定回归测试守护
- 新增测试: task_runner x4 + ground_link/virtual_pod*/bridge/px4_gateway 增量; 全量 483 passed
- 文档: 预定流程(需求) + 预定流程-操作指南(操作/待办) + L1方案补S1结论与实现状态
This commit is contained in:
keita
2026-10-13 15:50:32 +08:00
parent 5a944af4f5
commit ded17d7995
30 changed files with 3552 additions and 27 deletions
+14 -8
View File
@@ -1,7 +1,7 @@
"""px4_gateway.py —— PX4(MAVSDK) 侧网关:读飞控遥测 + 发 offboard 速度指令。
职责(桥接的飞控侧):
* 订阅 PX4 遥测(position / attitude_euler / gps_info / velocity_body),缓存为
* 订阅 PX4 遥测(position / attitude_euler / gps_info / velocity_ned),缓存为
OwnState 快照,供桥接层构造 表3(载机姿态下发) 与 GuidanceInput(引导输入);
* 复用 visual_track_control.MavsdkCommandGateway 发送 offboard 速度设定点
(不重造三分支映射,直接喂 GuidanceLaw 的 ControlOutput)。
@@ -98,9 +98,11 @@ class Px4Gateway:
self._state.position_time_ms = now # 仅此流刷新,姿态高频流不得代刷
def update_attitude(self, e: Any) -> None:
self._state.roll_rad = float(e.roll_rad)
self._state.pitch_rad = float(e.pitch_rad)
self._state.yaw_rad = float(e.yaw_rad)
"""MAVSDK attitude_euler() 返回 EulerAngle(roll_deg/pitch_deg/yaw_deg,度),
转弧度存入 OwnState(下游控制律统一用弧度 NED)。"""
self._state.roll_rad = math.radians(float(e.roll_deg))
self._state.pitch_rad = math.radians(float(e.pitch_deg))
self._state.yaw_rad = math.radians(float(e.yaw_deg))
self._state.has_attitude = True
self._state.time_ms = self._now_ms()
@@ -110,9 +112,11 @@ class Px4Gateway:
self._recompute_valid()
self._state.time_ms = self._now_ms()
def update_velocity_body(self, v: Any) -> None:
def update_velocity_ned(self, v: Any) -> None:
"""MAVSDK velocity_ned() 返回 VelocityNed(north/east/down_m_s),
水平合速度即地速(表3 ground_speed 语义)。"""
self._state.ground_speed_mps = math.hypot(
float(v.forward_m_s), float(v.right_m_s))
float(v.north_m_s), float(v.east_m_s))
self._state.time_ms = self._now_ms()
def own_state(self) -> OwnState:
@@ -125,7 +129,9 @@ class Px4Gateway:
# --- 遥测订阅(异步胶水)----------------------------------------------
async def start_telemetry(self) -> None:
"""订阅四路遥测流,后台任务持续刷新缓存。"""
"""订阅四路遥测流,后台任务持续刷新缓存。幂等:已订阅则直接返回。"""
if self._tasks:
return # 已订阅,避免重复起任务(runner 会先订阅,bridge.start 再触发时跳过)
t = self._drone.telemetry
self._tasks = [
asyncio.ensure_future(self._consume(t.position(), self.update_position)),
@@ -133,7 +139,7 @@ class Px4Gateway:
self._consume(t.attitude_euler(), self.update_attitude)),
asyncio.ensure_future(self._consume(t.gps_info(), self.update_gps)),
asyncio.ensure_future(
self._consume(t.velocity_body(), self.update_velocity_body)),
self._consume(t.velocity_ned(), self.update_velocity_ned)),
]
logger.info("[Px4Gateway] 遥测订阅已启动")