PID + AC = какая-то фигня. Подскажите, где ошибка.

Gexogyan
Offline
Зарегистрирован: 13.01.2020

Всем привет!

Пытаюсь настроить ПИД-регулятор на поддержку заданной температуры. В качестве нагревателя использую лампочку 220в через модуль с симистром.

Начинаю с настройки коэффициента на "P", но рост температуры ни то чтобы не образует волны, а даже не доходит до заданной и останавливается не доходя процентов 10. Коэф "P" поднимал до 100, результат ближе к заданному, но все равно не доходит до него и вообще никакого колебания нет.

График и фото прилагаю.

В чем моя ошибка?

01#include <GyverPID.h>
02#include <PIDtuner.h>
03#include <PIDtuner2.h>
04GyverPID pid;
05 
06#include <DS_raw.h>
07#include <microDS18B20.h>
08#include <microOneWire.h>
09 
10MicroDS18B20 <A5> ds;
11 
12#define ZERO_PIN 2    // пин детектора нуля
13#define INT_NUM 0     // соответствующий ему номер прерывания
14#define DIMMER_PIN 4  // управляющий пин симистора
15#include <GyverTimers.h>  // библиотека таймера
16float dimmer;               // переменная диммера
17int dt = 100; // помоему, нужен только для Ki
18 
19void setup() {
20  pid.Kp = 1;
21  pid.Ki = 0;
22  pid.Kd = 0;
23  pid.setDt(dt); //частота опроса с датчика
24  pid.setDirection(NORMAL); //работа на увеличение
25  pid.setpoint = 60; //нужная температура
26 
27  pinMode(ZERO_PIN, INPUT_PULLUP);
28  pinMode(DIMMER_PIN, OUTPUT);
29  attachInterrupt(INT_NUM, isr, RISING);  // для самодельной схемы ставь FALLING
30  Timer2.enableISR();
31  Serial.begin(9600);
32}
33 
34void loop() {
35  temp();
36  pidControl();
37 
38}
39 
40void temp() {
41  static uint32_t timer = millis();
42  if (millis() - timer >= 1000) {
43    timer = millis();
44    if (ds.readTemp()) {
45      Serial.println(ds.getTemp());
46    }
47    ds.requestTemp();
48  }
49}
50 
51void pidControl() {
52  static uint32_t tmr;
53  if (millis() - tmr > dt) {
54    tmr = millis();
55    pid.input = ds.getTemp(); // передаем новый измеренный сигнал с датчика
56    pid.getResult(); //делает рассчеты, ее нужно вызывать по таймеру с периодом dt
57    pid.output; //принимает значение управляющего сигнала
58    dimmer = map(pid.output, 0, 125, 9300, 500);
59  }
60}
61 
62// прерывание детектора нуля
63void isr() {
64  static int lastDim;
65  digitalWrite(DIMMER_PIN, 0);  // выключаем симистор
66  // если значение изменилось, устанавливаем новый период
67  // если нет, то просто перезапускаем со старым
68  if (lastDim != dimmer) Timer2.setPeriod(lastDim = dimmer);
69  else Timer2.restart();
70}
71// прерывание таймера
72ISR(TIMER2_A) {
73  digitalWrite(DIMMER_PIN, 1);  // включаем симистор
74  Timer2.stop();                // останавливаем таймер
75}

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

а прямо к лампочке прислонить?
или поставь -pid.setpoint = 50; //нужная температура

Gexogyan
Offline
Зарегистрирован: 13.01.2020

Лампочка осиливает температуру в 60 градусов. И 80 осиливает.

Если поставить 50 градусов, то будет доходить до ~45 и там останавливаться.

Kakmyc
Offline
Зарегистрирован: 15.01.2018

У тебя система настолько медленная, а опросы настолько частые, что колебаний ты не увидишь

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Тут даже фазное регулирование ни к чему.
Тупо ШИМ организуй с периодом 0,1Гц и скважность регулируй с дискретностью 10мс.

Gexogyan
Offline
Зарегистрирован: 13.01.2020

как я понял, датчик температуры 18D20 чаще чем каждые 0,85 сек опрашивать бесполезно. Поэтому выставлено на 1 сек.

но какое-то решение должно же быть? как его найти?

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Gexogyan пишет:

как я понял, датчик температуры 18D20 чаще чем каждые 0,85 сек опрашивать бесполезно. Поэтому выставлено на 1 сек.

но какое-то решение должно же быть? как его найти?

Я же говорю, система медленная, а опросы слишком частые.
Пересчитыйвай, значение хотя бы раз в 10сек, а не каждую секунду.

Gexogyan
Offline
Зарегистрирован: 13.01.2020

Понял. Спасибо! Буду пробовать