Skip to main content
GameDev.net gamedev.net
🔒 Locked

pacejka implementation

Started by shiboujin Mar 27, 2008 at 3:00 PM 65 replies 19.3k views
Original Post
shiboujin
shiboujin
Hey guys! I'm trying to implement pacejka for my racing type game and I don't quite understand how to do it. I understand the basic formulas and can't figure out how it plugs into a "real" car. Do you make a pacejka class for each tire? The source code I'm staring at only has 1 value for camber so I'm assuming you need to make a class and do calculations per tire. The outputs of the pacejka formulas give 3 major numbers, lateral/longitudinal/aligning moment (I still dont get what aligning moment is). These three numbers are floats. I don't get how these numbers correspond to the direction the car is traveling and its relative slip angle. So far my car game stores the over all car motion as a vector. Would slip angle simply turn the model of the car and have everything still travel along the same path? That doesnt sound very accurate though. Help! I'm misguided!
K_J_M
K_J_M
Hi.

I've used the Pacejka formulas quite sucesfully in my racing game

www.kjmsoftware.co.uk/

theres also a car physics resource download available on my site too.

There are two differetn versions of the pacejka formula, Longtitude and Lateral versions as far as i am aware.

As far as i can remember, aligning moment is the force returned for the steering wheel, used for force feedback joysticks.

Either the long or lat versions should only return a force. ie, 1 variable. You shouldnt be getting several outputs.

You call the pacejka formula with camber, load and slip angle, i think and you get a force returned based on those inputs.

Each pacejka requires a set of coeficient constants too, which specify the tire attributes.


The longitude slip angle is the amount of wheel spin you have, ie traction of wheel, forward rolling angular velocity over ground velocity.
The force returned from longtitude pacejka is the amount of traction your tire has with the ground which basically equates to longtitude acceleration.

The lateral slip angle, is the direction of travel of the car over its yaw orientation. Oversteer if you will.
The force returned from lateral pcejka is used to change the direction of travel of the car and also to slow down it's yaw angular velocity.

To start with, you can just treat your whole car as 1 tire and call the pacejka routines based on the lateral slip angle of the car and use a long slip angle variable for acceleration.

Both long and lat pacejkas should be treated as seperate routines.

A slightly more advanced approach is to combine both returned forces and to treat them as a x,y vector, and crop them to fit a circle or oval of output forces. Probably best to google it, as i'm not explaining this part very well.

Incidentaly, the racer website has the best pacejka pages i've seen and is what i have used.

http://www.racer.nl/

Hope that helps.

KJM
shiboujin
shiboujin
I love you :) It makes sense. I guess the force returned is the acceleration in a direction?
K_J_M
K_J_M
Well, the force returned for the longtitude pacejka can be either positive +, or negative -, so it can be either acceleration or decelleration.

If the wheel is rotating ( angular velocity ) slower than the road speed, then it will be skidding on the road, thus causing decelleration, a negative force.

If it's spinning faster than the road speed, then there is normal wheel spin, causing acceleration for the car.

For the lateral pacejka, this too can return a positive or negative force, but this specifies a direction , left or right.

as an example.

Take a toy car, place it on a slightly slippy table, rotate it to say 45 degrees to the right and push it forwards.

The car will slide forwards at an angle of 45 degrees, untill enough friction is built up to change the cars direction of travel until it travels in the direction it is pointing.

In this case, the slip angle is 45 degrees, and the sign of the force returned tells you what direction you need to alter your cars direction of travel. In this case say, a positive force is returned which means you need to rotate your direction of travel vector to the right.
A negative force would be to rotate left.


If the car has any angular yaw velocity, ie, it's spinning like a top, then you will need to slow that down too.

If the toy car is spinning on it's spot, ie no linear velocity, then all the wheels are in effect sliding sideways, although the car is spinning on its spot.

I used a constant friction value to slow down any yaw spin of the car. I'm not sure if this is entirely correct, but gives good results for a game.

Considering that the lateral pacejka needs a slip angle, calculated from the difference between the cars longtitude and lateral velocities, a 0 force will be returned if the car is stationary but spinning on it's spot. Because both long and lat car velocities will be 0.

Incidentally, to calculate the lateral slipangle, use

