Car Physics: Questions about traction and grip

Started by
5 comments, last by bmarci 8 years, 7 months ago
Hello all!
I have been working on a simple top-down 2D car simulator and have some questions to anyone who is experienced with this. The main problem I have is how to simulate a wheel losing grip. I have been reading Brian Beckman's series on racing and I understand that the tires have an adhesive limit and that the circle/ellipsis of traction can be used to know whether a wheel is gripping or not. Am I right to presume that the amount of traction on a tire needs to be capped to the circle? This is my per-frame code at the moment:

float speed = glm::length(velocity_local);

// Calculate weight distribution.
float weight = description.mass * G;
float wheelbase = description.cg_to_front_axle + description.cg_to_back_axle;
float front_weight = (description.cg_to_back_axle / wheelbase) * weight - (description.cg_height / wheelbase) * description.mass * acceleration_local.x;
float rear_weight = (description.cg_to_front_axle / wheelbase) * weight + (description.cg_height / wheelbase) * description.mass * acceleration_local.x;

// Assume the wheels are rolling and calculate the engine torque.
float wheel_angular_velocity = velocity_local.x / description.wheel_radius;
float transmission = description.gear_ratios[gear] * description.differential_ratio * description.transmission_efficiency;
float engine_rpm = ANGULAR_VELOCITY_TO_RPM * wheel_angular_velocity * transmission;
float engine_torque = throttle ? lerp_curve(description.torque_curve, engine_rpm) : 0.0f;

// Simplified traction model - use the torque on the wheels.
float drive_torque = engine_torque * transmission;
float traction_force = drive_torque / description.wheel_radius;

// Calculate the braking torque on the wheels.
float braking_torque = reverse ? 3500 : 0;
float braking_force = -braking_torque / description.wheel_radius * glm::sign(velocity_local.x);

// Calculate the lateral slip angles and determine the lateral cornering force.
float front_angular_velocity = car_angular_velocity * description.cg_to_front_axle;
float rear_angular_velocity = -car_angular_velocity * description.cg_to_back_axle;

float slip_angle_front = std::atan2(velocity_local.y + front_angular_velocity, std::abs(velocity_local.x)) - glm::sign(velocity_local.x) * steer_angle;
float slip_angle_rear  = std::atan2(velocity_local.y + rear_angular_velocity,  std::abs(velocity_local.x));

float cornering_force_front = front_weight * -description.cornering_stiffness * slip_angle_front;
float cornering_force_rear = rear_weight * -description.cornering_stiffness * slip_angle_rear;

// The wheels have a limited maximal traction before they start to slide.
float traction_circle_radius = 0.8;

glm::vec2 front_total_traction = glm::vec2(0, cornering_force_front * std::cos(steer_angle));
glm::vec2 rear_total_traction = glm::vec2(traction_force + braking_force, cornering_force_rear);

bool front_slipping = false;
float front_total_traction_length = glm::length(front_total_traction);
if (front_total_traction_length / front_weight >= traction_circle_radius)
{
    front_total_traction /= front_total_traction_length;
    front_total_traction *= traction_circle_radius * front_weight;
    front_slipping = true;
}

bool rear_slipping = false;
float rear_total_traction_length = glm::length(rear_total_traction);
if (rear_total_traction_length / rear_weight >= traction_circle_radius)
{
    rear_total_traction /= rear_total_traction_length;
    rear_total_traction *= traction_circle_radius * rear_weight;
    rear_slipping = true;
}

// Calculate the torque on the car body and integrate car yaw rate and orientation.
float cornering_torque_front = front_total_traction.y * description.cg_to_front_axle;
float cornering_torque_rear = rear_total_traction.y * description.cg_to_back_axle;
float car_torque = std::cos(steer_angle) * cornering_torque_front - cornering_torque_rear;

float car_angular_acceleration = car_torque / description.inertia;
car_angular_velocity += car_angular_acceleration * dt;
orientation += car_angular_velocity * dt;

// Calculate the wind drag force on the car. Simplification that the area facing the velocity direction is the front.
float area = description.height * 2.0f * description.halfwidth;
float drag_multiplier = 0.5f * description.air_density * area * description.drag_coefficient;
glm::vec2 drag_resistance = -drag_multiplier * speed * velocity_local;

