Adding ON/OFF control & temp display to PID SCRIPT

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

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

Yes I kind of regret even bring up the subject of 'setpoint tracking' as I don't recall if it is even implemented in this existing library. It is however a very common mode of operation now a days with micro based PID controllers. In the old days of standalone analog PID controllers there was a separate manual output adjustment knob and a separate setpoint adjustment knob. It was up to the operator when switching from manual to automatic to first 'match up' the setpoint value to the existing output value so that the output would not spike when first placed back into automatic mode. Setpoint tracking did this step automatically and became a common operating feature.

Lefty

Yeah..., but I've been tinkering with it in "MANUAL" mode and it still sends an output signal to the heater. It doesn't seem to do any calculations in manual mode, but it still just keeps the output going.?

Is there a way I could just have the code start on "pause" or something until I depress the on button, then it goes to run mode while its depressed then pauses again if I release? Is there such a thing?

I can achieve what I want by wiring the PWM output from the arduino through the switch which is normally open so when I press the heat button it goes...

In response to what you guys are telling me...

How can I make it so that ONLY when I push the button the PID goes from MANUAL mode that has an output value of ZERO to AUTO and fully calculating.

I've been tinkering with it in "MANUAL" mode and it still sends an output signal to the heater. It doesn't seem to do any calculations in manual mode, but it still just keeps the output going.?

odd. as soon as it gets set to manual the pid should stop writing to the output variable. it won't make it 0, or anything really. if you want the output to go to 0 and stay there, use SetMode(MANUAL); followed by Output=0;

if you've done this and the pid is still changing the output, I'm going to have to take a look at the library source. it should not do that.

Brett

YES!! I tinkered with the code enough and finally got the "ON" button working just like I want.

Here's what I did.

/********************************************************
 * 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 ledPin =  13;
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 = 4;   // choose the input pin to decrease temp
int buttonState = 0;     // variable for reading the pin status

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

void loop()
{
   buttonState = digitalRead(onPin);

if (buttonState == HIGH) {     
    // turn LED/HEATER on:    
    digitalWrite(ledPin, HIGH);
     myPID.SetMode(AUTO);  
  } 
  else {
    // turn LED/HEATER off:
    digitalWrite(ledPin, LOW); 
     myPID.SetMode(MANUAL);
      Output=0;
  }
 
 Input = analogRead(0);
  myPID.Compute();
  analogWrite(3,Output);
 }

Now.. I can start toying with adding in those up/down temp lines of code.

Edit [timestamp=1246661743]...

Never mind. Looks like Jetski made progress while I was writing! Guess I'll have to respond faster or not at all!

Brett:

I assumed your algorithm provided writing to the OUTPUT with value clamping when in MANUAL mode. I suggested Jetski always send the output value (even when the loop was in manual) so the OUTPUT would be correctly restricted. When Jetski wrote this...

it still sends an output signal to the heater

...it's probably because of my suggestion.

When in MANUAL mode, is there a way to change the OUTPUT through your algorithm?

Jetski:

It would help if you posted the latest version of your Sketch.

Yeah..., but I've been tinkering with it in "MANUAL" mode and it still sends an output signal to the heater.

MANUAL mode just turns off the PID algorithm. It allows MANUAL control. Once in MANUAL mode it's up to you to change the OUTPUT.

Sorry for the confusion I've caused. I hope I haven't led you too far astray.

  • Brian

Thanks for at least starting to reply baldy. :slight_smile:

I've done a bit more now to try and get the buttons functioning. I added this to the end of the loop:

     myPID.SetMode(MANUAL);
      Output=0;
  }
 unsigned long lastTime;
if(digitalRead(upPin)==HIGH)
{
  if (lastTime+250<millis()) {
    Setpoint+=1;
    lastTime=millis();
  }
}

if(digitalRead(downPin)==HIGH)
{
  if (lastTime+250<millis()) {
    Setpoint-=1;
    lastTime=millis();
  }
}
 Input = analogRead(0);
  myPID.Compute();
  analogWrite(3,Output);
 }

Does that look like it will work?

Now, I don't have any way of knowing what the temp is currently set at if the code is working.

Is there a way for me to query the board for the current "Setpoint" while im tinkering with it up and down?
Im on a mac, I see the button on the arduino program for serial monitor. When I click it it gives me a baud rate option and a place to enter commands or code.

Is it some kind of "print" or "report" command?

Brian:

When in MANUAL mode, is there a way to change the OUTPUT through your algorithm?

currently there is not. when in manual, it's essentially as though the pid isn't there. you make a fair point about the output limits thought. I'm not sure what the answer is. I could throw in another function, but I think that would be confusing to most users.

Brett:

Some benefits if you add SetOutput (and an InternalSetOutput) to your algorithm...

  • Output clamping is handled consistently
  • If InternalSetOutput is virtual, the developer can add customized scaling, conditioning, and handling for the output (like drum-sequencing)
  • SetOutput can ignore the request if the loop is AUTO providing safety from accidental output changes

But... It's my understanding that your PID algorithm is rather new to the Arduino community. If you plan to continue working on it, you'll probably serve the community more if you wait for more feedback before making changes.

  • Brian

So is there any way for my to read the setpoint?

or how about putting something in the loop that constantly sends the value of the setpoint through the usb?

baldy

Ugh! Don't remind me! To make matters worse, what little is left needs to be cut. The hair in front is below my nose. I look like a damaged muppet. :o

Does that look like it will work?

You're close...

This...

 unsigned long lastTime;

...needs to be declared at the top of your Sketch (with Setpoint, Input, and Output) and needs to be initialized in setup...

void setup( void )
{
  // Existing stuff
  lastTime = millis();
}

Change this...

  if (lastTime+250<millis()) {

...to this...

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

...to avoid a problem when millis wraps back to zero.

So is there any way for my to read the setpoint?
or how about putting something in the loop that constantly sends the value of the setpoint through the usb?

In setup, prepare the serial port...

void setup( void )
{
  Serial.begin( 115200 );
  // Existing stuff
}

...then you can output whatever you'd like using something like this...

  Serial.print( "sp: " );
  Serial.print( Setpoint );
  Serial.println( "" );

You may have to use a different baud rate than 115200.

Good luck,
Brian