Unity3D Коллайдер ПИД-регулятор? - PullRequest
1 голос
/ 01 февраля 2020

Я пытаюсь сделать ПИД-регулятор колесного коллайдера на основе следующего урока:

https://www.habrador.com/tutorials/pid-controller/1-car-follow-path/

Я внес изменение в метод FixedUpdate, чтобы измените направление рулевого управления на основе разности углов с помощью сплайн-путевой точки (если она определена в сценарии), а также попробуйте ввести режим «выбега» или «торможения» в зависимости от того, насколько быстро движется автомобиль и насколько узок угол поворота. очередь будет. В настоящее время «дрейф» устанавливает кривую трения колес на переменную жесткость трения между колесами вперед и вбок. Обычно, любой автомобиль имеет коэффициент боковой жесткости 2 на коллайдере, как здесь:

enter image description here

Теперь проблема в том, что трудно найти баланс идеальных настроек ПИД-регулятора и ожидаемого порога 1.) тормоза или выбег из-за угла поворота, который, возможно, выйдет из-под контроля 2.) "дрейф", когда угол наклона между двумя последующими путевыми точками впереди автомобиля составляет узкий угол для поворота автомобиля.

Вот мои текущие значения PID, честно говоря, я немного их настраивал (что, я знаю, в некоторой степени ожидается):

enter image description here

Вот соответствующий код - FixedUpdate l oop:

void FixedUpdate()
    {
        float motor = carControl.maxForwardTorque;

        //Manual controls for debugging
        //float motor = carControl.maxForwardTorque * im.throttle;
        //float steering = carControl.maxTurn * im.steer;

        //
        //Calculate the steering angle
        //
        //The simple but less accurate way -> will produce drunk behavior
        //float steeringAngle = maxSteeringAngle * Math.SteerDirection(transform, steerPosition, currentWaypoint);

        //Get the cross track error, which is what we want to minimize with the pid controller
        float CTE = AIVehicleMath.GetCrossTrackError(steerPosition, previousWaypoint, currentWaypoint);

        //But we still need a direction to steer
        if(splineWalker)
            CTE *= AIVehicleMath.SteerDirection(transform, steerPosition, splineWalker.transform.position);
        else
            CTE *= AIVehicleMath.SteerDirection(transform, steerPosition, currentWaypoint);

        float steeringAngle = PIDControllerScript.GetSteerFactorFromPIDController(CTE);

        //Limit the steering angle
        steeringAngle = Mathf.Clamp(steeringAngle, -carControl.maxTurn, carControl.maxTurn);

        //Average the steering angles to simulate the time it takes to turn the steering wheel
        float averageAmount = 30f;

        averageSteeringAngle = averageSteeringAngle + ((steeringAngle - averageSteeringAngle) / averageAmount);

        Debug.Log("Average steering angle is " + averageSteeringAngle);

        //
        //Apply everything to the car 
        //
        float signFactor = averageSteeringAngle/carControl.maxTurn;

        im.steer = signFactor;
        if (Mathf.Abs(averageSteeringAngle) > 15 && rb.velocity.magnitude > 15)
        {
            im.throttle = 0;
            im.brake = true;
        }
        else if (Mathf.Abs(averageSteeringAngle) > 5 && rb.velocity.magnitude > 15)
        {
            im.throttle = 0;
            im.brake = false;
        }
        else
        {
            im.throttle = 1;
            im.brake = false;
        }

        float currDistFromWP = Vector3.Distance(transform.position, allWaypoints[currentWaypointIndex].position);

        float speed = rb.velocity.magnitude;
        float timeFloatLeft = currDistFromWP / speed;

        Vector3 nextVector;
        Transform nodeA;
        Transform nodeB;
        if (currentWaypointIndex == allWaypoints.Count - 1)
        {
            nodeA = allWaypoints[currentWaypointIndex];
            nodeB = allWaypoints[0];
        }
        else
        {
            nodeA = allWaypoints[currentWaypointIndex];
            nodeB = allWaypoints[currentWaypointIndex + 1];
        }
        float distanceBetweenNextTwo = Vector3.Distance(nodeA.position, nodeB.position);
        float angleBetweenTwo = Vector3.Angle(transform.position, nodeB.position);

        if (currDistFromWP < 20 && angleBetweenTwo > 30)
            im.drift = true;
        else
            im.drift = false;
    }

Может кто-нибудь дать рекомендации о том, как я могу подойти к этому более эффективно, может быть? Независимо от того, что я делаю, машина продолжает вращаться в пьяном виде, даже когда я ограничиваю скорость до чего-то очень медленного, например, 10 или 20. И затем, конечно, представьте, что машина движется со скоростью 70 или 90! Сейчас это становится головной болью.

Цените любые предложения или комментарии. Еще раз спасибо.

...