помощь в ПИД
- Войдите на сайт для отправки комментариев
Пнд, 08/02/2021 - 21:50
Всем привет !!
Есть рабочий контроллер Электрокотла с 3 тэнами . Надоело менять тэны из-за того что один постоянно в работе . Хочу переделать на Пид регулировку , что бы все 3 тэна всегда были в работе , но не получается сделать включение и выключение котла с ПИД. Помогите советом .
код ..
/*Программа для автоматики управления тэнами и насосом ТТ котла Входа аналоговые : А0-вход для подключения клавиатуры А4 - подключение дисплея I2C А5 - подключение дисплея Входа дискретные: D2 -вход шины OneWire для подключения цифрового датчика температуры D18B20 СО D3 -вход шины OneWire для подключения цифрового датчика температуры D18B20 помещения Выхода: D5 - выход на подключение насоса СО D9 - выход на реле тэна 100%(шим) D10 - выход на реле тэна 66% D11 - выход на реле тэна 33% D6 - бипер */ //подключаем библиотеки #include <Wire.h> #include <EEPROM2.h> #include <LCD_1602_RUS.h> #include <OneWire.h> #include <DallasTemperature.h> #include <PID_v1.h> #include <CyberLib.h> // Установка переменных PID; double Setpoint, Input, Output; double aggKp=4, aggKi=0.2, aggKd=1; // Определяем агрессивные и консервативные параметры PID; double consKp=1, consKi=0.05, consKd=0.25; // Определяем указатели и другие параметры PID; PID myPID(&Input, &Output, &Setpoint, consKp, consKi, consKd, DIRECT); //Подключаем LCD-дисплей LCD_1602_RUS lcd(0x27,16,2); // Термометр котла будет подключен на Pin2 // Термометр комнаты будет подключен на Pin3 OneWire oneWire(2);//котел OneWire oneWireOut(3);//Комната //Создаем объект sensors, подключенный по OneWire DallasTemperature sensors(&oneWire); DallasTemperature sensorsOut(&oneWireOut); //Создаем переменные для работы с термометром DeviceAddress tempDeviceAddress; //переменная для хранения адреса датчика DeviceAddress tempDeviceAddressOut; //текущая температура теплоносителя float temp1 = 0; // текущая температура в помещении float temp2 = 0; //заданые температуры int setTmp = 33; // температура поддержания теплоносителя int setTmp1 = 32; // температура включения насоса отопления int setTmp2 = 28; // температура выключения насоса отопления int setTmp3 = 32; // температура в помещении int setLed=0; // Таймер подсветки int soundPin = 6; // объявляем переменную с номером пина, на который мы подключили пьезоэлемент //Реле подключено к пину D9, D10, D11, D13 #define RELAY_PIN1 11// 33% 1кВт #define RELAY_PIN2 10// 66% 2кВт #define RELAY_PIN3 9// 100% 3кВт #define RELAY_PIN4 5// насос циркуляционный //Подсветка управляется через пин D12 #define BACKLIGHT_PIN 12 //Создаем переменную для хранения состояния подсветки boolean backlightStatus = 1; //булевые переменые boolean pusk = LOW; //Объявим переменную для хранения команды пуск boolean avaria=LOW; // объявим переменую для хранения состояния аварии //Объявим переменную для хранения состояния реле boolean relayStatus33=LOW; boolean relayStatus66=LOW; boolean relayStatus100=LOW; boolean Vklnasos=LOW; boolean termostat = LOW; //Объявим переменную для хранения включения термостата. // лонг переменые для работы таймеров unsigned long currentTime; // текущее время //Объявим переменные для задания задержки long previousMillis1 = 0; long interval1 = 1000; // интервал опроса датчиков температуры //Аналоговая клавиатура подключена к пину A0 #define KEYPAD_PIN A0 //Определим значения на аналоговом входе для клавиатуры #define ButtonUp_LOW 130 #define ButtonUp_HIGH 200 #define ButtonDown_LOW 350 #define ButtonDown_HIGH 400 #define ButtonLeft_LOW 550 #define ButtonLeft_HIGH 650 #define ButtonRight_LOW -2 #define ButtonRight_HIGH 10 #define ButtonSelect_LOW 850 #define ButtonSelect_HIGH 890 void setup() { pinMode(soundPin, OUTPUT); //объявляем пин 6 как выход. tone(soundPin, 400, 300); delay(375.0); noTone(6); // Выключаем звук //Настроим пин для управления реле pinMode(RELAY_PIN1,OUTPUT); digitalWrite(RELAY_PIN1,LOW); pinMode(RELAY_PIN2,OUTPUT); digitalWrite(RELAY_PIN2,LOW); pinMode(RELAY_PIN3,OUTPUT); digitalWrite(RELAY_PIN3,LOW); pinMode(RELAY_PIN4,OUTPUT); digitalWrite(RELAY_PIN4,LOW); //Считаем из постоянной памяти заданную температуру setTmp=EEPROM_read_byte(0);//Температура СО setTmp1=EEPROM_read_byte(1);//Температура вкл насоса setTmp2=EEPROM_read_byte(2);//Температура выкл насоса setTmp3=EEPROM_read_byte(3);//Температура в комнате //Инициализируем термодатчик и установим разрешающую способность 12 бит (обычно она установлена по умолчанию, так что последнюю строчку можно опустить) sensors.begin(); sensors.getAddress(tempDeviceAddress, 0); sensors.setResolution(12); sensorsOut.begin(); sensorsOut.getAddress(tempDeviceAddressOut, 0); sensorsOut.setResolution(12); //работа пид регулятора в автомате Input = temp1; Setpoint = setTmp; myPID.SetMode(AUTOMATIC); myPID.SetOutputLimits(0, 100); //Выведем на дисплей стартовое сообщение на 2 секунды lcd.init(); lcd.backlight(); if (pusk == HIGH) { lcd.setCursor(0, 0); lcd.print("В РАБОТЕ "); } else { lcd.setCursor(0, 0); lcd.print("ОСТАНОВЛЕН"); } //Определим функцию для опроса аналоговой клавиатуры //Функция опроса клавиатуры, принимает адрес пина, к которому подключена клавиатура, и возвращает код клавиши: // 1 - UP // 2 - DOWN // 3 - LEFT // 4 - RIGHT // 5 - SELECT } int ReadKey(int keyPin) { int KeyNum=0; int KeyValue1=0; int KeyValue2=0; int KeyValue3=0; //Читаем в цикле аналоговый вход, для подавления дребезга и нестабильности читаем по два раза подряд, пока значения не будут равны. //Если значения равны 1023 – значит не была нажата ни одна клавиша. do { KeyValue1=analogRead(keyPin); KeyValue2=analogRead(keyPin); } while (KeyValue1==KeyValue2&&KeyValue2!=1023); //Интерпретируем полученное значение и определяем код нажатой клавиши if (KeyValue2<ButtonUp_HIGH&&KeyValue2>ButtonUp_LOW) {KeyNum=1;}//Up if (KeyValue2<ButtonDown_HIGH&&KeyValue2>ButtonDown_LOW) {KeyNum=2;}//Down if (KeyValue2<ButtonLeft_HIGH&&KeyValue2>ButtonLeft_LOW) {KeyNum=3;}//Left if (KeyValue2<=ButtonRight_HIGH&&KeyValue2>ButtonRight_LOW) {KeyNum=4;}//Right if (KeyValue2<ButtonSelect_HIGH&&KeyValue2>ButtonSelect_LOW) {KeyNum=5;}//Select //Возвращаем код нажатой клавиши return KeyNum; } void menu() { int keyCode=0; int k=0; lcd.init(); lcd.setCursor(0,0);lcd.print("Меню настройки"); lcd.setCursor(0, 1);lcd.print("Меню №"); lcd.setCursor(7, 1);lcd.print(k); delay_ms(1000); do{ keyCode=ReadKey(KEYPAD_PIN); if(keyCode==1){k++;delay(300);k=min(k,4);lcd.setCursor(7,1);lcd.print(k);} if(keyCode==2){k--;delay(300);k=max(k,0);lcd.setCursor(7,1);lcd.print(k);} }while(keyCode!=5); if(k==1) {setTemperature();} if(k==2) {setTemperature1();} if(k==3) {setTemperature2();} if(k==4) {setTemperature3();} } //Редактирование заданой температуры включения насоса ГВС void setTemperature() { //Редактирование заданой температуры включения насоса ГВС void setTemperature1() { //Редактирование заданой температуры выключения насоса ГВС void setTemperature2() { //Редактирование заданой температуры комнаты void setTemperature3() { } void loop() { Start currentTime=millis(); // time2=currentTime/3600000; // опрос клавиатуры int Feature=ReadKey(KEYPAD_PIN); if(Feature==5){;menu();}// переход в меню настройки // запуск котла нажать кнопку вверх if(Feature==1) { delay_ms(100); pusk=HIGH; EEPROM_write_byte(4,pusk); lcd.setCursor(0,0); lcd.print("В РАБОТЕ "); } // останов котла нажать кнопку вниз if(Feature==2&&pusk==HIGH) {delay_ms(100); pusk=LOW; EEPROM_write_byte(4,pusk); lcd.setCursor(0,0); lcd.print("ОСТАНОВЛЕН"); } if(Feature==3&&pusk==HIGH) {delay_ms(100); termostat = HIGH; EEPROM_write_byte(5,termostat); } if(Feature==4&&pusk==HIGH) {delay_ms(100); termostat = LOW; EEPROM_write_byte(5,termostat); lcd.setCursor(11,1); lcd.print("="); } //Модуль опроса датчиков и получения сведений о температуре //Вызывается 1 раз в секунду unsigned long currentMillis1 = millis(); if(currentMillis1 - previousMillis1 > interval1) { previousMillis1 = currentMillis1; //Запуск процедуры измерения температуры //sensors.setWaitForConversion(false); sensors.requestTemperatures(); sensorsOut.requestTemperatures(); //sensors.setWaitForConversion(true); //delay(750); // задержка для обработки информации внутри термометра, в данном случае можно не задавать //Считывание значения температуры sensors.getAddress(tempDeviceAddress, 0); temp1=sensors.getTempC(tempDeviceAddress); sensorsOut.getAddress(tempDeviceAddressOut, 0); temp2=sensorsOut.getTempC(tempDeviceAddressOut); // Вывод текущего значения температуры на дисплей lcd.setCursor(10, 0); lcd.print("P"); lcd.setCursor(0, 1); lcd.print("TCO"); lcd.setCursor(4,1); if (temp1>-127){lcd.print(temp1);} else {lcd.print("HET");delay(200);} if(temp1 ==(-127)){lcd.init();lcd.setCursor(4,1);lcd.print("сбой");avaria=HIGH;delay_ms(1000);} if(temp1 !=(-127)){avaria=LOW;} lcd.setCursor(8,1); lcd.print(" Tk"); lcd.setCursor(12,1); if (temp2>-127){lcd.print(temp2);} else {lcd.print("HET");delay(200);} //if(temp2 ==(-127)){lcd.init();lcd.setCursor(12,1);lcd.print("сбой");avaria=HIGH;delay_ms(1000);} //if(temp2 !=(-127)){avaria=LOW;} setLed++; } /****************************************** Выход котла на паузу**************************************/ // Пауза в работе котла при достижении температуры заданой if (temp1 >= (setTmp)) { myPID.SetMode(MANUAL); } if (temp1 < (setTmp - 1)) { myPID.SetMode(AUTOMATIC); } /****************************************** Пид регулятор**************************************/ // Настройка пид Input = temp1; Setpoint = setTmp - 2; //работа пид регулятора double gap = abs(Setpoint - Input); //смотрим разницу заданного от уставки if (gap < 6) { myPID.SetTunings(consKp, consKi, consKd); //если меньше 5 то работаем на коэфицентах } else { myPID.SetTunings(aggKp, aggKi, aggKd); //если больше то работаем на коэфицентах } myPID.Compute(); //Проверка условия включения/выключения нагревателя if (pusk==HIGH&&avaria==LOW) { if (temp1 < setTmp && relayStatus33 == LOW) { relayStatus33 = HIGH; digitalWrite(RELAY_PIN1, HIGH); lcd.setCursor(11, 0); lcd.print("= 33%"); lcd.setCursor(3, 1); lcd.print("+"); } if (temp1 > setTmp && relayStatus33 == HIGH) { relayStatus33 = LOW; digitalWrite(RELAY_PIN1, LOW); lcd.setCursor(11, 0); lcd.print("= 0%"); lcd.setCursor(3, 1); lcd.print("-"); } delay(500); if (temp1 < setTmp - 1 && relayStatus66 == LOW) { relayStatus66 = HIGH; digitalWrite(RELAY_PIN2, HIGH); lcd.setCursor(11, 0); lcd.print("= 66%"); lcd.setCursor(3, 1); lcd.print("+"); } if (temp1 >= setTmp - 1 && relayStatus66 == HIGH) { relayStatus66 = LOW; digitalWrite(RELAY_PIN2, LOW); lcd.setCursor(11, 0); lcd.print("= 33%"); // lcd.setCursor(3, 1); // lcd.print("-"); } delay(500); if (temp1 < setTmp - 2 && relayStatus100 == LOW) { relayStatus100 = HIGH; digitalWrite(RELAY_PIN3, HIGH); lcd.setCursor(11, 0); lcd.print("=100%"); lcd.setCursor(3, 1); lcd.print("+"); } if (temp1 >= setTmp - 2 && relayStatus100 == HIGH) { relayStatus100 = LOW; digitalWrite(RELAY_PIN3, LOW); lcd.setCursor(11, 0); lcd.print("= 66%"); // lcd.setCursor(3, 1); //lcd.print("-"); }} if (pusk==LOW&&avaria==HIGH) { if(pusk==LOW && relayStatus33 == HIGH && relayStatus66 == HIGH && relayStatus100 == HIGH) relayStatus33 = LOW; digitalWrite(RELAY_PIN1, LOW); relayStatus66 = LOW; digitalWrite(RELAY_PIN2, LOW); relayStatus100 = LOW; digitalWrite(RELAY_PIN3, LOW); lcd.setCursor(11, 0); lcd.print("= 0%"); lcd.setCursor(3, 1); lcd.print("-"); } // Работа с насосом //блок управления насосом отопления
Всем привет !!
Есть рабочий контроллер Электрокотла с 3 тэнами . Надоело менять тэны из-за того что один постоянно в работе . Хочу переделать на Пид регулировку , что бы все 3 тэна всегда были в работе , но не получается сделать включение и выключение котла с ПИД. Помогите советом .
При чем здесь ПИД? Вы хоть малость себе представляете, что эта штука сделана для "успокаивания" очень быстрых процессов? Где в Ваших котлах быстрые процессы? Они у Вас перекипают? Взрываются? Если они "постоянно в работе", то скорее всего они недостаточной мощности для Ваших задач. А если их надо "менять", то возможно возле них
Я думаю ТС имел ввиду - распределить общий нагрев по всем тэнам, так как в основном один трудится (и сгорает изсза этого), а остальные в основном в простое).
Поставить твердотельное реле и диммировать (пропуском периодов) сразу все тэны, но соседи будут не в восторге от того что свет мигает (по себе знаю). Если диммировать обрезанием синусоиды то не только соседи будут очень "рады"...
Можно просто пускать нагрев в цикле по тенам. К примеру , если мало нужно греть - n минут греет один, общее выключение, потом включается другой и тоже n минут греет и так далее. А если нужно поддать газку, то интервал n уменьшать и в какой-то момент включать уже два тена сразу (к примеру из 3х), чередуя их. Ничего диммировать не нужно.
Можно просто пускать нагрев в цикле по тенам. К примеру , если мало нужно греть - n минут греет один, общее выключение, потом включается другой и тоже n минут греет и так далее. А если нужно поддать газку, то интервал n уменьшать и в какой-то момент включать уже два тена сразу (к примеру из 3х), чередуя их. Ничего диммировать не нужно.
Ой-вэй! А где тут ПИД - хоть раз скажите.
Нахрена здесь интегральная и дифференциальная составляющие? Вот "чтобы було"????
При чем здесь ПИД? Вы хоть малость себе представляете, что эта штука сделана для "успокаивания" очень быстрых процессов? Где в Ваших котлах быстрые процессы? Они у Вас перекипают? Взрываются? Если они "постоянно в работе", то скорее всего они недостаточной мощности для Ваших задач. А если их надо "менять", то возможно возле них
ПИД регулятор с тремя каналами. Канал И может "успокаивать" довольно продолжительное время. ПИД можно использовать для многого, не обязательно для быстрых процессов.
Вы бредите?
Ну почитайте хоть чего нибудь. Не только комиксы. Да ПИД можно использовать для любых процессов, но интегральная составляющая будет работать при очень быстрых процессах (ну хоть в экзеле попробуйте), дифференциальная - вообще нахер не нужна. Если Вы мне покажете случай, когда она нужна, а я не смогу Вам оппонировать, то с меня пузырь коньяка.
http://arduino.ru/forum/pesochnitsa-razdel-dlya-novichkov/etyudy-dlya-pe...
Почитайте перевод нашего b707. Обратите внимание на слово долговременный в описании И канала.
http://arduino.ru/forum/pesochnitsa-razdel-dlya-novichkov/etyudy-dlya-pesochnitsy-teoriya-upravleniya-i-regulyatory#comment-512054
Почитайте перевод нашего b707. Обратите внимание на слово долговременный в описании И канала.
Боинг, конечно, классный мужик! Но дифференциальную составляющую он обошел боком.
И чего Вы там гутарите про долговременные процессы? Пропорциональной составляющей не хватает* - График представьте. При разных коэффициентах. Сходимость.... И т.д.
Короче- почитал ТЗ ТС. Ему надо случайно менять начальный ТЭН, чтобы сгорали реже. А ПИД здесь совсем не при чём.
mykaida, не пишите то о чем вы вообще нихера не бум-бум!
Интегральная составляющая регулятора обязательна для устранения статической ошибки регулирования, которая будет при использовании только пропорциональной составляющей.
Пропорциональная составляющая не сможет вывести процесс вровень с заданием, т.к. тогда она же становится равна нулю!
Дифференциальная применяется, в основном, при быстрых процессах, и очень редко применяется при регулировании температуры.
Всем привет !!
Есть рабочий контроллер Электрокотла с 3 тэнами . Надоело менять тэны из-за того что один постоянно в работе . Хочу переделать на Пид регулировку , что бы все 3 тэна всегда были в работе , но не получается сделать включение и выключение котла с ПИД. Помогите советом .
можно вместо этого, заменив дефайны на переменные, написать функцию, которая, например, раз в сутки (или реже/чаще) будет переназначать пины через random() или кольцевой массив, для уравнивания наработки на тэн.
если я правильно понял, что работают тэн1, или тэн1+тэн2, или тэн1+тэн2+тэн3.
Как то так
Подскажите, пожалуйста!
Для регулировки температуры управляю оборотами мотора охлаждающего вентилятора, подключая его к 1 из 6 обмоток трансформатора, пока вручную. Подходит ли ПИД алгоритм для автоматизации этого процесса? Или нужен какой-то другой алгоритм?
Если сможете прикрутить то подходит.