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

 
 
> 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
Ответов
AHTOXA
сообщение May 4 2010, 07:56
Сообщение #2


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(sigmaN @ May 4 2010, 12:00) *
Регулятор в целом работает, но скверно. Его невозможно настроить.
передаваемые в pid_Init() p_factor i_factor d_factor имеют слишком большой эффект.
p_factor 1 работает, но реакция медленная. А уже при 2 колеблется достаточно сильно. При 3 - 5 уже полный абзац.

Не может быть. Там же всё делится на SCALING_FACTOR, который равен 128. То есть, при ошибке менее 128 и p_factor=1 отклик будет нулевым. То же и при p_factor=2 и ошибке 64.

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


Вот это как раз по указанной мной причине. Увеличивайте коэффициенты, не бойтесь.

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


Там сейчас шаг 1/128 smile.gif

ЗЫ. Советую для тренировки сделать всё на плавучке, так гораздо легче почувствовать поведение системы. Оптимизировать всегда успеете.


--------------------
Если бы я знал, что такое электричество...
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
- - 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
- - sigmaN   ЦитатаУ них эта зависимость засунута в коэффициент...   May 5 2010, 12:36
|- - raf329   вызывать pid_Reset_Integrator() при error == 0 или...   May 24 2010, 10:32
|- - demiurg_spb   Цитата(raf329 @ May 24 2010, 14:32) вызыв...   May 24 2010, 11:14
|- - Tanya   Цитата(demiurg_spb @ May 24 2010, 15:14) ...   May 24 2010, 11:17
|- - demiurg_spb   Цитата(Tanya @ May 24 2010, 15:17) Не зна...   May 24 2010, 11:22
|- - raf329   c ПИД регулятором работаю впервые, так когда необх...   May 24 2010, 11:41
||- - demiurg_spb   Цитата(raf329 @ May 24 2010, 15:41) c ПИД...   May 24 2010, 12:08
|- - Tanya   Цитата(demiurg_spb @ May 24 2010, 15:22) ...   May 24 2010, 12:33
|- - demiurg_spb   Цитата(Tanya @ May 24 2010, 16:33) Предуп...   May 24 2010, 13:11
- - Jenyok2   Вот реализация ПИД алгоритма. В процедуре DoChart ...   Oct 9 2011, 16:40


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

 


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


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