PID Controller - Limiting Output

Hi Folks

I am using the brilliant PID library written by Brett Beauregard. The library is working great with the exception that I cannot get the SetOutputLimits() function to work. I am trying to limit my servo travel to 10-180degrees. I could always scale the myPID output to this range but I know the library has better functionality within ( to prevent PID wind up) if I can get the SetOutputLimits() function to work.

Can anybody see in my code what the problem may be??

PS…hope this is the correct part of the forum to post this message???

/ * 

/*-----( Import needed libraries )-----*/
#include <Wire.h>  // Comes with Arduino IDE
#include <LiquidCrystal_I2C.h> /// https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads  Move any other LCD libraries to another folder or delete them
#include <AnalogSmooth.h>
#include "ThingSpeak.h" // added for thinkgspeak connectivity
#include <Ethernet.h> *// added for thinkgspeak connectivity
#include <SPI.h> // added for thinkgspeak connectivity to ethernet sheild
#include <Servo.h> // added for the servos! https://www.arduino.cc/en/Reference/Servo
#include <PID_v1.h>

EthernetClient client; 

/*-----( Declare Constants )-----*/
//Connect Vcc and Ground, SDA to A4, SCL to A5 on Arduino
 int O2FlueTempAnaloguePin = 2;
 int O2AnaloguePin = 3;
 int Led1Pin = 3;
 int Led2Pin = 2;
 int LambdaController = 7;
 int myServoPin = 9;
 int FlueThreshold = 15;
 int HeatMeter = 4;

 const float VOLTAGE_MAX = 5.0;
 const float VOLTAGE_MAXCOUNTS = 1023.0;
 const float HEATMETERPOWERHIGH_KW = 20; //4.5VISH
 const float HEATMETERPOWERLOW_KW = 0;
 const float HEATMETERPOWERHIGH_BIT = 959;
 const float HEATMETERPOWERLOW_BIT = 185;
 
 double PID_SetPoint = 19;
 double P_PARAM = 10; //Needs to be a double to pass to PID library
 double I_PARAM = 5;  //Needs to be a double to pass to PID library
 double D_PARAM = 1;  //Needs to be a double to pass to PID library
 double SERVO_MAX = 180;  //Needs to be a double to pass to PID library
 double SERVO_MIN = 10;  //Needs to be a double to pass to PID library

 byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; // added for thinkgspeak connectivity
 unsigned long myChannelNumber = xxxxxx; // added for thinkgspeak connectivity
 const char * myWriteAPIKey = "xxxxxx"; // added for thinkgspeak connectivity
 
/*-----( Declare Variables )-----*/
 float O2;
 float FlueTemperature;
 unsigned long timer;
 int ServoPos = 0;
 float HeatMeterPower;
 double PID_Input,PID_Output;

/*-----( Declare objects )-----*/
// set the LCD address to 0x27 for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
 LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address
 AnalogSmooth as_O2 = AnalogSmooth(20);
 AnalogSmooth as_Flue = AnalogSmooth(20);
 Servo myservo;  // create servo object to control a servo
 PID myPID(&PID_Input, &PID_Output, &PID_SetPoint,P_PARAM ,I_PARAM ,D_PARAM , DIRECT );

 
