@@ -2307,12 +2307,15 @@ namespace car
23072307
23082308 float Simulation::read_driveline_gearbox_speed () const
23092309 {
2310- if (!has_physical_driveline ())
2310+ if (!has_physical_driveline () || !body )
23112311 {
23122312 return gearbox_input_angular_velocity;
23132313 }
23142314 PxVec3 axis = multibody.driveline .gearbox_output ->getGlobalPose ().q .rotate (PxVec3 (1 .0f , 0 .0f , 0 .0f ));
2315- return multibody.driveline .gearbox_output ->getAngularVelocity ().dot (axis);
2315+ // spin is relative to the chassis, the writers set chassis angular velocity plus axis spin
2316+ // so reading the absolute value back fed the chassis roll rate into the gearbox every substep
2317+ PxVec3 spin = multibody.driveline .gearbox_output ->getAngularVelocity () - body->getAngularVelocity ();
2318+ return spin.dot (axis);
23162319 }
23172320
23182321
@@ -3176,7 +3179,7 @@ namespace car
31763179
31773180 if (shift_cooldown > 0 .0f )
31783181 {
3179- shift_cooldown -= dt ;
3182+ shift_cooldown = PxMax (shift_cooldown - dt, 0 . 0f ) ;
31803183 }
31813184
31823185 if (is_shifting)
@@ -3438,6 +3441,7 @@ namespace car
34383441 // pedal closed means coast, blip may still raise revs for a matched downshift
34393442 bool coasting = drive_input <= spec.input_deadzone ;
34403443 float idle_angular_velocity = spec.engine_idle_rpm * PxPi * 2 .0f / 60 .0f ;
3444+ float max_angular_velocity = PxMax (spec.engine_max_rpm * PxPi * 2 .0f / 60 .0f , idle_angular_velocity);
34413445 float clutch_capacity = PxMax (spec.clutch_max_torque , 10 .0f );
34423446 float clutch_damping = clutch_capacity / 12 .0f ;
34433447 float electric_target = is_in_forward_gear () ? get_electric_motor_torque (engine_rpm, input.throttle ) * assisted_actuators.engine_torque_scale : 0 .0f ;
@@ -3454,7 +3458,12 @@ namespace car
34543458 axle_drive_torque = 0 .0f ;
34553459 engine_brake_torque = 0 .0f ;
34563460
3457- int substep_count = PxClamp (static_cast <int >(ceilf (dt / 0 .0025f )), 1 , 16 );
3461+ // the clutch damper couples two small inertias, so the substep has to resolve it or the slip
3462+ // rings, damping times substep times the coupling compliance must stay at or under one
3463+ float coupling_compliance = 1 .0f / engine_inertia + 1 .0f / driveline_inertia;
3464+ float clutch_substep = 1 .0f / PxMax (clutch_damping * coupling_compliance, 1e-6f );
3465+ float target_substep = PxMin (0 .0025f , clutch_substep);
3466+ int substep_count = PxClamp (static_cast <int >(ceilf (dt / target_substep)), 1 , 32 );
34583467 float substep = dt / static_cast <float >(substep_count);
34593468 float accumulated_axle_torque = 0 .0f ;
34603469 float accumulated_powertrain_reaction = 0 .0f ;
@@ -3474,6 +3483,10 @@ namespace car
34743483 accumulated_engine_torque += combustion_torque + idle_torque;
34753484 float clutch_slip = engine_angular_velocity - gearbox_input_angular_velocity;
34763485 float clutch_torque = PxClamp (clutch_slip * clutch_damping, -clutch_capacity * clutch, clutch_capacity * clutch);
3486+ // a damper cannot pull the two speeds past each other in one substep, without this cap the
3487+ // explicit integration flipped the slip sign every substep and dragged the engine to a stall
3488+ float non_overshoot_torque = fabsf (clutch_slip) / PxMax (substep * coupling_compliance, 1e-6f );
3489+ clutch_torque = PxClamp (clutch_torque, -non_overshoot_torque, non_overshoot_torque);
34773490 float shaft_torque = 0 .0f ;
34783491 float shaft_speed_difference = 0 .0f ;
34793492 // open driveline during shifts or with clutch out, shaft must not keep shoving the axle
@@ -3557,7 +3570,9 @@ namespace car
35573570 float friction_torque = spec.engine_friction * engine_angular_velocity + pumping_torque;
35583571 float engine_acceleration = (combustion_torque + idle_torque - friction_torque - clutch_torque) / engine_inertia;
35593572 float previous_engine_angular_velocity = engine_angular_velocity;
3560- engine_angular_velocity = PxClamp (engine_angular_velocity + engine_acceleration * substep, 0 .0f , spec.engine_max_rpm * PxPi * 4 .0f / 60 .0f );
3573+ // idle is the floor, the torque curve is only defined at or above it and there is no
3574+ // stall or restart model, so a dragged down engine could never come back
3575+ engine_angular_velocity = PxClamp (engine_angular_velocity + engine_acceleration * substep, idle_angular_velocity, max_angular_velocity);
35613576 engine_acceleration = (engine_angular_velocity - previous_engine_angular_velocity) / substep;
35623577
35633578 float efficiency = PxClamp (spec.drivetrain_efficiency , 0 .1f , 1 .0f );
@@ -3708,7 +3723,7 @@ namespace car
37083723
37093724 if (downshift_blip_timer > 0 .0f )
37103725 {
3711- downshift_blip_timer -= dt ;
3726+ downshift_blip_timer = PxMax (downshift_blip_timer - dt, 0 . 0f ) ;
37123727 }
37133728
37143729 if (is_shifting)
0 commit comments