Re: Combined Longitudinal, Lateral, and Yawing Tire Slip Forces

David Savinkoff <[email protected]> Sat, 26 Nov 2016 16:42:28 -0700 (MST)
Newsgroups gmane.games.torcs.general
Message-ID <1027749257.213522372.1480203748703.JavaMail.zimbra@mailid.telus.net>
Hi,
wheelSlipAccel was made better with:
wheelSlipAccel(index) = vt*(1.0f-sx); // wheel tangent velocity times traction
This is the best, and it makes sense.

----- David Savinkoff wrote:
> Hi,
> When an improvement is made, further improvements
> can be characterized. Here is a small improvement for
> SlipAccel in wheel.c
> 
> Drive this one, it is good.
> 
> Sincerely,
> David Savinkoff
> 
> ps.
> This one has a milestone name:
> torcs-1.3.7.contact.patch
> 
> apply this patch to torcs-1.3.7 sources with:
> patch -p0 < torcs-1.3.7.contact.patch
> from outside the torcs-1.3.7 directory
> or
> patch -p1 < torcs-1.3.7.contact.patch
> from within,
> then compile etc.
> 
> ----- David Savinkoff wrote:
> > Combined Longitudinal, Lateral, and Yawing Tire Slip Forces:
> > 
> > Hear ye NASA to NASCAR, tire makers, and all:
> > TORCS has it now! donuts (Nobody considered yaw slippage!)
> > 
> > Nowhere could I find any mention of Combined Longitudinal, Lateral,
> > and Yawing Tire Slip Forces. Unless it can be shown otherwise ...
> > I will take credit for this discovery; and hereby disclose this
> > information, code, and method to the public domain so that it
> > is useful to everyone, and cannot be patented.
> > 
> > Sincerely,
> > David Savinkoff
> > November 14 2016
> > 
> > See patch for information:
> >   // COMBINED LONGITUDINAL, LATERAL, and YAWING TIRE SLIP FORCES:
> >   // 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.
> >   // saz slip speed accounts for rotating the contact patch (yaw).
> > 
> >   saz = (1.1f*3.1416f) * car->DynGC.vel.az * car->carElt->_tireWidth(index);
> > 
> >   slip_magnitude = 0.000001f + /* Softening factor 0.000001 prevents divide by zero */
> >     sqrt( MAX(MAX((v2 + saz*saz), (vn*vn + wrl*wrl + saz*saz)), (vn*vn + (vt - wrl)*(vt - wrl) + saz*saz)) );
> > 
> >   sx = (vt - wrl) / slip_magnitude;
> >   sy = vn / slip_magnitude;
> >   saz /= slip_magnitude;
> > 
> >   s = sqrtf(sx*sx+sy*sy+saz*saz);
> > 
> > where:
> > wrl is the surface speed of the spinning wheel
> > vt is the axle speed over the ground in the direction the wheel is spinning
> > vn is wheel side slip speed
> > saz is wheel yaw slip speed (imagine steering a wheel with the vehicle stopped)
> > sx is normalized x-axis slip
> > sy is normalized y-axis slip
> > saz/slip_magnitude is normalized yaw slip
> > slip_magnitude normalizes the combined slip to be no greater than 1.0
> > s is COMBINED and NORMALIZED LONGITUDINAL, LATERAL, and YAW SLIP
> > Note that this method can be applied in slip displacement or slip speed (shown).
>

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

_______________________________________________
Torcs-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/torcs-users
torcs-1.3.7.contact.2.patch (text/x-patch, 13 KB)
--- torcs-1.3.7/src/modules/graphic/ssggraph/CarSoundData.cpp	2014-02-10 03:16:18.000000000 -0800
+++ torcs-1.3.7/src/modules/graphic/ssggraph/CarSoundData.cpp	2016-11-23 11:18:14.637402621 -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.7/src/modules/graphic/ssggraph/grskidmarks.cpp	2014-02-10 03:09:36.000000000 -0800
+++ torcs-1.3.7/src/modules/graphic/ssggraph/grskidmarks.cpp	2016-11-23 11:18:14.638402603 -0800
@@ -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.7/src/modules/simu/simuv2/car.cpp	2016-05-16 15:53:07.000000000 -0700
+++ torcs-1.3.7/src/modules/simu/simuv2/car.cpp	2016-11-23 11:18:14.644402503 -0800
@@ -64,7 +64,7 @@
 	}
 	k = k * k;
 	car->Iinv.x = 12.0 / (car->mass * (car->dimension.y * car->dimension.y + car->dimension.z * car->dimension.z));
