PID - Can't set Output Limits

Hi there,
Trying use the PID libraries but having some trouble generating Output that I would expect to see.

I would expect to see the PID Output set between the Output limits but what I get on the Serial Monitor is the PID algorithm giving me an output calculation directly on the inputvalues (in this case temperature). i.e with Kp set to 15, Input temp is 24 Deg C. Target temp is 60 DegC so the Output I see is (60-24)*15, where I would expect to see something in proportion to the Output limits.

All help appreciated

// PID Stuff

//Define variables we'll be connecting to.
double PIDOutput;

//Define the aggressive and conservative tuning parameters.
// double aggKp=15, aggKi=0.02, aggKd=40;       //When input is below setpoint.
//test
double aggKp=15, aggKi=0, aggKd=0;       //When input is below setpoint.
double consKp=15, consKi=0.1, consKd=40;     // When input is above setpoint. P will not do anything since the output only drives in one direction.

//Specify the links and initial tuning parameters.
PID myPID(&chambertemp, &PIDOutput, &mainheattarget, consKp, consKi, consKd, DIRECT);

unsigned long PIDWindowSize = 60000;
unsigned long PIDwindowStartTime;

// Instance setups

MAX6675 ChamberSensor(SCK_PIN, CS_PIN, SO_PIN);
BlynkTimer DataSendTimerBlynk;

/* Blynk app Virtual pin numbers
V4 Heat Conntrol Manual Button
*/

BLYNK_WRITE(V0)
{
  mainheattarget = param.asInt();
  Serial.println(mainheattarget);
}

BLYNK_WRITE(V4)
{
  heatcontrolman = param.asInt();
}

// Blynk DataSendFunction temporary will send to serial need virtual blynk graph data

void DataSendBlynk()
{
  chambertemp = ChamberSensor.readCelsius();
  Serial.println("Deg C = ");
  Serial.println(chambertemp);
  Blynk.virtualWrite(V5, chambertemp);

    Serial.println("PIDOutput = ");
    Serial.println(PIDOutput);
    Serial.println("PIDWindowSize = ");
    Serial.println(PIDWindowSize);
    Serial.println("Manual Control Button =");
    Serial.println(heatcontrolman);
}

void setup()
{

  // Debug console
  Serial.begin(115200);
  delay(5000);

  // Pin assignments
  pinMode(gassolenoid, OUTPUT);
  pinMode(wificonnectOK, OUTPUT);

  // Blynk.begin(auth, ssid, pass, "blynk-cloud.com", 80);

  // You can also specify server:
  //Blynk.begin(auth, ssid, pass, "blynk-cloud.com", 80);
  //Blynk.begin(auth, ssid, pass, IPAddress(192,168,1,100), 8080);

  Blynk.connectWiFi(ssid, pass);
  Blynk.config(auth, "blynk.cloud", 8080);
  Blynk.disconnect();

  // Blynk 1 second timer for sending data back to cloud

  DataSendTimerBlynk.setInterval(1000L, DataSendBlynk);

  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("WiFi connected OK");
    digitalWrite(wificonnectOK, LOW);
  }
  Serial.println(ssid);
  Serial.println("IP Address: ");
  Serial.println(WiFi.localIP());

  Blynk.connect();
  if (Blynk.connected()) {
    Serial.println("Blynk connect TRUE");
  }
    Serial.println("Main Loop");

  // PID setup

  PIDwindowStartTime=millis();
  //tell the PID to range between 0 and the full window size
  myPID.SetOutputLimits(0, PIDWindowSize);

  //turn the PID on
  myPID.SetMode(AUTOMATIC);
}


void loop()
{
  Blynk.run();
  if (heatcontrolman==1){
    digitalWrite(gassolenoid, HIGH);}
    else
    {if(chambertemp>mainheattarget)
  {  //We are over the setpoint set to normal.
    myPID.SetTunings(consKp, consKi, consKd);
  }
  else
  {
     //We are not over, so we must be below. set to aggresive.
     myPID.SetTunings(aggKp, aggKi, aggKd);
  }

  myPID.Compute();
  /************************************************
     turn the output pin on/off based on pid output
   ************************************************/
  unsigned long now = millis();
  if (now - PIDwindowStartTime > PIDWindowSize)
  { //time to shift the Relay Window
    PIDwindowStartTime += PIDWindowSize;
  }
  if (PIDOutput > now - PIDwindowStartTime) digitalWrite(gassolenoid, HIGH);
  else digitalWrite(gassolenoid, LOW);
    }
  DataSendTimerBlynk.run();
}

All the PID library does is calculate as normal and then make sure the result isn't outside the limits. There's nothing scaling in proportion to the window size, as you observe.

Nothing to stop you calculating that proportional response yourself of course.

// PID setup
PIDwindowStartTime = millis();

//tell the PID to range between 0 and the full window size
myPID.SetOutputLimits(0, PIDWindowSize);

//ensure there's only one PID compute cycle (sample) per output window period
myPID.SetSampleTime(PIDWindowSize - 1);

//turn the PID on
myPID.SetMode(AUTOMATIC);

Use constrain() ?

wildbill everything I'm finding tells me the output should be scaled within the Output limits.

e.g. the below from the PID RelayOutput example on Arduino Playground which used similar code to mine

To connect them together we use "time proportioning
control" It's essentially a really slow version of PWM.
First we decide on a window size (5000mS say.) We then
set the pid to adjust its output between 0 and that window
** size.** Lastly, we add some logic that translates the PID
output into "Relay On Time" with the remainder of the
window being "Relay Off Time"

No, at least not as you seem to expect.

The output limits have no effect on the PID calculation, it does its thing using the coefficients you provided and the result is the result. The output limits are then used to ensure that the output doesn't exceed them.

If the input is consistently less than the set point then the output will rise eventually to the top of the output limit.

Normally, the PID limits are zero to 255 because that's handy for PWM when you have something that can be proportionally controlled. Let's say you're getting an output of 100. I think that you expect that if you change the output limits to zero to 2550 that you will get an output of 1000. You won't. The limits don't impact the PID calculation in that way, they just cap the result you get.

So, in this example, you can leave the limits at default and multiply the output by ten to get a window size or you can set the limits and deal with the fact the window will be very short to start with but will rise up to something more useful over time.

Using QuickPID, I have a time proportioning control example here (c/w debounce).

Thanks for your responses and patience. I've been reading into how PID's work and wasn't able to see that when you get into practice in code like this, that window size has a big impact in the response of the system given the output calculation is unrelated to it.

Thanks again I'll make some changes to get it working they way I want.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.