Source code for suboptimumg.vehicle.suspension.tire
import math
from ...constants import in_to_m
from ..models import VehicleModel
[docs]
class Tires:
def __init__(
self,
vehicle_model: VehicleModel,
):
self.vehicle_model = vehicle_model
self.params = self.vehicle_model.tires
self.fl, self.fr, self.bl, self.br = [Tire() for _ in range(4)]
self.list = [self.fl, self.fr, self.bl, self.br]
[docs]
def initialize_tires(
self, fl_norm: float, fr_norm: float, bl_norm: float, br_norm: float
):
self.fl.normal = fl_norm
self.fr.normal = fr_norm
self.bl.normal = bl_norm
self.br.normal = br_norm
[docs]
def reset_tires(
self, fl_norm: float, fr_norm: float, bl_norm: float, br_norm: float
):
for tire in self.list:
tire.reset()
self.fl.normal = fl_norm
self.fr.normal = fr_norm
self.bl.normal = bl_norm
self.br.normal = br_norm
[docs]
class Tire:
# TODO: redo the tire model
# assumes maximum slip ratio
def __init__(self):
self.normal = 1e-6 # normal force (N) default value
self.lateral = 0 # lateral grip (N)
self.longitudinal = 0 # longitudinal grip (N)
[docs]
def reset(self):
self.normal = 1e-6
self.lateral = 0
self.longitudinal = 0
[docs]
def calc_mu(self, mu_long_lat_ratio, mu_lat_zero_load):
"""
Calculate mu_lat and mu_long according to an equation fitted from TTC data.
Parameters
----------
mu_long_lat_ratio : float
Ratio of longitudinal to lateral friction coefficients (unitless)
mu_lat_zero_load : float
Lateral friction coefficient at zero normal force (unitless)
Returns
-------
float
mu_lat - Lateral friction coefficient
float
mu_long - Longitudinal friction coefficient
Notes
-----
Uses quadratic fit from TTC (Tire Test Consortium) data.
Returns (0, 0) if tire is lifted (normal force <= 0).
"""
mu_lat = (
-7.66113e-8 * self.normal**2 - 2.82666e-4 * self.normal + mu_lat_zero_load
)
mu_lat = max(mu_lat, 0) # Clip if bad
mu_long = mu_lat * mu_long_lat_ratio
if self.normal <= 0: # if the tire is lifted up, it has no grip.
return 0, 0
return mu_lat, mu_long
[docs]
def is_current_lateral_force_valid(self, mu_long_lat_ratio, mu_lat_zero_load):
"""
Check whether the requested lateral force results in oversaturating the tire.
Parameters
----------
mu_long_lat_ratio : float
Ratio of longitudinal to lateral friction coefficients (unitless)
mu_lat_zero_load : float
Lateral friction coefficient at zero normal force (unitless)
Returns
-------
bool
True if current lateral force is valid, False otherwise
Notes
-----
Should be called only after lateral force is correctly updated.
"""
mu_lat, _ = self.calc_mu(mu_long_lat_ratio, mu_lat_zero_load)
max_lat = self.normal * mu_lat
return self.lateral < max_lat
[docs]
def long_remain(self, mu_long_lat_ratio, mu_lat_zero_load):
"""
Calculates the remaining longitudinal grip of the tire based on a friction ellipse
ELLIPSE EQN:
(x^2 / radius_x^2) + (y^2 / radius_y^2) = n^2
(f_lat^2 / mu_lat^2) + (f_long^2 / mu_long^2) = f_normal^2
f_long = mu_long * sqrt( f_normal^2 - ( f_lat^2 / mu_lat^2 ) )
Returns:
float: Remaining longitudinal grip (N).
"""
# Calculate remaining longitudinal grip with friction ellipse
mu_lat, mu_long = self.calc_mu(mu_long_lat_ratio, mu_lat_zero_load)
grip_diff = self.normal**2 - (self.lateral**2 / mu_lat**2)
f_long = mu_long * (math.sqrt(grip_diff))
return f_long