-	car->Iinv.y = 12.0 / (car->mass * (car->dimension.x * car->dimension.x + car->dimension.z * car->dimension.z));
+	car->Iinv.y = 12.0 / (car->mass * (k * car->dimension.x * car->dimension.x + car->dimension.z * car->dimension.z));
 	car->Iinv.z = 12.0 / (car->mass * (car->dimension.y * car->dimension.y + k * car->dimension.x * car->dimension.x));
 	
 	/* configure components */
@@ -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; // += see torcs/src/modules/simu/simuv2/simu.cpp :: SimUpdate() 
 }
 
 static void
@@ -256,7 +232,15 @@
 	if (fabs(car->DynGCg.vel.az) > 9.0) {
 		car->DynGCg.vel.az = SIGN(car->DynGCg.vel.az) * 9.0;
 	}
-		
+	
+	/* FIXME: Hack to stop stationary car from rotating */
+	if ((	car->DynGCg.vel.x*car->DynGCg.vel.x +
+		car->DynGCg.vel.y*car->DynGCg.vel.y +
+		car->DynGCg.vel.z*car->DynGCg.vel.z) < 0.01f )
+	{
+		car->DynGCg.vel.ax = car->DynGCg.vel.ay = car->DynGCg.vel.az = 0.0f;
+	}
+	
 	car->DynGC.vel.ax = car->DynGCg.vel.ax;
 	car->DynGC.vel.ay = car->DynGCg.vel.ay;
 	car->DynGC.vel.az = car->DynGCg.vel.az;
--- torcs-1.3.7/src/modules/simu/simuv2/collide.cpp	2014-04-12 06:55:29.000000000 -0700
+++ torcs-1.3.7/src/modules/simu/simuv2/collide.cpp	2016-11-23 11:18:14.646402442 -0800
@@ -37,7 +37,7 @@
 	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;
+			car->DynGCg.pos.z += 0.25f*(wheel->susp.spring.packers - wheel->rideHeight); // leverage of 4 wheels
 			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) {
--- torcs-1.3.7/src/modules/simu/simuv2/simu.cpp	2016-10-14 21:50:11.000000000 -0700
+++ torcs-1.3.7/src/modules/simu/simuv2/simu.cpp	2016-11-23 11:18:14.647402413 -0800
@@ -380,6 +380,7 @@
 				SimAxleUpdate(car, i);
 			}
 			CHECK(car);
+			car->DynGC.acc.az = 0.0f; // see torcs/src/modules/simu/simuv2/wheel.cpp :: SimWheelUpdateForce()
 			for (i = 0; i < 4; i++){
 				SimWheelUpdateForce(car, i);
 			}
--- torcs-1.3.7/src/modules/simu/simuv2/susp.cpp	2016-03-19 07:47:05.000000000 -0700
+++ torcs-1.3.7/src/modules/simu/simuv2/susp.cpp	2016-11-23 11:18:14.648402386 -0800
@@ -107,9 +107,9 @@
 	}
 	
 	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
 	}
 }
 
--- torcs-1.3.7/src/modules/simu/simuv2/wheel.cpp	2016-05-16 15:53:07.000000000 -0700
+++ torcs-1.3.7/src/modules/simu/simuv2/wheel.cpp	2016-11-23 11:18:14.649402361 -0800
@@ -46,8 +46,8 @@
 	Ca                    = GfParmGetNum(hdle, WheelSect[index], PRM_CA, (char*)NULL, 30.0f);
 	RFactor               = GfParmGetNum(hdle, WheelSect[index], PRM_RFACTOR, (char*)NULL, 0.8f);
 	EFactor               = GfParmGetNum(hdle, WheelSect[index], PRM_EFACTOR, (char*)NULL, 0.7f);
