Car physics traction circle and friction curve

Started by
11 comments, last by bmarci 2 years, 8 months ago

Hi

I'm working on 3D car physics in Unity. I'm using one raycast per wheel and calculating my own spring/suspension forces etc, not using Unity's WheelCollider (but still using a Rigidbody).

I'm trying to create a simple-to-use car controller but still based on somewhat realistic calculations. I calculate engine revs, torque, gears, drive torque, slip ratio, traction force, traction torque.

I got most of it pretty nice and stable. But the friction model is not great. I either get a super stable car that can't drift or one that loses grip everywhere.

The one thing I just can't figure out is how to combine the friction circle and tire friction curves. I have read everything google can find for me, multiple times. There is info about the friction circle and friction curves, but never how to combine them.

First question, should you really combine them? They seem to be somewhat overlapping.

But if you don't use the friction circle, how do you combine longitudinal and latitudinal forces?

Thanks!

Advertisement

Hello, a good writing on this topic can be found in Brian Beckman's Physics of racing series:

http://ceb.ac.in/knowledge-center/E-BOOKS/Physics%20Of%20Racing%20Series%20-%20Brian%20Beckman.pdf

You can find a decent method of how to combine the Fx and Fy in case you are using the magic formula.

Having written several car physics simulations, using rays, spheres, and cylinders for the wheels, I can attest that tweaking is super sensitive to get the right amount of grip/drift without either just tipping over all the time, or just gliding like on ice, or getting the “train on rail” behavior.

Much of this comes from the fact that game cars typically are much more arcade-ey than actual physical cars; they drive faster, accelerate faster, turn tighter, and are expected to stand up to more abuse than you'll even get from your family sedan on the freeway. Simulating “real cars” is almost always boring to most game players, because real physics is … not game-ey.

Also, 32-bit floating point doesn't help. The precision of about 6 digits ends up sometimes being just barely enough. If you can use a 64-bit simulation, the tuning can end up being less hyper-dependent on the specifics of how the integrator/collider/timestep works, and be a little more consistent. Still not a panacea, but every so slightly less black art.

enum Bool { True, False, FileNotFound };

Thanks for you replies!

@bmarci

I have read Brian Beckman's Physics of racing a lot, but unfortunately the math often quickly goes over my head. Chapter 25 on Combination Grip is hard for me to follow. I understand the idea though.

I have also read a lot of your old posts here on gamedev, lots of usefull stuff!

I'm using slip ratio equation, but not the magic formula. I do a simple capped linear equation like in Marco Monster's Car Physics for Games. For lateral forces, I have tried slip angle, but I really don't like it. It doesn't really account for sideways velocity. Instead I simply use F=ma to calculate the force a wheel needs to keep it from sliding sideways. This has worked surprisingly well.

My latest attempt (from today) to combine these two involves removing the cap on the longitudinal force generated by the slip ratio. Then I create a 2D vector out of the long/lat forces and cap it's magnitude to my calculated “MaxTireFrictionForce”. If I detect that the force vector's magnitude is over MaxTireFrictionForce, then I set IsSlidingFlag=true that reduces the friction for the next physics frame.

The MaxTireFrictionForce calcuation is = (IsSlidingFlag ? SlidingTireFriction : TireFriction) * SuspensionForce * GroundGrip.

Currently I always have GroundGrip = 1.0

I'm planning to have a curve to smooth out the transition to between SlidingTireFrction and TireFriction.

This works better than my previous attempts. But I lose grip very easy, especially when going over the top of a hill, when there is less force from the suspension. I tried a simple test by doubling the MaxTireFrictionForce and that of course immediately improved grip while cornering. Though still bad over a hill.
But I don't like to arbitrarily multiply with a magic value. Maybe it's not good to use the SuspensionForce like this?

@hpus0603

Yes, I have been trying for years to get my simulation where I wanted. I have also created many simpler variants along the way. It's endlessly fiddling with constants and trying to clamp values that jitter back and forth.

Decept said:
I'm using slip ratio equation, but not the magic formula.

Ok, yes, the Beckman's method is based on modifying the pacejka inputs, so it'll not help in your case. Also I had the same feeling for years about PHORS, probably because all the imperial units, they didn't make sense ?

