LINUX.ORG.RU

ПИД(PID)-регулятор: управление поворотом угла двигателя с помощью драйвера

 


1

3

Всем привет, кого не видел) Вопрос следующий: давно хотел как-нибудь использовать ПИД-регулятор в проекте, и вот настал тот час, когда надо, а я не могу понять, как же его присобачить с имеющимися данными. У меня есть драйвер двигателя (BLSD-20), редуктор. Я опрашиваю количество прошедших оборотов двигателем с неким интервалом, и знаю, сколько мне надо получить оборотов, чтобы редуктор повернулся на нужный угол, соответственно, знаю на какой угол в текущий момент отклонился редуктор. Соль в том, что управлять двигателем с помощью драйвера я могу только заданием скорости его вращения. Итого у меня получается диапазон выставления скорости: 0 - 66,(6) оборотов/сек. Один оборот - 3,6 градусов редуктора Начитавшись литературы по ПИД, отлично понял составные части этого регулятора, и тем не менее не понимаю, как задать управляющую величину.

Основной методичкой взял вот этот манускрипт http://robofob.ru/materials/articles/pages/Karpov_mobline1.pdf

Мои размышления такие:

  1. Моя задача повернуть на некий угол, пусть будет = 90 град.

  2. Значит, в начале движения у меня ошибка 90 град.

  3. Я начинаю суммировать все обороты (angle_sum) и получаю ошибку error = 90 - angle_sum

  4. Далее пропускаю её через регулятор, должен получить управляющее воздействие, судя по методичке, это снова будет какой-то угол, который надо как-то превратить в скорость.

Теоретическая выкладка из методички


// Параметры пропорционального звена
static double kp = 10; // Коэффициент пропорционального звена

// Параметры интегратора
static double ki = 0.001; // Коэффициент интегрального звена
#define iMin -0.2 // Минимальное значение интегратора
#define iMax 0.2 // Максимальное значение интегратора
static double iSum = 0; // Сумма ошибок (значение, накопленное в интеграторе)

// Параметры дифференциатора
static double kd = 1; // Коэффициент дифференциального звена
static double old_y = 0; // Предыдущее значение сигнала

static double PIDctl (double error, double y)
{    
    double up, ui, ud;

    // Пропорциональная компонента
    up = kp * error;

    // Интегральная компонента
    iSum = iSum + error; // Накапливаем (суммируем)
    if (iSum < iMin) iSum = iMin; // Проверяем граничные значение
    if (iSum > iMax) iSum = iMax;
    ui = ki * iSum;

    // Дифференциальная компонента
    ud = kd * (y - old_y);
    old_y = y;

    return up + ui + ud;
}

Подскажите, как перейти от теории к практике, какие подводные камни меня ожидают



Последнее исправление: Tumyq (всего исправлений: 16)

И почему-то не сработало форматирование

Теперь по умолчанию markdown. Читай справку.

ox55ff ★★★★★
()

Пиши так:

```cpp
static double PIDctl (double error, double y)
```

Получишь:

static double PIDctl (double error, double y)
ox55ff ★★★★★
()

не понял, нафига тебе тут пид, если ты можешь просто отсчитать нужное количество оборотов. если бы у тебя ременная передача была и проскальзывала, либо двигатель бы «шаги» пропускал, то тогда да, а так — просто смотри, повернулся на нужный угол, значит хватит крутить.

anonymous
()

Во-первых, ПИД тут не нужен, если у тебя нет внешнего воздействия, к которому надо адаптироваться этим ПИД-ом, во-вторых, там элементарная математика же. В-третьих, у ПИД-а есть принципиальный недостаток в необходимости подбора коэффициентов...

peregrine ★★★★★
()

Тут PID можено натянуть только если у тебя скорость движка управляется PWM, причём двуполярным. На входе - текущая позиция выраженная в количестве оборотов и заданная позиция выраженная в количестве оборотов, на выходе - PWM от -V до +V. PID позволит сбрасывать скорость при приближении к заданной позиции и открутить назад если из-за инерции оно проехало заданное значение.

Если PWM нету или он однополярный, то PID тут никуда не прикрутишь.

Stanson ★★★★★
()
Ответ на: комментарий от anonymous

Это не шаговик. В драйвере есть настраиваемое ускорение. Суть - чтобы быстро и побороть инертность

Tumyq
() автор топика
Ответ на: комментарий от Tumyq

С первого взгляда, как уже все сказали, ПИД не нужен. Если надо быстро - максимальное напряжение на двигатель подавай, пока он близко не подойдет к заданному углу, тогда снижай скорость.

Если по-простому, ПИД нужен как минимум если у тебя есть датчики обратных связей и если есть возмущающее воздействие, которое вносит ошибку в твое задание. У тебя пока такого не видно.

curufinwe ★★★★★
()
Ответ на: комментарий от Harald

Отвечая на вопрос об управлении и обратной связи. Я писал, что опрашиваю состояние с неким интервалом, получаю количество оборотов. Собственно, и получаю некое количество оборотов за интервал опроса - это и есть относительная скорость. Соответственно, для двигана выставляю тоже скорость. Да и суть ПИД-а в обратной связи, если есть чем крутить, и что получать, то его можно прикрутить, главное - составить соответствие управляющей величины на выходе. Хотелось бы, чтобы вы с этим помогли. Кое-что я накрутил уже, и вроде как начал получать результат с точностью одного оборота, но чую, что где-то несостыковка с величинами

Tumyq
() автор топика
Ответ на: комментарий от Tumyq

чтобы быстро и побороть инертность

всё равно мне кажется, что проще подобать режим работы двигателя, чтобы компенсировать инертность. например, крутишь на полную пока абсолютная разница «оборотов», скажем, больше 10, а если меньше, то крутим потихоньку, пока разница не станет равна 0.

это почти пид получается, но чуть проще, без накопления ошибки.

можно и вовсе какую-то простую зависимость использовать, линейную или может быть логарифмическую, типа v = m * log(k * (error - с) + 1), где m — масштаб; k — скорость изменения скорости (при малых k получается почти линейная зависимость); c — константа, вместо интегральной составляющей, если надо.

anonymous
()
Ответ на: комментарий от anonymous

Спасибо, попробую. Выглядит просто и со вкусом. Сейчас у меня кое-что получилось, но не совсем точно выходит под нагрузкой, ошибка возросла до +- 2, а то и 3 оборотов. Пробую вертеть коэффициенты. Если интересно, вот, что получилось


// Параметры пропорционального звена
static double kp = 10; // Коэффициент пропорционального звена

// Параметры интегратора
static double ki = 0.001; // Коэффициент интегрального звена
#define iMin -0.2 // Минимальное значение интегратора
#define iMax 0.2 // Максимальное значение интегратора

static double iSum = 0; // Сумма ошибок (значение, накопленное в интеграторе)

// Параметры дифференциатора
static double kd = 1; // Коэффициент дифференциального звена
static double old_y = 0; // Предыдущее значение сигнала

// Диапазон скоростей
static double minSpeed = 0;
static double maxSpeed = 20;

// Диапазон сигнала управления
static double minU = 0;
static double maxU = 66;

static double min_integral = iMin;
static double max_integral = iMax;
static double maxErr = maxSpeed;

//счетчик и заданный угол поворота
uint16_t rotor_count = 0;
uint16_t need_degree = 90;

void loop() //условно функция опроса
{
    rotor_count += опрос..
    double curent_degree = rotor_count * 3.6;

    // Определение ошибки управления
    double error = need_degree - curent_degree;
    // Выход регулятора
    double Y = PIDctl(error, t_deg);
    // Вычисление управляющего воздействия
    double U = y2u(Y);
    // Подача управляющего сигнала на вход объекта управления
    BLSD_rotate(U);
    
    //если поворот совершен, сброс накопителя значений
    if (U == 0.0) rotor_count = 0;
}

static double y2u(double y)
{
    double u;
    double maxY = kp * maxErr + ki * max_integral + kd * maxErr;
    double minY = -maxY;
    u = (y - minY)/ (maxY - minY) * (maxU - minU) + minU;
    if(u > maxU) u = maxU;
    if(u < minU) u = minU;
    return u;
}

PIDctl() взят в чистом виде из методички

Tumyq
() автор топика
Ответ на: комментарий от Tumyq

Да, но у тебя измеряется только скорость вращения, а не угол. Соответственно, ПИД регулятором ты можешь регулировать только скорость вращения.

Harald ★★★★★
()
Ответ на: комментарий от Tumyq

в функции PIDctl() ты проверяешь граничные значения iSum, которые у тебя от -0.2 (iMin) до 0.2 (iMax), в это же время

    ...

uint16_t rotor_count = 0;
uint16_t need_degree = 90;

    ...

    rotor_count += опрос..
    double curent_degree = rotor_count * 3.6;

    // Определение ошибки управления
    double error = need_degree - curent_degree;

    ...

    iSum = iSum + error; // Накапливаем (суммируем)
    if (iSum < iMin) iSum = iMin; // Проверяем граничные значение
    if (iSum > iMax) iSum = iMax;

error, судя по всему, гораздо больше 0.2. и получается, что твоя интегральная составляющая не работает.

ещё, когда поворот совершён (я так понял, когда мы достигли цели), то надо обнулять не только rotor_count, но и iSum. наверное.

anonymous
()

Кто-то должен был это сказать

Заголовок треда при беглом взгляде читается ПИДОРЮ. Сделайте с этим что-нибудь.

anonymous
()
Ответ на: комментарий от anonymous

непонятно, что такое t_deg и, соответственно, y в PIDctl(). если что, то дифф. составляющая учитывает разницу текущей и предыдущей ошибки.

anonymous
()
Ответ на: комментарий от anonymous

Верно, iSum у себя обнуляю, потерялась в ходе переписывания здесь (хотел поинформативнее названия переменных указать).

t_deg это curent_degree - так же не переименовал.

Tumyq
() автор топика
Ответ на: комментарий от Tumyq

«Дифференциатор – это достаточно простой в реализации элемент. Его задача – умножить разность между текущим значением выходного сигнала и значением выхода в предыдущий момент времени на какой-то постоянный коэффициент» — Карпов В.Э.

у товарища какая-то рекурсия получается: текущее значение выходного сигнала зависит от диф. составляющей, которая зависит от текущего значения выходного сигнала. или как?

я, конечно, не иксперт, но мне кажется автор не точен. а вот с википедией я согласен. там дифф. сост. = de/dt.

в коде у тебя вовсе градусы, вместо ошибки.

anonymous
()
Ответ на: комментарий от anonymous

На самом деле градусы появились после вычислений редуктора. Он 1/100, то есть полный оборот будет когда двигатель сделает 100 оборотов, соответственно, 3.6 градусов у меня получаются на один оборот. Вся идея в том, что я знаю, сколько градусов мне нужно для проворота, опрашивая получаю градусы текущего оборота - получаю ошибку, и мне нужно это скоррелировать с управляющей величиной (у меня это скорость). Поэтому введена функция y2u(), которая по сути представляет из себя линейное отображение градусов в диапазон значений скорости. Можно было бы просто коэффициент вывести, но если потребуется сделать поворот на другой угол, все равно надо пересчитать, плюс это было удобно спереть у автора.

Tumyq
() автор топика
Последнее исправление: Tumyq (всего исправлений: 2)
Ответ на: комментарий от Tumyq

ладно, твой вариант дифф. составляющей вроде как должен нормально влиять.

про интегральную понял, что я выше писал? вероятно стоит поменять значения iMin и iMax.

и попробуй всё-таки вариант только с пропорциональной составляющей, то есть когда v = k * error или тот логарифм.

anonymous
()
Ответ на: комментарий от anonymous

Пока интегральную не начал крутить, все работало с грехом по полам) Понял, поменял на 90 и -90. Вроде, это максимум отклонения должны быть, но не факт. Так как Y прилетает чуть ли не от 900 до -900. Видимо, kp надо сделать меньше. Далее попробовал настроить коэффициенты методом из методички, но все эти колебания при kp так или иначе отфильтрованы в y2u, крутил полчаса никуда система в устоявщиеся колебания не вошла. В общем, пока что-то все разъехалось

Tumyq
() автор топика
Последнее исправление: Tumyq (всего исправлений: 1)
Ответ на: комментарий от anonymous

и попробуй всё-таки вариант только с пропорциональной составляющей, то есть когда v = k * error или тот логарифм.

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

Tumyq
() автор топика
Последнее исправление: Tumyq (всего исправлений: 1)

