Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,10 @@ jobs:
- name: Configure (validation preset)
run: cmake --preset validation -Dpybind11_DIR="$(python3 -m pybind11 --cmakedir)"

# Bound validation compilation memory so hosted runners do not terminate
# concurrent compiler processes before the authoritative test run.
- name: Build (validation preset)
run: cmake --build --preset validation
run: cmake --build --preset validation --parallel 2

- name: List registered tests
run: ctest --preset validation -N | tee ctest-list.txt
Expand Down
11 changes: 9 additions & 2 deletions core/src/fourteen_dof_dynamics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -377,15 +377,22 @@ class FourteenDOFDynamics : public IVehicleDynamics {
mb::WheelLoad wl {};
const auto F = inner_->tire_forces_body();
wl.force_world = 0.5 * (F[wheel_base] + F[wheel_base + 1]);
const auto mot = axle_prescribed_motion(wheel_base, steer_rad);
const auto wp = dae->step(*st, mot, wl, 0.0);
const auto mot_left = axle_prescribed_motion(wheel_base, steer_rad);
auto mot_right = mot_left;
mot_right.steer_rack_dy = -mot_left.steer_rack_dy;
auto st_left = *st;
auto st_right = *st;
const auto wp_left = dae->step(st_left, mot_left, wl, 0.0);
const auto wp_right = dae->step(st_right, mot_right, wl, 0.0);
*st = std::move(st_left);
double toe_comp = 0.0, camber_comp = 0.0;
mb::compliance_targets_rad(*topo, wl, toe_comp, camber_comp);
mb_compliance_toe_rad_[wheel_base == 0 ? 0 : 1] = toe_comp;
for (int j = 0; j < 2; ++j) {
const int i = wheel_base + j;
const bool right = (i == WHEEL_FR || i == WHEEL_RR);
const double s = right ? -1.0 : 1.0;
const auto& wp = right ? wp_right : wp_left;
gamma[i] = s * (wp.camber_rad + camber_comp);
toe[i] = s * (wp.toe_rad + toe_comp);
}
Expand Down
4 changes: 3 additions & 1 deletion core/src/free_3d_dynamics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1001,16 +1001,18 @@ class Free3DDynamics final : public IVehicleDynamics {
const Mat3 R = state_.orientation.toRotationMatrix();
for (int i = 0; i < NUM_WHEELS; ++i) {
const bool front = (i == WHEEL_FL || i == WHEEL_FR);
const bool right = (i == WHEEL_FR || i == WHEEL_RR);
mb::IHardJointDaeModel* dae = front ? mb_dae_front_.get() : mb_dae_rear_.get();
if (!dae) continue;
mb::PrescribedCornerMotion mot;
mot.travel_z = state_.susp_compression[i];
mot.travel_z_dot = state_.susp_velocity[i];
mot.steer_rack_dy = front ? steer_rad * kRackPerRad : 0.0;
if (right) mot.steer_rack_dy = -mot.steer_rack_dy;
mb::WheelLoad wl;
wl.force_world = R * tire_F_[i];
const mb::WheelPose wp = dae->step(mb_state_[i], mot, wl, dt);
const double s = (i == WHEEL_FR || i == WHEEL_RR) ? -1.0 : 1.0;
const double s = right ? -1.0 : 1.0;
gamma_dae_[i] = s * wp.camber_rad;
toe_dae_[i] = s * wp.toe_rad;
// Real linkage travel geometry at the current vertical travel: the wheel-centre
Expand Down
6 changes: 3 additions & 3 deletions docs/VALIDATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,12 @@ version and the new numbers have to land in the same commit.

<!-- VALIDATION-CURRENCY BEGIN -->
```text
tests: 585/585
tests: 587/587
config: cmake --preset validation && cmake --build --preset validation && ctest --preset validation
presets: CMakePresets.json@c98fe5e64c842faaeb06598af46476f3507c18a6
toolchain: cmake 3.31.10
commit: fc897a014b54a541520be5be2c4082c8c509746d
date: 2026-10-30
commit: 69d5da46f6aac8e4a937747c91d42e9caf145833
date: 2026-11-02
excluded: gui_v3_e2e (GUI v3 test group formally deferred -- VDSIM_BUILD_GUI_V3_TESTS=OFF)
excluded: gui_v3_api_smoke (GUI v3 test group formally deferred -- VDSIM_BUILD_GUI_V3_TESTS=OFF)
excluded: closedloop_wallclock_timing (label timing, excluded by the validation test preset: wall-clock S6/S7 verdicts depend on host load -- local low-load evidence in the work order 31 PR description)
Expand Down
6 changes: 3 additions & 3 deletions tests/fixtures/d0_flat_contact_l4_baseline.csv
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ step,t_s,state_pos_x_m,state_pos_y_m,state_pos_z_m,state_q_w,state_q_x,state_q_y
1,0.0050000000000000001,0.075000842055719205,0,0,0.99999999999992606,0,-3.8469516600097953e-07,0,15.000489835976351,0,0,0,-0.00030535708261022289,0,46.875452868993435,46.875452868993435,46.997078463169778,46.997078463169778,0.12258230659828048,0.12258230659828048,0.098067519786607327,0.098067519786607327,-0.00030564731232229827,-0.00030564731232229827,0.00038025295321797691,0.00038025295321797691,0,0,-1.5400227480573836,0,0,-1.5400227480573836,-0,-0,139.52854928508373,0,0,139.52854928508373,0,0,4064.5345604728045,4064.5345604728045,3290.4529395271943,3290.4529395271943,-2.296319937249304e-05,-2.296319937249304e-05,0.0025718297971890382,0.0025718297971890382,0,0,0,0,0,0,0,0,0,-7.69390332001978e-07,0.16863157719149249,0,0
20,0.10000000000000001,1.5022170147817413,0,0,0.99999994458621799,0,-0.00033290773639700058,0,15.049791163504317,0,0,0,-0.012212710858036506,0,47.022456772614568,47.022456772614568,47.406244784091506,47.406244784091506,0.12201397600590154,0.12201397600590154,0.09874876387528729,0.09874876387528729,-0.012395339232331271,-0.012395339232331271,0.014479770152611439,0.014479770152611439,0,0,-11.411368349790227,0.40931735055312296,0,-11.411368349790227,-0.40931735055312296,-0,439.63300236674439,0,0,439.63300236674439,0,0,3995.5658852032761,3995.5658852032761,3359.4216147967227,3359.4216147967227,-0.00017309191190712653,-0.00017309191190712653,0.0079872980629114108,0.0079872980629114108,-9.8529845104622846e-06,9.8529845104622846e-06,0,0,0,0,0,0,0,-0.00066581548509245258,0.57096101560810031,0,0
100,0.5,7.5678138295115049,0,0,0.99999929859325298,0,-0.001184404070444386,0,15.278192230370577,0,0,0,0.0024769054254307581,0,47.736081097014662,47.736081097014662,48.125785886544179,48.125785886544179,0.11960865552329332,0.11960865552329332,0.10079354681577557,0.10079354681577557,0.0031884458753672134,0.0031884458753672134,-0.0027972207774733695,-0.0027972207774733695,0,0,-11.41897735425802,5.1425122879128127,0,-11.41897735425802,-5.1425122879128127,-0,439.73456835817711,0,0,439.73456835817711,0,0,3995.5437621611195,3995.5437621611195,3359.4437378388793,3359.4437378388793,-0.00017319869166564577,-0.00017319869166564577,0.0079891161720930248,0.0079891161720930248,-0.00012379000617606902,0.00012379000617606902,0,0,0,0,0,0,0,-0.0023688086947215984,0.57109081567425612,0,0
200,1,15.235744012369338,0.32504193164313022,0,0.99844009671353695,0.020551245310336818,0.00050946083423899493,0.051911078206058642,15.426441614431715,-0.15681686481537321,0,0.03419453967165912,-0.0011298234413202803,0.26999012395235572,47.407940753988477,48.85140499505836,47.987193150050636,49.091262219198882,0.093597775872696062,0.14909221340663417,0.071698289439124735,0.12719272697306283,-0.02551155315505451,0.021679905042366408,-0.022631653574999019,0.024559804622422052,0,0,-191.63562806687256,2100.420790275276,0,-37.960031370697536,1067.4333787015578,0,336.7667166197113,844.31154036015619,0,338.38117476245009,1592.2695665244128,0,2982.8015717899639,5095.1852934245671,2259.8022065754321,4372.1859282100349,-8.5191744723423857e-05,-5.7730205581704137e-05,0.0091148595465764693,0.004702053945345344,-0.078011719601018922,-0.020311797920368507,-0.036902126734384352,-0.035915312447611758,0,0,0,0,0.041102866169148253,-0.0011163425877231045,0.2970504098996537,3.7350615738686321,0
300,1.5,22.878848395693332,1.5378920219833456,0,0.99272128667030057,0.023651104844006354,0.0022515169050280927,0.11806778943872558,15.545574488839133,-0.22557939030474722,0,0.00027365873951771895,3.074700310741997e-05,0.26224469553479518,47.770780697549775,49.198741990545528,48.403959577635682,49.442783159806481,0.088862078298180186,0.15365706478971594,0.066995113702774986,0.13179010019431076,-1.0992165787572111e-05,0.0004411110313866229,-0.00012153090935185865,0.00033057228782232484,0,0,-198.49763992253122,2145.7097096153375,0,-43.261319387505388,1293.8762513463619,0,338.96325133413421,879.60291269602385,0,339.98106917498654,1768.2738250619045,0,2891.6246644592816,5188.1425708841398,2166.8449291158586,4463.3628355407172,-9.7793681557438556e-05,-5.2994676012562844e-05,0.0095769167883368693,0.0046274223399719143,-0.084272926612623963,-0.024260336997927883,-0.040320524098892106,-0.039280929590051437,0,0,0,0,0.047507471603900897,-0.0011146100463822024,0.29146280500573257,4.0582686705757203,0
400,2,30.264560037560177,3.5358246099017232,0,0.98785293705686517,0.011937465068114439,0.0039696139150467331,0.1548816123406461,15.053798120279334,-0.13498435105277409,0,-0.025894496353199271,-0.0055457619416762818,0.10893381482530461,46.469352587517683,47.082778990796228,46.399262166830532,47.039418650465883,0.11072363603398558,0.1449973970590103,0.076194760972824627,0.11046852199784933,0.010399935098624295,-0.024646588465600354,0.023783856407157088,-0.011262667157067547,0,0,-409.32767627448277,1186.3409447030556,0,-374.05022556250435,432.2157254556472,0,-341.69552385095841,528.31939809838332,0,-340.32107200729052,744.82172433946653,0,3694.7979071871769,4787.2486162203013,2567.7388837796971,3660.1895928128215,-0.0061228822510572024,-0.0047003858953748243,-0.0081239534995432815,-0.0056550814711737261,-0.031809729978274803,-0.0087567591236522094,-0.019930396278595833,-0.019708156198444932,0,0,0,0,0.024817320854008163,0.0041450137252345056,-0.97694755432621694,1.9287146552936572,0
200,1,15.221931336194984,0.43271712890769587,0,0.99722948109587606,0.027379592026988031,0.0014499438898444821,0.069149241763029431,15.397454971695264,-0.20599125164785642,0,0.047078830063626287,-0.0011566622299149991,0.36608164837317347,47.090958585449854,48.95705540224094,47.751570374305722,49.219261637025618,0.084610866690610131,0.15862553010380664,0.062183391206719632,0.13619805461991613,-0.03438738311051226,0.030328886952237094,-0.031400109203410555,0.033316160859338834,0,0,-175.13942689528827,1853.5846221810698,0,-151.71676090731557,2466.2130742922295,0,339.90425819741228,932.86433112109307,0,341.9805851302076,2252.3184352671201,0,2634.2656511673576,5462.8431240120663,1892.1443759879328,4720.7218488326407,-3.4722023103223291e-05,-3.3207832956878638e-05,0.011033731414875217,0.0043998813052848126,-0.077961088882453858,-0.045352215549487651,-0.049920554131191695,-0.048117006828480476,0,0,0,0,0.054835496644645966,-0.00089470259048626669,0.23670636641105369,5.0016267699112467,0
300,1.5,22.757658664328311,2.0476759990780478,0,0.98669194330963539,0.0319740640792383,0.0047279898574980684,0.15935593602379419,15.460108524160098,-0.32078144978403073,0,0.0015275166924602459,3.3759963968526353e-05,0.35943058751417173,47.258357857220275,49.118125586982913,48.020221198668416,49.395709142696397,0.077485848458137413,0.16563894290917999,0.055014972938381181,0.14316806738942375,-0.00093680895886937715,0.0014137585044854662,-0.0010601125640585702,0.0012904548992962522,0,0,-182.8003796455458,1893.3828315636194,0,-168.72955457460853,2842.7969697547896,0,344.3279128022341,957.25307763062733,0,346.12432810262527,2595.050729423237,0,2486.8477909075255,5613.6864792254473,1741.3010207745513,4868.1397090924738,-5.569592088955776e-05,-2.1492925537586896e-05,0.012180643097867974,0.0043180007554293022,-0.087766448294284594,-0.051561695271352161,-0.056582459629133997,-0.054583602079212472,0,0,0,0,0.064649017222341829,-0.00086037492492559598,0.22596064916727768,5.5255854808692861,0
400,2,29.880526331057563,4.7032598191138169,0,0.97778470871401391,0.016004842240760018,0.0055585165655862544,0.20892585125706556,14.94830620867531,-0.1855914156648083,0,-0.038734388445863667,-0.0053317288401120207,0.14319035090425317,46.040267210597335,46.839833837108579,45.960410357178198,46.807831247945678,0.1046397467375508,0.15113825962551786,0.070028932902574073,0.11652744579054114,0.019341296643186207,-0.032883094624630127,0.032159050530968916,-0.020065340736847383,0,0,-413.07922717164979,1219.5292183899651,0,-386.20552140426918,941.38133236288627,0,-341.40942164041496,659.03940117601223,0,-339.04863114239112,1048.2835973011709,0,3511.7179115848912,4973.371864196225,2381.6156358037733,3843.2695884151071,-0.0064470697606759785,-0.0045147140631560919,-0.0087618396256799545,-0.0053636543891800951,-0.034548879362442234,-0.018444191154328229,-0.026977879854738505,-0.026580466011402525,0,0,0,0,0.033627847242005508,0.0041824266167956184,-0.98653096582889477,2.5802048907011241,0
44 changes: 44 additions & 0 deletions tests/integration/test_fourteen_dof.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,50 @@ TEST(FourteenDOF, L4KinematicLevelAndAttach) {
EXPECT_GT(std::abs(dyn->state().velocity.x()), 5.0);
}

TEST(FourteenDOF, L4MirroredRackChangesFrontSlipInSameDirection) {
const std::string kin = std::string(VDSIM_SOURCE_DIR)
+ "/configs/parts/susp_kinematics/kin/mp_front_sedan.yaml";
auto slip_for = [&](double steer, bool attach) {
auto dyn = vdsim::create_fourteen_dof_kinematic();
vdsim::VehicleParams vp;
vp.aero_drag_coeff = 0.0;
vp.camber_per_roll = 0.0;
vdsim::TireParams tp;
tp.lugre.enabled = false;
vdsim::SolverParams sp;
dyn->initialize(vp, tp, sp);
if (attach) {
auto topo = vdsim::mb::SuspensionTopology::from_yaml(kin);
EXPECT_TRUE(vdsim::mb::attach_topology_front(*dyn, topo));
}
dyn->reset(init_state(15.0, vp.wheel_radius_nominal));
vdsim::CmdL4 cmd;
cmd.steer_angle_wheel = steer;
dyn->step(cmd, flat_contacts(), 1e-6);
return dyn->wheel_slip_angle();
};

const auto attached_zero = slip_for(0.0, true);
const auto plain_zero = slip_for(0.0, false);
for (double steer : {0.06, -0.06}) {
const auto attached = slip_for(steer, true);
const auto plain = slip_for(steer, false);
const double kinematic_l =
(attached[vdsim::WHEEL_FL] - attached_zero[vdsim::WHEEL_FL])
- (plain[vdsim::WHEEL_FL] - plain_zero[vdsim::WHEEL_FL]);
const double kinematic_r =
(attached[vdsim::WHEEL_FR] - attached_zero[vdsim::WHEEL_FR])
- (plain[vdsim::WHEEL_FR] - plain_zero[vdsim::WHEEL_FR]);
EXPECT_GT(std::abs(kinematic_l), 1e-5);
EXPECT_GT(std::abs(kinematic_r), 1e-5);
EXPECT_GT(kinematic_l * kinematic_r, 0.0);
}

const auto attached_zero_again = slip_for(0.0, true);
EXPECT_EQ(attached_zero[vdsim::WHEEL_FL], attached_zero_again[vdsim::WHEEL_FL]);
EXPECT_EQ(attached_zero[vdsim::WHEEL_FR], attached_zero_again[vdsim::WHEEL_FR]);
}

TEST(FourteenDOF, StaticSuspensionPopulatedAtRest) {
vdsim::VehicleParams vp; vp.aero_drag_coeff = 0.0;
vdsim::TireParams tp; vdsim::SolverParams sp;
Expand Down
35 changes: 35 additions & 0 deletions tests/integration/test_l5_driving.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,41 @@ TEST(L5StrutDae, AttachReportsEnabled) {
EXPECT_TRUE(vdsim::free_3d_mb_dynamics_enabled(*h.dyn, 1));
}

TEST(L5StrutDae, MirroredRackSteersFrontWheelsInSameDirection) {
auto toe_for = [](double steer) {
L5StrutSetup h;
attach_corner_dae(*h.dyn);
h.reset_level(0.0);
vdsim::CmdL4 cmd;
cmd.steer_angle_wheel = steer;
h.run(cmd, 1, 0.001);
return vdsim::free_3d_wheel_toe(*h.dyn);
};

const auto zero = toe_for(0.0);
const auto pos = toe_for(0.06);
const auto neg = toe_for(-0.06);
const double pos_l = pos[vdsim::WHEEL_FL] - zero[vdsim::WHEEL_FL];
const double pos_r = pos[vdsim::WHEEL_FR] - zero[vdsim::WHEEL_FR];
const double neg_l = neg[vdsim::WHEEL_FL] - zero[vdsim::WHEEL_FL];
const double neg_r = neg[vdsim::WHEEL_FR] - zero[vdsim::WHEEL_FR];

EXPECT_GT(pos_l, 1e-5);
EXPECT_GT(pos_r, 1e-5);
EXPECT_LT(neg_l, -1e-5);
EXPECT_LT(neg_r, -1e-5);
EXPECT_EQ(zero[vdsim::WHEEL_FL], zero[vdsim::WHEEL_FR]);
const auto camber = [&] {
L5StrutSetup h;
attach_corner_dae(*h.dyn);
h.reset_level(0.0);
vdsim::CmdL4 cmd;
h.run(cmd, 1, 0.001);
return vdsim::free_3d_wheel_camber(*h.dyn);
}();
EXPECT_EQ(camber[vdsim::WHEEL_FL], -camber[vdsim::WHEEL_FR]);
}

TEST(L5StrutDae, SettleStillHoldsWeight) {
L5StrutSetup h;
attach_corner_dae(*h.dyn);
Expand Down
Loading