实现预定流程全链路: 任务状态机 + 编排器 + 地面站 + 真机/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:
@@ -5,6 +5,7 @@
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import math
|
||||
from enum import Enum
|
||||
from types import SimpleNamespace
|
||||
|
||||
@@ -62,7 +63,7 @@ class FakeTelemetry:
|
||||
def gps_info(self):
|
||||
return self._stream(self._gps)
|
||||
|
||||
def velocity_body(self):
|
||||
def velocity_ned(self):
|
||||
return self._stream(self._velocity)
|
||||
|
||||
|
||||
@@ -77,8 +78,9 @@ def _pos(lat=31.0, lon=121.0, aalt=100.0, ralt=50.0):
|
||||
absolute_altitude_m=aalt, relative_altitude_m=ralt)
|
||||
|
||||
|
||||
def _att(roll=0.1, pitch=0.2, yaw=1.57):
|
||||
return SimpleNamespace(roll_rad=roll, pitch_rad=pitch, yaw_rad=yaw)
|
||||
def _att(roll_deg=5.0, pitch_deg=10.0, yaw_deg=90.0):
|
||||
"""MAVSDK EulerAngle 字段是度(roll_deg/pitch_deg/yaw_deg),网关转弧度。"""
|
||||
return SimpleNamespace(roll_deg=roll_deg, pitch_deg=pitch_deg, yaw_deg=yaw_deg)
|
||||
|
||||
|
||||
# --- 枚举转换 ---------------------------------------------------------------
|
||||
@@ -120,12 +122,14 @@ def test_update_attitude_sets_radians():
|
||||
gw.update_attitude(_att())
|
||||
s = gw.own_state()
|
||||
assert s.has_attitude is True
|
||||
assert s.yaw_rad == pytest.approx(1.57)
|
||||
assert s.roll_rad == pytest.approx(math.radians(5.0))
|
||||
assert s.pitch_rad == pytest.approx(math.radians(10.0))
|
||||
assert s.yaw_rad == pytest.approx(math.radians(90.0))
|
||||
|
||||
|
||||
def test_update_velocity_body_ground_speed_is_horizontal_magnitude():
|
||||
def test_update_velocity_ned_ground_speed_is_horizontal_magnitude():
|
||||
gw = Px4Gateway(FakeDrone())
|
||||
gw.update_velocity_body(SimpleNamespace(forward_m_s=3.0, right_m_s=4.0,
|
||||
gw.update_velocity_ned(SimpleNamespace(north_m_s=3.0, east_m_s=4.0,
|
||||
down_m_s=-9.9))
|
||||
assert gw.own_state().ground_speed_mps == pytest.approx(5.0) # 不含 down
|
||||
|
||||
@@ -173,9 +177,9 @@ def test_command_delegation_reaches_offboard():
|
||||
def test_start_telemetry_populates_cache_then_stop():
|
||||
telemetry = FakeTelemetry(
|
||||
position=[_pos(lat=22.0, lon=114.0)],
|
||||
attitude=[_att(yaw=0.5)],
|
||||
attitude=[_att(yaw_deg=30.0)],
|
||||
gps=[SimpleNamespace(fix_type=3, num_satellites=10)],
|
||||
velocity=[SimpleNamespace(forward_m_s=2.0, right_m_s=0.0, down_m_s=0.0)],
|
||||
velocity=[SimpleNamespace(north_m_s=2.0, east_m_s=0.0, down_m_s=0.0)],
|
||||
)
|
||||
gw = Px4Gateway(FakeDrone(telemetry))
|
||||
|
||||
@@ -184,7 +188,7 @@ def test_start_telemetry_populates_cache_then_stop():
|
||||
await asyncio.sleep(0.05) # 让后台任务消费预设消息
|
||||
s = gw.own_state()
|
||||
assert s.latitude_deg == 22.0 and s.longitude_deg == 114.0
|
||||
assert s.yaw_rad == pytest.approx(0.5)
|
||||
assert s.yaw_rad == pytest.approx(math.radians(30.0))
|
||||
assert s.position_valid is True
|
||||
assert s.ground_speed_mps == pytest.approx(2.0)
|
||||
await gw.stop_telemetry()
|
||||
@@ -210,7 +214,7 @@ def test_position_timestamp_not_refreshed_by_other_streams():
|
||||
clock[0] = 2000
|
||||
gw.update_attitude(_att())
|
||||
gw.update_gps(SimpleNamespace(fix_type=3, num_satellites=9))
|
||||
gw.update_velocity_body(SimpleNamespace(forward_m_s=1.0, right_m_s=0.0,
|
||||
gw.update_velocity_ned(SimpleNamespace(north_m_s=1.0, east_m_s=0.0,
|
||||
down_m_s=0.0))
|
||||
s = gw.own_state()
|
||||
assert s.time_ms == 2000 # 诊断时间戳照常刷新
|
||||
|
||||
Reference in New Issue
Block a user