Ещё раз, у тебя нет обратной связи по углу поворота, ПИД регулятор тут не применим

Harald ★★★★★
()

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

Harald ★★★★★
()
Ответ на: комментарий от Harald

Ещё раз, у тебя нет обратной связи по углу поворота, ПИД регулятор тут не применим

Почему нет, куда подевались?

Банальный пример, твой редуктор чем-то прижали, но вал двигателя проскальзывает

Случай, что его прижали, я не рассматриваю, потому что его не прижмут.

Tumyq
() автор топика
Ответ на: комментарий от Tumyq

Случай, что его прижали, я не рассматриваю, потому что его не прижмут.

Пыль, износ шестерёнок, случайные инородные тела в редукторе, не?

Harald ★★★★★
()
Ответ на: комментарий от Tumyq

Почему нет, куда подевались?

У тебя же нет датчика, чтобы измерять фактический угол поворота выходного вала редуктора?

Harald ★★★★★
()
Ответ на: комментарий от Harald

Я опрашиваю аппаратный драйвер, который шлёт мне 2 импульса на оборот с двигателя, у которого 3 датчика Холла.

Tumyq
() автор топика
Ответ на: комментарий от Harald

Просто скажите, что имеете в виду. Зачем вообще надо рассчитывать механическую нагрузку, если речь идёт об обратной связи от системы. Хоть и не в лучшем виде, но с опросом в 20 мсек - вполне. Задача ПИД рассчитать реальное отклонение системы, и скомпенсировать его. Понятно, что для каждой системы реальные значения обусловлены рядом причин. Если бы надо было считать механическую задачу, то решалось бы другими средствами.

Tumyq
() автор топика
Ответ на: комментарий от anonymous

можно и вовсе какую-то простую зависимость использовать, линейную или может быть логарифмическую, типа v = m * log(k * (error - с) + 1)

Применил,стало больше уверенности в действиях - двиган перестал выбрасывать время от времени большие перепады, чуть сбросил скорость - стало намного стабильнее,1 оборот погрешности все таки остался, но кто бы мог требовать большего от него. В общем, спасибо за помощь - помогло.

Tumyq
() автор топика
Ответ на: комментарий от Tumyq

не за что.

может быть так, что сам драйвер или режим измерений оборотов дают погрешность, так как с ненулевой ошибкой скорость, очевидно, тоже должна быть ненулевая. попробуй покрутить ровно на один оборот каким-нибудь примитивным способом — получится или нет? может быть станет ясно в чём причина.

anonymous
()
Ответ на: комментарий от anonymous

На медленной скорости инерция отсутствует, и покрутить на точное кол-во оборотов удается, вся пляска начинается, когда мне нужно крутануть быстрее - я выставляю на драйвере максимальное ускорение, и далее регулирую только скорость. Можно ускорение совсем убрать или сделать меньше (что подразумевал автор драйвера, когда вносил ускорение как отдельный параметр, мне не ясно), тогда разгоняется ну совсем медленно, и смысл вертеть скорость отпадает.

Tumyq
() автор топика
Последнее исправление: Tumyq (всего исправлений: 1)
Ответ на: комментарий от Tumyq

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

Iron_Bug ★★★★★
()
Последнее исправление: Iron_Bug (всего исправлений: 1)
Ответ на: комментарий от Iron_Bug

Я не борюсь с физикой. Общие понятия процесса мне известны, в том числе - физические постулаты. Речь о расчете разбега с максимально приближенным результатам. Я планирую после торможения медленно подкрутить до нужного оборота. И могу позволить себе немного недокрутить. Ошибка и погрешность существуют в любой движущейся механической системе, для того и существуют контроллеры и процессоры, которые способны корректировать это явление на ходу, а не на инженерном листке. Я еще вставлю подкручивание параметров по ходу работы двигателя, чтоб НИХТО НЕ ДОХАДАЛСЯ)

Tumyq
() автор топика
Ответ на: комментарий от Tumyq

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

Iron_Bug ★★★★★
()
Ответ на: комментарий от Iron_Bug

Могу и не впарить - вообще не понял, зачем надо это делать.. Расскажите еще про момент силы, импульс и момент импульса. У меня другая тема, рамки поставленной задачи я описал выше.

Tumyq
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.