Dual-shepherd soft axis-split (HERDING_AXIS_LEAK)
The strict 100/0 axis mask reaches drive standoff and deadlocks
because each dog has only one degree of freedom left to push the
flock. Soften the mask: each dog leads its assigned axis (full gain)
and contributes ``HERDING_AXIS_LEAK`` on the other axis. ``0.0`` is
the old strict behaviour; ``1.0`` is no mask (both dogs run full
policy, role-redundant). Default ``0.3`` breaks the deadlock while
preserving the "one dog per axis" coordination story.
Implementation:
* `controllers/shepherd_dog/shepherd_dog.py` reads
`HERDING_AXIS_LEAK` from env / runtime cfg (clamped to [0, 1]),
prints it next to the axis tag, and multiplies the off-axis
velocity component by it instead of zeroing.
* `tools/run_webots.sh` writes `HERDING_AXIS_LEAK` into
`herding_runtime.cfg` so Webots-stripped controller subprocesses
still see it; defaults to 0.3 when unset.
Webots smoke test (HERDING_NDOGS=2, HERDING_AXIS_LEAK=0.3, strombom,
diff/field, 5 sheep, LiDAR perception, no GT): **5/5 penned at step
13204**, vs the strict 100/0 mask which timed out at 0/5. Penning
trail 1/5 → 2/5 → 4/5 → 5/5 between steps 6200 and 13400 — slower
than single-dog (Strömbom diff/field n=5: 7528) as expected since
the work is split, but the coordination demonstrably succeeds.
This gives the writeup a clean three-row ablation:
α=0.0 (strict) → deadlock, 0/5
α=0.3 (default) → 5/5 @ 13204
α=1.0 (no mask) → both dogs run full policy (single-dog
baseline applied twice; no axis story)
126 pytest cases still pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -230,6 +230,7 @@ HERDING_DRIVE=$DRIVE
|
||||
HERDING_WORLD=$WORLD
|
||||
HERDING_LIDAR=$LIDAR_VARIANT
|
||||
HERDING_NDOGS=$NDOGS
|
||||
HERDING_AXIS_LEAK=${HERDING_AXIS_LEAK:-0.3}
|
||||
HERDING_USE_GT=${HERDING_USE_GT:-0}
|
||||
EOF
|
||||
|
||||
|
||||
Reference in New Issue
Block a user