-	wheel->lfMax          = GfParmGetNum(hdle, WheelSect[index], PRM_LOADFMAX, (char*)NULL, 1.6f);
-	wheel->lfMin          = GfParmGetNum(hdle, WheelSect[index], PRM_LOADFMIN, (char*)NULL, 0.8f);
+	wheel->lfMax          = GfParmGetNum(hdle, WheelSect[index], PRM_LOADFMAX, (char*)NULL, 1.4f);
+	wheel->lfMin          = GfParmGetNum(hdle, WheelSect[index], PRM_LOADFMIN, (char*)NULL, 1.0f);
 	wheel->opLoad         = GfParmGetNum(hdle, WheelSect[index], PRM_OPLOAD, (char*)NULL, wheel->weight0 * 1.2f);
 	wheel->mass           = GfParmGetNum(hdle, WheelSect[index], PRM_MASS, (char*)NULL, 20.0f);
 
@@ -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 = 0.000000f; // 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, saz; // slip vector
+	tdble F, Bx;
 	tdble mu;
 	wheel->state = 0;
 
@@ -209,52 +209,51 @@
 	}
 
 	// HORIZONTAL FORCES
-	waz = wheel->steer + wheel->staticPos.az;
+	waz = wheel->steer + wheel->staticPos.az - (SimDeltaTime*car->DynGC.vel.az /* account for yaw induced wheel direction */);
 	CosA = cos(waz);
 	SinA = sin(waz);
 
 	// 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);
+	v = sqrtf(v2);
 
-	// slip angle
-	if (v < 0.000001f) {
-		sa = 0.0f;
-	} else {
-		sa = atan2(wheel->bodyVel.y, wheel->bodyVel.x) - waz;
+	wrl = wheel->spinVel * wheel->radius;
+
+	if (fabsf(vt - wrl) <= 0.1f) { // Adds numerical stability by catching traction
+		vt = wrl;
 	}
-	NORM_PI_PI(sa);
 
-	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;
+		sx = sy = saz = 0.0f;
 	} else {
-		sx = (vt - wrl) / fabs(vt);
-		sy = sin(sa);
+		// COMBINED LONGITUDINAL, LATERAL, and YAWING TIRE SLIP FORCES:
+		// 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.
+		// saz slip speed accounts for rotating the contact patch (yaw).
+		saz = (1.1f*3.1416f) * car->DynGC.vel.az * car->carElt->_tireWidth(index);
+		slip_magnitude = 0.000001f + /* Softening factor 0.000001 prevents divide by zero */
+				sqrt( MAX(MAX((v2 + saz*saz), (vn*vn + wrl*wrl + saz*saz)), (vn*vn + (vt - wrl)*(vt - wrl) + saz*saz)) );
+		sx = (vt - wrl) / slip_magnitude;
+		sy = vn / slip_magnitude;
+		saz /= slip_magnitude;
 	}
 
-	Ft = 0.0f;
-	Fn = 0.0f;
-	s = sqrt(sx*sx+sy*sy);
+	s = sqrtf(sx*sx+sy*sy+saz*saz);
 
 	{
-		// calculate _skid and _reaction for sound.
-		if (v < 2.0f) {
+		// calculate _skid and _reaction for sound (suspiciously; affects traction also).
+		if ((v < 0.01f) || (zforce < 0.002f)) {
 			car->carElt->_skid[index] = 0.0f;
 		} 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]);
+	// MAGIC FORMULA // Note: F = sin(...) below returns normalized force!
+	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 +261,35 @@
 	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
+	s += 0.000001f; // add 0.000001 to avoid divide by zero later.
+	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);
+	car->DynGC.acc.az += -F * saz/s * SimDeltaTime * car->Iinv.z; // see torcs/src/modules/simu/simuv2/simu.cpp :: SimUpdate()
+
+	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
+
+	waz = wheel->steer + wheel->staticPos.az; /* don't include yaw induced wheel direction here */
+	CosA = cos(waz);
+	SinA = sin(waz);
 
 	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(wheel->bodyVel.y, wheel->bodyVel.x) - waz;
 	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) = vt*(1.0f-sx); // Is wheelSlipAccel the wheel tangent velocity times traction ?
 	car->carElt->_reaction[index] = zforce;
 }
 
@@ -301,8 +304,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;