Adding ON/OFF control & temp display to PID SCRIPT

Hey all I am currently playing with some of the PID scripts and my arduino.

I've got it hooked up to two things, a heater to heat to the set temp and a thermocouple to take the readings and adjust accordingly.

My questions are about the script...

I've got the following script uploaded to my board:

/********************************************************

  • PID Simple Example
  • Reading analog input 0 to control analog PWM output 3
    ********************************************************/

#include <PID_Beta6.h>

//Define Variables we'll be connecting to
double Setpoint, Input, Output;

//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint, 2,5,1);

void setup()
{
//initialize the variables we're linked to
Input = analogRead(0);
Setpoint = 150;

//turn the PID on
myPID.SetMode(AUTO);
myPID.SetSampleTime(250);
myPID.SetTunings(2,3,1);

}

void loop()
{
Input = analogRead(0);
myPID.Compute();
analogWrite(3,Output);
}

Now, when the board is turned on, it starts heating to the setpoint and does a magnificent job of keeping it there.

What I am trying to achieve is adding a on/off button to trigger the board to start heating the element ONLY when the signal from the button is received Also, I would like to add two buttons that adjust the temperature UP or DOWN, and a LCD readout of the Setpoint, and the ACTUAL temperature VIA a single serial wire.

Can anyone point me to the direction where I might find an example of this? Or simply throw the code down in a post? I would imagine the first two things I am trying to achieve are relatively simple in terms of coding. The simple on/off thing and temp up/down in response to the buttons.

Thanks in advance for all your responses!

Okay... So i've got 3 SPST pushbutton switches (Normally Open) hooked up to +5v and the outputs of each going to digital pins 4--- (Trigger or operation button) 5---(Increase temp by 1 degree) and 6----(Decrease temp)

As far as the On/off operation goes.. Am I kind of on the right track??... I'd like to keep the code as simple as possible.

void setup()
{
//initialize the variables we're linked to
Input = analogRead(0);
Input = digitalRead(4);
Input = digitalRead(5);
Input = digitalRead(6);
Setpoint = 150;

//turn the PID on
myPID.SetMode(AUTO);
myPID.SetSampleTime(250);
myPID.SetTunings(2,3,1);
myPID.SetOutputLimits(0, 178.5);

}

void loop()
{
Input = analogRead(0);
myPID.Compute();

if(digitalRead(4),HIGH);
analogWrite(3,Output);
}else{
I dont know what to put here??
}

How's this going?

Did I do okay introducing the new inputs? Should it be digital or analog?

I may be able help with one item on your list.

This PID algorithm appears to include mode (myPID.SetMode). If mode works with this implementation the way I've seen it work with other implementations (the way it should work) you can use it to "turn off" and "turn on" the PID loop.

Setting mode to manual should...

  • Leave the output value at the current value
  • Stop updating the internal values from the input

Setting mode back to auto should...

  • Reset the internal values
  • Provide a "bumpless" transition from the current (old) output value to the next (new) output value
  • Seamlessly resume calculations

Good luck,
Brian