atan2(lateral_car_velocity , longtitude_car_velocity)

The order , lat long, might be wrong i can never remember off the top of my head. And the velocities are in car frame coordinates, and not world frame coordinates. A car in a game for instance, might be travelling forwards , but its world coordinates might be x = 1, going sideways left to right in the world. Whereas the cars local coordinates would be long velocity = 1, lat = 0.

Therefore, i assume that a constant friction value is used to slow down the cars stationary spin.

But in real life, a car can be yaw spinning as well as having linear velocities, so the pacejka force is used to change the direction of travel for the car only.

Marco monsters tutorial explains how to calculate the lateral slip angle and has c source code too. It can be found within my car physics download.

Hope that sheds a bit more light on the subject.

KJM
shiboujin
shiboujin
I'll have to read that a few times through. I have been reading through that download you pointed at. I am trying to integrate the Pacejka formula into an existing physics engine and they just dont seem to want to match up. Figures. I managed to get the pacejka.cpp file into a C#/XNA format, I just need to integrate all of that into

From what I can tell. before you calculate pacejka, you need to update:
slipangle
slipratio
normalforce
camber

and as you said the two outputs are the lateral and longitude forces.

So that means I need to make my physics engine calculate and plug in those 4 forces right?
K_J_M
K_J_M
Yes you only really need the slipangle and slipratio as inputs, the normalforce or load / weight on the tire and camber can be constants. In real life of course, as the car pitches and rolls the camber and loads on each tire change dynamicaly.

But in actual fact, you dont really need the pacejka formula to return a force, but instead use the slip angle / ratio as the force to use. Although you would probably have to scale it to some arbitry value that works for your physics engine.

The pacejka formula just returns a good real world approximation of tire force, ie, a very accurate model of a real tire, based on the coeficients used. But it's not necesary to start with.

I used the ODE physics engine in my game along with the pacejka implementation, so it can be done and works quite well.

I would first concentrate on the lateral force first by getting your cars longtitude and lateral velocities. These would be your car chassis linear x,z velocities for the ground plane in 3d, treated as a 2d vector and then rotated to the yaw angle of your car chassis.

This transforms your cars world linear x,z velocities into car frame velocities, forwards speed ( as you see on a car speedo ) and sideways speed.

Then it's a simple case of using

slipangle = atan2 (sideways speed , forwards speed)

force = slipangle / scale amount to work with your physics engine

to calculate the slipangle, which can be used as the force to turn the car chasis left or right until it's slip angle becomes 0, which is when the car is traveling in the direction it is pointing with no lateral velocity.

KJM
shiboujin
shiboujin
Ok. I think I'm starting to get this. Still a few Qs.

Slip Angle = the current angle the car IS (45 degrees in your example) right?
What is slip ratio?

And I don't quite get what "force" is. Would that be the change in velocity or just a factor I should be using for the rest of the car physics?

I'm so frustrated. The JigLibX Library I have has really simple vehicle physics to the point where I cant even tell if there is a suspension.
shiboujin
shiboujin
Double post!

Slip Ratio = [(Vehicle Speed – Wheel Speed)/Vehicle Speed] x 100

So slip ratio is the diff between the car speed and the wheel speed. So doesnt that mean slip ratio can be a negative number? IE the wheels are going faster than the car (acceleration)
K_J_M
K_J_M
Q - "Slip Angle = the current angle the car IS (45 degrees in your example) right?

Not just the angle the car is, but the angle between the direction of travel of the car and it's yaw orientation. This is oversteer, as in a rally car, when the rear steps out causing a skid.
Any sideways velocity will cause a lateral slip angle.

If the car is travelling normaly down a road in a straight line, rolling forwards, then there is no slip angle.

If the car has no forwards speed, but is sliding sideways only, it has a slip angle of 90 degrees.

Here is the code i used to get the slip angle and force. Blitz basic source.

;get the real world x,z velocities of the car, returned from your physics engine.
x_velocity# = dBodyGetLinearVelX#(car)
z_velocity# = dBodyGetLinearVelZ#(car)

;rotatate the x,z velocities of the car in world frame coordinates to local frame car coordinates. Simple 2d rotation.

