The Wheel Physics

You know how hard it is to get the physics right?

First you need the right forumla. You then need to convert them to code. That all doesn’t work if you don’t apply them properly. And sometimes it just becomes off.

So getting to the point of this post. (This guide will not go into getting the values below like wheel radSec, there are guides for them already)

Wheel traction as its the only part of the car that (should) touch the ground is fairly important in a car physics simulation - there are people who say that its half the battle. Well to do this there is something called the ‘magic forumla’. One of the versions of this formula requires ~12 of these numbers. As someone who cares slightly less about the accuracy and more about fun, i can use a simplified version that looks like this:

magic(slip, Fz) = Fz * D * sin(C * atan(B*slip - E * (B*slip - atan(B*slip))))

With parameters [Fz, B, C, D, E, slip], with basic values: B = 10, C = 2, D = 1, E = 1. Fz is the normal force on the tyre (can be guessed at a quarter of the weight of the car).

As seen here: a curve

If you want to see this function in action, i have a development file for testing the values here using Geogebra: here

But it basically peaks somewhere near slip = 0.1 - 0.3, and drops off after that, think a curvy static vs kinetic friction graph.

Slip is calculated from 2 different values from the 2 directions on the wheel - latitudinal (slipangle) and longitudinal (slipratio). Slipangle is the angle between the the angle of the tyre and the angle of the car, like this:

slipangle = atan((vel.x [+|-] yawspeed*wheel_Offset) / vel.length()) - steeringCur
With [vel.x = car velocity sideways (m/s), [+ -] = front or rear, yawspeed = rotation (rad/s), wheel_Offset = wheel distance from the center allong the car), vel.length = total velocity, steeringCur = angle of turning only on front wheels]

Slipratio is the ratio between the velocity of the car and the velocity of the bottom of the tyre:

slipratio = (radSec*wheel_radius - vel.z) / vel.length()

With [radSec = wheel rotation speed (rad/sec), vel.z = velocity in current direction, others obvious or already defined]

So after all that you input the values into the forumla, the result is the force on the tyre in each direction (x and y).

But you say: ‘What happens we join them together, shouldn’t they affect each other?’.

And you’d be right. Because currently the result is that you could max both of the directions and get sqrt(2) force instead of 1.

So how do you mix them, the formulas are seperate systems? Well you need to do some more work before you even get to use the formula. And it turns out there is this fancy math thing you can do that allows you to scale them based on how close they are to their maximum and it looks like this: First you need the maximum of the magic forumla for your constants, people who know maths would usually first guess the first derivative being 0. But that formula with the embedded atans does NOT have a nice derivative - at all. So i made an appoximation using the newtons method of getting the maxmium (which should be 1 if Fz and D are 1). Called ‘maxratio’ and ‘maxangle’. So next you divide the slipratio and slipangle by the max. Calulate a rho:

p = sqrt((slipratio/maxratio)^2 + (slipangle/maxangle)^2)

Use the magic forumla and give it:

latForce = ((slipangle/maxangle)/p)*magic(p*maxangle, Fz)
longForce = ((slipratio/maxratio)/p)*magic(p*maxratio, Fz)

This makes sure ‘using maths’ that they are dependant on each other.

If you wanted to play this game is avaliable on the link game link on the page

Mostly me (with some massive help from a friend who knows more math than me)


As an aside, you might notice that slipangle and slipratio both rely on velocty. This means at slow speeds the values jump around alot, but thats a whole other problem..