126 lines
4.1 KiB
C#
126 lines
4.1 KiB
C#
namespace Car_simulation
|
|
{
|
|
public class WheelSystem
|
|
{
|
|
// Physical properties
|
|
public float Radius { get; set; } = 0.3f; // meters
|
|
public float WheelInertia { get; set; } = 2.0f; // kg·m² per wheel
|
|
public float CarMass { get; set; } = 1500f; // kg - Car mass integrated into wheel system
|
|
|
|
public int WheelCount { get; set; } = 4;
|
|
public int DrivenWheels { get; set; } = 2; // 2WD
|
|
|
|
// State
|
|
public float TotalEnergy { get; set; } = 0f; // Joules (rotational + translational)
|
|
public float AngularVelocity => GetOmega();
|
|
public float RPM => GetRPM();
|
|
public float CarSpeed => GetCarSpeed(); // Now returns actual car speed
|
|
|
|
public float ResistanceTorque { get; set; } = 0f;
|
|
|
|
// Calculations
|
|
public float GetTotalRotationalInertia()
|
|
{
|
|
return WheelInertia * WheelCount;
|
|
}
|
|
|
|
public float GetEquivalentCarInertia()
|
|
{
|
|
// Convert car mass to equivalent rotational inertia at wheels
|
|
// I = m * r² (from v = ω * r, so KE_translational = 0.5 * m * v² = 0.5 * m * (ωr)² = 0.5 * m * r² * ω²)
|
|
return CarMass * Radius * Radius;
|
|
}
|
|
|
|
public float GetTotalInertia()
|
|
{
|
|
// Total inertia = rotational inertia of wheels + equivalent inertia of car mass
|
|
return GetTotalRotationalInertia() + GetEquivalentCarInertia();
|
|
}
|
|
|
|
public float GetOmega()
|
|
{
|
|
if (TotalEnergy <= 0 || GetTotalInertia() <= 0) return 0f;
|
|
return MathF.Sqrt(2f * TotalEnergy / GetTotalInertia());
|
|
}
|
|
|
|
public float GetRPM()
|
|
{
|
|
return AngularVelocity * PhysicsUtil.RAD_PER_SEC_TO_RPM;
|
|
}
|
|
|
|
public float GetCarSpeed()
|
|
{
|
|
// v = ω * r (no slip assumed for base calculation)
|
|
return AngularVelocity * Radius;
|
|
}
|
|
|
|
public float GetRotationalEnergy()
|
|
{
|
|
// Just the energy from wheel rotation
|
|
float omega = GetOmega();
|
|
return 0.5f * GetTotalRotationalInertia() * omega * omega;
|
|
}
|
|
|
|
public float GetTranslationalEnergy()
|
|
{
|
|
// Just the energy from car motion
|
|
float speed = GetCarSpeed();
|
|
return 0.5f * CarMass * speed * speed;
|
|
}
|
|
|
|
public float GetEnergyFromSpeed(float speed)
|
|
{
|
|
// Calculate total energy for given car speed
|
|
// Total energy = rotational energy of wheels + translational energy of car
|
|
float omega = speed / Radius;
|
|
float rotationalEnergy = 0.5f * GetTotalRotationalInertia() * omega * omega;
|
|
float translationalEnergy = 0.5f * CarMass * speed * speed;
|
|
return rotationalEnergy + translationalEnergy;
|
|
}
|
|
|
|
public void SetSpeed(float speed)
|
|
{
|
|
TotalEnergy = GetEnergyFromSpeed(speed);
|
|
}
|
|
|
|
// Apply work to the entire system (wheels + car)
|
|
public void ApplyWork(float work)
|
|
{
|
|
TotalEnergy += work;
|
|
TotalEnergy = Math.Max(TotalEnergy, 0);
|
|
}
|
|
|
|
public void ApplyTorque(float torque, float deltaTime)
|
|
{
|
|
if (torque == 0) return;
|
|
float work = torque * AngularVelocity * deltaTime;
|
|
ApplyWork(work);
|
|
}
|
|
|
|
public void ApplyResistance(float deltaTime)
|
|
{
|
|
if (ResistanceTorque <= 0 || AngularVelocity == 0) return;
|
|
|
|
float omega = AngularVelocity;
|
|
|
|
if (MathF.Abs(omega) < 0.1f)
|
|
{
|
|
// Static friction - return without applying resistance to allow startup
|
|
return;
|
|
}
|
|
|
|
float resistanceSign = -MathF.Sign(omega);
|
|
float alpha = (resistanceSign * ResistanceTorque) / GetTotalInertia();
|
|
|
|
float omegaNew = omega + alpha * deltaTime;
|
|
|
|
if (MathF.Sign(omegaNew) != MathF.Sign(omega))
|
|
{
|
|
omegaNew = 0;
|
|
}
|
|
|
|
float energyNew = 0.5f * GetTotalInertia() * omegaNew * omegaNew;
|
|
TotalEnergy = Math.Max(energyNew, 0);
|
|
}
|
|
}
|
|
} |