PID Relay Output example Question?

Hello everyone

I was playing around with the PID library examples tonight to try and better understand them. I want to regulate a mechanical relay depending on the temperature that is read by my AD597 thermocouple interface IC. The IC feeds a analog signal into my Arduino Uno. Which I then read and display on a GLCD. The relay will regulate the temperature to stay at a fixed value by means of switching the electrical heating elements on and off.

So according to the library PID RelayOutput Example, it should be able to do this. I've modified the code a bit to display some variables on a GLCD for me. The code can be seen below.

The thing that is not happening is that whenever the PID output pin is high it doesn't switch my relay on. Relay stays constantly off. I have a LED from the output pin as well and I can see that the LED is switching on and off, but the LED is very dim. I then removed my shield and loaded the default example sketch and connected an LED from the output to ground. I then measured the voltage out at the output pin and it is only 108 mV? I changed the pin then and tried a different output, same story. I then loaded a blink example and it switches on the led fully as well as the relay when using the same output pins?

 * PID RelayOutput Example
 * Same as basic example, except that this time, the output
 * is going to a digital pin which (we presume) is controlling
 * a relay.  the pid is designed to Output an analog value,
 * but the relay can only be On/Off.
 *
 *   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"
 ********************************************************/

// include the library header
#include <glcd.h>
#include <PID_v1.h>

// include the Fonts
#include <fonts/allFonts.h>

#define RelayPin 2

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


//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, DIRECT);

int WindowSize = 5000;
unsigned long windowStartTime;


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

int sensorPin    =  A5;          // select the input pin for the potentiometer
int Temp;


  const int numReadings = 10;
  
  int readings[numReadings];      // the readings from the analog input
  int index = 0;                  // the index of the current reading
  int total = 0;                  // the running total
  int Raw_Value_Avg = 0;          // the average  
  int Raw_Value = 0;

void setup() 
{

    // initialize all the readings to 0: 
    for (int thisReading = 0; thisReading < numReadings; thisReading++)
    readings[thisReading] = 0; 
    
//*************************************************************  
  
  // Initialize the GLCD 
  GLCD.Init();

 // Select the font for the default text area
  GLCD.SelectFont(System5x7);

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

  windowStartTime = millis();  

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

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

//*************************************************************
}

void loop() 
{
 
  //initialize the variables we're linked to
  Setpoint = 100; 
  
  Raw_Value = analogRead(sensorPin);
  
  Averaging_RAW_Value();
  
  Temp = Raw_Value_Avg / 2.04;
  
//*************************************************************
  Input = Temp;
  myPID.Compute();

  /************************************************
   * turn the output pin on/off based on pid output
   ************************************************/
  if(millis() - windowStartTime>WindowSize)
  { //time to shift the Relay Window
    windowStartTime += WindowSize;
  }
  if(Output < millis() - windowStartTime)
  {
   digitalWrite(RelayPin, HIGH);
 
/* 
    GLCD.CursorToXY(15, 25);
    GLCD.print("HIGH");    
    delay(500);
    GLCD.ClearScreen();
    delay(500);
*/      
  }
  
  else
  {
   digitalWrite(RelayPin,LOW);
/* 
    GLCD.CursorToXY(15, 35);
    GLCD.print("LOW");
    delay(500);
    GLCD.ClearScreen();
    delay(500);
*/  
  }

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


  GLCD.CursorToXY(15, 15);
  GLCD.print(Temp);  
  GLCD.DrawCircle(40,16, 1);  // X, Y, Radius; Draws a little circle to be the Degree symbol    
  
  GLCD.CursorToXY(44,15);                                                                     // Print unit of measurent
  GLCD.print("C");  
   
}



  void Averaging_RAW_Value()
  {     
    // subtract the last reading:
    total= total - readings[index]; 
  
    //void Read_Raw_Value();
    Raw_Value = analogRead(sensorPin);                

    readings[index] = Raw_Value;

    // add the reading to the total:
    total= total + readings[index];       
    // advance to the next position in the array:  
    index = index + 1;                    
  
    // if we're at the end of the array...
    if (index >= numReadings)              
    // ...wrap around to the beginning: 
    index = 0;                           
  
    // calculate the average:
    Raw_Value_Avg = total / numReadings;         
    // send it to the computer as ASCII digits    
  }

I don't understand the PID controller library very well, but what I think I know is that the window period is the evaluation period to evaluate whether the temperature is below or above the set point to either turn the relay on or off.

The set point is the point you want to reach and it is just a numerical value that you can relate to another valiable (i.e. not a percentage value or something similar)?

So my big question is how I can get the output to switch on fully to get the mechanical relay to switch? Thank you everyone.

Dirk

Dirka:
The thing that is not happening is that whenever the PID output pin is high it doesn't switch my relay on. Relay stays constantly off. I have a LED from the output pin as well and I can see that the LED is switching on and off, but the LED is very dim. I then removed my shield and loaded the default example sketch and connected an LED from the output to ground. I then measured the voltage out at the output pin and it is only 108 mV?

How is the relay being driven? Not directly from an I/O pin, I hope.

Hello PeterH

I'm driving it through a PNP transistor. The relay is opto isolated through a optocoupler from the Arduino I/O .

The opto isilator's output will not be able to source current only sink it.
So you need a pull up resistor to +5V.

Hello Grumpy Mike

But why is the relay then able to switch whenever I use the blink example? But not when using the PID control?

Because when that opto is off the base of your driving transistor floats, this could let in a small ammount of current but not enough to drive a relay.

Thanks Mike

I will retry it after inserting a pullup resistor. What value would you recommend? 1K / 10K ?

I would try 10K.

Thanks, I'll give feedback on it as soon as I've implemented it.

Hello Mike

The problem is not the pull up resistor (Although I understand why you say I should implement it). The PID output is outputting a voltage of 0.8 V only rather than 5V. When driving the transistor directly from the digital output utilizing the PID controller it works but when I opto isolate it by means of an optocoupler it doesn't work, irrelevant whether I use a pull up resistor or not.

It seams that my optocoupler can't handle the PID control for some reason, I think that the 0.8 V isn't enough to bias the optcoupler transistor "on" enough to let enough current through to power the relay coil but that is just me speculating.

I think I will try and implement my own bang-bang protocol to regulate the temperature (Since if I output 5V to the opto, the relay is able to switch - Blink example). The temperature won't be changing that much that I will require a PID controller so a bang-bang controller should work fine. Thanks for the input though.

Hello Everyone

I've made a rookie mistake in my attempt to utilize the PID library. In the example the relay I/O pin's output state isn't declared in the void setup as an output. As soon as I've done this it was working. Yeay, saves me the time of figuring out PID control. Thank you very much Brett Beauregard.

 pinMode(RelayPin, OUTPUT);

Thanks!! i had your same problem. You helped me. :slight_smile: