roboforum.ru

Технический форум по робототехнике.

ПИД (на ПИКе)

Re: ПИД (на ПИКе)

boez » 30 мар 2011, 12:11

dccharacter писал(а):Ну и вот так оно пляшет вокруг 55

А почему у тебя чистый пропорционал? Ты интегральную составляющую добавь хотя бы медленную, а так у тебя ошибка в 0 не уйдет никогда, таково свойство чистого пропорционала.
Ну и вообще, у тебя в коде нет ограничения выхода. Вернее оно есть, на интегральной составляющей, но ты ее не используешь. И непонятно, что у тебя там со знаковостью по выходу, ШИМ вообще реверсивный или нет? Если нет, выход нужно ограничивать от 0 до max_pwm, если да - то от -max_pwm до max_pwm и по знаку регулятора управлять реверсом. А энкодер у тебя реверсивный?

И еще - чтобы интегральная нормально работала, ей как правило дробные разряды надо делать (ну например весь регулятор 16-битный, а накопитель интеграла 32-битный и при суммировании из него берутся старшие 16 бит). Иначе не сможешь работать с малыми коэффициентами И.

Вот рабочий код ПИД-регулятора, выставляй правильно максимум и минимум и дальше крути коэффициенты, начни с маленьких и потом добавляй. Д можешь для начала нулем поставить. Затем, когда добьешься устойчивой работы - можешь его увеличивать. Сам по себе он не дает более быстрой реакции, но он позволит увеличить И без перерегулирования и колебаний.
Код: Выделить всёРазвернуть
typedef struct
{
   long ival;
   long errflt;
   short min;
   short max;
   short err;
   short out;
   short ki;
   short kp;
   short kd;
} TPIReg;

#define PI_T3_KOEFF_I  80
#define PI_T3_KOEFF_P  150
#define PI_T3_KOEFF_D  500

void SpdCtrlInitPiReg(TPIReg *reg)
{
   reg->ival = 0;
   reg->errflt = 0;
   reg->min  = 10;
   reg->max  = 255;
   reg->ki = PI_T3_KOEFF_I;
   reg->kp = PI_T3_KOEFF_P;
   reg->kd = PI_T3_KOEFF_D;
}

short SpdCtrlStepPIReg(TPIReg *reg, short err)
{
   short res;
   short diff;

   reg->err = err;

   diff = err - (reg->errflt>>4); //Input filter+differentiator
   reg->errflt += diff;

   reg->ival += ((long)err)*reg->ki;
   res = reg->ival >> 16;

   if (res<reg->min) {
      res = reg->min;
      reg->ival = ((long)res)<<16;
   }
   else if (res>reg->max)
   {
      res = reg->max;
      reg->ival = ((long)res)<<16;
   }

   res += (((long)err*reg->kp)>>8)+(((long)diff*reg->kd)>>8);

   if (res<reg->min) {
      res = reg->min;
   }
   else if (res>reg->max)
   {
      res = reg->max;
   }

   reg->out = res;

   return res;
}



Добавлено спустя 3 минуты 40 секунд:
Да, если увидишь что и ПИ нормально справляется - можешь выкинуть все, что связано с дифференциалом, для экономии места и времени. Еще можно min, max, ki, kd, kp из структуры выкинуть и сделать чистыми константами. Но мне было удобнее по командам с терминала прибавлять-убавлять коэффициенты и таким образом настраивать регулятор на объекте. А уже потом один раз вписать их в константы и перепрошить контроллер.

Re: ПИД (на ПИКе)

dccharacter » 30 мар 2011, 12:41

Попытаюсь объясниться
1. Только П - потому что с виду это очень просто отладить
2. Основная проблема не то, что колебания наличествуют - это я как раз понимаю, а то, что колебания происходят не вокруг target - вот это меня напрягает сильно. И это у меня часто выходит с разными модификациями кода - инога система уравновешивается на 60-ти, когда таргет 40, иногда на 12-ти... Я уж и так верчу и эдак....
3. Вот про дробные - у меня затык. Если два unsigned char в один unsigned int я слить могу, то когда начинается преобразование signed int в unsigned char я уже начинаю методом подбора все делать, а когда появляются double (которые, на секундочку, даже в sprintf вывести нельзя для отладки в Hi Tech C), тут вообще тушите свет сливайте воду.
4. Что такое min и max вообще нигде не поясняется. Из микрочиповского аппнота сделал вывод, что это границы для того, чтобы не вылететь за размер переменной.

Re: ПИД (на ПИКе)

Duhas » 30 мар 2011, 13:00

читать надо внимательнее... П регулятор всегда не доходит до цели..

Re: ПИД (на ПИКе)

dccharacter » 30 мар 2011, 13:40

Duhas писал(а):читать надо внимательнее...

Ага! Фиг бы с ним, коль так. А когда цель - 40, а пляшем вокруг 55???
Да пустой разговор. Ясно же, что дело либо в типах переменных, либо в полярности ШИМа.

Ладно, спасибо всем, буду читать и изучать типы - ссылок вы мне много накидали :-)

Re: ПИД (на ПИКе)

Duhas » 30 мар 2011, 13:52

а это и есть ошибка регулирования ))) легко ))))

Re: ПИД (на ПИКе)

boez » 30 мар 2011, 17:28

dccharacter писал(а):3. Вот про дробные - у меня затык. Если два unsigned char в один unsigned int я слить могу, то когда начинается преобразование signed int в unsigned char я уже начинаю методом подбора все делать, а когда появляются double...
4. Что такое min и max вообще нигде не поясняется. Из микрочиповского аппнота сделал вывод, что это границы для того, чтобы не вылететь за размер переменной.

Никаких double! Настоящие джедаи используют токо fixed point :) На самом деле все очень просто - какая-то часть бит целого числа выделяется под дробную часть. Например часто это младшие 16 бит 32-битного числа, так называемый формат 16.16. Это значит, что числу 1.0 сответствует 0х10000=65536, числу 0.5 - 0х8000 = 32768, а одна единичка соответствует вещественному числу 1/65536 = 0.00лень переводить. Можно и в 16 бит поместить число с дробной частью, самые распространенные форматы это 8.8 или 4.12. Складываются такие числа как и целые, а при умножении нужно результат сдвигать вниз на f1+f2-f, где f1 и f2 - число бит после запятой у множителей, f - у произведения. В моем регуляторе есть примеры:

reg->ival += ((long)err)*reg->ki; // f1=0, f2=16, f=16 - не сдвигаем. reg->ki чисто дробный и находится в диапазоне -0.5..0.4999с_мелочью, ival 15.16, в старшем бите у обоих знак. Вообще реально знак имеет смысл токо у ireg, но раз уже вычисления знаковые - то и у коэффициентов тоже вырос знак.
res += (((long)err*reg->kp)>>8)+(((long)diff*reg->kd)>>8); //f1=0, f2=8, f=0 - сдвиг >>8, kp, kd в формате 7.8. В старшем бите знак, поэтому 7.8 а не 8.8, диапазон -128.0..127.99с_мелочью

А min и max - это ограничения диапазона управляющих воздействий. у тебя же ШИМ может быть не какой попало - в compare регистр ты можешь вписать число от 0 до T, где T - период таймера в тиках. Ну если реверс есть - то ограничиваем выход от -T до T и потом в compare пишем abs(reg->out), а на реверсную ногу порта выводим sign(reg->out). Причем ограничение нужно именно двойное, отдельно ограничиваем интеграл и отдельно потом всю сумму (выходное значение). Работа при reg->out = max (или min) называется насыщением регулятора - это например может быть когда нагрузка на валу не дает мотору набрать нужную скорость или просто мы ему дали задание, которое превышает скорость холостого хода мотора. При этом ШИМ достигает 100% и так и стоит все время, пока условия не изменятся (нагрузка уменьшится или мы задание снизим). Ограничение интеграла при этом не дает ему уползти в бесконечность, если бы его не было - интеграл бы рос неограниченно и это привело бы к переполнению. Или же когда условия, вызвавшие насыщение ушли бы, мотор продолжал бы молотить на 100% уже с отрицательной ошибкой, пока интеграл назад не отмотается. ну а второе ограничение - по выходу - нужно просто для того, чтобы не вписать в compare число, меньшее 0 или большее T, потому что таймерный блок при этом поведет себя некорректно.

Вообще, есть более хитрые методы ограничения интеграла, которые позволяют ему забираться немного за max и min, это улучшает динамику регулятора вблизи насыщения, описаны например в аппнотах TI, но мне такое реализовывать было лень.

Вообще, длительная ситуация err>0 (или err<0) обязана приводить к насыщению out=max (соответственно out=min) если интегральный коэффициент ненулевой. А чистый П-регулятор для регулятора скорости не имеет смысла - он же не сведет ошибку в ноль.

Re: ПИД (на ПИКе)

dccharacter » 30 мар 2011, 21:07

Круто. А это что, сильно быстрее работает, чем даблы??? Просто когда оперируешь даблами не надо морочиться со сдвигами - раз, функции обрезания мантиссы для них есть, осталось только бошку и знания в порядок привести и все. Но может быть, это неэффективно с т.зр. процессорного времени?

Добавлено спустя 3 часа 18 минут 22 секунды:
boez писал(а):Вот рабочий код ПИД-регулятора, выставляй правильно максимум и минимум

Что-то не фурычит твой код :-(((

Стал разбираться, вижу, например, такое:
((long)err*reg->kp)>>8

При тех коэффициентах, что у тебя в дефайне (150 что ли) ну просто смешное значение будет на выходе. Близкое к нулю. Но у тебя работает. А у меня нет.... Ладно, значит у меня руки кривые. Но при игре с коэффициентами (при выставлении всех трех в ~7000), значение, возвращаемой ПИД-функцией идеально равно значению ошибки.... что-то все это странно.

Re: ПИД (на ПИКе)

boez » 31 мар 2011, 09:56

Значение kp=256 соответствует единице, т.е. как раз ошибка 1 в 1 передается на выход в виде пропорциональной составляющей, ну там к ней понятное дело интеграл прибавляется. При 7000 она должна зверски усиливаться. Да, интеграл у меня реально маленький (медленный управляемый процесс, времена порядка секунд, цикл 1 мс), тебе нужен побольше, а если упрешься в его максимум (32767) - надо уменьшить число дробных знаков в интеграторе с 16 до 8. Но ты сначала добейся работы с медленным :)
Да, ты сюда все-таки напиши - какие у тебя диапазоны значений по скорости (target, current, error) и по выходу (ШИМ).

А fixed на мелких контроллерах однозначно быстрее double - ведь например для того, чтобы сложить 2 дабла, нужно вычесть их порядки, на полученную величину сдвинуть мантиссу одного из них (а перед этим по знаку разности определить кого сдвигать), потом сложить мантиссы (у даблов - 48-разрядные!) а потом еще сдвигать обратно мантиссу вверх, пока не получим 1 в старшем разряде и полученное число сдвигов прибавить к порядку результата. Короче, целая функция на несколько десятков команд вместо двух команд сложения (для 16 бит на 8-битном МК). double хорош на толстых интелах, у которых сопроцессор есть.

Re: ПИД (на ПИКе)

dccharacter » 31 мар 2011, 10:50

я ставил target 50, ШИМ не подавал, соответственно error = 50. И на выходе ПИД тоже четко 50 - это при коэффициентах 7000.

Re: ПИД (на ПИКе)

boez » 31 мар 2011, 11:34

dccharacter писал(а):я ставил target 50, ШИМ не подавал, соответственно error = 50. И на выходе ПИД тоже четко 50 - это при коэффициентах 7000.

Так не бывает. 50*7000 = 350000. 350000>>8 = 1367. Чтобы из этого получить 50, надо как-то сильно постараться :)
Давай сюда подробности:
1. Чему равно значение скорости (current) на максимальной скорости мотора.
2. Какое число соответствует максимальному ШИМ?
3. Что все-таки с реверсом? Он есть или его нет? Если есть, как устроен, как управляется?
4. С какой частотой вызывается функция регулятора?

Да, kd выставь в 0 и забудь про него пока у тебя ПИ не заработает. А ki и kp - ты мне на 4 вопроса вверху ответь и я тебе посоветую примерные значения. Особенно про реверс поподробнее расскажи, ты там в одном из первых сообщений пишешь что множишь ошибку на kp и результат в compare регистр - а если ошибка отрицательная?

Re: ПИД (на ПИКе)

dccharacter » 31 мар 2011, 11:48

Сейчас что знаю, остальное вечером, когда будет физический доступ к установке :-)

1. в районе 100 тиков
2. 255.
3. Он есть, но я не правил код твоего ПИДа, т.е. фактически не включал его. Управляется изменением полярности ШИМ. Это функция ECCP в PIC. Т.е. для включения реверса я меняю уровень на одной ноге (вход IN1 Н-моста) и меняю полярность ШИМ на другой (вход IN2 Н-моста).
4. Точно не помню, но что-то около 15-20 раз в сек.

Re: ПИД (на ПИКе)

boez » 31 мар 2011, 12:29

dccharacter писал(а):Сейчас что знаю, остальное вечером, когда будет физический доступ к установке :-)

1. в районе 100 тиков
2. 255.
3. Он есть, но я не правил код твоего ПИДа, т.е. фактически не включал его. Управляется изменением полярности ШИМ. Это функция ECCP в PIC. Т.е. для включения реверса я меняю уровень на одной ноге (вход IN1 Н-моста) и меняю полярность ШИМ на другой (вход IN2 Н-моста).
4. Точно не помню, но что-то около 15-20 раз в сек.