coding badly is correct. (that is a sentence I never thought I'd write!)
that is to say, Brian is correct.

you can have your on/off button toggle the Auto/Manual state of the pid using the SetMode(..) function. when in manual mode, the pid will stay out of things, and you can write whatever you want to the output variable.

for ease of coding you're still free to all Call myPID.Compute(). it will see that the current mode is manual and will immediately return without calculating.

glad to hear that the library is working for you!

Brett

Okay... So I have done a bit of tinkering and moving the code around. I've taken small portions of code from the "button library" to see if I can get this going.....

It complied Okay in the arduino program, but I am wondering if anyone see's anything that is wrong right off the bat.

I've put my goals to hook up the LCD untill later when I get the buttons working and doing what I want.

I think I have the on/off thing going... I just need someone to give me some pointers on how to make "buttonPin2" and "buttonPin3" to increase and decrease the setpoint by 1 degree.

Here's what I've got so far.

/********************************************************

  • PID Simple Example
  • Reading analog input 0 to control analog PWM output 3
    ********************************************************/

#include <PID_Beta6.h>

//Define Variables we'll be connecting to
double Setpoint, Input, Output;

const int buttonPin1 = 1; // the number of the RUNpushbutton pin
const int buttonPin2 = 2; // the number of the UPpushbutton pin
const int buttonPin3 = 3; // the number of the DOWNpushbutton pin

// variables will change:
int buttonState = 0; // variable for reading the pushbutton status

//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint, 2,5,1);

void setup()
{

// initialize the pushbuttons as inputs:
pinMode(buttonPin1, INPUT);
pinMode(buttonPin2, INPUT);
pinMode(buttonPin3, INPUT);

//initialize the variables we're linked to
Input = analogRead(0);
Setpoint = 100;

//set initial tunings

myPID.SetSampleTime(250);
myPID.SetTunings(2,3,1);
myPID.SetOutputLimits(0, 220);

}

void loop()
{
// read the state of the pushbutton value:
buttonState = digitalRead(buttonPin1);

// check if the RUNpushbutton is pressed.
// if it is, the buttonState is HIGH:
if (buttonState == HIGH) {
// Perform action:
Input = analogRead(0);
myPID.Compute();
analogWrite(3,Output);
}
else {
// Turn PID OFF
myPID.SetMode(MANUAL);
}

}

the basic way to increase the setpoint would be

if(digitalRead(buttonPin2)==HIGH)
{
   Setpoint+=1;
}

the problem with this is that since loop excecutes so quickly, this code may be hit several times in the time it takes to press and release the button.

what I have done in similar situations is instead of looking at the current state of the button, I looked for a CHANGE in the state of the button. so something like:

int lastState = LOW;
void loop()
{
   int currentState = digitalRead(buttonPin2);
  if(currentState == HIGH && lastState ==LOW)  //only go in if we were off last time, and on this time
  {
    Setpoint+=1;  //increment the setpoint
  }
  lastState = currentState;  //remember the button state for next time
}

Hope that helps. Brett

That code could still trigger multiple events due to contact bouncing. I would suggest setting a minimum elapsed time before letting the button trigger another event. For example:

unsigned long lastTime;
if(digitalRead(buttonPin2)==HIGH)
{
  if (lastTime+250<millis()) {
    Setpoint+=1;
    lastTime=millis();
  }
}

That way, you can click the button once, and it'll increase one degree, or hold it down to increase at a rate of 4 per second. With a bit more coding, you could have it count how long the button stays down, and after say, 2 seconds, have it increase the rate of change.

That code could still trigger multiple events due to contact bouncing

That's a good point goose. I like your way better.

Brett

Given that this system is still under development and that you're trying to control something that could be dangerous (heaters have been know to cause burns ;)), I suggest starting the PID loop in manual. This gives you an opportunity to look things over before letting the (potentially buggy) code take control...

void setup()
{
  // stuff already in your setup...
  myPID.SetMode(MANUAL);   
}

If the PID code supports writes to the output (some sort of command like myPID.WriteOutput or myPID.SetOutput), you should move these two lines of code...

   myPID.Compute();
   analogWrite(3,Output);

...to the bottom of loop so they always execute. This will provide output clamping in one place (the PID code).

Even if the PID code does not support writes to the output, there is no harm in moving the two lines of code. When the loop is in manual, Output won't change.

  • Brian

Thanks for all the tips everyone!

I am just finishing up wiring the thing and I will apply the changes to the code that have been recommended.

Now... Since I don't have the LCD hooked up at present... Is there a way to monitor the "setpoint" as I change it up and down with the buttons? Like to make sure that they're doing what they're supposed to? I notice on the arduino program there is a serial monitor button...

goose2283:

This...

  if (lastTime+250<millis()) {

...doesn't work quite the way you expect when millis is close to wrapping. Let's say that the previous time through loop, lastTime was set to 0xFFFFFFFF - 249. This time through the loop we have...

  if ( (0xFFFFFFFF - 249)+250<millis()) {
  if ( 1<millis()) {

For the 250ms until millis() wraps back to zero the condition is always true. Generally, it's better to calculate the delta then compare...

  if (millis()-lastTime>=250) {
  • Brian

Yes, the Arduino's serial command is the simplest way to debug or use as a temporary user interface to test out the basic application, then later you can can add the LCD UI stuff. You can use the Arduino's serial monitor or a PC serial terminal program to monitor system performance and even send setpoint and mode commands to the your Arduino sketch.

Lefty

Well... I have cleaned up a bit to take things one step at a time..

So...

All I want is for the PID code to send the PWM output signal ONLY then the button is ON.

//********************************************************
 * PID Simple Example
 * Reading analog input 0 to control analog PWM output 3
 ********************************************************/

#include <PID_Beta6.h>

//Define Variables we'll be connecting to
double Setpoint, Input, Output;

//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint,2,5,1);
    
const int onPin = 1; // choose the input pin to trigger heater
const int upPin = 2;   // choose the input pin to increase temp
const int downPin = 3;   // choose the input pin to decrease temp
int buttonState = 0;     // variable for reading the pin status


void setup() {
  // Declare inputs
  pinMode(onPin, INPUT);    // declare pushbutton as input
  pinMode(upPin, INPUT);    // declare pushbutton as input
  pinMode(downPin, INPUT);    // declare pushbutton as input
  //initialize the variables we're linked to
  Input = analogRead(0);
  Setpoint = 100;
    
    myPID.SetSampleTime(250);
    myPID.SetTunings(2,3,1);
    myPID.SetOutputLimits(0, 220);
  
 
}

void loop() {
  // read the state of the pushbutton value:
  buttonState = digitalRead(onPin);
  
  // check if the pushbutton is pressed.
  // if it is, the buttonState is HIGH:
  if (buttonState == HIGH) {     
    // turn PID on:    
    WHAT CODE HERE?;
  } 
  else {
    // turn PID off:
    WHAT CODE HERE?; 
  }
  Input = analogRead(0);
  myPID.Compute();
  analogWrite(3,Output);
}

Did I do all the declarations and stuff right?

in regards to "myPID.SetMode(MANUAL);"

doesn't the mode refer to auto or manual tuning? Not operation...

From what I understand that Coding Baldy said MANUAL mode is OFF?

doesn't the mode refer to auto or manual tuning?

No.

MANUAL mode is OFF?

Yes.


The terms are historical. Long ago, closed-loop control was performed by a human. The person would walk about, write instrument readings on paper, perform calculations, then adjust valves. In other words, control was performed manually. Automatic means a machine is performing the closed-loop control.

  • Brian

In the PID controllers I have worked with the auto/manual mode selector, when in manual mode the setpoint value (as a percentage of range) is sent directly to the output (as a percentage of range). This gives the user the ablitly to manually place the output value anywhere from fully off to fully on and allows for a 'bumpless transfer' when setting the mode back to automatic.

Lefty

MANUAL mode is OFF?

When I was first starting with pid, the way I used to keep track was by thinking of it as "Manual Override."

in manual mode, you get to set the output to whatever you want. in automatic, the pid controller does the work. automatically.

I'm open to changing this. Any suggestions on a better naming convention? Something that's easier for the beginners, but is still understood by the old salts?

I may have over simplified somewhat in my explanation of manual mode. It does indeed turn off PID calculation and 'freezes' the output value at it's last updated value. However if one wishes to manipulate the output directly while in manual mode and 'setpoint tracking' is implemented, the setpoint changes as manual changes are made to the output. This allows for the 'bumbless transfer' I mentioned and also usually allows the same up/down users controls to be used no matter which mode on has placed the controller in. It may sound somewhat confusing to a newcomer to PID control but is intuitive once one has to 'operate' a controller.

Lefty

when in manual mode the setpoint value (as a percentage of range) is sent directly to the output (as a percentage of range)

Yikes! I can see where someone like me might be confused by that and do the wrong thing. (changing the OUTPUT but thinking I was changing the SETPOINT).

The algorithms I've seen have an OUTPUT that is read-only when the loop is AUTO and read-write when the loop is MANUAL.

  • Brian

I'm open to changing this

Please don't. AUTOMATIC / MANUAL are the (very) commonly used terms. I suspect using different terms will create considerably more confusion.

  • Brian