Skip to content

VDSim v0.4 — stunt physics (jump → vertical loop)

Status: near-complete (updated 2026-06-09, branch feat/v0.4-slope-jump-m5). Core stunt (jump + vertical loop + Ld5 + loop validation) shipped; M3 banked curve descoped to v0.5, theory doc 20_ld5_stunt.md outstanding. See "Milestones" for the close-out list. v0.3.0 remains drivetrain + LuGre only (V0.2_DRIVETRAIN.md, V0.2_TIRE_LUGRE.md).

Baseline at v0.4 entry

  • v0.2 done: composable subsystems, scene GUI (app.html), multi-vehicle runtime.
  • v0.3.0 done: engine inertia + torque-RPM, LuGre tire, ISO re-validation pass.
  • L3 today: small-angle heave/roll/pitch about static equilibrium; no airborne.
  • T23 Python jump spec exists (docs/tasks/T23_jump_14dof/REPORT.md); not in C++/GUI.

v0.4 theme — 3D contact + Ld5 + loop MVP

One release adds ramp jump (airborne), curved/banked track, full 3D chassis attitude (Ld5), and a single vertical loop scenario playable from GUI/batch/ vdsim_realtime. Road L2/L3 behaviour on flat ground stays the default; stunt modes are opt-in (level=L5, stunt scenario YAML).

Workstreams (all v0.4.0)

WS Name Delivers
WS-A 3D contact foundation T23 → C++; is_valid wired; world-z L3+; bump/droop
WS-B Ground & track ramp / banked curve / loop mesh; IContactProvider extensions
WS-C Ld5 dynamics 6-DOF body + wheels; quaternion; tire at arbitrary attitude
WS-D Runtime & GUI scenarios, /app stunt presets, STATE fields, telemetry
WS-E Validation T23 regression tests + loop sanity suite (separate from ISO)

Internal build order (same tag v0.4.0)

WS-A (contact + jump) ──► WS-B (geometry) ──► WS-C (Ld5) ──► loop on Ld5
                              │                    │
                              └──── GUI (WS-D) ────┴──► WS-E

WS-A — 3D contact foundation (jump)

Port T23 spec into C++ (fourteen_dof_dynamics.cpp + L2 coupling):

Item From To
z state perturbation about static eq world z (sprung + unsprung)
gravity g_z_effective ≈ 0 full -g on sprung/unsprung
tire vertical linear max(0, k·((z_road+r)−z_u)) → airborne Fz=0
L2 contact is_valid ignored off-ground → no Fx/Fy; no quasi-static Fz
springs linear only droop + bump (progressive, not hard clip)
state.position.z unused published in STATE / Python / FMI

Exit: tests/stunt/test_jump_l3.cpp — five T23 sanity checks green.

WS-B — Ground & track geometry

Provider Use
RampGround T23 half-cosine + lip + cliff (1D profile)
CurvedGround arc / spline segment; per-wheel z + surface normal
MeshGround triangle mesh raycast (loop surface)

Scenarios under configs/scenarios/:

  • jump_ramp.yaml — straight jump (L3+ or Ld5)
  • banked_oval.yaml — moderate banking (L3+ on curves)
  • vertical_loop.yaml — loop primitive (Ld5 only)

Builder/GUI: stunt track panel — ramp height, loop radius R, entry speed hint v_min ≈ √(5gR) (friction-free estimate).

WS-C — Ld5 (6-DOF chassis)

New dynamics level L5 / Ld5_Full3D (Ld4 stays hardpoint kinematics).

  • State: position, quaternion, v, ω; wheel spin; suspension internals (reuse L3 or Ld4).
  • Integration: RK4 with substeps; no small-angle linearization for body attitude.
  • Tire: Pacejka/LuGre in wheel contact frame (works inverted at loop apex).
  • Airborne: WS-A branch reused.
  • Flat road: L2/L3 unchanged; level=L5 opt-in only.

Exit: jump regression passes on Ld5; energy conserved in ballistic phase (spot check).

