Vehicle simulation headache

Started by
8 comments, last by K_J_M 11 years, 7 months ago
Hello and sorry for the long post, I'm trying to implement my first car simulation stuff. I've been through Marco Monster's tutorial and also Physics of Racing Series and most of the Racer.nl docs.
For the sake of simplicity I'm starting in 2d, using SAE conventions (X pointing forward, Y to the right)

In a nutshell this is my simulation step:
1. Calculate current engine RPM from driven wheel rotation (with limiter and autoclutch)
2. Calculate drive torque on driven wheels and brake torques
3. Calculate forces and traction torques at each wheel with Pacejka MF (same method for all wheels)
4. Accumulate wheel torques and calculate angular velocities
5. Accumulate body forces (from wheel forces) and resistance
6. Accumulate torques on body caused by the wheels' forces
7. Calculate body movement and angular velocity
8. Dynamic weight transfer

The straight line acceleration and braking seems to be working;
I tried with different timesteps between 1000 and 20000 Hz. Even at 1000Hz the wheels seem to be fine, no jittering, not even at low speed 1-2km/h. The undriven wheels are also rolling because of the torque generated by the negative slip ratio, so that part seems to be ok.

My problem starts with steering, and I'm not sure I'm calculating with the right force values.

Here are some simplified code;
Calculate tyre forces:
[source lang="cpp"]
for (int i=0;i&lt4;i++) {
// Calculate wheel velocity according to body movement and rotation
VHFLOAT flen=...; // Lenghth of the force arm (Wheel distance from CM)
VHVECTOR vrolln=...; // Turning force direction vector (unit length) - perpendicular to the vector from CM to the wheel

// Calculate the wheel velocity in CAR space
VHVECTOR vel=car.vel;
Transform_World_Car(vel);
vel.x+=flen*car.body_ang_vel*vrolln.x;
vel.y+=flen*car.body_ang_vel*vrolln.y;

// Transform the velocity vetor to the current wheel's local space
Transform_Car_Wheel(vel,i);

// Calculate slip ratio and slip angle
VHFLOAT wheelspeed=car.wheels.roll_ang_vel*car.wheels.radius;
if (VHABS(vel.x)&lt0.0000001) {
if (VHABS(wheelspeed)>0.1) car.wheels.slip_ratio=0.01*VHSGN(wheelspeed);
else car.wheels.slip_ratio=0;
car.wheels.slip_angle=car.wheels.steer_angle;
if (VHABS(vel.y)>0.1) car.wheels.slip_angle+=(vel.x/vel.y);
} else {
car.wheels.slip_ratio=(wheelspeed-vel.x)/VHABS(vel.x);
if (car.wheels.slip_ratio>3) car.wheels.slip_ratio=3;
car.wheels.slip_angle=VHATAN(vel.y/vel.x)+car.wheels.steer_angle;
}

// Calculate pacejka values
CPacejka pac;
TPacejkaParameters pars;
pars.fz=car.wheels.fz/1000.0;
pars.slip_ratio_percent=car.wheels.slip_ratio*100.0;
pars.slip_angle_degree=car.wheels.slip_angle*(180.0/PI);
pars.camber_angle_degree=car.wheels.camber;
pac.Calculate(&car.wheels.tyre_magic_values,&pars,car.wheels.tyre_forces);

// Calculate traction torque from longitudinal force
car.wheels.road_torque=-car.wheels.tyre_forces.fx*car.wheels.radius;
}
[/source]
Calculating the total forces on body. This is where I'm not sure about tyre forces. I don't cap to the friction circle, only setting the FX and FY into a vector and summing them for all wheels.
[source lang="cpp"]
VHVECTOR f_total=VHVECTOR(0,0);

// Wheel forces
for (int i=0;i&lt4;i++) {
VHVECTOR f_wheel;
f_wheel.x=car.wheels.tyre_forces.fx;
f_wheel.y=car.wheels.tyre_forces.fy;

Transform_Wheel_Car(f_wheel,i);
f_total.x+=f_wheel.x;
f_total.y+=f_wheel.y;
}
Transform_Car_World(f_total);

// Drag
VHVECTOR f_drag=...;
// Rolling resistance
VHVECTOR f_rr=...;

car.total_forces.x=f_total.x+f_drag.x+f_rr.x;
car.total_forces.y=f_total.y+f_drag.y+f_rr.y;
[/source]

And finaly accumulating the forces and torques on the body:
[source lang="cpp"]
// --- Position ---
car.acc.x=car.total_forces.x/car.mass;
car.acc.y=car.total_forces.y/car.mass;
... // Integrate velocity and position

// --- Orientation ---
car.body_ang_acc=0;
for (int i=0;i&lt4;i++) {
// Wheel forces in CAR space
VHVECTOR f_wheel;
f_wheel.x=car.wheels.tyre_forces.fx;
f_wheel.y=car.wheels.tyre_forces.fy;
Transform_Wheel_Car(f_wheel,i);

// Using only the force component that is perpendicular to the (CM->Wheel) vector
// Calculate the length of the CM->Wheel vector (length of the force arm)
VHFLOAT flen=...;
// Calculate a (unit lenght) vector perpendicular to the CM->Wheel vector
VHVECTOR varmn=...;

// Finaly the force component that is perpendicular to the force arm
VHFLOAT f_roll=varmn.x*f_wheel.x+varmn.y*f_wheel.y;

// The torque caused by this wheel
VHFLOAT t=f_roll*flen;
// Calculate angular acceleration
car.turn_ang_acc+=t/car.inertia;
}

... // Integrate angular velocity and orientation[/source]


But somehow the code above doesn't work even with very small steering angle (1degree)
Using "controlled" values in the body torque calculation works fine;
using constant 20N at the front wheels and -20N at the rear turns the body in the right direction.

The lateral Pacejka generates around 1-2kN which seems to be good, and the signs for front and rear tyre values are also good.

Using 0.01 throttle factor which is a very very very little acceleration, the body rotating in the right direction but much faster, if I add more throttle 0.1 which is still little acceleration (the slip ratio is still in acceptable range - no spinning tyre) the car body goes crazy.
Not jittering and no sign of instability, it just turns back and forth.

This is how I think it should work (with constant engine torque) not exact force values, just to demonstrate:
Step1: Right turn 1degree, front wheels generate +1kN, rear wheels 0kN lateral forces
Step2: Body has positive ang_vel, front wheels have 200N, rear wheels -2kN because of the body turns the slip angle is 60-90degrees

And as a simplified model, step1 starts turning the car right and step2 generates a counter torque, and their difference will make the car turn depending on the steering angle.


Do you guys have any idea? Thanks in advance!
Advertisement
Hi.

I'm affraid i don't have a solution for you, but since no one yet has replied to you, i thought i'd share my experiences.

I recognise some of Marco Monsters formula's in your code.

I remember implementing his tutorial some years ago and found that his algorithms produced a very unstable and jittery car, especially at low speeds.

I would reccomend stripping back your code to treat the car body as one wheel and get that moving and turning correctly.

Then add in your longitude and engine calculations.

There is also the issue of the traction circle / elipse. Which constrains the longitude and lateral forces so they don't exceed their specified limits.

I'm not sure if this is an issue for you or not.

I have a simplified Lateral Pacejka demo i could upload for you to have a look at, including the source.

This treats the car as 1 wheel and might help you to see where your problem lies.

Windows Demo here. 1.5mb

http://www.trinosis.com/files/lateral_pacejka_car_physics_demo.zip
KJM,


I recognise some of Marco Monsters formula's in your code.

I remember implementing his tutorial some years ago and found that his algorithms produced a very unstable and jittery car, especially at low speeds.

I would reccomend stripping back your code to treat the car body as one wheel and get that moving and turning correctly.


Yes, I also implemented Marco Monster's physics a couple of years ago, and it was good to simulate a gokart, but didn't look good as a street car.
I even managed to eliminate the instability issuses, except some weird behaviour at high speed handbraking and turning in the same time.
So I wanted a fresh start with four independent wheels with even different tyre properties depending on the ground they are touching (if there is a contact at all :))

I plotted my pacejka curves and they seem to be good. I implemented Brian Bechman's version and compared to the Racer's source they produce very similar results.

I feel I calculate the contact patch's (CP) velocity incorrectly, thus the slip angle is not good.
I only added the car body velocity and the wheel sideway motion caused by the car's rotation together, and forgot about the rolling wheel's motion. So I added the wheel's rolling velocity (pointing backward in case of car moving forward) and the result got much better, but still far from good.

You might be right, I'll try with a simple solution first, without proper tyre calculations.

Thanks for the demo, but:

//call pacejka to get the lateral force at the given slip angle
car_lateral_force# = pacejka_fy(sideslip_angle#) / 400 ; scale the force down to suit the sim

That /400 seems to be an "ugly" hack :)
Your pacejka_fy is the very same as what I use.


Maybe I should fill in some holes on my basic physics knowledge:

F_total = sum(all forces applied on the body)
Acceleration = F_total/Mass

T_total = sum(all torques applied on the body)
AngularAcc = T_Total/Inertia

For calculating the torque applied by each force, I take only the force component that is perpendicular to the vector between the CM and the force position. So if the force is pointing towards to or away from the CM there is no torque generated.
And Torque = Force*Distance_to_CM

Are the above right?
Hi.

"I plotted my pacejka curves and they seem to be good. I implemented Brian Bechman's version and compared to the Racer's source they produce very similar results."

Yes, i've had a look at Brian Beckmans Physics Of Racing Series too.

His alternate Pacejka curve formula produces similar curves to Pacejka, but they don't take into account load and camber if i remember correctly.

Which are essential for a realistic sim, for load transfer when cornering for instance. As the loads on the tires change.

That /400 seems to be an "ugly" hack

Yes, i ddn't use real world values in the demo. Theres no calculations using Newtons for force ect. It's just a basic implementation to get the basic sim working.

Your Torque theory sounds right to me.

Here's a paragraph from my "Physics For Game Developers" book on Torque.

"Force is what causes linear acceleration, while torque is that which causes rotational acceleration.
Torque is force times distance. Specifically, to calculate the torque applied by a force acting on an object, you need to calculate the perpendicular distance from the axis of rotation to the line of action of the force and then multiply this distance by the magnitude of the force.
This calculation gives the magnitude of the torque.
"

Yes, i've had a look at Brian Beckmans Physics Of Racing Series too.
His alternate Pacejka curve formula produces similar curves to Pacejka, but they don't take into account load and camber if i remember correctly.


Yes, they count on load :)


I stripped the model down as you suggested to not one wheel but two. One for front with steering and one for back with driving.
It is still not good, the straight movement works fine but not the turning.
I use very simple calculations:
Slip ratio as usual:
slip_ratio=(wheel_roll_vel-wheel_long_vel)/abs(wheel_long_vel);
Slip angle also:
slip_angle=atan2(wheel_lat_vel,wheel_long_vel)+steer_angle;

And the forces:
Fx=slip_ratio*0.25*Fz
Fy=slip_angle*0.1*Fz
Both values are capped to a maximum.

I suspect the slip_angle is not right, so let's make the turning straight :)
Suppose (on a clock face) the wheel is heading towards 12 o'clock.
Based on the actual velocity these slip angles should be produced;
Move direction 12..3 o'clock -> slip 0..-90 degrees
Move 3..6 -> slip -90..0
Move 6..9 -> slip 0..90
Move 9..12 -> slip 90..0

Are the above assumptions right? Meanwhile I make sure my favorite atan2() results accordingly :)
I get slightly different slip angles in my demo.

12..3 -> slip 0 to -90 degrees
3..6 -> slip +90 to 0
6..9 -> slip 0 to -90
9..12 -> slip 90 to 0

The important thing is that your 12 - 3 and 9 - 12 slip angles have different signs for going forwards and 3 - 6 and 6 - 9 have different signs for going backwards.

So, Lateral Pacejka will return the correct signed force for skidding left and right.

I have different signs when the car spins past 90 degrees and starts going backwards. But i wouldnt worry about that until you get it working correctly going forwards.

Just to state the obvious, you are working in Degrees and not Radians, and not getting them confused ?

I would still reduce your code further to simulate what i do in my demo, with one wheel. Since your still having problems.

