ПИД-контроллер в C # Micro Framework проблем - PullRequest
1 голос
/ 05 февраля 2012

Я построил трехколесный с нуля на основе платы .NET Micro Framework от TinyCLR.com.Я использовал FEZ Mini , который работает на 72 МГц.Узнайте больше о моем проекте по адресу: http://bit.ly/TriRot.

Итак, после проверки перед полетом, где я инициализирую и испытываю каждый компонент, например, калибрую IMU и вращаю каждый двигатель, проверяя, что я получаюданные приемника и т. д. он входит в постоянный цикл, который затем вызывает метод контроллера полета в каждом цикле.

Я пытаюсь настроить свой ПИД-регулятор , теперь используя ЦиглераМетод Николса , но я всегда получаю все больше и больше промахов.В конце концов я смог получить [в основном] стабильные колебания, используя только пропорциональное управление (настройка K i и K d = 0);хронометраж периода K с секундомером в среднем составил 3,198 секунды.

Я наткнулся на ответ ( Рекс Логан ) на аналогичный вопрос chris12892 .

Первоначально я использовал переменную "Duration" в миллисекундах, что сделало мой коптер очень агрессивным, очевидно, потому что я умножал ошибку работающего интегратора на тысячи в каждом цикле.Затем я разделил его еще на тысячу, чтобы довести до секунд, но я все еще сражаюсь ...

Чего я не понимаю из ответа Рекса:

  1. Почемуон игнорирует переменную времени в интегральной и дифференциальной частях уравнений?Правильно ли это или это опечатка?
  2. Что он подразумевает под замечанием

    В обычной системе выборки дельта-член будет равен единице ...

    Один что?Должна ли это быть одна секунда при нормальных обстоятельствах?Что, если это значение колеблется?

Мой метод управления полетом ниже:

private static Single[] FlightController(Single[] imuData, Single[] ReceiverData)
{
    Int64 TicksPerMillisecond = TimeSpan.TicksPerMillisecond;
    Int64 CurrentTicks = DateTime.Now.Ticks;
    Int64 TickCount = CurrentTicks - PreviousTicks;
    PreviousTicks = CurrentTicks;
    Single Duration = (TickCount / TicksPerMillisecond) / 1000F;

    const Single Kp = 0.117F; //Proportional Gain (Instantaneou offset)
    const Single Ki = 0.073170732F; //Integral Gain (Permanent offset)
    const Single Kd = 0.001070122F; //Differential Gain (Change in offset)

    Single RollE = 0;
    Single RollPout = 0;
    Single RollIout = 0;
    Single RollDout = 0;
    Single RollOut = 0;
    Single PitchE = 0;
    Single PitchPout = 0;
    Single PitchIout = 0;
    Single PitchDout = 0;
    Single PitchOut = 0;

    Single rxThrottle = ReceiverData[(int)Channel.Throttle];
    Single rxRoll = ReceiverData[(int)Channel.Roll];
    Single rxPitch = ReceiverData[(int)Channel.Pitch];
    Single rxYaw = ReceiverData[(int)Channel.Yaw];

    Single[] TargetMotorSpeed = new Single[] { rxThrottle, rxThrottle, rxThrottle };
    Single ServoAngle = 0;

    if (!FirstRun)
    {
        Single imuRoll = imuData[1] + 7;
        Single imuPitch = imuData[0];

        //Roll ----- Start
        RollE = rxRoll - imuRoll;

        //Proportional
        RollPout = Kp * RollE;

        //Integral
        Single InstanceRollIntegrator = RollE * Duration;
        RollIntegrator += InstanceRollIntegrator;
        RollIout = RollIntegrator * Ki;

        //Differential
        RollDout = ((RollE - PreviousRollE) / Duration) * Kd;

        //Sum
        RollOut = RollPout + RollIout + RollDout;
        //Roll ----- End

        //Pitch ---- Start
        PitchE = rxPitch - imuPitch;
        //Proportional
        PitchPout = Kp * PitchE;

        //Integral
        Single InstancePitchIntegrator = PitchE * Duration;
        PitchIntegrator += InstancePitchIntegrator;
        PitchIout = PitchIntegrator * Ki;

        //Differential
        PitchDout = ((PitchE - PreviousPitchE) / Duration) * Kd;

        //Sum
        PitchOut = PitchPout + PitchIout + PitchDout;
        //Pitch ---- End

        TargetMotorSpeed[(int)Motors.Motor.Left] += RollOut;
        TargetMotorSpeed[(int)Motors.Motor.Right] -= RollOut;

        TargetMotorSpeed[(int)Motors.Motor.Left] += PitchOut;// / 2;
        TargetMotorSpeed[(int)Motors.Motor.Right] += PitchOut;// / 2;
        TargetMotorSpeed[(int)Motors.Motor.Rear] -= PitchOut;

        ServoAngle = rxYaw + 15;

        PreviousRollE = imuRoll;
        PreviousPitchE = imuPitch;
    }
    FirstRun = false;

    return new Single[] { 
    (Single)TargetMotorSpeed[(int)TriRot.LeftMotor], 
    (Single)TargetMotorSpeed[(int)TriRot.RightMotor], 
    (Single)TargetMotorSpeed[(int)TriRot.RearMotor],
    (Single)ServoAngle
    };
}

Редактировать: Я обнаружил, что у меня есть две ошибкимой код выше (исправлено сейчас).Я интегрировал и дифференцировал последние значения IMU, а не последние значения ошибок.Это полностью избавило от безудержной ситуации.Единственная проблема сейчас в том, что она кажется немного медленной.Когда я нарушаю работу системы, она очень быстро реагирует и останавливает ее продолжение, но для возврата к заданному значению (0) требуется много времени, около 10 секунд или более.Это теперь просто до настройки PID?Ниже я приведу предложения и сообщу, если какие-то из них будут иметь значение.

У меня есть один вопрос: являясь доской .NET, я не хочу делать ставку на что-либоточной синхронизации, поэтому вместо того, чтобы пытаться определить, на какой частоте я выполняю этот метод, конечно, если я вычисляю фактическое время и коэффициент, который в уравнениях, это должно быть лучше, или я что-то неправильно понимаю?

...