WS-D — Runtime, GUI, batch

  • vdsim_realtime: --scenario= loads stunt YAML; loop + ramp worlds.
  • VDS1 STATE: full quaternion already partial — verify ω, no gimbal issues in clients.
  • gui/app.html: setup → Stunt preset (ramp / loop); L5 level selector; Fz + z telemetry.
  • vdsim_batch / vdsim_lab: Experiment(level="L5") + stunt scenario.
  • CARLA bridge (optional v0.4.0): is_valid + mesh height feed-through if low cost.

WS-E — Validation & positioning

Suite Scope
ctest 190 unchanged on default L2/L3 flat (no stunt in default path)
tests/stunt/* jump (T23), banked curve, loop minimum-speed pass/fail
docs/VALIDATION.md new Stunt section — not ISO 4138; demo/education tier
docs/theory/20_ld5_stunt.md Ld5 equations + loop entry speed

Loop MVP acceptance (v0.4.0):

  1. With design entry speed → completes loop without rail (or with optional light guide rail behind a flag; default off for “physics loop”).
  2. Below v_min → fails to crest (rolls back or falls — no silent teleport).
  3. Apex: inverted, all wheels Fz > 0 or documented flight-only apex (either documented).
  4. No NaN / runaway energy over 3 laps.

Milestones (single release v0.4.0)

# Milestone WS Status (2026-06-09)
M1 T23 C++ jump + contact wired A ✓ done (Stunt.JumpAirborneInterval, JumpLandingNoSink)
M2 RampGround + ramp scene + GUI A,B,D ✓ done (RampGround, jump_ramp_demo.yaml, app.js render)
M3 CurvedGround + banked scenario B → moved to v0.5 (banked curve groups with terrain)
M4 Ld5 core + jump on Ld5 C ✓ done (Free3DDynamics, L5CoastOnFlatNoSink)
M5 loop ground + vertical_loop scene B,C ✓ done (LoopGround, vertical_loop_demo.yaml, FreeLoopCompletesLap)
M6 Loop validation suite + theory doc E partial — validation tests ✓ (loop 4 + jump); theory 20_ld5_stunt.md not written

Tag v0.4.0 when M1, M2, M4, M5, M6 are green. M3 (banked curve) is descoped to v0.5 (see V0.5_TERRAIN_L5.md M5/M5b) — CurvedGround arc/spline and a banked-oval scenario belong with the terrain/L5 work, not stunt presets.

Confirmed gaps at v0.4 close (2026-06-09 audit)

  • theory docs/theory/20_ld5_stunt.md (M6) — Ld5 EOM + loop entry speed v_min ≈ √(5gR). Documents already-shipped behaviour; write before the tag.
  • GUI stunt authoring preset panel (WS-D) — confirmed absent: app.html/app.js render loaded stunt scenes (ramp/loop mesh, z/pitch/roll telemetry) but there is no setup panel to author a ramp/loop scene from the GUI. Descoped to v0.5 GUI work.
  • M3 banked curve (above) — to v0.5.

Explicit non-goals (v0.4.0)

  • V2V collision, double loop, corkscrew (v0.5+ backlog).
  • Production sign-off of loop loads (bump-stop model stays educative).
  • Replacing default L3 for normal road sims.
  • Full loop track editor (parametric R + entry only).

Dependencies

v0.3.0 (drivetrain + LuGre)
    └──► v0.4.0 M1..M6 (this doc)

LuGre should land before M4 (landing grip). T23 port (M1) can start in parallel with v0.3.0 tail if interfaces are frozen.

Risks

Risk Mitigation
Ld5 destabilizes flat L3 separate create_full_3d(); default level unchanged
Loop only works with rail ship rail as debug flag; document physics loop as goal
ISO numbers move stunt tests isolated; v0.3 already re-baselined drivetrain/tire
GUI scope creep M2/M5 = presets only, not general track CAD
  • docs/tasks/T23_jump_14dof/REPORT.md — jump specification to port
  • docs/theory/06_ld3_fourteen_dof.md — current L3 vertical model
  • docs/SUMMARY.md — T23/T24 stunt tier summary
  • V0.2_PLAN.md — v0.2 scope; v0.3 items listed there move to v0.3.0 only