Once thats working as it should, then implement 2 wheels and when that works go to 4.

Also make the load and camber on the wheels constant, at this stage to simplyfy things as much as possible.

Could you upload a demo, so i could get a look at what's actually happening. Or a short video perhaps.


I don't understand these two lines

Fx=slip_ratio*0.25*Fz
Fy=slip_angle*0.1*Fz

To cap the forces to a traction circle / elipse you just normalise each and then multiply by a maximum length, if they exceed a maximum force.

You treat both as a 2d direction vector.

Also remember that Fz is used in the Pacejka equations. So i don't know why you're using it in those two lines.

Just remove those two lines from your code and see what happens.

Pacejka expects slip angles from -90 to +90, load (Fz) and camber as inputs and outputs FY as force.

12..3 -> slip 0 to -90 degrees
3..6 -> slip +90 to 0
6..9 -> slip 0 to -90
9..12 -> slip 90 to 0

Just to state the obvious, you are working in Degrees and not Radians, and not getting them confused ?

I would still reduce your code further to simulate what i do in my demo, with one wheel. Since your still having problems.

Also make the load and camber on the wheels constant, at this stage to simplyfy things as much as possible.


I use radians, I just wrote in degrees for better understanding :)
And no wight transfer, the load is balanced 50-50%
My slipangle signs are far from yours.
The ATAN2(vel_lat,vel_long) formula needs some tweaking, because if the wheel moving backwars eg: atan2(0,-1) results 2PI slip angle which wouldn't make sense.

This version (what you also use) works better:
slipangle = atan2(vel_lat , abs(vel_long)) * sgn(vel_long)

...but
It starts turning as expected and after a while the car body starts spinning, like it was moving on ice. Only 30Nm torque on the rear wheel, the tyre is not spinning.

This is why I need at least 2 wheels. If the front wheel's steering generates angular velocity on the body, the rear one is needed to damp it to prevent infinte rotation.
Now it feels the car body gets too much angular acceleration

I keep trying, and capture a video when I get home.
Ok, from what you've written then, it seems the problem might lie with the forces acting against the wheels from the angular velocity of the car.

If we assume your car is stationary and points at 12 o clock with the front wheels centred, but is spinning on it's axis (yaw) then the wheels generate 0 slip angle because there is no long or lat linear velocities of the car.

But there will be friction against the wheels as the car spins, acting in the opposite direction to the movement of the wheel.

I ended up just using a constant friction value applied to the angular velocity of the car at each update.

I don't think the force acting against the wheels changes much if at all but i wasn't able to find a definitve answer to this question and so just ended up using a constant friction force.

You could use Pacejka to return a force with a slip angle of 90 degrees ( 1/2 * Pi Radians ) for all wheels to slow down the angular velocity of the car or apply a constant as i do.

Using Pacejka seperately for the front and rear wheels makes sense because if the front wheels are turned you can call Pacejka with a different slip angle.

For the front wheels pointing straight ahead the slip angle would be 90 degrees as the car spins, and if turned 90 degrees the slip angle would be 0.
Heureka....#1

Thanks K_J_M for the tips, finaly I managed to solve it. The problem was around the slip angle sign variations at each slip "quarters" that you first mentioned.

I just tried to apply an instant 10rad/s angular velocity to the body and was watching the front/rear wheels' slip angles and generated lateral forces, and played with the signs until I got the long-awaited damping forces :) So my car came to rest after 2-3 secs.

The formula that worked:
slip_angle = -atan2(vel_lat, abs(vel_long));

The negative sign is probably because I'm screwing up the wheel's streering angles, but no sgn() is needed!

Puting that back into the four-wheels-pacejka-based-model it worked like a charm. No additional cheats and tricks needed, everything works out fine ;)
It doesn't make donuts yet, not even with spinning wheels, maybe because I don't cap to the friction limit and having tyres with high cornering stiffness.

Anyhow, it's a very good starting point, thanks again!

I'm sure there's gonna be more headaches as I progress :)
Hey, thats great.

Congrats on getting it working.

Glad i could help. smile.png

This topic is closed to new replies.

Advertisement