yaw# = dBodyGetYaw#(car) ; get the yaw orientation of the car
s# = Sin(yaw#)
c# = Cos(yaw#)
lateral_velocity# = (x_velocity# * c#) + (z_velocity# * s#)
longitude_velocity# = (x_velocity# * -s#) + (z_velocity# * c#)

; get the angle between the two velocities.
slip_angle# = ATan2(lateral_velocity# , longitude_velocity#)

;either use the slip_angle# as the force to change the cars direction of travel or call a pacejka function for a more accurate force.

; lateral pacejka force based on slip_angle#
lateral_force# = lateral_pacejka(slip_angle#)

Now that you have worked out the slip angle, and a force for that slip angle, you can use that to change your cars direction of travel.

Again it's simply a case of a 2d rotation of your x_velocity#, z_velocity# to either left or right by the amount of force thats been worked out.

Then to set cars actual velocities in your physics engine with the new velocities.


"What is slip ratio?"

The slip ratio is just the difference between the road speed (car speed) and wheel speed.

So.

Slip Ratio = Vehicle Speed – Wheel Speed

The slip ratio can be positive or negative, but youll have to take into account the direction of each. The car could be moving backwards along the road, negative longtitude velocity, but the wheels could be spinning forwards giving positive angular velocity.

The slip ratio again can be used directly as the force to alter the cars acceleration / deceleration or passed to the longtitude pacejka function to return a more accurate force.


"I'm so frustrated. The JigLibX Library I have has really simple vehicle physics to the point where I cant even tell if there is a suspension."

I can sympathise, there is really very little information regarding car physics programming available, period.

Are there any other physics libraries available for XNA ?

KJM
shiboujin
shiboujin
Thanks again. I think I get it now.

unfortunately, there really arent any good physics libraries for XNA. All are in alpha stages. My current phys library basically said that if there was more than X amount of lateral force, that it would change the lateral forces. It had nothing for slip angle or slip ratio.

I got everything in and decided to check numbers out last night. Somehow the vehicle speed and wheel speed are in two different units. So I get to figure out how to make them play nice. Even with that, I think my values for slip angle are wrong since I think they should be 0-360 not 1000+ so I need to figure that part out.

What are example numbers for the lateral and long forces outputted?

BTW thanks for being so helpful. Youre the only good source so far lol.
K_J_M
K_J_M
It's suprising there arnt any decent physics libraries for xna. I would have thought it would have supported a wide variety, as there are many out there now.
I havnt had a proper look at xna yet, so am still a bit ignorant of it.

The slip angle variables you should be getting will be in the range -180 +180 degrees, or -+ Pi, although my code traps them at 90 degrees maximum, i think. Because im testing for whether the car is going forwards or backwards.

I would suggest you do a quick heads up on the Atan2 trigonomic ratio, just to familiarise yourself with it. It will be difficult for me to explain. But bare in mind it's an Angle thats returned, which can be directly used as a force.

http://en.wikipedia.org/wiki/Atan2

The size of your long and lat velocities are irrelevent, it's the ratio's between them that are important and Atan2 returns an angle for the ratio.


"BTW thanks for being so helpful. Youre the only good source so far lol."

No problem, glad to help. :)
I've spent many years trying to figure this stuff out myself.

KJM
shiboujin
shiboujin
I feel like I understand what you are getting at but I can't get the values from the physics engine very well. The car's yaw is alluding me now. I can get the yaw in relation to the world but that does no good. And for some reason I can't get the right car speed or wheel speed I dont know which.

Theoretically, if you arent slipping, the vehicle speed and wheel speed should be the same. Slip Ratio of 0. But my values keep flying above and below that value. I can understand that if you let off the gas, the car is slowing down. The ratio should be positive. And when you give it a little gas, the ratio should be negative. But mine are either at any time and don't seem to hover anywhere near 0.

I'm going to take a break... Maybe search again for an XNA physics engine that already has good vehicle physics.

Edit: I'm so pissed off at JigLibX. I'm going to see about porting the marco monster rigid body physics... sounds easier in the long run. I can't do physics >_<

[Edited by - shiboujin on April 5, 2008 3:37:03 PM]
K_J_M
K_J_M
I'm sorry you're finding it difficult to get it working.

It does sound like your phsyics engine is not returning correct values, and if thats the case theres no way to get the slip angle and ratio correct.

