Демонстрационная адаптация физики автомобилей Марко Монстра на C ++, машина ведет себя хаотично - PullRequest
1 голос
/ 20 марта 2019

Я пытаюсь принять демонстрацию по физике Marco Monster (документ: http://www.asawicki.info/Mirror/Car%20Physics%20for%20Games/Car%20Physics%20for%20Games.html и код ссылки C: https://github.com/spacejack/carphysics2d/blob/master/marco/Cardemo.c) в C ++. Я столкнулся с проблемой, что машина вращается вокруг себя и движется впередось непредсказуемым образом (так как он реагирует на входные данные, но непредсказуемо). Последние 4 дня я потратил на то, чтобы найти проблему и ничего не получил. Пожалуйста, помогите, поскольку я отчаялся с этим. Я разделил функциональностьавтомобиль на отдельные классы (для лучшего обслуживания) и сделал вывод, что проблема возникает в классе Wheel и в классе Car. Вот код:


Wheel.h

class Wheel
{

public:

    Wheel(const bool &isABSOn, const float &frontAxleToCG, const float &rearAxleToCG, const float &tireGripValue, const float &lockedTireGripCoef,
        const float &lateralStiffnessFront, const float &lateralStiffnessRear, const float &brakeForceCoef, const float &ebrakeForceCoef,
        const float &brakeTorque);

    void SetValues(bool &isEbrakeOn, float &drivetrainTorque, float &steeringAngle, float &brakingInput,
        float &frontAxleLoad, float &rearAxleLoad, float &surfaceCoefficient, float &angularVelocity, Vector2f &localVelocity);

    void Update();

    Vector2f GetSumForce();
    float GetLateralTorque();


private:

    bool m_IsEBrakeOn;
    const bool m_IsABSOn;

    float m_YawSpeed, m_VehicleAngularVelocity, m_VehicleRotationAngle, m_VehicleSideSlip, m_VehicleSlipAngleFrontAxle, m_VehicleSlipAngleRearAxle,
        m_VehicleSteeringAngleRadInput,
        m_SurfaceTypeGripCoefficient, m_DrivetrainTorqueNm, m_BrakingForceInputPercentage, m_FrontAxleLoad, m_RearAxleLoad;

    const float m_CGtoFrontAxle, m_CGtoRearAxle, m_BaseTireGripValue, m_LockedTireGripCoefficent, m_LateralStiffnessFront,
        m_LateralStiffnessRear, m_BreakForceCoefficent, m_EBrakeForceCoefficent, m_BrakeTorqueLimit, m_StableSpeedBoundary;

    Vector2f m_LocalVehicleVelocity, m_VehicleLateralForceFront, m_VehicleLateralForceRear, m_VehicleLongtitudonalForceRear;

    float FrontTireGripValue();
    float RearTireGripValue();
    float CombinedBrakingForceValueRearAxle();

};

Wheel.cpp

Wheel::Wheel(const bool &isABSOn, const float &frontAxleToCG, const float &rearAxleToCG, const float &tireGripValue, const float &lockedTireGripCoef,
const float &lateralStiffnessFront, const float &lateralStiffnessRear, const float &brakeForceCoef, const float &ebrakeForceCoef,
const float &brakeTorque)
: m_IsABSOn{ isABSOn }
, m_CGtoFrontAxle{ frontAxleToCG }
, m_CGtoRearAxle{ rearAxleToCG }
, m_BaseTireGripValue{ tireGripValue }
, m_LockedTireGripCoefficent{ lockedTireGripCoef }
, m_LateralStiffnessFront { lateralStiffnessFront }
, m_LateralStiffnessRear{ lateralStiffnessRear }
, m_BreakForceCoefficent{ brakeForceCoef }
, m_EBrakeForceCoefficent{ ebrakeForceCoef }
, m_BrakeTorqueLimit{ brakeTorque }
, m_StableSpeedBoundary{ 40.f } {}

   void Wheel::Update()
{
    if ((-0.01f < m_LocalVehicleVelocity.x) || (m_LocalVehicleVelocity.x < 0.01f))
    {
        m_YawSpeed = 0.f;
    }
    else
    {
        m_YawSpeed = ((m_CGtoFrontAxle + m_CGtoRearAxle) / 2.f) * m_VehicleAngularVelocity;
    }

    if ((-0.01f < m_LocalVehicleVelocity.x) || (m_LocalVehicleVelocity.x < 0.01f))
    {
        m_VehicleRotationAngle = 0.f;
    }
    else
    {
        m_VehicleRotationAngle = std::atan2(m_YawSpeed, m_LocalVehicleVelocity.x);
    }

    if ((-0.01f < m_LocalVehicleVelocity.x) || (m_LocalVehicleVelocity.x < 0.01f))
    {
        m_VehicleSideSlip = 0.f;
    }
    else
    {
        m_VehicleSideSlip = std::atan2(m_LocalVehicleVelocity.y, m_LocalVehicleVelocity.x);
    }

    m_VehicleSlipAngleFrontAxle = m_VehicleSideSlip + m_VehicleRotationAngle - m_VehicleSteeringAngleRadInput;
    m_VehicleSlipAngleRearAxle = m_VehicleSideSlip - m_VehicleRotationAngle;

    m_VehicleLateralForceFront.x = 0.f;
    m_VehicleLateralForceFront.y = m_LateralStiffnessFront * m_VehicleSlipAngleFrontAxle;
    m_VehicleLateralForceFront.y = std::fminf(FrontTireGripValue(), m_VehicleLateralForceFront.y);
    m_VehicleLateralForceFront.y = std::fmaxf(-FrontTireGripValue(), m_VehicleLateralForceFront.y);
    m_VehicleLateralForceFront.y *= m_FrontAxleLoad;

    m_VehicleLateralForceRear.x = 0.f;
    m_VehicleLateralForceRear.y = m_LateralStiffnessRear * m_VehicleSlipAngleRearAxle;
    m_VehicleLateralForceRear.y = std::fminf(RearTireGripValue(), m_VehicleLateralForceRear.y);
    m_VehicleLateralForceRear.y = std::fmaxf(-RearTireGripValue(), m_VehicleLateralForceRear.y);
    m_VehicleLateralForceRear.y *= m_RearAxleLoad;

    m_VehicleLongtitudonalForceRear.x = m_SurfaceTypeGripCoefficient * (m_DrivetrainTorqueNm - (CombinedBrakingForceValueRearAxle() * utils::Sign(m_LocalVehicleVelocity.x)));
    m_VehicleLongtitudonalForceRear.y = 0.f;
}

Vector2f Wheel::GetSumForce()
{
    if (m_LocalVehicleVelocity.Length() < 1.0f && m_DrivetrainTorqueNm < 0.5f)
    {
        m_LocalVehicleVelocity.x = m_LocalVehicleVelocity.y = 0.f;
        m_VehicleLateralForceFront.x = m_VehicleLateralForceFront.y = m_VehicleLateralForceRear.x = m_VehicleLateralForceRear.y = 0.f;
    }

    return Vector2f
    {
        m_VehicleLongtitudonalForceRear.x + std::sinf(m_VehicleSteeringAngleRadInput) * m_VehicleLateralForceFront.x + m_VehicleLateralForceRear.x,
        m_VehicleLongtitudonalForceRear.y + std::cosf(m_VehicleSteeringAngleRadInput) * m_VehicleLateralForceFront.y + m_VehicleLateralForceRear.y
    };
}

float Wheel::GetLateralTorque()
{
    return m_CGtoFrontAxle * m_VehicleLateralForceFront.y - m_CGtoRearAxle * m_VehicleLateralForceRear.y;
}

void  Wheel::SetValues(bool &isEbrakeOn, float &drivetrainTorque, float &steeringAngle, float &brakingInput,
    float &frontAxleLoad, float &rearAxleLoad, float &surfaceCoefficient, float &angularVelocity, Vector2f &localVelocity)
{
    m_IsEBrakeOn = isEbrakeOn;
    m_DrivetrainTorqueNm = drivetrainTorque;
    m_VehicleSteeringAngleRadInput = steeringAngle;
    m_BrakingForceInputPercentage = brakingInput;
    m_FrontAxleLoad = frontAxleLoad;
    m_RearAxleLoad = rearAxleLoad;
    m_SurfaceTypeGripCoefficient = surfaceCoefficient;
    m_LocalVehicleVelocity = localVelocity;
    m_VehicleAngularVelocity = angularVelocity;
}

float Wheel::CombinedBrakingForceValueRearAxle()
{
    return (m_BrakeTorqueLimit * m_BrakingForceInputPercentage);
}

float Wheel::FrontTireGripValue()
{
    return m_BaseTireGripValue * m_SurfaceTypeGripCoefficient;
}

float Wheel::RearTireGripValue()
{
    if ((CombinedBrakingForceValueRearAxle() > m_DrivetrainTorqueNm) && (!m_IsABSOn) && (m_LocalVehicleVelocity.Length() > m_StableSpeedBoundary))
    {
        return m_BaseTireGripValue * m_LockedTireGripCoefficent * m_SurfaceTypeGripCoefficient;
    }
    else
    {
        return m_BaseTireGripValue * m_SurfaceTypeGripCoefficient;
    }
}

Car.h

class Car
{

public:

    Car(VehicleCfg *pVehicleSpecs);

    InputControl *m_pThisSteeringAndPedals;

    void Draw() const;
    void Update(float &elapsedSec);

private:

    bool m_NOSStatus, m_IsEBrakeOn;

    int m_GearShifterInput;

    float m_VehicleThrottleInpute, m_VehicleSteeringAngleRadInput, m_VehicleBrakeInput, 
        m_DrivetrainTorqueOutput, m_FrontAxleLoad, m_RearAxleLoad,
        m_ElapsedSec, m_VehicleHeadingDirectionAngleRad, m_CSHeading, m_SNHeading,
        m_VehicleRotationAngle, m_YawSpeed, m_VehicleAngularVelocity, m_VehicleSideSlip,
        m_VehicleSlipAngleFrontAxle, m_VehicleSlipAngleRearAxle,
        m_SurfaceCoefficent, m_AngularTorque, m_AngularAcceleration, m_VehicleHealthStatus;

    const float m_FrontToCG, m_RearToCG, m_CarMass, m_Inertia, m_RollingResistance, m_DragCoefficient;

    Point2f m_WorldVehicleCoordinate;

    Vector2f m_LocalVehicleVelocity, m_WorldVehicleVelocity, m_VehicleLocalAcceleration, m_VehicleWorldAcceleration,
        m_WheelForces, m_ResistanceForces, m_TotalForce;

    Suspension *m_pThisSuspension;
    Drivetrain *m_pThisDrivetrain;  
    Wheel *m_pThisWheel;
    ModularRenderer *m_pThisVehicleDrawn;

};

Car.cpp

void Car::Update(float &elapsedSec)
{
    m_ElapsedSec = elapsedSec;

    m_GearShifterInput = m_pThisSteeringAndPedals->GetCurrentGearValue();
    m_VehicleThrottleInpute = m_pThisSteeringAndPedals->GetCurrentThrottleValue(m_ElapsedSec, m_VehicleThrottleInpute);
    m_VehicleSteeringAngleRadInput = m_pThisSteeringAndPedals->GetCurrentSteeringValue(m_ElapsedSec);
    m_VehicleBrakeInput = m_pThisSteeringAndPedals->GetCurrrentBrakeValue(m_ElapsedSec);
    m_NOSStatus = m_pThisSteeringAndPedals->GetIsNOSOnValue();
    m_IsEBrakeOn = m_pThisSteeringAndPedals->GetIsEBrakeOnValue();

    m_CSHeading = std::cosf(m_VehicleHeadingDirectionAngleRad);
    m_SNHeading = std::sinf(m_VehicleHeadingDirectionAngleRad);

    m_LocalVehicleVelocity.x = m_CSHeading * m_WorldVehicleVelocity.y + m_SNHeading * m_WorldVehicleVelocity.x;
    m_LocalVehicleVelocity.y = -m_SNHeading * m_WorldVehicleVelocity.y + m_CSHeading * m_WorldVehicleVelocity.x;

    m_pThisDrivetrain->SetValues(m_NOSStatus, m_GearShifterInput, m_VehicleThrottleInpute, m_LocalVehicleVelocity.Length());
    m_DrivetrainTorqueOutput = m_pThisDrivetrain->GetDrivetrainOutput(m_ElapsedSec);

    m_pThisSuspension->SetValues(m_VehicleLocalAcceleration, m_LocalVehicleVelocity.Length());
    m_FrontAxleLoad = m_pThisSuspension->GetFrontAxleWeight();
    m_RearAxleLoad = m_pThisSuspension->GetRearAxleWeight();


    m_pThisWheel->SetValues(m_IsEBrakeOn, m_DrivetrainTorqueOutput, m_VehicleSteeringAngleRadInput, m_VehicleBrakeInput, m_FrontAxleLoad,
        m_RearAxleLoad, m_SurfaceCoefficent, m_VehicleAngularVelocity, m_LocalVehicleVelocity);
    m_pThisWheel->Update();
    m_WheelForces = m_pThisWheel->GetSumForce();
    m_AngularTorque = m_pThisWheel->GetLateralTorque();

    m_ResistanceForces.x = -((m_RollingResistance * m_LocalVehicleVelocity.x) + (m_DragCoefficient * m_LocalVehicleVelocity.x * std::abs(m_LocalVehicleVelocity.x)));
    m_ResistanceForces.y = -((m_RollingResistance * m_LocalVehicleVelocity.y) + (m_DragCoefficient * m_LocalVehicleVelocity.y * std::abs(m_LocalVehicleVelocity.y)));

    m_TotalForce.x = m_WheelForces.x + m_ResistanceForces.x;
    m_TotalForce.y = m_WheelForces.y + m_ResistanceForces.y;

    m_VehicleLocalAcceleration.x = m_TotalForce.x / m_CarMass;
    m_VehicleLocalAcceleration.y = m_TotalForce.y / m_CarMass;

    if (m_WorldVehicleVelocity.Length() < 1.0f && m_VehicleThrottleInpute < 0.5f)
    {
        m_LocalVehicleVelocity.x = m_LocalVehicleVelocity.y = 0.f;
        m_VehicleAngularVelocity = m_AngularTorque = m_AngularAcceleration = 0.f;
    }

    m_AngularAcceleration = m_AngularTorque / m_Inertia;

    m_VehicleWorldAcceleration.x = m_CSHeading * m_VehicleLocalAcceleration.y + m_SNHeading * m_VehicleLocalAcceleration.x;
    m_VehicleWorldAcceleration.y = -(m_SNHeading) * m_VehicleLocalAcceleration.y + m_CSHeading * m_VehicleLocalAcceleration.x;

    m_WorldVehicleVelocity.x += m_ElapsedSec * m_VehicleWorldAcceleration.x;
    m_WorldVehicleVelocity.y += m_ElapsedSec * m_VehicleWorldAcceleration.y;

    m_WorldVehicleCoordinate.x += m_ElapsedSec * m_WorldVehicleVelocity.x;
    m_WorldVehicleCoordinate.y += m_ElapsedSec * m_WorldVehicleVelocity.y;

    std::cout << "m_WorldVehicleCoordinate: " << m_WorldVehicleCoordinate.x << ", " << m_WorldVehicleCoordinate.y << "\n";

    m_VehicleAngularVelocity += m_ElapsedSec * m_AngularAcceleration;

    m_VehicleHeadingDirectionAngleRad += m_ElapsedSec * m_VehicleAngularVelocity;

    m_pThisVehicleDrawn->SetVariables(int(0), int(0), int(0), int(0), m_VehicleHeadingDirectionAngleRad, m_VehicleSteeringAngleRadInput, m_WorldVehicleCoordinate);

}

void Car::Draw() const
{
    m_pThisVehicleDrawn->DrawTheVehicle();
}

Я думаю, что ошибка возникает из-за какой-то особенности, которая возникает в вычислениях, но я не вижу, где это происходит.

1 Ответ

1 голос
/ 20 марта 2019

Так как машина вращается, я посмотрел на ваше использование угловой скорости. Значение m_VehicleAngularVelocity не инициализируется ни в одном классе, поэтому оно имеет неопределенное значение. Единственный раз, когда для него установлено значение, вы проверяете, остановили ли автомобиль.

Непредсказуемое движение, вероятно, является аналогичной проблемой.

Вы должны инициализировать всех членов вашего класса в конструкторе, чтобы избежать этих проблем.

Почему Wheel::SetValues принимает все свои параметры по ссылке? Поскольку они просто копируют их во внутренние переменные, а они являются базовыми типами, просто передайте их по значению.

...