реклама на сайте
подробности

 
 
> PID регулятор от Atmel, как-то не радует он меня. А должен.
sigmaN
сообщение May 4 2010, 06:00
Сообщение #1


I WANT TO BELIEVE
******

Группа: Свой
Сообщений: 2 617
Регистрация: 9-03-08
Пользователь №: 35 751



В общем-то ПИД регулятор применяю впервые.

Для начала решил стабилизировать обороты самого обычного кулера. Потом, естественно, доберусь и до температуры.
С кулером удобнее и нагляднее экспериментировать.

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

После внимательного изучения всей учёной части я таки впал в искушение и не стал кодить сам, а скачал атмеловскую аппноту AVR221

Код регулятора:
Код
#define SCALING_FACTOR  128

//Needed to avoid sign/overflow problems
// Maximum value of variables
#define MAX_INT         INT16_MAX
#define MAX_LONG        INT32_MAX
#define MAX_I_TERM      (MAX_LONG / 2)

typedef struct PID_DATA{
  //! Last process value, used to find derivative of process value.
  int16_t lastProcessValue;
  //! Summation of errors, used for integrate calculations
  int32_t sumError;
  //! The Proportional tuning constant, multiplied with SCALING_FACTOR
  int16_t P_Factor;
  //! The Integral tuning constant, multiplied with SCALING_FACTOR
  int16_t I_Factor;
  //! The Derivative tuning constant, multiplied with SCALING_FACTOR
  int16_t D_Factor;
  //! Maximum allowed error, avoid overflow
  int16_t maxError;
  //! Maximum allowed sumerror, avoid overflow
  int32_t maxSumError;
} pidData_t;
//===========================================================

void pid_Init(int16_t p_factor, int16_t i_factor, int16_t d_factor, struct PID_DATA *pid)
// Set up PID controller parameters
{
  // Start values for PID controller
  pid->sumError = 0;
  pid->lastProcessValue = 0;
  // Tuning constants for PID loop
  pid->P_Factor = p_factor;
  pid->I_Factor = i_factor;
  pid->D_Factor = d_factor;
  // Limits to avoid overflow
  pid->maxError = MAX_INT / (pid->P_Factor + 1);
  pid->maxSumError = MAX_I_TERM / (pid->I_Factor + 1);
}
//===========================================================

int16_t pid_Controller(int16_t setPoint, int16_t processValue, struct PID_DATA *pid_st)
{
  int16_t error, p_term, d_term;
  int32_t i_term, ret, temp;

  error = setPoint - processValue;

  // Calculate Pterm and limit error overflow
  if (error > pid_st->maxError){
    p_term = MAX_INT;
  }
  else if (error < -pid_st->maxError){
    p_term = -MAX_INT;
  }
  else{
    p_term = pid_st->P_Factor * error;
  }

  // Calculate Iterm and limit integral runaway
  temp = pid_st->sumError + error;
  if(temp > pid_st->maxSumError){
    i_term = MAX_I_TERM;
    pid_st->sumError = pid_st->maxSumError;
  }
  else if(temp < -pid_st->maxSumError){
    i_term = -MAX_I_TERM;
    pid_st->sumError = -pid_st->maxSumError;
  }
  else{
    pid_st->sumError = temp;
    i_term = pid_st->I_Factor * pid_st->sumError;
  }

  // Calculate Dterm
  d_term = pid_st->D_Factor * (pid_st->lastProcessValue - processValue);

  pid_st->lastProcessValue = processValue;

  ret = (p_term + i_term + d_term) / SCALING_FACTOR;
  if(ret > MAX_INT){
    ret = MAX_INT;
  }
  else if(ret < -MAX_INT){
    ret = -MAX_INT;
  }

  return((int16_t)ret);
}


ШИМ у меня 8бит.
каждые 250ms делаю так
Код
int16_t regOut;
        cooler = coolers.collection[i];
        regOut = pid_Controller(cooler->rpm_goal, cooler_get_rpm(cooler->id), &cooler->pid );
        regOut += cooler->current_pwm_duty;
        if( regOut > 255 )
            regOut = 255;
        if( regOut < 0 )
            regOut = 0;
        cooler->current_pwm_duty = regOut;
        cooler->setPWM( cooler->current_pwm_duty );

Регулятор в целом работает, но скверно. Его невозможно настроить.
передаваемые в pid_Init() p_factor i_factor d_factor имеют слишком большой эффект.
p_factor 1 работает, но реакция медленная. А уже при 2 колеблется достаточно сильно. При 3 - 5 уже полный абзац.
i_factor вообще лучше не трогать. Там даже 1 всё ломает. )
d_factor туда-сюда +/-5 - 10 ещё терпимо, но толку это не даёт

Также, заметил очень большой "зазор". Регулятор считает, что всё хорошо, хотя на самом деле обороты от заданных могут отличаться на 200 - 300(при 1100 заданных).

Мне не нравится что здесь всё как то уж больно целочисленно делается.
Есть идея переписать это дело под фиксированную точку, чтобы коэффициенты можно было задавать с шагом хотя-бы 0.1 вместо нынешней единицы.
Однако чувствую, что просто чего-то ещё не понял и того-же эффекта можно достичь другими методами.
Может быть мне стоит разделить входные setPoint и processValue на 2(а может и на 4), тем самым уменьшу ошибку и диапазон коэффициентов расширится?