I would advise simply using a physics engine to create car physics instead of coding your own. As writing your own engine is much more difficult to do. But like you said, finding an engine that does a decent job of it will take some investigation.

All the best.

KJM
shiboujin
shiboujin
OK! I did a metric crap ton of hmwk on several subjects. I actually started to make my own physics engine just so I could do basic things but when it came to collision detection, rigid bodies seemed to be the best way to go. Then, after studying rigid bodies, it turns out the physics engine I was using was basically that. So instead of coding it all from scratch, im back to using JigLibX... lol

I went in line by line of the tire physics and made sure I understood everything. I came to the conclusion that the tire's frictions and forces are calculated very linearly.

So the suspension and setup of the car is simple but good enough for now. The tire's on the other hand must be changed.

/diatribe

So, im back to needing 4 values:
slipangle
slipratio
normalforce
camber

I know I can leave normalforce and camber to fixed values for now. I might have an idea how to get those values but lets go one step at a time.

Qs:
Slip ratio - should it be "car speed - wheel speed" or the "[(Vehicle Speed – Wheel Speed)/Vehicle Speed] x 100" that I found earlier?

Wheel speed == (the wheel's angular velocity * 2) * (radius * pi * 2)?
It can be simplified but since angular velocity is radians/time, one revolution per unit of time is 2 radians/time.

Car speed I thought would be as simple as car.length() vector but not only does that not take into account sideways/up/down movement but if I isolate the X value, I get that in relation to the world. I'm new to the game physics thing so I don't get it. What is the best way to get the car's forward movement in the same units as the wheels speed?

Lastly, I have no clue how to compute slip angle. I assume there is some kind of relationship between the orientation matrix and the vector the car is traveling but I can only fathom that math at this point.

Edit: Am I calculating slip ratio and slip angle (etc) for each tire? As in, I do not pass in the car's slip angle/ratio, I am dealing with the wheel's slip angle/ratio?

Edit2:
Heres the Marco Monster formula for slip angle into code.

if(bodyVelocity.x > 0.05 || bodyVelocity.x < -0.05){

int sign = 1;
if(bodyVelocity.x < 0){

sign = -1;
}
slipanglefront = atan(((bodyVelocity.y + bodyAngularVelocity.z*frontAxelOffset.x)/bodyVelocity.x) - steerangle*sign);

slipanglerear = atan((bodyVelocity.y - bodyAngularVelocity.z*rearAxelOffset.x)/bodyVelocity.x);
}

Of course now I'm back to figuring out the car's velocity but now I need to find front axle offset and the body's angular velocity.

[Edited by - shiboujin on April 9, 2008 1:51:42 PM]
K_J_M
K_J_M
Ok, glad to see your still sticking with it.

Marco monsters tutorial is needlessly complicated.

The best approach to take is to simplify everything down to it's barest minimum, to simply get it working, then you can add complexity for a more accurate sim at a later date.

What i will do, is to knock up a small demo with source code for you to port across to your system, then when thats working you can modify it further or change it to suit your needs.

But to answer your questions.


"
Qs:
Slip ratio - should it be "car speed - wheel speed" or the "[(Vehicle Speed – Wheel Speed)/Vehicle Speed] x 100" that I found earlier?

Wheel speed == (the wheel's angular velocity * 2) * (radius * pi * 2)?
It can be simplified but since angular velocity is radians/time, one revolution per unit of time is 2 radians/time.
"


A

To get a basic system up an running, all you need to do, is use a 1 to 1 correclation of the wheel speed to ground speed. So actualy calculating the linear velocity of the wheel from it's angular velocity isnt necessary at this point.

In fact, you can also think of the wheel speed in terms of engine revs, 1 rpm = 1 unit of road speed.

It doesnt matter that the wheels actual angular velocity doesnt match the road precisely, as all we're concerned with is calculating the slip ratio from the difference in the two.

I would also leave calculating the slip ratio until after you have the slip angle working correctly.

For acceleration, just use a simple accelerate physics body code.


"
Q
Car speed I thought would be as simple as car.length() vector but not only does that not take into account sideways/up/down movement but if I isolate the X value, I get that in relation to the world. I'm new to the game physics thing so I don't get it. What is the best way to get the car's forward movement in the same units as the wheels speed?
"


A
Yes, this is the problem of world frame coordinates of the car, and car frame coordinates.

You'll need to swap between the two and the code i posted previously does that.


;get the real world x,z velocities of the car, returned from your physics engine.

x_velocity# = dBodyGetLinearVelX#(car)
z_velocity# = dBodyGetLinearVelZ#(car)

;rotatate the x,z velocities of the car in world frame coordinates to local frame car coordinates. Simple 2d rotation.

yaw# = dBodyGetYaw#(car) ; get the yaw orientation of the car
s# = Sin(yaw#)
c# = Cos(yaw#)
lateral_velocity# = (x_velocity# * c#) + (z_velocity# * s#)
longitude_velocity# = (x_velocity# * -s#) + (z_velocity# * c#)




"Q
Lastly, I have no clue how to compute slip angle. I assume there is some kind of relationship between the orientation matrix and the vector the car is traveling but I can only fathom that math at this point.
"



A

Slip angle is calculated from the angle between the longtitude and lateral velocities of the car, in car frame coordinates.

; get the angle between the two velocities.
slip_angle# = ATan2(lateral_velocity# , longitude_velocity#)




"Q
Edit: Am I calculating slip ratio and slip angle (etc) for each tire? As in, I do not pass in the car's slip angle/ratio, I am dealing with the wheel's slip angle/ratio?
"


A
No, there is no need to calculate for each tire. The easiest method is to treat the cars chassis as 1 tire.


Like i said, i'll create a small demo for you, with source so you can see how i do things.

Give me a day or two.

KJM

K_J_M
K_J_M
I had some free time this morning so managed to put together a demo.

http://www.kjmsoftware.co.uk/pacejka_car_physics_demo.zip


It contains source and 2 .exe's.

A demo whereby you drive a car about ( oblong ) crashing into other cubes to see the effect it has. This demo uses lateral pacejka.

The source for it is included.

As you dive the car about, it slips and slides until it's slip angle becomes too great and the force generated too low, whereby the car spins around.

I've also included an exe and source to my lateral pacejka curve generator.

This shows the curve that the lateral pacejka coeficents use. You can alter the coeficient values to see the effects it has on the curve.

The curve shows the force returned from lateral pacejka for a given slip angle.

Bare in mind this is just a simple demo to demonstrate how the lateral pacejka works. It's the first step only.

For a more sophisticated sim, you would include longtitude slip ratio, which also has a relationship to grip, a wheel spinning tire generates a fraction of the grip than it does at 0 slip ratio.

KJM
shiboujin
shiboujin
I like how you can do, in one night, what I've been trying to do for weeks >_<

I'll take a look at the code (once I figure out what a .bb extension is). The demo does basically what I'm looking for I could care less about long forces right now. I really want the slip forces.

I can def get the velocity's X and Y coordinates. I'm not quite sure where yaw information would be stored. I guess the source code should help me out with that.

I actually managed to get the car's velocity by comparing where it was and where it is and it actually matched up with the vector within a certain margin of error (floating points I guess were the downfall). I also found the wheel's forward velocity by "rim velocity" from the physics engine I was using and the ratios seem about right. When speeding up, slip ratio is negative (tires going faster than the car) and when you slow down, its positive.

I need to buy you a gift or something. Why havent you written a book?

Edit: got the source to open. its just a text file... I'm so dumb.

Edit2:
Yaw = Acos( Dot(V1, V2))
thats in radians, do I need degrees for pacejka? I think it uses radians.

Now V1, and V2 have to be unit vectors from what I remember. The problem is that I have the vector of where I'm going. Car.Body.Velocity.Normalize(). but where I'm pointed seems kinda tricky. I think its Car.Body.Orientation.Forward.Normalize().

Basically the formula you printed out will easily give me the car's pure forward speed (long velocity) AND slip angle. so it solves basically all my problems.

I also figured out normalforce. Theres a dampening algorithm that outputs a float of how much the car is pushing the wheel to the ground. IE its 0 if the car is in the air and roughly 1200 at rest. It's also 1600 at the rear tires on accel and roughly 800 on decel. Sound about right?

Edit3:
Hows this look?

Vector3 unitFwdVec = carObject.Car.Chassis.Body.Orientation.Forward;
Vector3 unitDirVec = carObject.Car.Chassis.Body.Velocity;

unitFwdVec.Normalize();
unitDirVec.Normalize();

double xVel = carObject.Car.Chassis.Body.Velocity.X;
double zVel = carObject.Car.Chassis.Body.Velocity.Z;

//double latVel = Vector3.Dot(carObject.Car.Chassis.Body.Velocity, carObject.Car.Chassis.Body.Orientation.Left);
//double longVel = Vector3.Dot(carObject.Car.Chassis.Body.Velocity, unitFwdVec);

double yaw = Math.Acos(Vector3.Dot(unitFwdVec, unitDirVec));

double carSin = Math.Sin(yaw);
double carCos = Math.Cos(yaw);

double latVel = ((xVel * carCos) + (zVel * carSin));
double longVel = ((xVel * (-carSin)) + (zVel * carCos));

float slipAngle = Math.Atan2(latVel, longVel);


[Edited by - shiboujin on April 10, 2008 10:28:50 AM]
K_J_M
K_J_M
"
Q
thats in radians, do I need degrees for pacejka? I think it uses radians.
"

A
I dont think it's pacejka related, but dependant on the system your using.
If your system uses radians then you should think in terms of Radians and pass the slip angle to pacejka in radians.


"
Q
I actually managed to get the car's velocity by comparing where it was and where it is and it actually matched up with the vector within a certain margin of error (floating points I guess were the downfall). I also found the wheel's forward velocity by "rim velocity" from the physics engine I was using and the ratios seem about right. When speeding up, slip ratio is negative (tires going faster than the car) and when you slow down, its positive."

A
Yes, velocity is just a change of position over time.
So, just subtracting your current position from the position in the last pass of your code, would give the velocity for 1 pass of your code.

Acceleration is the change in velocity.


I'm not sure about how you're getting your Yaw angle. I would have thought your physics sim would have a simple instruction for that, Pitch, Yaw and Roll, unless it's using Quaternions for rotation.
In which case, a bit more math would be involved in order to get Yaw. But there are algorithms for converting between Quaternions and Euler.

Yaw is only needed in this example because the car is sitting on a flat plane, to keep things simple.

For a more advanced sim, you would need to take into account, a cars pitch and roll as well as yaw, ie, if it's positioned on a slope. In that case, you would need to calculate everything in 3d.


"I need to buy you a gift or something. Why havent you written a book?"

Well, i don't consider myself an expert, so i dont feel qualified to write a book. I'm sure there are much better car physics coders out there than me.
Trouble is, they all seem to keep there code to themselves. :(

KJM
shiboujin
shiboujin
I did a search for the word "quaternion" and came up with nothing. As far as I can tell, it uses matrix rotations. but theres no yaw/pitch/roll in the whole thing!

:( yaw is basically the last variable I need to get this working. omg!

Edit:
I found the original formula for yaw online somewhere. I mean it makes decent sense. Altho I think it should be sine but I dont know.

http://www.codeguru.com/forum/archive/index.php/t-329530.html
this page says its Atan2(M12, M11) but I'm not sure how reliable it is since he says yaw is rotation around x. I think that would be pitch. *shrugs*

Edit2:

Racer uses M31, M33 in the same fashion to get yaw. It could be using a different axis system though. Other combo's ive found are M23, M13, and if I got them backwards (yaw and roll) they could also be M12, M11 or M32, M31... I guess when I get home to my dev computer, ill try them out until I get the right value. But apparently this is the best way to extract euler type angles from a rotation matrix. Which (unless I'm wrong) is what I'm trying to do here.

[Edited by - shiboujin on April 10, 2008 2:20:29 PM]
K_J_M
K_J_M
Yeh ok. I understand.

The rotation matrix, if it's euler, should contain 3 direction vectors, all at right angles to each other, called Direction Cosines, and together specify 3 axis of rotation, so it should simply be a case of finding which axis is the yaw.
This should be a unit vector, x,y,z. From that, you can either use the Dot product to find the angle between that direction vector and your world frame axis to get the actual Yaw angle or the atan2 method described in your link.

I still think your physics engine should have a command to do that for you though. Every physics engine i've used has.

Also a quick link to Quaternions

http://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation

KJM

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.