Arduino PID Алгоритм генерации превышения - PullRequest
0 голосов
/ 16 мая 2019

У меня есть код (ESP8266 с кодом Arduino) ниже, который реализует ПИД-логику для достижения и поддержания температуры 5-литрового варочного котла, используя твердотельное реле и электрический нагревательный элемент мощностью 3 кВт 220 В.Даже используя алгоритм автонастройки, kp, ki, kd генерируют очень высокий выброс (+ 5ºC выше заданного значения).

int WindowSize = 5000;
unsigned long windowStartTime;
double KettleSetpoint, KettleInput, KettleOutput;
PID _kettlePID = PID(&KettleInput, &KettleOutput, &KettleSetpoint, 1, 1, 1, DIRECT);

PID_ATune aTune(&KettleInput, &KettleOutput);
double aTuneStep = 5000, aTuneNoise = 1, aTuneStartValue = 0;
unsigned int aTuneLookBack = 20;
byte ATuneModeRemember = 2;
double kp = 2, ki = 0.5, kd = 2;

...

void KettleHeaterService::StartPID(double kp, double ki, double kd)
{
  _kettlePID.SetTunings(kp, ki, kd);
  _kettlePID.SetOutputLimits(0, WindowSize);
  windowStartTime = millis();
  _kettlePID.SetMode(AUTOMATIC);
}

void KettleHeaterService::StartAutoTune()
{
  KettleOutput = aTuneStartValue;
  aTune.SetNoiseBand(aTuneNoise);
  aTune.SetOutputStep(aTuneStep);
  aTune.SetLookbackSec((int)aTuneLookBack);
  ATuneModeRemember = _kettlePID.GetMode();
}

void KettleHeaterService::Compute()
{
  KettleInput = _activeStatus->Temperature;
  KettleSetpoint = _activeStatus->TargetTemperature;

  if (_activeStatus->PIDTuning)
  {
    Serial.println("tuning..");
    if (aTune.Runtime() != 0)
    {
      _activeStatus->PIDTuning = false;
      _activeStatus->BrewStarted = false;
      _activeStatus->StartTime = 0;
      _activeStatus->EndTime = 0;
      _brewSettingsService->KP = aTune.GetKp();
      _brewSettingsService->KI = aTune.GetKi();
      _brewSettingsService->KD = aTune.GetKd();
      _brewSettingsService->writeToFS();
      _kettlePID.SetMode(ATuneModeRemember);
      _kettlePID.SetTunings(_brewSettingsService->KP, _brewSettingsService->KI, _brewSettingsService->KD);
    }
  }
  else
    _kettlePID.Compute();

  Serial.print("OUTPUT: ");
  Serial.println(KettleOutput);

  unsigned long now = millis();
  if (now - windowStartTime > WindowSize)
  {
    windowStartTime += WindowSize;
    Serial.println("time to shift the Relay Window");
  }

  if (KettleOutput > now - windowStartTime)
  {
    digitalWrite(HEATER_BUS, HIGH);
    _activeStatus->PWM = 1023;
    Serial.println("on");
  }
  else
  {
    digitalWrite(HEATER_BUS, LOW);
    _activeStatus->PWM = 0;
    Serial.println("off");
  }
}

Есть ли ошибка в этой логике?Почему мой алгоритм настройки не генерирует значения kp, ki, kd правильно, чтобы избежать перерегулирования?

...