// Calculate the rolling friction force on the car.
glm::vec2 rolling_resistance = glm::vec2(-description.wheel_rolling_friction * velocity_local.x, 0);

// Sum the forces on the car's CG and integrate the velocity.
glm::vec2 force = rear_total_traction + front_total_traction + drag_resistance + rolling_resistance;

acceleration_local = force / description.mass;
velocity_local += acceleration_local * dt;

// Calculate the acceleration and velocity in world coordinates and integrate world position.
float sn = std::sin(orientation);
float cs = std::cos(orientation);

acceleration.x = cs * acceleration_local.x - sn * acceleration_local.y;
acceleration.y = sn * acceleration_local.x + cs * acceleration_local.y;
velocity.x = cs * velocity_local.x - sn * velocity_local.y;
velocity.y = sn * velocity_local.x + cs * velocity_local.y;

position += velocity * dt;
This gets me a car that can accelerate and steer, however the tires never seem to lose grip the way I expect them to. I can move at 200 km/h and make a abrupt turn without spinning (the car simply moves in approximately the same arc as when going slow). Am I missing some step to simulate a sliding car apart from capping the traction?
Also, as a side question, is using the torque on the rear wheels as the forward traction force an acceptable approximation? I saw this being done in "on the envelope" calculations by Brian, ignoring slip ratios and wheel turn rate integration. However, I am not sure how correct this actually is.
Any input is appreciated!

Advertisement

Did you take into account that surfaces coefficient of friction depends whether its sliding or stationary (always lower when sliding)?

For example does it work if you greatly reduce the friction when sliding (assuming the sliding is actually triggered in the first place!)

o3o

That makes intuitive sense to me, but I am not sure where it would fit in. No resources I have looked at has had an explicit opposing friction force (apart from rolling friction). It feels like the radius of the circle of traction would be smaller when the car starts to slide (making the maximum forward/backward traction and cornering forces smaller which makes it more difficult to correct the car trajectory). However, I need to check versus the circle to know whether I am sliding... So, either I am wrong in how I am detecting when the car starts to slide, or I will need a state that remains across frames.

The model you are probably looking for is the Pacejka model https://en.wikipedia.org/wiki/Hans_B._Pacejka

I have not tried to implement tire physics but was active in sim racing for a long time and have seen the various attempts to get tires right, most are a compromise tbh.

The tire model is only part of the work though as you need things like the changes in wheel positions that the different types of suspension system bring under load, sprung weight shifts and even tire flex under lateral G all effect grip levels.

That said for a top down I believe the Pacejka without the rest should give you a fun representation of car control that does what you are looking for in a believable way

Thank you for the reply! I have encountered the Pacejka model before when researching, but it seemed like it was mostly used for more realistic simulations when I feel like there should be relatively simple model to get a car to lose grip when the traction exceeds the maximum friction. I might look into it again and actually implement it, but I am hesitant to complicate the model with magic equations before I have a working simple model. Additionally, I have also tried to keep track of the wheel spin and calculate the slip ratio before (as I believe is an input to the Pacejka formulas), but it always ended up being rather unstable as the traction could change pretty drastically for low slip ratios and cause the wheel spin to fluctuate.

Hi, for a 2d car you can start with a simple linear model with some limit at max grip. And scaling it with normal load and a magic number, let's call it grip factor.

f=min(1, slip*10) * fz * mu

where;
f - resultant force
fz - weight on the wheel
mu - grip factor
slip - slipangle or ratio

the *10 is just a scale, so the tire reaches the limit at slip=0.1 you get the idea ;)

if you separate it to two different versions, for longitudinal and lateral, you can have a pretty nice handling

the fz can be an importanf factor if you calculate dynamic weight transfer, this will decrease grip on inside wheels when turning, so on rear wheels when braking, thus makink it spin out easier...etc.

hope this helped a bit

f=min(1, slip*10) * fz * mu


of course, this works only one direction, you must trim the slip value between -1 and 1 !!!

This topic is closed to new replies.

Advertisement