Ещё вопрос как быть с частотой регулирования: как выбрать её оптимальной?

А ещё есть функция pid_Reset_Integrator(), которая сбрасывает сумму ошибок в 0. Когда её вызывать?


--------------------
The truth is out there...
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
sigmaN
сообщение May 5 2010, 12:36
Сообщение #2


I WANT TO BELIEVE
******

Группа: Свой
Сообщений: 2 617
Регистрация: 9-03-08
Пользователь №: 35 751



Цитата
У них эта зависимость засунута в коэффициенты I_Factor и D_Factor.
Понятно. В общем один раз выбрал частоту, настроил коэффициенты и забыл smile.gif)))

Кстати, а что там с частотой? Как её правильно выбрать?

вот нашел
Цитата
Есть простое правило для цифровых управляющих систем, которое гласит, что продолжительность итерации управляющего цикла должна быть между 1/10 и 1/100 желаемого времени стабилизации системы в новом положении.
1/10 и 1/100 - неплохой зазорчик )) Подозреваю, что тут нужно учитывать инерционность системы. Потому что если у меня будет желаемое время стабилизации 0.5с а двигатель здоровенный и тупой, реагирует на команды через 3секунды, то наверное ничего хорошего не выйдет из того, что я буду вызывать регулятор каждые 5ms smile.gif


--------------------
The truth is out there...
Go to the top of the page
 
+Quote Post
raf329
сообщение May 24 2010, 10:32
Сообщение #3





Группа: Участник
Сообщений: 8
Регистрация: 16-12-08
Пользователь №: 42 519



вызывать pid_Reset_Integrator() при error == 0 или когда???

Сообщение отредактировал raf329 - May 24 2010, 10:32
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение May 24 2010, 11:14
Сообщение #4


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(raf329 @ May 24 2010, 14:32) *
вызывать pid_Reset_Integrator() при error == 0 или когда???
А Вы сами-то что об этом думает?
Когда ошибка равна нулю - это значит что регулятор вышел на установившуюся мощность и зачем его лишать интегральной составляющую в этом момент (вдруг он плохо настроен и только на ней и теплится)?


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
Tanya
сообщение May 24 2010, 11:17
Сообщение #5


Гуру
******

Группа: Модераторы
Сообщений: 8 752
Регистрация: 6-01-06
Пользователь №: 12 883



Цитата(demiurg_spb @ May 24 2010, 15:14) *
Когда ошибка равна нулю - это значит что регулятор вышел на установившуюся мощность

Не значит.
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение May 24 2010, 11:22
Сообщение #6


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(Tanya @ May 24 2010, 15:17) *
Не значит.
Может значить, а может и нет (я утрировал).


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
Tanya
сообщение May 24 2010, 12:33
Сообщение #7


Гуру
******

Группа: Модераторы
Сообщений: 8 752
Регистрация: 6-01-06
Пользователь №: 12 883



Цитата(demiurg_spb @ May 24 2010, 15:22) *
Может значить, а может и нет (я утрировал).

Предупреждать надо. Вы же не утром писали...

Цитата(raf329 @ May 24 2010, 14:32) *
вызывать pid_Reset_Integrator() при error == 0 или когда???

Можете вызывать джинна Обнулятора и в этот момент. Только один раз.
Или держать интегральный член нулевым до уменьшения скорости в ... X раз.
А еще лучше - плавно менять задатчик, не вызывая джинна.
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение May 24 2010, 13:11
Сообщение #8


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(Tanya @ May 24 2010, 16:33) *
Предупреждать надо. Вы же не утром писали...
Когда встал - тогда и утро!
Тем не менее, бью челом! Простите холопа:-)


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post

Сообщений в этой теме
- sigmaN   PID регулятор от Atmel   May 4 2010, 06:00
- - Dog Pawlowa   Цитата(sigmaN @ May 4 2010, 09:00) В обще...   May 4 2010, 06:54
- - MSprut   Делал регулятор для бензинового двигателя на атмел...   May 4 2010, 07:21
- - AHTOXA   Цитата(sigmaN @ May 4 2010, 12:00) Регуля...   May 4 2010, 07:56
- - sigmaN   ЦитатаДля успешной работы регулятора нужно иметь д...   May 4 2010, 17:54
- - kamil yaminov   Может еще посмотреть в сторону всяких апериодическ...   May 5 2010, 03:50
- - DL36   Заготовка с плавающей точкой   May 5 2010, 04:58
- - sigmaN   А почему в атмеловском примере нигде не учитываетс...   May 5 2010, 11:39
|- - SSerge   Цитата(sigmaN @ May 5 2010, 18:39) А поче...   May 5 2010, 12:27
|- - raf329   c ПИД регулятором работаю впервые, так когда необх...   May 24 2010, 11:41
||- - demiurg_spb   Цитата(raf329 @ May 24 2010, 15:41) c ПИД...   May 24 2010, 12:08
- - Jenyok2   Вот реализация ПИД алгоритма. В процедуре DoChart ...   Oct 9 2011, 16:40


Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 20th July 2025 - 04:00
Рейтинг@Mail.ru


Страница сгенерированна за 0.01471 секунд с 7
ELECTRONIX ©2004-2016