Skip to content

physics: fit dyn_bike_si_of to Jolt (tires, direct drive); P8b training now helps on Jolt - #753

Merged
transfix merged 1 commit into
masterfrom
feat/dyn-bike-jolt-fit
Oct 21, 2026
Merged

transfix merged 1 commit into
masterfrom
feat/dyn-bike-jolt-fit

Conversation

@transfix

Copy link
Copy Markdown
Owner

nav_plant::dyn_bike_si_of now gives P8a's dynamic model the values that Jolt's one-tick residual asks for. Re-run on Jolt, the P8b gate shows that training through the dynamic model now helps rather than only hurting less.

The change

  • Tires. Jolt's lateral friction ramps linearly to its peak at tire_peak_slip_angle, a cornering stiffness of 1/α_peak per unit load (jolt_backend.cpp). The old Pacejka tire, peaking at the same angle, started at B·C = C·tan(π/2C)/α_peak, about 4.5× steeper.
    • B is now set so that B·C = kJoltTireStiffness/α_peak, with kJoltTireStiffness = 1.12.
    • Front and rear are alike: front_stiffness defaults to 1 (it was 0.85), since Jolt's tires have no load sensitivity.
    • For both presets this is ×0.30 front and ×0.25 rear against the old values.
  • A direct drive (one gear and no torque converter, like the RoboRacer) gets no drive lag and no drag or rolling resistance. The driver model's integral trim tracks the commanded acceleration, so the command is the achieved acceleration.
  • A geared drive through a converter (the Humvee) keeps its 0.1 s lag and its resistances.
  • drive_lag now defaults to −1 (the vehicle's own value); an explicit value still wins.

Where the values come from. fit_dyn_bike (#749) fitted Jolt runs of both presets (slalom and city, 50 Hz) on seeds 100–102 and judged them on seed 103. The best single rule for both vehicles was the one above: the held-out twist residual came out about 11× lower than with the spec-sheet values (geometric mean over four runs).

The P8b Jolt gate, before and after

City RoboRacers, 20 held-out seeds × 48 agents × 400 ticks, paired bootstrap, Linux, master 65e7230 against this branch:

training dynamic-trained, before / after dynamic − untrained seed, before after
lr 5e-5, 150 steps (the test's default) 50.8% / 51.6% +0.2 [−1.8, +2.2] +0.9 [−1.0, +3.0]
lr 1e-4, 300 steps 48.5% / 52.1% −2.1 [−4.2, +0.1] +1.5 [−1.4, +4.1]
lr 2e-4, 300 steps 43.1% / 53.8% −7.5 [−10.0, −5.3] +3.1 [+0.7, +5.5]
checkpoints selected on 32 validation seeds 52.2% / 53.2% +1.6 [−0.4, +3.6] +2.6 [+0.7, +4.6]
  • The point-mass arm and the seed are unchanged: the point mass is 51.4%, 49.9%, 22.2% and 52.2% across the four rows, and the seed 50.6%.
  • Fitted minus before, on the dynamic arm:
    • lr 2e-4: +10.6 [+8.0, +13.1];
    • lr 1e-4: +3.5 [+0.5, +6.4];
    • default lr: +0.7 [−1.4, +2.9], within the noise.
  • Validation reach of the dynamic arm, under selection with 32 seeds, now rises steadily over training, 0.497 → 0.526 at step 210. Before, it fell to 0.41.
  • The selected checkpoint is the same with 8 or 32 validation seeds.
  • The gate logs and run_gate.sh are in /home/joe/src/cvc/p8b-gate-2026-10-20 on the build box.

Tests

  • DynBike.HumveeParametersFromItsSpecSheet asserts the new rule, for both presets.
  • DynBike.SteadyLateralNeverExceedsMuG now measures the body's lateral acceleration, vy' + r·vx, over the last second.
    • With the softer tires the Humvee drifts past its limit instead of settling into steady understeer. There, r·vx alone overstates the lateral acceleration (4.80 against μg = 3.92 at μ 0.4).
    • The body's lateral acceleration peaks at 3.67 m/s² (0.94 μg), and more Newton iterations or a smaller step change nothing.
  • dyn_bike_golden.json is regenerated. dyn_bike: the golden for libcvc's Jolt-fitted dyn_bike_si_of CVC-Lab/GRL-SNAM#134 carries the same file for the torch twin, which passes against it to 1e-9.
  • Local: nav/physics ctest 402/402 (Linux, Jolt 5.6.0 from cvcpkg).

Interactions with open PRs

…ng now helps on Jolt

dyn_bike_si_of's spec-sheet tire overstated the cornering stiffness 4.5x. Jolt's lateral friction
ramps linearly to its peak at tire_peak_slip_angle, 1 / alpha_peak per unit load. A Pacejka tire
peaking there starts at B C = C tan(pi / 2C) / alpha_peak. The one-tick residual of Jolt runs
(the Humvee and the RoboRacer, held-out seeds) asks for:

- B C = kJoltTireStiffness / alpha_peak, kJoltTireStiffness = 1.12, front and rear alike
  (front_stiffness defaults to 1, was 0.85: Jolt's tires have no load sensitivity);
- a direct drive (one gear, no torque converter) with no drive lag and no drag or rolling
  resistance, because the driver model's integral trim tracks the commanded acceleration. A
  geared drive through a converter keeps its 0.1 s lag and resistances. drive_lag < 0 (the
  default) means the vehicle's own; an explicit value still wins.

Those values lower the held-out twist residual about 11x against the spec sheet's.

The P8b Jolt gate rerun (city RoboRacers, 20 held-out seeds, paired bootstrap). The dynamic-trained
policy against the untrained seed, before -> after:
- lr 2e-4 / 300 steps: -7.5 [-10.0, -5.3] -> +3.1 [+0.7, +5.5];
- lr 1e-4 / 300: -2.1 -> +1.5;
- checkpoints selected on 32 validation seeds: +1.6 [-0.4, +3.6] -> +2.6 [+0.7, +4.6];
- lr 5e-5 / 150: +0.2 -> +0.9 (within the noise).
The dynamic arm's validation reach now rises over training (0.497 -> 0.526) instead of falling to
0.41.

Tests:
- DynBike.HumveeParametersFromItsSpecSheet asserts the new rule for both presets.
- DynBike.SteadyLateralNeverExceedsMuG measures the body's lateral acceleration (vy' + r vx).
  Past its limit the softer-tired Humvee drifts instead of settling, where vx r alone overstates it
  (4.80 against mu g 3.92 at mu 0.4); the body's peaks at 3.67.
- dyn_bike_golden.json is regenerated.
- nav/physics ctest 402/402.
transfix added a commit to CVC-Lab/GRL-SNAM that referenced this pull request Oct 21, 2026
Copies libcvc's regenerated tests/fixtures/dyn_bike_golden.json (transfix/libcvc#753): tire B*C = 1.12/alpha_peak front and rear, and a direct drive with no drive lag, drag or rolling resistance. grl_snam/dyn_bike.py reads the vehicle from the file, so no code changes.
@transfix
transfix merged commit 2028671 into master Oct 21, 2026
24 checks passed
transfix added a commit that referenced this pull request Oct 21, 2026
…rom half the grip)

With #753's tires (B C = 1.12 / tire_peak_slip_angle) the Pacejka peak sits
at a larger slip, so the 0.25 rad steer ramps no longer reached it. The ramps
now go to the 0.6 rad lock. The Humvee understeers: its front tire passes the
peak at 0.5-0.8 g on mu 0.9 (0.3-0.7 g on mu 0.6), and the rear never does.
The gate is PSD below half the grip, indefinite somewhere above it, and the
rear tire never past its peak.
transfix added a commit that referenced this pull request Oct 21, 2026
… dyn_bike_si_of

The 0.06 s residual table now shows the dynamic model before #753 / with its
values now / the kinematic bicycle. Below 0.5 g the fitted values are 1.3-9x
closer, and the RoboRacer's speed residual matches the kinematic bicycle's.
Refitted against #753's values, the flat-ground fits find nothing left: tire
factors back at x1, and the defaults do as well as a fit on the held-out seed.
The datasets are byte-identical (Jolt drives; dyn_bike_si_of only enters the
residuals).
transfix added a commit that referenced this pull request Oct 21, 2026
… golden regenerated

#753 fitted dyn_bike_si_of's tires to Jolt and made its defaults front_stiffness
1 and drive_lag by drivetrain. dyn4_si_of still passed the old 0.85 and 0.1, so
the four-wheel Humvee's front B was 0.85x the single track's and four dyn4 tests
failed. Its defaults are now 1.0 and -1.0, and dyn4_golden.json is regenerated
with the new tires.

The envelope test measures the body's lateral acceleration (vy' + r vx), as
DynBike.SteadyLateralNeverExceedsMuG does since #753: on the softer tires r vx
alone read 1.03 mu g at mu 0.4. NAV_TRAINING.md's P8a parameters (stale since
#753) and dyn4's gate numbers are updated. nav_dyn_4w_test 12/12.
transfix added a commit that referenced this pull request Oct 21, 2026
…energy balance (#748)

dyn_bike.h gains dyn_ph_* (H, the SE(2) coadjoint J, the linearized tires' D(v), G for u = (F_x, delta), the power and the Pacejka tires' tangent D). dyn_plant, its adjoint and its golden are unchanged.

nav_dyn_bike_test's DynBikePH gates: J skew and D PSD; dyn_plant's momentum change is the pH vector field to 0.22% of m g in the linear regime; the energy balance holds to 1.4% of the flow at every step 0.005-0.06 s, the residual falling with the steering amplitude (linearization); on #753's Jolt-fitted tires the tangent D is PSD below half the grip and indefinite above it, always the front tire (understeer).
transfix added a commit that referenced this pull request Oct 21, 2026
… (P8d) (#731)

diff::dyn4_plant (nav/detail/dyn_4w.h): P8a's single-track vehicle on its four wheels, with load transfer through per-corner springs and dampers, per-wheel friction and Ackermann steering, written over a scalar type with dyn4_plant_vjp on forward-mode duals. nav_plant::dyn4_si_of / dyn4_params_at derive it from a vehicle_desc on dyn_bike_si_of's Jolt-fitted defaults (#753). nav_dyn_4w_test gates the single-track limit, load transfer, mu-split braking, a bump, the VJP, the controller step, the envelopes against Jolt's Humvee, Ackermann, and dyn4_golden.json for the torch twin (CVC-Lab/GRL-SNAM#123, golden in #135).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant