I can add a little more detail to asdasdasdasdasdf’s comment.

The suspension has travel limits but sometimes we need to compress the wheel beyond the travel limit in order to place it on the ground plane. That can happen if the wheel drives over a kerb or a sharp incline. If we push the wheel beyond the suspension limit it will start to visibly penetrate the car. However, if we place the wheel at the suspension limit it will visibly penetrate the ground. We need some extra code to solve this problem.

If the wheel needs to move P distance along the suspension travel direction to place it on the ground but the suspension limit is L (P >L) then the wheel is placed at L and the suspension spring reacts to a suspension compression of L. The remainder (P-L) is passed to a hard constraint. The hard constraint works on the rigid body at the suspension point and pushes it upwards along the suspension travel direction to resolve the remainder (P-L) at the next simulate call. The car gets an impulse at the suspension point that is just large enough to push the wheel out of the ground and maintain the wheel at the suspension limit.

The remaining constraints are the sticky tire constraints along the lateral and longitudinal direction of each tire. The problem is that at very small slip values the slip tends to oscillate around zero. It is actually a computationally difficult problem to bring the car smoothly to rest. This can be solved by reducing the timestep but that is a computationally expensive solution. PhysX vehicles instead use a velocity constraint. The basic idea is that the code records the lateral and longitudinal speeds at each tire. If the longitudinal speed is less than a small threshold speed and has maintained that condition for a threshold time then the constraint kicks in for that tire. The constraint attempts to enforce a velocity constraint on the rigid body along the longitudinal tire direction. The target velocity reduces each frame and asymptotically approaches zero. The same process is repeated for the lateral speed of each tire. I can’t remember the exact details but I think the logic is that the lateral constraints always start after the longitudinal constraints. The sticky tire constraints are broken as soon as the tire is driven by an engine torque.

PhysX allows 12 1d constraints for each custom joint. That worked out great for 4-wheeled cars: 4 suspension limit constraints, 4 lateral velocity constraints, 4 longitudinal velocity constraints. Most of the time zero constraints are active but a 4-wheeled car could theoretically make all 12 active. In practice, I can’t imagine a case where we need a sticky tire constraint and a suspension limit constraint but let’s ignore that for the moment. You might have noticed that the code in PxVehicleUpdate.cpp breaks vehicles up into blocks of 4 wheels and handles 4 wheels at a time. One of the reasons for that is that each block of 4 wheels needs to grab a physx constraint that is made up of 12 1d constraints.

I hope this helps.