Как синхронизировать ПИД-библиотеку Arduino с внешним таймером для управления скоростью вращения?

Я пытался использовать библиотеку Arduino PID для управления скоростью поворота (в градусах/сек) робота, следующего за стеной.

Операционная система робота использует TIMER5 на Arduino MEGA2560 для обновления ряда чувствительных ко времени параметров (курс, расстояние спереди/сзади/влево/вправо и т. Д.), Которые используются во всем коде. Для управления скоростью поворота разница между текущим и предыдущим заголовками (соответствующим образом измененными для переходов 0/180) умножается на 10, чтобы получить град/сек, а затем это значение является "входом" в ПИД. ПИД-выход-это регулятор скорости вращения колес для достижения желаемого заданного значения скорости поворота.

К сожалению, нынешняя ПИД-библиотека Arduino имеет внутренний таймер (который можно изменить, но не отключить), который имеет свое собственное представление о времени. Кроме того, внутренний таймер библиотеки PID недоступен внешнему миру - он используется только в PID::Compute().

Типичная конфигурация кода для использования PID выглядит примерно следующим образом:

loop()
{
    //lots of other stuff
    if(TIMER5 ISR has been triggered)
    {
        //compute turn rate = 10*delta_heading
    }

    if(myPID.Compute()) //the internal timer is used inside this function
    {
       //use the PID output to control something (like wheel speeds)
    }
}

loop() работает на максимальной скорости, но myPID.Compute() генерирует новый вывод только по истечении внутреннего ПИД-таймера (в противном случае он возвращается немедленно, ничего не делая). Однако входная скорость поворота вычисляется по другому графику, что приводит к непредсказуемому поведению.

Возможным решением является:

loop()
{
    //lots of other stuff

    if(myPID.Compute()) //the internal timer is used inside this function
    {
        New_Hdg_Val = GetNewHdgVal();
        turn_rate = ComputeTurnRate(New_Hdg_Val, Prev_Hdg_Val);
        Prev_Hdg_Val = New_Hdg_Val;
        
       //use the PID output to control something (like wheel speeds)
    }
}

Итак, теперь скорость поворота вычисляется на тех же временных интервалах, что и PID::Compute (), что выглядит нормально, если значение таймера, используемое PID, совпадает со значением TIMER5 ISR, используемым остальной частью программы; неуклюже, неэлегантно, но, возможно, НОРМАЛЬНО.

К сожалению, потому что ПИД вычисляет новое значение выходного внутри ПИД::Compute (и), новое значение расчет идет до поворота скорость вычислений, что означает, что скорость разворота используется для производства новой продукции использует свою очередь, скорость передачи информации, которая, по крайней мере, 100mSec из даты (допустим, по умолчанию 100mSec ПИД время образца установка) - ой!!

Итак, как же другие используют библиотеку Arduino PID в системах с внешним (по отношению к библиотеке PID) источником синхронизации?

, 👍1

Обсуждение

Я не знаю, как другие используют PID-библиотеку; -). Не задумываясь над проблемой: как насчет вычисления скорости вращения в каждом цикле цикла? За пределами "если" (myPID.Блок Вычислить ())'. Вызывает ли это проблему, если она вычисляется до каждого myPID.Вычислить " звонок? Вы тратите небольшое количество вычислительного времени, но у вас есть самые фактические значения скорости поворота., @Peter Paul Kiefer

Питер, я, конечно, мог бы это сделать. Вычисление тривиально, но получение измерения заголовка от MPU6050 нет, и нет никакой гарантии, что (блокирующее) измерение MPU6050 не начнется непосредственно перед тем, как истечет внутренний таймер PID, что означает, что теперь циклы PID::Compute() больше не являются периодическими. Это большая проблема, потому что внутренняя математика PID предполагает периодичность., @user3765883

Я не думаю, что чтение MPU является проблемой. Даже если вы прочитаете все значения из него (я не знаю, так ли это), вы сможете достичь частоты дискретизации 100 Гц. Это значит макс. 10 мс на считывание. И если вам нужно значение для " compute ()", вы должны прочитать MPU до выполнения PID, поэтому он каким-либо образом блокирует PID. Метод вычисления PID работает с "millis()" и интервалом выборки 100 мс по умолчанию. Если это начнется максимум через 10 мс, кого это волнует? И вы делаете "много других вещей" в функции цикла перед этим. Сколько для этого нужно времени? ;-), @Peter Paul Kiefer

Я заглянул в код вычислительного метода, и, честно говоря, он меня не очень впечатлил. Автору нужны постоянные интервалы времени, потому что он использует трюк для сохранения деления и умножения (производной, интеграла). Но теперь каждая задержка в цикле может привести к ошибкам в интеграле и производной. Он утверждает, что промышленный контроллер лучше всего работает с постоянными интервалами. Но промышленный контроллер работает в системах реального времени, которые гарантируют фиксированные интервалы. И "петля" Arduino не предоставляет функции реального времени. Особенно, если выполняется много других вещей., @Peter Paul Kiefer

Если бы мне понадобился ПИД-контроллер, я бы написал свою собственную версию. Автор ссылается на фрагмент кода, который я бы предпочел использовать. http://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/ (но без улучшений "временного интервала"), @Peter Paul Kiefer

Вы синхронизируете его, вызывая myPID.Функция Compute() в функции внешнего обработчика таймера. Если ваша функция цикла является длительной, переместите критически важные по времени функции в обработчик таймера., @Dave X

Я использую TIMER5 на Mega 2560 для запуска всего, что зависит от времени, включая вычисления PID. Я использую пользовательскую функцию PID_calcs, которая имитирует внутреннюю работу PID.Compute(), и PID_calcs вызывается каждый раз при запуске TIMER5, гарантируя равные интервалы времени., @user3765883