sigmaN 0 4 мая, 2010 Опубликовано 4 мая, 2010 · Жалоба В общем-то ПИД регулятор применяю впервые. Для начала решил стабилизировать обороты самого обычного кулера. Потом, естественно, доберусь и до температуры. С кулером удобнее и нагляднее экспериментировать. Ну, задача известная: поддерживать заданную частоту вращения ротора безколлекторного двигателя постоянного тока. После внимательного изучения всей учёной части я таки впал в искушение и не стал кодить сам, а скачал атмеловскую аппноту 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. Когда её вызывать? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
DogPawlowa 0 4 мая, 2010 Опубликовано 4 мая, 2010 · Жалоба В общем-то ПИД регулятор применяю впервые. Для успешной работы регулятора нужно иметь достаточную частоту отсчетов, иначе никакими коэффициентами невозможно регулировать. А Вы даже не объяснили, что на входе регулятора, что на выходе. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MSprut 0 4 мая, 2010 Опубликовано 4 мая, 2010 · Жалоба Делал регулятор для бензинового двигателя на атмеловской ПИД-заготовке. Управлял заслонкой карбюратора через ШД и редуктор. Время отклика системы где-то 1-2сек, сделал измерение оборотов 10 раз/сек и одновременно пересчет управляющего воздействия. Работает вполне сносно, только i_factor очень маленький получился иначе время реакции снижается. Фактически не ПИД, а ПД регулятор получился. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 14 4 мая, 2010 Опубликовано 4 мая, 2010 · Жалоба Регулятор в целом работает, но скверно. Его невозможно настроить. передаваемые в 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 :) ЗЫ. Советую для тренировки сделать всё на плавучке, так гораздо легче почувствовать поведение системы. Оптимизировать всегда успеете. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sigmaN 0 4 мая, 2010 Опубликовано 4 мая, 2010 · Жалоба Для успешной работы регулятора нужно иметь достаточную частоту отсчетов, иначе никакими коэффициентами невозможно регулировать. А Вы даже не объяснили, что на входе регулятора, что на выходе. На входе заданные обороты(об/мин) и измеренные в данный момент времени. Измерение происходит каждый оборот кулера. Вызов функции регулятора - каждые ~250ms Про выход думал будет понятно из кода. В общем воздействую я на систему путем изменения скважности ШИМ. Не может быть. Там же всё делится на SCALING_FACTOR, который равен 128. То есть, при ошибке менее 128 и p_factor=1 отклик будет нулевым. То же и при p_factor=2 и ошибке 64.Логично. SCALING_FACTOR я что-то не учел. Вот это как раз по указанной мной причине. Увеличивайте коэффициенты, не бойтесь.Ситуация немного прояснилась, спасибо. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
kamil_yaminov 1 5 мая, 2010 Опубликовано 5 мая, 2010 · Жалоба Может еще посмотреть в сторону всяких апериодических звеньев в качестве регулятора? Гибкость не такая как у ПИД, зато реализация проще некуда. Да и проще они в настройке. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Гость DL36 5 мая, 2010 Опубликовано 5 мая, 2010 (изменено) · Жалоба Заготовка с плавающей точкой Изменено 5 мая, 2010 пользователем DL36 Нарушение п.3.4 Правил форума. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sigmaN 0 5 мая, 2010 Опубликовано 5 мая, 2010 · Жалоба А почему в атмеловском примере нигде не учитывается частота вызова функции? А в приведеннем примере наоборот есть real tauQuant // период квантования (реальный!!! период запуска функции регулятора), размерность - секунды Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SSerge 4 5 мая, 2010 Опубликовано 5 мая, 2010 · Жалоба А почему в атмеловском примере нигде не учитывается частота вызова функции? У них эта зависимость засунута в коэффициенты I_Factor и D_Factor. при изменении частоты дискретизации эти коэффициенты нужно будет пересчитать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sigmaN 0 5 мая, 2010 Опубликовано 5 мая, 2010 · Жалоба У них эта зависимость засунута в коэффициенты I_Factor и D_Factor.Понятно. В общем один раз выбрал частоту, настроил коэффициенты и забыл :)))) Кстати, а что там с частотой? Как её правильно выбрать? вот нашел Есть простое правило для цифровых управляющих систем, которое гласит, что продолжительность итерации управляющего цикла должна быть между 1/10 и 1/100 желаемого времени стабилизации системы в новом положении. 1/10 и 1/100 - неплохой зазорчик )) Подозреваю, что тут нужно учитывать инерционность системы. Потому что если у меня будет желаемое время стабилизации 0.5с а двигатель здоровенный и тупой, реагирует на команды через 3секунды, то наверное ничего хорошего не выйдет из того, что я буду вызывать регулятор каждые 5ms :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
raf329 0 24 мая, 2010 Опубликовано 24 мая, 2010 (изменено) · Жалоба вызывать pid_Reset_Integrator() при error == 0 или когда??? Изменено 24 мая, 2010 пользователем raf329 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 24 мая, 2010 Опубликовано 24 мая, 2010 · Жалоба вызывать pid_Reset_Integrator() при error == 0 или когда???А Вы сами-то что об этом думает? Когда ошибка равна нулю - это значит что регулятор вышел на установившуюся мощность и зачем его лишать интегральной составляющую в этом момент (вдруг он плохо настроен и только на ней и теплится)? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Tanya 4 24 мая, 2010 Опубликовано 24 мая, 2010 · Жалоба Когда ошибка равна нулю - это значит что регулятор вышел на установившуюся мощность Не значит. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 24 мая, 2010 Опубликовано 24 мая, 2010 · Жалоба Не значит.Может значить, а может и нет (я утрировал). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
raf329 0 24 мая, 2010 Опубликовано 24 мая, 2010 · Жалоба c ПИД регулятором работаю впервые, так когда необходимо вызывать данную ф-ию? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться