Mecanum Webots via Supervisor kinematic injection

Replace the failing ODE-rolled mecanum chassis dynamics with a
Supervisor.setVelocity call that uses the gym mecanum forward
kinematics formula directly. Wheel motors still spin (visual);
chassis motion comes from the gym model so training and deployment
match by construction.

Results (seed=42, n=10 sheep): BC + RL mecanum pen 10/10 in both
field and field_round. n=5 mecanum cells still 0/5 due to tracker
phantoms anchored to wall corners under the 360° LiDAR — documented
in docs/status.md as the remaining gap.

Cleanup: drop deploy-time hacks (HERDING_HEADING_*, HERDING_OMEGA_CLAMP,
HERDING_TRACKER_*) that were workarounds for the old ODE chaos;
revert the proto inertiaMatrix, roller dampingConstant, and reduced
motor torque since they no longer carry load; refresh comments
around the mecanum config presets.
This commit is contained in:
Johnny Fernandes
2026-05-18 22:46:37 +00:00
parent 1df84ae4b5
commit 27c0f65722
25 changed files with 2635 additions and 76 deletions
+15 -8
View File
@@ -179,19 +179,26 @@ def main():
f"'{FIELD_SHAPE}'. This should not happen — file a bug.")
from herding.config import (
HerdingConfig, HERDING_WEBOTS, HERDING_MEC_WEBOTS,
HerdingConfig, HERDING_WEBOTS, HERDING_MEC_WEBOTS, HERDING_MEC_WEBOTS_360,
DomainRandomConfig, RobotConfig,
)
if args.use_webots_preset:
# Pick the drive-matched Webots preset — for mecanum we use the
# variant that simulates the physical-roller proto's strafe
# efficiency and forward bleed so the policy trains under the
# same imperfect kinematics it sees at deployment.
base = HERDING_MEC_WEBOTS if args.drive_mode == "mecanum" else HERDING_WEBOTS
# Mecanum uses the 360° preset (the deployable mecanum target);
# diff drive keeps the canonical 140° preset.
if args.drive_mode == "mecanum":
base = HERDING_MEC_WEBOTS_360
preset_name = "HERDING_MEC_WEBOTS_360"
else:
base = HERDING_WEBOTS
preset_name = "HERDING_WEBOTS"
# Small compass noise for mecanum training (robustness margin
# for the Webots compass sensor).
compass_std = 0.1 if args.drive_mode == "mecanum" else 0.0
herding_cfg = base.replace(
domain_random=DomainRandomConfig(
fp_rate=args.fp_rate,
wheel_slip_std=args.wheel_slip_std,
compass_noise_std=compass_std,
),
robot=RobotConfig(
action_smooth=args.action_smooth,
@@ -199,10 +206,10 @@ def main():
strafe_to_forward_bleed=base.robot.strafe_to_forward_bleed,
),
)
preset_name = "HERDING_MEC_WEBOTS" if args.drive_mode == "mecanum" else "HERDING_WEBOTS"
print(f"[demos] {preset_name} preset + DR: fp_rate={args.fp_rate} "
f"action_smooth={args.action_smooth} wheel_slip_std={args.wheel_slip_std} "
f"strafe_eff={herding_cfg.robot.strafe_efficiency:.2f}")
f"strafe_eff={herding_cfg.robot.strafe_efficiency:.2f} "
f"compass_noise={compass_std}")
else:
herding_cfg = None
if args.fp_rate > 0.0 or args.action_smooth > 0.0 or args.wheel_slip_std > 0.0: