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 из структуры выкинуть и сделать чистыми константами. Но мне было удобнее по командам с терминала прибавлять-убавлять коэффициенты и таким образом настраивать регулятор на объекте. А уже потом один раз вписать их в константы и перепрошить контроллер.