Я построил трехколесный с нуля на основе платы .NET Micro Framework от TinyCLR.com.Я использовал FEZ Mini , который работает на 72 МГц.Узнайте больше о моем проекте по адресу: http://bit.ly/TriRot.
Итак, после проверки перед полетом, где я инициализирую и испытываю каждый компонент, например, калибрую IMU и вращаю каждый двигатель, проверяя, что я получаюданные приемника и т. д. он входит в постоянный цикл, который затем вызывает метод контроллера полета в каждом цикле.
Я пытаюсь настроить свой ПИД-регулятор , теперь используя ЦиглераМетод Николса , но я всегда получаю все больше и больше промахов.В конце концов я смог получить [в основном] стабильные колебания, используя только пропорциональное управление (настройка K i и K d = 0);хронометраж периода K с секундомером в среднем составил 3,198 секунды.
Я наткнулся на ответ ( Рекс Логан ) на аналогичный вопрос chris12892 .
Первоначально я использовал переменную "Duration" в миллисекундах, что сделало мой коптер очень агрессивным, очевидно, потому что я умножал ошибку работающего интегратора на тысячи в каждом цикле.Затем я разделил его еще на тысячу, чтобы довести до секунд, но я все еще сражаюсь ...
Чего я не понимаю из ответа Рекса:
- Почемуон игнорирует переменную времени в интегральной и дифференциальной частях уравнений?Правильно ли это или это опечатка?
Что он подразумевает под замечанием
В обычной системе выборки дельта-член будет равен единице ...
Один что?Должна ли это быть одна секунда при нормальных обстоятельствах?Что, если это значение колеблется?
Мой метод управления полетом ниже:
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, я не хочу делать ставку на что-либоточной синхронизации, поэтому вместо того, чтобы пытаться определить, на какой частоте я выполняю этот метод, конечно, если я вычисляю фактическое время и коэффициент, который в уравнениях, это должно быть лучше, или я что-то неправильно понимаю?