Как можно стабилизировать Arduino-квадрокоптер?

Я построил квадрокоптер на Arduino и использую MPU6050 для считывания углового положения и скорости самолета. Проблема в том, что я не могу заставить вещь стабилизироваться. Посмотрите это видео здесь, чтобы понять, что я имею в виду.

Итак, как вы можете видеть из кадра (а вы его смотрели, верно?), я даже не получаю устойчивых колебаний, они просто случайны. Чего я не понимаю, так это того, как люди заставляют свои квадрокоптеры колебаться очень быстро (возможно, 10 раз в секунду), а затем подстраивают свои ПИД-усиления, чтобы сгладить их, в то время как если я подниму свое p-усиление достаточно высоко, чтобы оно приспособь это быстро, квадрокоптер просто придет в бешенство и попытается меня убить.

И, говоря о коэффициенте усиления, вот PID, который я написал:

float KrP = 0.002000;
float KrI = 0.000001;
float KrD = 0.200000;

void adjustRoll(float currentRoll, int newRoll) {
  if (thrust <= 1200){
    inAutoRoll = false;
    NWPower = thrust;
    NEPower = thrust;        //PID еще не готов к включению? Просто установите мощность двигателя
    SWPower = thrust;        //равно дросселю.
    SEPower = thrust;

    I_roll = 0;              // Сбросить интеграл.
    return;                  // Больше ничего не делать
  }

  float newRate = 2 * (newRoll - currentRoll); // Как быстро дрон должен попытаться
                                                                       // настроить на основе ошибки.

  if (newRate > 50)newRate = 50;        // Не корректируйте слишком быстро!
  else if (newRate < -50)newRate = -50;

  float offset = newRate - rollRate;

  I_roll += KrI * offset;

  if(!inAutoRoll) {        // Включается ли PID только что? (требование по дроссельной заслонке выполнено).
    lastRollRateOffset = offset;  //Плавный переход.
    inAutoRoll = true;
  }


  float adjust = (KrP * offset) + (KrI * I_roll) + (KrD * (offset - lastRollRateOffset));

  NWPower += adjust;
  NEPower -= adjust;
  SWPower += adjust;
  SEPower -= adjust;

  if (NWPower > maxOut) NWPower = maxOut; 
   else if (NWPower < minOut) NWPower = minOut;

  if (NEPower > maxOut) NEPower = maxOut;
   else if (NEPower < minOut) NEPower = minOut;

  if (SWPower > maxOut) SWPower = maxOut;
   else if (SWPower < minOut) SWPower = minOut;

  if (SEPower > maxOut) SEPower = maxOut;
   else if (SEPower < minOut) SEPower = minOut;

  lastRollRateOffset = offset;
}

И если вам интересно... да, я знаю об интегральной установке. Причина, по которой я не рассмотрел это в своем коде, заключается в том, что квадрокоптер далеко не стабилен, поэтому я пока не беспокоюсь о совершенстве. Кроме того, у меня I-gain установлено на 0,000001, так что это не имеет значения. Причина, по которой я это сделал, заключается в том, что (насколько мне известно) квадрокоптер может летать только с P и D, а с учетом того, как ведет себя мой, я думаю, что большее I-усиление только усугубит ситуацию.

Подробнее о моем PID: PID корректирует скорость вращения квадрокоптера, что, как я понимаю, является лучшим способом управления квадрокоптером. Коррекция скорости вращения определяется путем умножения ошибки (в градусах) на два. Почему два? Не знаю. Я поэкспериментировал с некоторыми другими множителями, и два, кажется, в порядке. Это тоже простое число, так что да...

В любом случае! Что мне нужно сделать, чтобы квадрокоптер стал стабильным? Я видел удивительно совершенные квадрокоптеры, использующие ту же Arduino и тот же MPU6050, но мой просто наклоняется во все стороны.

Некоторые возможные проблемы пришли мне в голову:

  1. Неверный алгоритм расчета необходимой скорости вращения на основе ошибки.
  2. Неверный алгоритм PID.
  3. Плохое усиление PID.
  4. Я не балансировал свои реквизиты, но если серьезно, пару кусков изоленты, приклеенных к реквизиту, действительно исправят это? Не похоже, что будет.

Спасибо за любую помощь, которую вы можете предложить!

, 👍3

Обсуждение

Вы запускали какие-то скетчи для тестирования подсистем? Например, вы специально проверяли, правильно ли работает MPU6050, в порядке ли драйверы двигателей и т. д.?, @James Waldby - jwpat7

МПУ вроде в порядке. Когда я наклоняю его, он дает мне разумные значения для тангажа рыскания, а также для скорости вращения. Драйвера тоже работают нормально. У меня есть квадрокоптер, подключенный к моему компьютеру, поэтому у меня есть все данные, которые мне могут понадобиться, на моем экране, пока он работает., @Ember

Относительно 4: Самое классное в квадрокоптерах то, что все регулировки и балансировка управления /могут/ выполняться математически, а не физически., @Dave X

Это далеко, далеко выходит за рамки этого сайта. Если вы хотите построить что-то, что летает, потратьте некоторое время на изучение существующих решений и алгоритмов управления, которые они используют, и прочитайте ветки по замене прошивки на rcgroups; также не используйте «настоящую» Arduino — почти каждый проект, начатый там, уже давно перешел к лучшему выбору., @Chris Stratton

Можете ли вы опубликовать больше кода? Где обновляется PID?, @Nick Gammon

случайное поведение — большая проблема Drone. Вы решили эту проблему? Мой дрон имеет такое же случайное поведение. инфракрасный, @infrared4ever


3 ответа


Лучший ответ:

1

Чтобы помочь решить эту проблему, я написал программу в разделе Обработка, которая выводит в виде графика все данные от квадрокоптера, включая скорость крена, угол крена, тягу и т. д. После этого я понял, что проблема была не в PID, а в том, как я обрабатывал данные, выходящие из MPU6050. Вы можете прочитать все об этом в этом вопросе, который я разместил здесь до того, как нашел полное решение.

Квадрокоптер теперь может взлетать, но, к сожалению, не очень стабильно. Это может быть из-за плохого усиления PID, но я подозреваю, что это из-за вибрации в значениях скорости вращения от MPU6050. Причина, по которой я так думаю, в том, что я не вижу устойчивых колебаний, а скорее случайное движение. В любом случае, если я найду более полное решение, я обновлю этот ответ.

,

1

Для стабильности и настройки необходимо сделать время цикла настройки совместимым с физической системой. Насколько быстро вызывается этот корректирующий код относительно того, насколько быстро колеблется физическая система? Без этого контроля настройка усиления будет затруднена, особенно для krI и krD.

Например, если вы обновляете данные каждую миллисекунду и требуется 1/10 секунды, чтобы физически измениться с -90 на 0 при текущей настройке roll_thrust, kP достаточно только для регулировки roll_thrust kP *(RollDelta/2)*DT/dt=0,002*(90/2)*0,1/0,001=9 Это разумная корректировка для тяги/мощности двигателя 1200+? Если вы сэмплируете достаточно быстро, чтобы сделать его способным к полной регулировке (+/-800?) с этим конкретным kP, вам может потребоваться сэмплировать в 88 раз быстрее (1 мс / (800/9) = 0,01125 мс). С другой стороны, я бы вычислил, как быстро вы можете производить выборку, а затем выбрал бы krP, который мог бы обеспечить корректировку с полным смещением в разумные сроки.

Возможно, подумайте о adjust как о переменной состояния roll_thrust, измеряемой в единицах ESC_микросекунд, а krP — это коэффициент преобразования любой ошибки, которую вы измеряете. Это ошибка угла крена? ошибка скорости вращения? Ошибка абсолютной скорости вращения? Это выглядит так:

float newRate = 2 * (newRoll - currentRoll); // Как быстро дрон должен попытаться
if (newRoll - currentRoll < 0) {             // настроить на основе ошибки.
   newRate = 0 - newRate;
}

по существу:

float newRate = 2 * abs(newRoll - currentRoll); 

что может сделать управление прерывистым. Если currentRoll является заданным значением позиционного угла крена, он не сможет определить, находится ли он на той или иной стороне.

Если вы хотите, чтобы при угле крена -90 градусов был полный газ в одну сторону и 90 градусов — в другую, тогда krP должен быть порядка 900us/90deg=10us/градус. И krI=krD=0 для начала.

Я бы закодировал отдельные PID для управляющих переменных thrust, roll_thrust, pitch_thrust, yaw_thrust, а затем суммируйте их вместе, чтобы получить выходы {NE,NW,SE,SW}Power. Тогда вы сможете контролировать и контролировать в пространстве {thrust,roll_angle,pitch_angle,yaw_rate}, и кодирование будет более простым и интерпретируемым.

,

Спасибо за ваш отзыв! Однако мне нужно кое-что уточнить: 1) Я думаю, вы, возможно, неправильно прочитали мой код, потому что не должно быть никакого накопления в настройке P, которая не имеет долговременной памяти между отдельными циклами в PID. 2) Мой дроссель увеличивается между 1100 мкс и 1900 мкс, так что это диапазон 800, а не 2500 (ESC принимают сигнал ppm 1000-2000 мкс)., @Ember

Кроме того, как я могу написать позиционный ПИД-регулятор для управления ПИД-регулятором скорости, который у меня уже есть, и при этом иметь хоть малейшее представление о том, какой из ШЕСТЬ коэффициентов усиления ПИД-регулятора мне придется настроить? Я пробовал, но не знаю, как посмотреть на поведение квадрокоптера и определить, какое из шести усилений мне нужно изменить. Вот почему я просто остановился на [ошибке 2*], чтобы упростить задачу., @Ember

Ты прав. Я пропустил, что тяги были инициализированы в цикле - это старая добрая позиционная форма PID - я нажимаю на бит формы скорости. krP, krI и krD — это просто коэффициенты масштабирования от различных форм ошибки до выходной переменной. Я думаю, что я все еще не понимаю, что такое измеренные входные данные., @Dave X

На самом деле, это PID-регулятор скорости, позвольте мне объяснить: «тяга» - это сигнал 1100-1900 ppm от рычага тяги на моем передатчике. Каждому двигателю назначается эта тяга в начале, затем ПИД-регулятор регулирует эту тягу для каждого двигателя, чтобы попытаться заставить квадрокоптер двигаться с желаемой скоростью вращения (определяется 2 * погрешностью в градусах от желаемого угла). Итак, чтобы ответить на ваш вопрос: измеренные входные данные: 1) текущий угол квадрокоптера и 2) текущая скорость вращения квадрокоптера. Кроме того, с моей стороны ошибка if(newroll-current roll<0). Я вынул его., @Ember

Вы уверены, что приведение вращательной_скорости (град/сек) к значению 2*error_deg является правильной схемой управления? Это выходит за рамки всего Arduino, но я думаю, что вы хотели бы работать над стабильностью в пространстве градусов. Возможно, несоблюдение запланированной кривой скорости при более высоком усилении является причиной вашей нестабильности., @Dave X

Я не уверен, что вы подразумеваете под «стабильностью в пространстве градусов» или под «отслеживанием запланированной кривой скорости при более высоких коэффициентах усиления». Вы имеете в виду, что я должен больше сосредоточиться на положении, а не на скорости? В любом случае, прямо сейчас я работаю над написанием программы, которая будет отображать данные для меня, когда я управляю квадрокоптером. Так я смогу лучше понять, в чем проблема., @Ember

Да, сосредоточьтесь на управлении положением крена, а не скоростью крена. Во-вторых, я имею в виду, что проблема стабильности, которую вы видите при высоких коэффициентах усиления, может быть связана с тем, что желаемая скорость (newRate = 2 * (newRoll - currentRoll) может не подходить для физической системы., @Dave X


0

Чтобы убедиться, что приемник получает правильный сигнал от излучателя, обязательно некоторое время тщательно проверяйте сигнал на приемнике. Как только сигнал на приемнике будет проверен, можно двигаться вперед шаг за шагом. Первым шагом является приведение в действие 4 ESC/моторов одним и тем же сигналом, поступающим от дроссельной заслонки. Как только поведение 4 моторов будет соответствовать изменениям дроссельной заслонки, поступающим от эмиттера, пора переходить к следующему шагу. Следующий шаг связан с микшированием тангажа/крена/рысканья, поступающего от эмиттера. Микс добавляется/удаляется в/из дроссельной заслонки, адресованной каждому двигателю. Поведение 4-х моторов должно показывать именно тот микс, который исходит от эмиттера. "приемлемый" mix примерно так (в тех же единицах, градусах или микросекундах):

Что-то вроде этого:

int throttle_gaz;
int roll_length, pitch_length, yaw_length;

throttle_gaz=pulse_duration[throttle_chanel];
if ( abs(throttle_gaz-1500) <= 50 )
{
 throttle_gaz=1500; 
}
roll_length=pulse_duration[roll_chanel]-1500;            //РУЛОН
if (abs (roll_length) <=100 )
{
roll_length=0;   
}
roll_length/=3;

pitch_length=pulse_duration[pitch_chanel]-1500;           //ПОДАЧА
if (abs (pitch_length) <= 100 )
{
  pitch_length=0;   
}
pitch_length/=3;

yaw_length=pulse_duration[yaw_chanel]-1500;             // Рыскание
if (abs (yaw_length) <=100 )
{
  yaw_length=0;   
}
yaw_length/=3;

//добавляем/вытягиваем из THROTTLE (pulse_duration[throttle_chanel])
//меняем знак (+/-) согл
pulse_length_esc1=throttle_gaz + roll_length + pitch_length - yaw_length;
pulse_length_esc2=throttle_gaz - roll_length +  pitch_length +  yaw_length;
pulse_length_esc3=throttle_gaz + roll_length - pitch_length  + yaw_length;
pulse_length_esc4=throttle_gaz - roll_length -  pitch_length  -  yaw_length;
,

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

как новичок в создании полетного контроллера, я ищу учебник, описывающий все шаги для достижения такой цели., @infrared4ever