Checkpoint 8

This commit is contained in:
Johnny Fernandes
2026-05-12 22:41:03 +01:00
parent a01a5c9cef
commit 5c2ee4bba5
31 changed files with 3189 additions and 380 deletions
+28 -4
View File
@@ -14,6 +14,7 @@ from herding.control.sequential import compute_action as sequential_action
from herding.control.strombom import (
DELTA_DRIVE, F_FACTOR, compute_action as strombom_action,
)
from herding.control.universal import compute_action as universal_action
from herding.world.geometry import PEN_ENTRY
@@ -119,8 +120,10 @@ def test_sequential_targets_closest_to_pen():
def test_active_scan_initial_phase_rotates():
teacher = ActiveScanTeacher(strombom_action)
# First call → opening rotation regardless of input.
vx, vy, mode = teacher((0.0, 0.0), 0.0, {"s0": (5.0, 0.0)}, PEN_ENTRY)
vx, vy, omega, mode = teacher(
(0.0, 0.0), 0.0, {"s0": (5.0, 0.0)}, PEN_ENTRY)
assert mode == "scan_initial"
assert omega == 0.0
assert math.isclose(math.hypot(vx, vy), 1.0, abs_tol=1e-6)
@@ -129,7 +132,8 @@ def test_active_scan_hands_off_to_base_after_opener():
# Burn through the opener.
for _ in range(2):
teacher((0.0, 0.0), 0.0, {"s0": (0.0, 8.0)}, PEN_ENTRY)
_vx, _vy, mode = teacher((0.0, 0.0), 0.0, {"s0": (0.0, 8.0)}, PEN_ENTRY)
_vx, _vy, _omega, mode = teacher(
(0.0, 0.0), 0.0, {"s0": (0.0, 8.0)}, PEN_ENTRY)
# Either drive (Strömbom mode label) or collect; not scan_initial.
assert "scan" not in mode
@@ -141,7 +145,7 @@ def test_active_scan_holds_last_action_on_brief_empty():
teacher((0.0, 0.0), 0.0, {"s0": (0.0, 8.0)}, PEN_ENTRY)
last = teacher.last_action
# Now a single empty frame → hold.
vx, vy, mode = teacher((0.0, 0.0), 0.0, {}, PEN_ENTRY)
vx, vy, _omega, mode = teacher((0.0, 0.0), 0.0, {}, PEN_ENTRY)
assert mode == "hold"
assert (vx, vy) == last
@@ -150,10 +154,30 @@ def test_active_scan_explores_after_sustained_empty():
teacher = ActiveScanTeacher(strombom_action, initial_scan_steps=1)
teacher((0.0, 0.0), 0.0, {}, PEN_ENTRY) # opener
for _ in range(EMPTY_DEBOUNCE_STEPS):
last_vx, last_vy, mode = teacher((5.0, 5.0), 0.0, {}, PEN_ENTRY)
last_vx, last_vy, _omega, mode = teacher(
(5.0, 5.0), 0.0, {}, PEN_ENTRY)
assert mode in ("explore", "scan_at_centre")
def test_active_scan_preserves_mecanum_omega():
"""Regression: ActiveScanTeacher must propagate omega from a mecanum
base teacher, not silently drop it. Without this, BC mecanum demos
have omega=0 everywhere and the policy never learns to rotate.
"""
teacher = ActiveScanTeacher(universal_action, initial_scan_steps=1)
# Burn the opener so we exit phase 1.
teacher((0.0, 0.0), 0.0, {"s0": (8.0, 8.0)}, PEN_ENTRY,
drive_mode="mecanum")
# Place a sheep off to the side so the dog needs to face it.
# Dog at origin facing +x (heading=0); target at (0, 8) → desired
# heading +π/2, so omega should be positive.
vx, vy, omega, mode = teacher(
(0.0, 0.0), 0.0, {"s0": (0.0, 8.0)}, PEN_ENTRY,
drive_mode="mecanum")
assert mode in ("collect", "drive", "recovery")
assert abs(omega) > 0.05, f"omega should be non-zero on mecanum, got {omega}"
def test_active_scan_reset_clears_state():
teacher = ActiveScanTeacher(strombom_action, initial_scan_steps=5)
for _ in range(3):