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





 ((
((