void setup()   
{ 
  Serial.println("Setup Start");
  
  pinMode(Led1Pin, OUTPUT);
  pinMode(Led2Pin, OUTPUT);
  pinMode(LambdaController, OUTPUT); 
  digitalWrite(LambdaController,HIGH);
  digitalWrite(Led1Pin,LOW);
  digitalWrite(Led2Pin,LOW);
  
  myservo.attach(myServoPin); // attaches servo

  
  Serial.begin(9600);
  lcd.begin(20,4); 
  
  lcd.setCursor(3,0); //Start at character 4 on line 0
  lcd.print(F("O2 Sensor!"));
  delay(1000); 

  lcd.setCursor(0,1); //Start at character 4 on line 0
  lcd.print(F("Begin EthernetClient"));
  
  Ethernet.begin(mac); // added for thinkgspeak connectivity
  if (Ethernet.begin(mac) == 1) {
     lcd.setCursor(0,2);
     lcd.print(F("Ethernet OK        "));
     delay(1000);
     lcd.setCursor(0,2);
     lcd.print(F("IP Address.........."));
     lcd.setCursor(0,3);
     for (byte thisByte = 0; thisByte < 4; thisByte++) {
       // print the value of each byte of the IP address:
       lcd.print(Ethernet.localIP()[thisByte], DEC);
       lcd.print(F("."));}  // Print IP Address
  }
  
  delay(1000);
  
  lcd.clear(); 
  lcd.setCursor(0,0);
  lcd.print(F("Thingspeak Begin "));
  ThingSpeak.begin(client); // added for thinkgspeak connectivity
  lcd.setCursor(0,2);
  lcd.print(F("OK"));
  delay(1000);
  lcd.clear(); 


  lcd.setCursor(0,0);
  lcd.print(F("ServoSweep"));

// SERVO SWEEP
  for (ServoPos = 10; ServoPos <= 180; ServoPos += 1) { // goes from 0 degrees to 180 degrees
     // in steps of 1 degree
     myservo.write(ServoPos);              // tell servo to go to position in variable 'pos'
     delay(15);                       // waits 15ms for the servo to reach the position
   }
   for (ServoPos = 180; ServoPos >= 10; ServoPos -= 1) { // goes from 180 degrees to 0 degrees
     myservo.write(ServoPos);              // tell servo to go to position in variable 'pos'
     delay(15);                       // waits 15ms for the servo to reach the position
   }
// SERVO SWEEP
  
  
  lcd.setCursor(0,1);
  lcd.print(F("Complete"));
  delay(1000);
  lcd.clear(); 
  
  timer = millis(); //sets timer for thingspeak

Serial.println("Setup Complete");

}/*--(end setup )---*/


void loop()  
{
// Read Sensors //

//Flue
int raw = as_Flue.analogReadSmooth(O2FlueTempAnaloguePin); //Smoothed raw flue signal
float Vout = raw * (VOLTAGE_MAX / VOLTAGE_MAXCOUNTS);
FlueTemperature = (Vout-1.25)/0.005;

Serial.print(F("Flue Temperature = "));
Serial.print(FlueTemperature);
Serial.println(F("degC"));



//O2
if(FlueTemperature>FlueThreshold)
  {
  O2 = as_O2.analogReadSmooth(O2AnaloguePin)*20/VOLTAGE_MAXCOUNTS; // smoothed O2 read
  PID_Input = O2;
  myPID.SetMode(AUTOMATIC);
  myPID.SetOutputLimits(180, 10);
  myPID.Compute();
  ServoPos = PID_Output;
  myservo.write(ServoPos);
  }
  else
  {
  O2 = 0;
  myPID.SetMode(MANUAL);
  ServoPos = SERVO_MAX;
  myservo.write(ServoPos); // open damper when boiler off
  }
  
Serial.print(F("O2 = "));
Serial.print(O2);
Serial.println(F("%"));


Serial.print(F("Servo Position = "));
Serial.print(ServoPos);
Serial.println(F("deg"));

//HeatMeter
int Raw = analogRead(HeatMeter);
HeatMeterPower = (Raw - HEATMETERPOWERLOW_BIT) * (HEATMETERPOWERHIGH_KW - HEATMETERPOWERLOW_KW)/ (HEATMETERPOWERHIGH_BIT - HEATMETERPOWERLOW_BIT);

Serial.print(F("Heat Meter = "));
Serial.print(HeatMeterPower,2);
Serial.println(F("kW"));
Serial.println(F(""));


delay(500);

if (millis()-timer >15000)
{
  lcd.setCursor(19,3);
  lcd.print(F("@"));
  digitalWrite(Led2Pin,HIGH); 
  ThingSpeak.setField(1,O2);
  ThingSpeak.setField(2,FlueTemperature);
  ThingSpeak.setField(3,HeatMeterPower);
  ThingSpeak.setField(4,ServoPos);
  Serial.println(F("Thgspkupdate"));
  ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
  Serial.println(F("ThgSpkUpdated"));
  timer = millis(); //resets timer for thingspeak
  lcd.setCursor(19,3);
  lcd.print(F(" "));
  digitalWrite(Led2Pin,LOW);
}
else if(millis()-timer <0)
{
  timer = 0;
}

}/* --(end main loop )-- */





/* ( THE END ) */

maybe it should be

myPID.SetOutputLimits(10,180);

From http://playground.arduino.cc/Code/PIDLibrarySetOutputLimits

Parameters
min: Low end of the range. must be < max (double)
max: High end of the range. must be > min (double)

I tried that whilst debugging....no joy!

I am closing this thread to prevent any cross posting conflicts as there is a dedicated user group on Google forums which I suspect may be able to help with this particular problem.

https://groups.google.com/forum/#!topic/diy-pid-control/YBYCQn6P4sw