Ага. Хорошо. Тогда я бы начал действительно с проверки регулятора в П-режиме. Только с заранее известной ошибкой. Ставим коэффициент П скажем 2.5 (это в целых будет 2.5*256 = 640). Если ШИМ 255 = 100 тиков, то 50 тиков скорости должны получаться при шим 128 (округлим, пусть будет 125). Такой шим получится при ошибке 50 (50*2.5=128). Значит если дать задание 100, то мотор должен выйти на скорость 50 и ошибка тоже будет 50. Это я специально выбрал такой П-коэффициент, чтобы максимум задания вывести на максимум ШИМ, при этом какое бы задание не дали - на холостом ходу из него будет отрабатываться примерно половина. Дадим 50 - скорость будет 25. На малых заданиях пропорциональность потеряется, но это уже фигня, это просто самый первый тест, пока его не пройдем - дальше двигаться некуда. Что-то не так - выдаем жестко число 125 на ШИМ, 100 на задание, смотрим все промежуточные числа и ищем почему у нас на выходе регулятора не 125 или около того.

А дальше включаем И с маленьким коэффициентом, и смотрим что получается. Должно получаться сначала то же самое (ошибка=половине задания), а потом ошибка потихоньку будет падать и за какое-то время сойдет к нулю. Характерные времена считаются как
t_i = t_cycle/ki_real
где
ki_real = (max_ref/max_out)*(ki/65536), а здесь ki это уже число из моего регулятора.

Еще я бы уменьшил t_cycle хотя бы до 10 мс (считать регулятор 100 раз в секунду) - хотя увеличится шум от энкодера. Кстати, частота сигнала энкодера какая при максимальном ШИМ?

Ну в общем, для начала стоит взять характерное время секунд 10, это будет соответствовать ki_real=0.001 при 100 Гц, или 0.005 при 20 Гц. Соответственно ki = (0.001/0.4)*65536 = 160. при 20 Гц соответственно 160*5=800.

Ну вот какой-то такой план планомерной победы над регулируемой системой :) Следующий шаг - увеличение ki, чтобы моторчик выходил на режим не за полминуты, а побыстрее :)

Re: ПИД (на ПИКе)

dccharacter » 31 мар 2011, 12:42

Слушай, похоже у меня несколько раз все работало корректно, просто я до этого не допетрил :-). Ок, сегодня будем играться :-)))

Re: ПИД (на ПИКе)

dccharacter » 01 апр 2011, 01:39

Так, при ШИМ 255 получаем ~205 тиков.
Это при напряжении 15,6В и на частоте (прескейлер 16, постскейлер 8, итого 128. частота проца 4МГц) 1мкс*255*128 = ~32мс, или 30Гц.

Добавлено спустя 12 минут 31 секунду:
че-то не пойму - не фурычит и все. На выходе PIDа не пойми что и не пойми откуда берется... Супер, блин.

Добавлено спустя 1 час 24 минуты 28 секунд:
Так, заставил более-менее сносно работать ПИД из Вики (естественно, дело было не в ПИД-е!!!!! Это же сразу было понятно - осталось себя по лбу треснуть).

Вот что он выдает с таргетом 30 (и с дополнительным ограничением диапазона на выходе ПИД-функции:
.032, -002, 069
.029, 001, 100
.040, -010, 061
.032, -002, 069
.029, 001, 100
.040, -010, 061
.032, -002, 069
.030, 000, 100
.041, -011, 061

А вот таргет = 72:
.091, -019, 055
.046, 026, 255
.084, -012, 255
.094, -022, 065
.051, 021, 255
.079, -007, 255
.094, -022, 094
.059, 012, 255

Ну тема ясная, у меня очень грубо коэффициенты настраиваются, поэтому точности ожидать не стоит. Пойду теперь твой ПИД мучать.

Добавлено спустя 9 минут 21 секунду:
Вау, работает! Выход на таргет минуты за три! Сейчас буду перечитывать твои советы и тонко настраивать :-)

Добавлено спустя 22 минуты 40 секунд:
Надо же, предсказания сбываются. P-only. Магия, не иначе.

Добавлено спустя 13 минут 12 секунд:
Ну кое-как настроил, сейчас при почти любых таргетах работает с перерегулированием процентов в 15-20 (интегральная большая). Кто какой погрешности добивался? +-10% - это сильно грубо?

Добавлено спустя 4 минуты 6 секунд:
На втором графике (синеньком) при таких параметрах:
target = 82
#define PI_T3_KOEFF_I 5000
#define PI_T3_KOEFF_P 260
#define PI_T3_KOEFF_D 200
обновление 30Гц
Вложения
PID-only.png
P-only.png

Re: ПИД (на ПИКе)

Int_13h » 01 апр 2011, 08:18

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


Rambler\'s Top100 Mail.ru counter