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;
Car Physics: Questions about traction and grip
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!)
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.
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 !!!
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.