I copy here the other solution I have, sometimes it's better than Beckman's. I have no idea where did I get it from :(

So you'll need the optimal slip values (where the forces are at max).
The slip_vector_tc is the tire slip in the tire coordinates (a vector form of difference between velocity of the wheel and free rolling velocity)
I use the standard left handed coordinates (X-right, Y-Up, Z-forward) but stick to the SAE naming regarding forces, that can be confusing for first.

VFLOAT opt_sr=CalculateCurrentOptimalSlipRatio();
VFLOAT opt_sa=CalculateCurrentOptimalSlipAngle();

VFLOAT s=sim.slip_ratio/opt_sr;
VFLOAT a=sim.slip_angle/opt_sa;

VFLOAT rho=VSQRT(s*s+a*a);
if (rho>1) { // Over the limit, we need to cut
	VFLOAT old_fx=sim.fx;
	VFLOAT old_fy=sim.fy;

	VFLOAT beta=VATAN2(sim.slip_vector_tc.x,sim.slip_vector_tc.z);

	VFLOAT f=props.tire_model.GetFxMax()*VPOW(VCOS(beta),2.0)+
			 props.tire_model.GetFyMax()*VPOW(VSIN(beta),2.0);

	sim.fx=-f*VCOS(beta);
	sim.fy=-f*VSIN(beta);
}

The suspension force should be good to get the normal load (Fz). I use the tire deflation to get this because of temperatures and pressure changes…etc, but they give more or less the same result. The suspension is much more stable, the tire has much higher frequency. Losing grip at the top of the hill is normal, but a lot depends on the settings. No winning formula, you must experiment. I downloaded a lots of Racer and rFactor cars, just to check out the settings. You probably did that already.

Very nice, thank you so much!

Do you know if this is based on some physics equation, or does it just work nice? ?

There are a couple of values that I don't fully understand. How do you get the slip_vector_tc.x, the free rolling velocity sideways is always zero no?

What is tire_model.GetFxMax() and GetFyMax()?

Those imperial units in PHORS… just this makes my head spin, as if the equations are not hard enough. ?

Decept said:
Do you know if this is based on some physics equation, or does it just work nice? ? There are a couple of values that I don't fully understand. How do you get the slip_vector_tc.x, the free rolling velocity sideways is always zero no? What is tire_model.GetFxMax() and GetFyMax()?

I don't think it's related to physics, rather works nice.

Yes, the free rolling velocity always points forward in tire coordinates, no sideways, the velocity is the world velocity transformed to tire coords, and the slip_vector is their difference.

The GetFxMax() and GetFyMax() are the maximum forces the tire can generate at the optimal slip values (peak value of the tire formula)

What a week! Now I finally got some time to look at this again.

Thanks, now I understand the slip_vector and FxMax/FyMax.

I'm guessing your VATAN2 takes the parameters like this VATAN2(adjacent, opposite)? Because it seemed so strange to me until I realized this. Unity's function is like this Atan2(opposite, adjacent), or rather Atan2(y,x).

What do you do if rho ≤ 1? I do my equivalent of this:
sim.fx = a * props.tire_model.GetFxMax();
sim.fy = s * props.tire_model.GetFyMax();

It works now, but I have to tweak the values, because I slide at anything above crawl speed. I'm currently using the same optimal slipRatio/slipAngle and FxMax/FyMax values as I did with my equation.

I haven't actually thought about downloading Racer and rFactor cars to look at the settings. I will definitely check that out.

Decept said:
I'm guessing your VATAN2 takes the parameters like this VATAN2(adjacent, opposite)?

Yes, my VATAN2 is a macro for the standard atan2(y,x) or atan2f(y,x) functions (depending on the current floating point precision).

I do nothing if rho ≤ 1. Because I normalize the forces, so if the length of their vector sum is below 1 it means the forces don't exceed the traction limit.

Decept said:
sim.fx = a * props.tire_model.GetFxMax();
sim.fy = s * props.tire_model.GetFyMax();

This is a geometric cut, like when the traction circle and traction force vector intersect. It is quite good at a certain point. Also a personal preference if it fits your needs.
In reality the longitudinal and lateral forces are not reduced equally. For example when you lock up the front wheels you can not steer, even if you have huge slip angles and the tire formula gives decent lateral forces, the sideway forces are almost zero at the end.

Good luck with what you are working on!

This topic is closed to new replies.

Advertisement