Files
code-test-drone/legacy/utils/tests/stereo_ranger/target_store_test.py
T
keita df91b1110e 精简仓库结构并增强任务链路:归档双目可选后端、新增LOS判据与自定义返航
归档 legacy/:stereo_yolo/stereo_ranger/target_tracker 三包 + 175 条测试 + demo/配置/权重/三份规格;运行链路不再依赖,默认 pytest 446 条,归档测试按需运行。

目标有效性第二判据改为 LOS 运动学一致性(pod_bridge/los_consistency.py),删除 require_vision;pod_locked() 叠加该判据,状态机随之后退重搜。

自定义返航(task_runner/return_home.py):保持转场高度回起飞点 → 恢复初始航向 → 垂直降落,不再爬 RTL_RETURN_ALT;未起飞/无起飞点/超时/异常仍退回 PX4 原生 RTL。

任务链安全兜底:主循环异常→紧急返航、stop 幂等、landing_stop 保留遥测、in_air 流复用+超时、解锁/起飞与吊舱识别仅执行一次、rtl_timeout 上限。

入口共享件拆到 utils/sitl_support.py;pod_sitl_test.py→l1_sitl_test.py;删除旧架构 test.py;相机脚本移入 tools/。

新增 .gitignore 并剔除历史误跟踪的 59 个 .pyc;requirements 按实际依赖重写;文档全面对齐,新增 legacy/README.md 与 tools/README.md。
2026-10-21 14:48:41 +08:00

74 lines
2.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""目标隔离测试(规格 §4:track_id 优先 + 框位置最近邻、帧末老化清理)。"""
from stereo_ranger import StereoConfig, TargetStore
CFG = StereoConfig() # isolation_gate_px = 50,filter_reset_frames = 5
def test_track_key_stable_across_position_move():
store = TargetStore(CFG)
key_1 = store.resolve(0, 7, (100.0, 100.0), 1)
key_2 = store.resolve(0, 7, (400.0, 100.0), 2) # 位置大幅移动仍是同一目标
assert key_1 == key_2
assert store.count == 1
def test_nearest_neighbor_keeps_identity_within_gate():
store = TargetStore(CFG)
key_1 = store.resolve(0, None, (100.0, 100.0), 1)
key_2 = store.resolve(0, None, (130.0, 140.0), 2) # 距离 50 ≤ 门限
assert key_1 == key_2
def test_beyond_gate_creates_new_key():
store = TargetStore(CFG)
key_1 = store.resolve(0, None, (100.0, 100.0), 1)
key_2 = store.resolve(0, None, (200.0, 100.0), 2) # 距离 100 > 门限
assert key_1 != key_2
assert store.count == 2
def test_class_id_separates_states():
store = TargetStore(CFG)
assert store.resolve(0, None, (100.0, 100.0), 1) != store.resolve(1, None, (100.0, 100.0), 1)
def test_two_boxes_same_frame_claim_distinct_states():
store = TargetStore(CFG)
key_1 = store.resolve(0, None, (100.0, 100.0), 1)
key_2 = store.resolve(0, None, (110.0, 100.0), 1) # 同帧第二框不得接管已占用状态
assert key_1 != key_2
assert store.count == 2
def test_state_evicted_after_reset_frames_unseen():
store = TargetStore(CFG)
key = store.resolve(0, None, (100.0, 100.0), 1)
store.distance_filter.advance(key, 5.0)
store.consistency.advance(key, 9.6)
for frame in range(2, 7): # 第 2~6 帧:连续 5 帧缺席
store.end_frame(frame)
assert store.count == 0
assert store.distance_filter.value(key) is None
assert store.consistency.streak(key) == 0
def test_present_but_invalid_keeps_position_state():
store = TargetStore(CFG)
key = store.resolve(0, None, (100.0, 100.0), 1)
store.distance_filter.advance(key, 5.0)
for frame in range(2, 8):
store.resolve(0, None, (100.0, 100.0), frame) # 每帧仍出现
store.distance_filter.invalidate(key)
assert store.count == 1 # 位置状态保留
assert store.distance_filter.value(key) is None # 滤波状态已按门限清空
def test_clear_resets_everything():
store = TargetStore(CFG)
key = store.resolve(0, 5, (100.0, 100.0), 1)
store.distance_filter.advance(key, 5.0)
store.clear()
assert store.count == 0
assert store.distance_filter.value(key) is None