Re: Patch for wheel spin velocity traction

David Savinkoff <[email protected]> Tue, 5 Apr 2016 03:05:06 -0600 (MDT)
Newsgroups gmane.games.torcs.general
Message-ID <1347150810.29006148.1459847106439.JavaMail.zimbra@mailid.telus.net>
car->carElt->_wheelSlipAccel(index) = slip_magnitude;
in wheel.c seems to work best. Now you can feel real
traction interaction of the tire with the road, right through
the suspension and inertia of the vehicle.

----- David Savinkoff wrote:
> This patch has more suspension improvements lifted from
> TORCS on Sourceforge, and further tweaks to my code.
> 
> ----- David Savinkoff wrote:
> > Hi,
> > torcs-1.3.6/src/modules/graphic/ssggraph/grskidmarks.cpp:
> > 
> > if (cur_clr[3] > 0.06f) {
> > // 0.06 works better than 0.1 // something here improves traction ?!
> > 
> > ----- David Savinkoff wrote:
> > Hi,
> > 
> > This patch applies the latest change to wheel.cpp in
> > TORCS on Sourcforge:
> > $Id: wheel.cpp,v 1.26.2.6 2016/03/06 20:59:31 berniw Exp $
> > 
> > This patch (see patch) also removes a discontinuity by tanh() in
> > modules/graphic/ssggraph/grskidmarks.cpp
> > (The Magic Formula in wheel.cpp should determine traction)
> > 
> > Good to see torqs-1.3.7 on the way.
> > 
> > ----- David Savinkoff wrote:
> > Hi,
> > 
> > This patch removes an un-needed tanh() from
> > modules/graphic/ssggraph/grskidmarks.cpp
> > and re-arranges some of my changes in wheel.cpp
> > ( the tanh() trick was used to range limit input: -1 to 1 )
> > 
> > This patch is the most physically correct,
> > and the best performing one yet.
> > 
> > Please apply this patch.
> > 
> > ----- David Savinkoff wrote:
> > Hi,
> > 
> > This patch fixes a performance issue without compromise.
> > Smaller, Faster, and Better sound and driving performance.
> > You can hear which tire is squealing as you drift past
> > another car. Yahoo!
> > 
> ----- David Savinkoff wrote:
> > OK,
> > 
> > This patch goes beyond traction; it includes 2 bug fixes
> > from Speed Dreams.
> > 
> > Yes, two serious physics impacting bugs.
> > 
> > Now you can get twice the realism by driving to the
> > track in one car, and racing at the track in another.
> > 
> > ----- David Savinkoff wrote:
> > Hi,
> > This patch implements rolling resistance correctly along
> > with some small changes. (wheel.cpp car.cpp)
> > 
> > Massive improvement. The TORCS simuv2 reference
> > measure 'is' about to show all car sims 'how it is done'.
> >
> > ----- David Savinkoff wrote:
> > Hi,
> > 
> > Yet another small improvement. Note that if some of these
> > improvements appear odd, they are indicating problems
> > hidden elsewhere.
> > 
> > ----- David Savinkoff wrote:
> > Hi,
> > This patch will probably be the last I make for
> > wheel.cpp because I've meticulously examined and
> > tested the code here repeatedly with results that have
> > converged to perfection.
> > 
> > Please apply this patch.
> > 
> > ----- David Savinkoff wrote:
> > > This patch removes legacy duct tape which was used as a
> > > work-around for a previously nonexistent friction circle.
> > > 
> > > There is another piece of duct tape which impedes the car
> > > from accelerating forward while allowing unimpeded sideways
> > > acceleration when drifting. I'll remove that when I find it.
> >
> > This problem seems to be diminished as TORCS is made more
> > correct.
> > 
> > > Note that RELAXATION2 is a low-pass Infinite Impulse Response
> > > filter of the form: f(s) = (1/as) / (b+1/as) where s is in the s-domain,
> > > 'a' is a spring-constant, and 'b' is a friction constant
> > > mechanically acting on the rotation of the wheel. This will
> > > certainly affect the physics of TORCS.
> > 
>  ----- David Savinkoff wrote:
> > Hi Everybody,
> > 
> > This patch makes TORCS the best simulator wherever
> > 'The Rubber meets the Road' is concerned. Try it.
> > 
> > ----- David Savinkoff wrote:
> > > Hi,
> > > 
> > > In my last patch I had the following code:
> > > slip_magnitude = 0.3f + sqrt( MAX(MAX((vn*vn + vt*vt)
> > > 
> > > Where (v2) should be equal to (vn*vn + vt*vt) but is not,
> > > because of lack of precision of the float data type.
> > > 
> > > Here I use (v2) for velocity squared because the car drives
> > > noticeably better, and (v2) is obviously more accurate.
> > > 
> > slip_magnitude = 0.3f + sqrt( MAX(MAX((v2)
> > > 
> > > BTW is there somewhere I can find recent TORCS source code
> > > changes so that I can test and experiment?
> > > 
> > > Sincerely,
> > > David Savinkoff
> > 
> > Hi,
> > 
> > Here is another patch for floating point improvements.
> > 
> > I used sqrtf() where it seemed to make a speed improvement
> > on my slow computer.
> > 
> > I used (double) to get more accuracy for CosA and SinA
> > 
> > It is obvious that (float) is not sufficient in some
> > circumstances, and that (double) is slower in others.
> > 
> > I hope these improvements in wheel.cpp help with making
> > other problems more characterizable.
> > 
> > Sincerely,
> > David Savinkoff
> > 
> > ps.
> > 
> > Speed Dreams should incorporate this patch too.
> > Note that this patch will give you deja vu a few times
> > per lap.

------------------------------------------------------------------------------

_______________________________________________
Torcs-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/torcs-users
torcs-1.3.6.2016apr05.diff (text/x-patch, 13.5 KB)
--- torcs-1.3.6/src/modules/graphic/ssggraph/CarSoundData.cpp	2014-02-10 03:16:18.000000000 -0800
+++ torcs-1.3.6/src/modules/graphic/ssggraph/CarSoundData.cpp	2016-03-05 17:29:31.000000000 -0800
@@ -315,29 +315,30 @@
 
     }
 
+// Calculate road-tire contact noise positions with an efficient formula.
+// note that sin(az) is nearly equal to az [in radians].
+// note that cos(az) is close to 1.0 for moderate yaw angles.
+// note that the contact patch is beneath GC (approx -0.3 metres).
+    tdble az = car->_yaw;
     for (i = 0; i<4; i++) {
-        tdble az = car->_yaw;
-        tdble Sinz = sin(az);
-        tdble Cosz = cos(az);
-                
         tdble x = car->priv.wheel[i].relPos.x;
         tdble y = car->priv.wheel[i].relPos.y;
                 
-        tdble dx = x * Cosz - y * Sinz;
-        tdble dy = x * Sinz + y * Cosz;
+        tdble dx = x - y*az; // x*cos(az) - y*sin(az)
+        tdble dy = x*az + y;
                 
         tdble dux = -car->_yaw_rate * y;
         tdble duy = car->_yaw_rate * x;
                 
-        dux = dux * Cosz - duy * Sinz;
-        duy = dux * Sinz + duy * Cosz;
+        dux = dux - duy*az;
+        duy = dux*az + duy;
                 
         wheel[i].u[0] = car->pub.DynGCg.vel.x + dux;
         wheel[i].u[1] = car->pub.DynGCg.vel.y + duy;
         wheel[i].u[2] = car->pub.DynGCg.vel.z;
         wheel[i].p[0] = car->pub.DynGCg.pos.x + dx;
         wheel[i].p[1] = car->pub.DynGCg.pos.y + dy;
-        wheel[i].p[2] = car->pub.DynGCg.pos.z;
+        wheel[i].p[2] = car->pub.DynGCg.pos.z - 0.3f;
     }
 }
 
--- torcs-1.3.6/src/modules/graphic/ssggraph/grskidmarks.cpp	2014-02-10 03:09:36.000000000 -0800
+++ torcs-1.3.6/src/modules/graphic/ssggraph/grskidmarks.cpp	2016-03-22 14:24:34.000000000 -0700
@@ -199,11 +199,7 @@
 			}
 		}
 
-		if (car->_skid[i] > 0.1f) {
-			cur_clr[3] = tanh(skid_sensitivity*car->_skid[i]);
-		} else {
-			cur_clr[3] = 0.0f;
-		}
+		cur_clr[3] = skid_sensitivity*car->_skid[i]; // linear (tanh removed, see wheel.cpp)
 
 		for (int c = 0; c < 3; c++) {
 			tdble tmp = grCarInfo[car->index].skidmarks->strips[i].smooth_colour[c];
@@ -216,7 +212,7 @@
 		}
 
 		if (car->pub.speed > 1.0f) {
-	    	if (cur_clr[3] > 0.1f) {
+	    	if (cur_clr[3] > 0.1f) { // 0.06 works better than 0.1 // something here improves traction ?!
                 
 				basevtx = new ssgVertexArray(4 * 2 + 1);
 				tdble sling_left = 0.0f;
--- torcs-1.3.6/src/modules/simu/simuv2/axle.cpp	2013-08-29 07:21:44.000000000 -0700
+++ torcs-1.3.6/src/modules/simu/simuv2/axle.cpp	2016-03-20 17:59:40.000000000 -0700
@@ -2,9 +2,9 @@
 
     file                 : axle.cpp
     created              : Sun Mar 19 00:05:09 CET 2000
-    copyright            : (C) 2000-2013 by Eric Espie, Bernhard Wymann
+    copyright            : (C) 2000-2016 by Eric Espie, Bernhard Wymann
     email                : [email protected]
-    version              : $Id: axle.cpp,v 1.8.2.5 2013/08/29 14:21:44 berniw Exp $
+    version              : $Id: axle.cpp,v 1.8.2.6 2016/03/19 13:28:35 berniw Exp $
 
  ***************************************************************************/
 
@@ -82,7 +82,7 @@
 	axle->thirdSusp.v = (vl + vr)/2.0f;
 	SimSuspUpdate(&axle->thirdSusp);
 	tdble fthird = 0.0f;
-	if (axle->thirdSusp.x < axle->thirdSusp.spring.xMax) {
+	if (axle->thirdSusp.x < axle->thirdSusp.spring.xMax && axle->thirdSusp.force > 0.0f) {
 		fthird = axle->thirdSusp.force/2.0f;
 	}
 
--- torcs-1.3.6/src/modules/simu/simuv2/car.cpp	2014-02-10 02:06:30.000000000 -0800
+++ torcs-1.3.6/src/modules/simu/simuv2/car.cpp	2016-02-19 17:53:01.000000000 -0800
@@ -146,7 +146,6 @@
 	tdble	m, w, minv;
 	tdble	SinTheta;
 	tdble	Cosz, Sinz;
-	tdble	v, R, Rv, Rm, Rx, Ry;
 	
 	Cosz = car->Cosz = cos(car->DynGCg.pos.az);
 	Sinz = car->Sinz = sin(car->DynGCg.pos.az);
@@ -199,41 +198,18 @@
 		F.M.y -= car->aero.lift[i] * (car->axle[i].xpos - car->statGC.x);
 	}
 	
-	/* Rolling Resistance */
-	v = sqrt(car->DynGCg.vel.x * car->DynGCg.vel.x + car->DynGCg.vel.y * car->DynGCg.vel.y);
-	R = 0;
-	for (i = 0; i < 4; i++) {
-		R += car->wheel[i].rollRes;
-	}
-	if (v > 0.00001) {
-		Rv = R / v;
-		if ((Rv * minv * SimDeltaTime) > v) {
-			Rv = v * m / SimDeltaTime;
-		}
-	} else {
-		Rv = 0;
-	}
-	Rx = Rv * car->DynGCg.vel.x;
-	Ry = Rv * car->DynGCg.vel.y;
-	
-	if ((R * car->wheelbase / 2.0 * car->Iinv.z) > fabs(car->DynGCg.vel.az)) {
-		Rm = car->DynGCg.vel.az / car->Iinv.z;
-	} else {
-		Rm = SIGN(car->DynGCg.vel.az) * R * car->wheelbase / 2.0;
-	}
-	
 	/* compute accelerations */
 	car->DynGC.acc.x = F.F.x * minv;
 	car->DynGC.acc.y = F.F.y * minv;
 	car->DynGC.acc.z = F.F.z * minv;
 	
-	car->DynGCg.acc.x = (F.F.x * Cosz - F.F.y * Sinz - Rx) * minv;
-	car->DynGCg.acc.y = (F.F.x * Sinz + F.F.y * Cosz - Ry) * minv;
+	car->DynGCg.acc.x = (F.F.x * Cosz - F.F.y * Sinz) * minv;
+	car->DynGCg.acc.y = (F.F.x * Sinz + F.F.y * Cosz) * minv;
 	car->DynGCg.acc.z = car->DynGC.acc.z;
 	
 	car->DynGCg.acc.ax = car->DynGC.acc.ax = F.M.x * car->Iinv.x;
 	car->DynGCg.acc.ay = car->DynGC.acc.ay = F.M.y * car->Iinv.y;
-	car->DynGCg.acc.az = car->DynGC.acc.az = (F.M.z - Rm) * car->Iinv.z;
+	car->DynGCg.acc.az = car->DynGC.acc.az = F.M.z * car->Iinv.z;
 }
 
 static void
--- torcs-1.3.6/src/modules/simu/simuv2/collide.cpp	2014-04-12 06:55:29.000000000 -0700
+++ torcs-1.3.6/src/modules/simu/simuv2/collide.cpp	2016-02-26 11:36:54.224354425 -0800
@@ -29,6 +29,7 @@
 	tdble dotProd;
 	tWheel *wheel;
 	const float CRASH_THRESHOLD = -5.0f;
+	tdble dz = 0.0f;
 
 	if (car->carElt->_state & RM_CAR_STATE_NO_SIMU) {
 		return;
@@ -36,8 +37,9 @@
 
 	for (i = 0; i < 4; i++) {
 		wheel = &(car->wheel[i]);
-		if (wheel->state & SIM_SUSP_COMP) {
-			car->DynGCg.pos.z += wheel->susp.spring.packers - wheel->rideHeight;
+		if ( (wheel->state & SIM_SUSP_COMP)&&(!(wheel->state & SIM_WH_ONAIR)) ) {
+			dz = MAX(dz, wheel->susp.spring.packers - wheel->rideHeight);
+			wheel->rideHeight = wheel->susp.spring.packers;
 			RtTrackSurfaceNormalL(&(wheel->trkPos), &normal);
 			dotProd = (car->DynGCg.vel.x * normal.x + car->DynGCg.vel.y * normal.y + car->DynGCg.vel.z * normal.z) * wheel->trkPos.seg->surface->kRebound;
 			if (dotProd < 0.0f) {
@@ -54,6 +56,7 @@
 			}
 		}
 	}
+	car->DynGCg.pos.z += dz; // elevate car when it has slightly impacted into ground. (SD r6312)
 }
 
 const tdble BorderFriction = 0.0f;
--- torcs-1.3.6/src/modules/simu/simuv2/susp.cpp	2014-02-09 23:53:35.000000000 -0800
+++ torcs-1.3.6/src/modules/simu/simuv2/susp.cpp	2016-03-20 18:49:32.000000000 -0700
@@ -2,9 +2,9 @@
 
     file                 : susp.cpp
     created              : Sun Mar 19 00:08:41 CET 2000
-    copyright            : (C) 2000 by Eric Espie
+    copyright            : (C) 2000-2016 by Eric Espie, Bernhard Wymann
     email                : [email protected]
-    version              : $Id: susp.cpp,v 1.10.2.7 2014/02/10 07:53:35 berniw Exp $
+    version              : $Id: susp.cpp,v 1.10.2.10 2016/03/19 14:47:05 berniw Exp $
 
  ***************************************************************************/
 
@@ -85,6 +85,7 @@
 	/* K is < 0 */
 	f = spring->K * (susp->x - spring->x0) + spring->F0;
 	if (f < 0.0f) {
+		// Compression spring, so the force can never change the sign.
 		f = 0.0f;
 	}
 	
@@ -98,13 +99,17 @@
 {
 	susp->state = 0;
 	if (susp->x < susp->spring.packers) {
+		// Packers are not scaled with susp->spring.bellcrank, because they are a hard
+		// rubber element or plate spring packs directly mounted on the piston of the
+		// damper.
 		susp->x = susp->spring.packers;
 		susp->state = SIM_SUSP_COMP;
 	}
+	
 	susp->x *= susp->spring.bellcrank;
-	if (susp->x > susp->spring.xMax) {
+	if (susp->x >= susp->spring.xMax) { // Tested OK with '>=' (SD r6020)
 		susp->x = susp->spring.xMax;
-		susp->state = SIM_SUSP_EXT;
+		susp->state = SIM_SUSP_EXT; // susp->state updated also
 	}
 }
 
@@ -113,7 +118,17 @@
 
 void SimSuspUpdate(tSuspension *susp)
 {
-	susp->force = (springForce(susp) + damperForce(susp)) * susp->spring.bellcrank;
+	tdble internalForce = springForce(susp) + damperForce(susp);
+	if (internalForce <= 0.0f) {
+		// The damping can at its best cancel out the spring force. Requred because
+		// of numerical integration artefacts with (if the velocity is 0 there is no
+		// damping, so the spring accelarates the system for one time step; if the
+		// damping is set very high this can result in a counterforce larger than the
+		// spring force in the next timestep)
+		susp->force = 0.0f;
+	} else {
+		susp->force = internalForce * susp->spring.bellcrank;
+	}
 }
 
 
--- torcs-1.3.6/src/modules/simu/simuv2/wheel.cpp	2013-08-29 06:01:32.000000000 -0700
+++ torcs-1.3.6/src/modules/simu/simuv2/wheel.cpp	2016-04-05 00:05:55.000000000 -0700
@@ -4,7 +4,7 @@
     created              : Sun Mar 19 00:09:06 CET 2000
     copyright            : (C) 2000-2013 by Eric Espie, Bernhard Wymann
     email                : [email protected]
-    version              : $Id: wheel.cpp,v 1.26.2.5 2013/08/29 13:01:32 berniw Exp $
+    version              : $Id: wheel.cpp,v 1.26.2.6 2016/03/06 20:59:31 berniw Exp $
 
  ***************************************************************************/
 
@@ -174,12 +174,12 @@
 {
 	tWheel *wheel = &(car->wheel[index]);
 	tdble axleFz = wheel->axleFz;
-	tdble vt, v, v2, wrl; // wheel related velocity
+	tdble vt, vn, v, v2, wrl, slip_magnitude; // wheel related velocity
 	tdble Fn, Ft;
 	tdble waz;
-	tdble CosA, SinA;
-	tdble s, sa, sx, sy; // slip vector
-	tdble stmp, F, Bx;
+	double CosA, SinA;
+	tdble s, sx, sy; // slip vector
+	tdble F, Bx;
 	tdble mu;
 	wheel->state = 0;
 
@@ -193,8 +193,8 @@
 		wheel->forces.z = wheel->rel_vel/SimDeltaTime*wheel->mass;
 		wheel->rel_vel = 0.0;
 	} else {
-		wheel->rel_vel -= SimDeltaTime * wheel->susp.force / wheel->mass;
 		wheel->forces.z = axleFz + wheel->susp.force;
+		wheel->rel_vel -= SimDeltaTime * wheel->forces.z / wheel->mass;
 	}
 
 	// update wheel coord, center relative to GC
@@ -215,46 +215,37 @@
 
 	// tangent velocity.
 	vt = wheel->bodyVel.x * CosA + wheel->bodyVel.y * SinA;
+	vn = wheel->bodyVel.y * CosA - wheel->bodyVel.x * SinA;
 	v2 = wheel->bodyVel.x * wheel->bodyVel.x + wheel->bodyVel.y * wheel->bodyVel.y;
-	v = sqrt(v2);
-
-	// slip angle
-	if (v < 0.000001f) {
-		sa = 0.0f;
-	} else {
-		sa = atan2(wheel->bodyVel.y, wheel->bodyVel.x) - waz;
-	}
-	NORM_PI_PI(sa);
+	v = sqrtf(v2);
 
 	wrl = wheel->spinVel * wheel->radius;
+
 	if ((wheel->state & SIM_WH_ONAIR) != 0) {
 		sx = sy = 0.0f;
-	} else if (v < 0.000001f) {
-		sx = wrl;
-		sy = 0.0f;
 	} else {
-		sx = (vt - wrl) / fabs(vt);
-		sy = sin(sa);
+		// Normalize the friction circle to get normalized vector components (sx, sy) while
+		// braking (vt), accelerating (wrl), or wheel counter spin (vt - wrl) for any angle.
+		// Softening factor 0.32 added to slip_magnitude affects low velocities and divide by zero.
+		slip_magnitude = sqrt( MAX(MAX((v2), (vn*vn + wrl*wrl)), (vn*vn + (vt - wrl)*(vt - wrl))) );
+		sx = (vt - wrl) / (0.32f + slip_magnitude);
+		sy = vn / (0.000001f + slip_magnitude);
 	}
 
-	Ft = 0.0f;
-	Fn = 0.0f;
-	s = sqrt(sx*sx+sy*sy);
+	s = sqrtf(sx*sx+sy*sy) + 0.000001f; // add 0.000001 to avoid divide by zero later.
 
 	{
-		// calculate _skid and _reaction for sound.
-		if (v < 2.0f) {
-			car->carElt->_skid[index] = 0.0f;
+		// calculate _skid and _reaction for sound (importantly; affects traction also).
+		if ((v < 0.01f) || (zforce < 0.002f)) {
+			car->carElt->_skid[index] = 0.000001f;
 		} else {
-			car->carElt->_skid[index] =  MIN(1.0f, (s*zforce*0.0002f));
+			car->carElt->_skid[index] = s; // linear (tanh removed in grskidmarks.cpp)
 		}
 	}
 
-	stmp = MIN(s, 1.5f);
-	
 	// MAGIC FORMULA
-	Bx = wheel->mfB * stmp;
-	F = sin(wheel->mfC * atan(Bx * (1.0f - wheel->mfE) + wheel->mfE * atan(Bx))) * (1.0f + stmp * simSkidFactor[car->carElt->_skillLevel]);
+	Bx = wheel->mfB * s;
+	F = sin(wheel->mfC * atan(Bx * (1.0f - wheel->mfE) + wheel->mfE * atan(Bx))) * (1.0f + s * simSkidFactor[car->carElt->_skillLevel]);
 
 	// load sensitivity
 	mu = wheel->mu * (wheel->lfMin + (wheel->lfMax - wheel->lfMin) * exp(wheel->lfK * zforce / wheel->opLoad));
@@ -262,31 +253,28 @@
 	F *= zforce * mu * wheel->trkPos.seg->surface->kFriction * (1.0f + 0.05f * sin(-wheel->staticPos.ax * 18.0f));	/* coeff */
 
 	wheel->rollRes = zforce * wheel->trkPos.seg->surface->kRollRes;
-    car->carElt->priv.wheel[index].rollRes = wheel->rollRes;
 
-	if (s > 0.000001f) {
-		// wheel axis based
-		Ft -= F * sx / s;
-		Fn -= F * sy / s;
-	}
+	// wheel axis based
+	Ft = -(F - wheel->rollRes) * sx/s; // rolling resistance is the rolling vector component only.
+	Fn = -F * sy/s;
 
-	RELAXATION2(Fn, wheel->preFn, 50.0f);
-	RELAXATION2(Ft, wheel->preFt, 50.0f);
+	wheel->rollRes *= fabsf(sx/s); // not used (removed from /src/modules/simu/simuv2/car.cpp)
+	car->carElt->priv.wheel[index].rollRes = wheel->rollRes; // not used in /src/modules/graphic/ssggraph/CarSoundData.cpp
 
 	wheel->relPos.az = waz;
 
 	wheel->forces.x = Ft * CosA - Fn * SinA;
 	wheel->forces.y = Ft * SinA + Fn * CosA;
 	wheel->spinTq = Ft * wheel->radius;
-	wheel->sa = sa;
+	wheel->sa = atan2(sy, sx);
 	wheel->sx = sx;
 
 	wheel->feedBack.spinVel = wheel->spinVel;
 	wheel->feedBack.Tq = wheel->spinTq;
 	wheel->feedBack.brkTq = wheel->brake.Tq;
 
-	car->carElt->_wheelSlipSide(index) = sy*v;
-	car->carElt->_wheelSlipAccel(index) = sx*v;
+	car->carElt->_wheelSlipSide(index) = vn;
+	car->carElt->_wheelSlipAccel(index) = slip_magnitude;
 	car->carElt->_reaction[index] = zforce;
 }
 
@@ -301,8 +289,6 @@
 		wheel = &(car->wheel[i]);
 		wheel->spinVel = wheel->in.spinVel;
 
-		RELAXATION2(wheel->spinVel, wheel->prespinVel, 50.0f);
-
 		wheel->relPos.ay += wheel->spinVel * SimDeltaTime;
 		NORM_PI_PI(wheel->relPos.ay);
 		car->carElt->_wheelSpinVel(i) = wheel->spinVel;