Repository navigation
physics: log nav_plant runs for fitting a plant model, and dyn_plant's residual against Jolt - #749
Merged
9 commits merged intoOct 21, 2026
Merged
9 commits merged into
9 commits merged into
Conversation
…s residual against Jolt A port-Hamiltonian vehicle model fitted to the physics needs the physics' trajectories in a plant-learning format, and a baseline to beat. This adds both. - cvc::physics::plant_log (plant_log.h): samples a sim_world's agents on a nav_plant every tick as planar rigid bodies in SI: the centre of mass's pose on SE(2), its body twist, the steering, the command nav held over the tick (zero-order hold), the measured acceleration, contacts and wheels on the ground. - one_tick_residuals: the plan's per-tick drift (D14) with diff::dyn_plant beside the kinematic bicycle. Both step from Jolt's state with the held command, binned by the lateral g Jolt measured. Ticks with a static contact, a wheel off the ground, an impact (> 1.5 g) or at rest are left out, and counted. - cut_flights / write_npy: equal-length windows, [x, y, psi, vx, vy, r, drive, steer] float64. - cvc-plant-log: drives the Humvee or RoboRacer on Jolt through nav in a slalom (swerves past 0.3 g), the coef trainer's city, or a cvc::world city bundle (vehicle routes on its rasterized map, the vehicles spawned on its terrain), and writes flights.npy, meta.json and residual.json. src/cvc/tools/liesphgp_pack.py packs runs into the dataset pickle LieSPHGP's loaders read (the SE(3)-lifted 20-wide rows of its ROV loader with control_dim 2, or 8-wide SE(2)), with observation noise at a stated sigma. - nav_plant_options::ground_height: a start's ground for a terrain that is not flat (empty: ground_z, as before). - The roadmap's drift section publishes dyn_plant's residual at nav's 0.06 s tick: 4-18x closer than the kinematic bicycle above 0.5 g in position; worse in speed for the RoboRacer, whose driver model is faster than dyn_bike_si_of's 0.1 s drive lag. physics_plant_log_test (4): a run a model made leaves that model no residual (kinematic and dynamic, nsub 1/2/6); flights, their layout and the .npy; a Humvee slalom on Jolt (row k's command is the one held over the tick, the centre of mass moves with its logged twist to 0.023 m/s, peak 0.87 g); ground_height spawns as ground_z does.
…unding (1e-9) The run is made in the test and replayed in plant_log.cpp; a compiler may contract the two into FMAs differently (aarch64), so compare to rounding rather than to 1e-12. Include <iterator>.
…ven; gentler margins - fit_dyn_bike / dyn_bike_cost: dyn_bike_si_of's knobs a spec sheet does not give, fitted to logged runs by coordinate descent on the one-tick twist residual (drive and steering lags, factors on the tires' B, the yaw inertia, and drag + rolling resistance). dyn_bike_si_of is unchanged; this measures what the plant wants. one_tick_residuals takes a dyn_bike_si too. cvc-plant-log --fit-dyn fits on every seed but the last and reports the last. - Bundle routes: the goal is drawn from the free cells 5-15% of the map away. Drawing from the whole map landed in that ring ~6% of the time, which was the "planner fails on ~60% of goals". The planner keeps 2 m off building meshes, and an agent stopped for 5 s is replanned from where it stands. - --accel-margin / --brake-margin (nav_plant's), recorded in meta.json: at the full ±6 m/s^2 the RoboRacer's low chassis box pitches onto the ground under braking and acceleration. - --verbose (each agent every 5 s) and --samples (samples.csv); samples carry the roll. physics_plant_log_test: + FitsTheDynamicModelToRunsOfAKnownVehicle (a run made by a vehicle off the spec sheet: every knob recovered on its grid, cost 0).
…itted to Jolt The RoboRacer's city column is from runs planning with 0.4 of its acceleration and braking (its chassis box scraped the ground at the full 6 m/s^2). The fit (fit_dyn_bike, held-out seed) puts both vehicles' tires 2.5-4x softer than the spec sheet's B, and the RoboRacer with no drive lag and no uncompensated resistance. dyn_bike_si_of's defaults are unchanged.
… to delete an open file
…phgp # Conflicts: # src/cvc/CMakeLists.txt
The scene drivers and the directory writer move out of the standalone cvc-plant-log tool into cvc/physics/plant_log_scene.h (plant_log_options, drive_plant_log_scene, write_plant_log), so a trainer can drive the scenes in process. The command line becomes the `cvc plant-log` subcommand of cvc-cli, and the tool and its CVC_BUILD_PLANT_LOG option are gone. The three scenes run through `cvc plant-log` write files byte-identical to the old tool's (flights.npy, meta.json, residual.json, samples.csv), and the same stdout but for the timing. physics_plant_log_test adds the options' defaults and a swerve driven twice to identical runs; cvc_cli_test covers the subcommand.
… 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).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A port-Hamiltonian vehicle model fitted to the physics (a learned plant on SE(2), CVC-Lab/LieSPHGP's method) needs two things this PR adds:
What it adds
cvc::physics::plant_log(cvc/physics/plant_log.h) samples asim_world's agents on anav_plantevery tick, as planar rigid bodies in SI. Each sample holds:one_tick_residuals: the per-tick drift (D14's method) withdiff::dyn_plantbeside the kinematic bicycle.cut_flights/write_npy: equal-length windows of[x, y, psi, vx, vy, r, drive, steer], float64.cvc plant-log(a cvc-cli subcommand overcvc/physics/plant_log_scene.h) drives the Humvee or the RoboRacer on Jolt through nav, in one of three scenes:cvc::worldcity bundle: vehicle routes on its rasterized map, vehicles spawned on its terrain.It writes
flights.npy,meta.jsonandresidual.json. The scenes and the writer are library calls (plant_log_options,drive_plant_log_scene,write_plant_log), so a trainer can drive them in process.src/cvc/tools/liesphgp_pack.py(standard library and numpy only) packs runs into the dataset pickle LieSPHGP's loaders read (t,train_trajectories,test_trajectories,test_trajectories_noisy,settings).control_dim: 2, or the 8-wide SE(2) rows.--checkre-reads the file against that contract.nav_plant_options::ground_height: each start's ground height, for a terrain that is not flat. Empty meansground_z, as before.Roadmap: the drift section now publishes the dynamic model's residual (below).
Measured (local, Linux, Jolt 5.6.0+cvc.6 from cvcpkg; 4 seeds x 60 s, mu 0.9; spec-sheet dyn_bike, before #753; see "After #753" below)
The models' one-tick position residual at nav's 0.06 s tick (6 substeps), in mm, dynamic / kinematic:
dyn_bike_si_of'sdrive_lag) is slower than the vehicle's driver model.The 50 Hz datasets are 5 s flights from the slalom, the city, and the 3 km Austin south bundle, with seed 101 held out:
dx/dtmatchesR v_bto 0.024 m/s at p99.Tests:
physics_plant_log_test4/4:.npy;ground_heightspawns asground_zdoes.All nav/physics ctest cases pass (402/402). The tool and the packer were run as above; the packer's check passes on all four pickles.
Follow-ups (later commits on this branch)
Fitting dyn_bike to Jolt (
fit_dyn_bike,dyn_bike_cost,cvc plant-log --fit-dyn): a coordinate descent on the one-tick twist residual over the knobs a spec sheet does not give: drive and steering lags, factors on the tires' B, the yaw inertia, and drag + rolling resistance. It fits on seeds 100-102 and is judged on seed 103.Tires: the spec sheet's Pacejka B is 2.5-4x stiffer than Jolt's tires behave.
RoboRacer drive: its driver model tracks the commanded acceleration with an integral trim. So it has no drive lag, and it makes up for drag and rolling resistance.
Held out, at nav's 0.06 s tick: the fitted model's position rms against the spec sheet's and the kinematic bicycle's, in mm:
The RoboRacer's speed residual comes down to the kinematic bicycle's.
The Austin fits are not trustworthy: they land on the grids' edges, absorbing what the planar model leaves out on rough terrain.
Adopted in physics: fit dyn_bike_si_of to Jolt (tires, direct drive); P8b training now helps on Jolt #753 (merged):
dyn_bike_si_ofnow gives Jolt-fitted values. See "After physics: fit dyn_bike_si_of to Jolt (tires, direct drive); P8b training now helps on Jolt #753" below.Test:
FitsTheDynamicModelToRunsOfAKnownVehiclechecks that a run made by a vehicle off the spec sheet gives back every knob on its grid.Austin routes. The "planner fails on ~60% of goals" was the goal draw, not the planner: drawing from the whole map lands 150-450 m away only ~6% of the time, and all 8 tries missed.
RoboRacer chassis contacts. Its chassis box is centred on the axle line, 2-3 cm above the ground at rest, so at nav's full ±6 m/s² the pitch puts it on the ground. Contact ticks have a median longitudinal acceleration of -6.2 m/s².
--accel-margin/--brake-margin(nav_plant's own knobs, recorded in meta.json) at 0.4 take the city's contact ticks from 413 to 12, and the windows kept from 88 of 384 to 352 of 384.--verboseprints each agent every 5 s.--sampleswrites samples.csv. Samples now carry the roll.Datasets regenerated:
Austin gives 83 Humvee and 67 RoboRacer flights.
Folded into cvc-cli (2026-10-20). The command line is now
cvc plant-log. The standalonecvc-plant-logtool and itsCVC_BUILD_PLANT_LOGoption are removed, and its scene drivers and directory writer moved into the library ascvc/physics/plant_log_scene.h.cvc plant-logwrite byte-identical files to the old tool's (swerve with--fit-dyn --samples, city at 0.06 s with--steer commandand the margins, Austin with--verbose --fit-dyn):flights.npy,meta.json,residual.jsonandsamples.csv. Stdout is the same too, apart from the per-tick timing.physics_plant_log_test7/7, adding the options' defaults and a swerve driven twice to identical runs.cvc_cli_testadds fourplant-logcases (56/56 of its help, dispatch and plant-log tests locally).CI fixes.
CutsFlightsAndWritesThemAsNpyremoved the.npywhile its stream was still open; it is closed first now.src/cvc/CMakeLists.txtwith the relay's move tosrc/arisrvwas resolved by keeping both.After physics: fit dyn_bike_si_of to Jolt (tires, direct drive); P8b training now helps on Jolt #753 (master merged in; 7d95ba9). Every scene was rerun with
dyn_bike_si_of's Jolt-fitted values.Datasets: flights, meta.json and the four LieSPHGP pickles are byte-identical. Jolt drives the vehicles, and
dyn_bike_si_ofenters only the residuals.Residuals at 0.06 s, position rms in mm, dynamic before physics: fit dyn_bike_si_of to Jolt (tires, direct drive); P8b training now helps on Jolt #753 / dynamic now / kinematic:
Below 0.5 g the dynamic model is 1.3-9x closer than before. The RoboRacer's speed residual now matches the kinematic bicycle's there (0.001-0.035 m/s rms, was 0.018-0.090). What is left is the RoboRacer in the city above 0.5 g, and its yaw rate there.
Refits against physics: fit dyn_bike_si_of to Jolt (tires, direct drive); P8b training now helps on Jolt #753's values (50 Hz, fit on seeds 100-102, judged on 103):
Nothing is left to fit on flat ground: the defaults do as well as a refit on the held-out seed. The Austin fits still land on the grids' edges.
Roadmap: both tables are replaced with these. The datasets' rerun is
/home/joe/src/cvc/plant-log-runs-2026-10-20/post753/(local).Tests:
physics_plant_log_test7/7 after the merge.