Go Down

Topic: PID controller with relay output and DS18B20 as feedback (Read 7382 times) previous topic - next topic

Mathniel

Hi.

Using the example called: "PID_RelayOutput" from the PID-v1 library, i'm trying to change the sensor input from an analog input to using a DS18B20 temperature sensor on a digital pin on the arduino UNO board.

(i'm building a temperature regulator for driving a SSR by the means of a temperature feedback from a DS18B20 sensor)

My problem is that i can't get the PID loop to respond even if i set the SP to 1 or 100, the output stays on (high/true). The current temperature is approx. 20 degrees C.
I know that i have a valid temperature reading, since i have connected to a LCD and i get a fine reading of the actual temperature.
I'm not quite sure how to set the signal from the DS18B20 as the input for my PID since all previous posts only says "use the temperature signal directly.."

Therefore i have simply replaced the input=AnalogRead in the code with: "Input=sensors.getTempCByIndex(0);"
Which is how i write the temperature reading to my LCD. Can't tell if this is correct or not.



Code: [Select]

/********************************************************
 * 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 <PID_v1.h>

// Libraries for the DS18B20 sensor
#include <OneWire.h>
#include <DallasTemperature.h>





// Temp. sensor on PIN 7 on the Arduino
#define ONE_WIRE_BUS 7

//Solid state relay on PIN 13 on the Arduino
#define RELAY_PIN 13

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

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

//Specify the links and initial tuning parameters
double Kp=2, Ki=5, Kd=1;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);

int WindowSize = 5000;
unsigned long windowStartTime;

void setup()
{
  windowStartTime = millis();

  //initialize the variables we're linked to
  Setpoint = 20;

  //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()
{
  sensors.requestTemperatures();
  Input = sensors.getTempCByIndex(0);
  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(RELAY_PIN, HIGH);
  else digitalWrite(RELAY_PIN, LOW);

}





What else could i have done wrong? I've tried setting the PID as REVERSE/DIRECT, but i still do not get a response from the output when the setpoint passes the actual temperature.

Coding Badly

Code: [Select]

double Kp=2, Ki=5, Kd=1;


What led you to believe those are reasonable tuning parameters?


Mathniel

I did not say they were reasonable?
But I need a response from the PID before I can start finding the right parameters.
Ziegler and Nichols-method could be used, but I need the regulator to be able to change its output.

wildbill

Your logic is apparently backwards. I added some prints:
Code: [Select]

  sensors.requestTemperatures();
  Input = sensors.getTempCByIndex(0);
  Serial.print("Input: ");
  Serial.println(Input);
  myPID.Compute();
  Serial.print("Output: ");
  Serial.println(Output);


and set the setpoint to 30C (ambient is about 23C)

Output increases continually (obviously, because I have no heater attached) until it's 5000. As it increases, the LED simulating the heater stays on less and less until at 5000 it's off all the time. As Output rises, you should be calling for more and more heat but unless the relay logic is reversed you seem to be doing the opposite. 

Mathniel

Hi wildbill

Did you get my program to work??
I can see that you have only added some prints (as you're saying) and have not altered anything else in the sketch.
I guess that means that my program should work?

I have tried setting the SP to 1, 20, 30 and 100. The output is high all the time.

wildbill

All I changed was those debugging prints and the setpoint. The LED on the Uno attached to pin 13 comes on for progressively less and less time until output reaches 5000 at which time it stays off.

I see I've assumed you're heating something - is that correct?

johnwasser

Relay modules are often Active Low (set the output LOW to engage the relay).  If your SSR is NOT Active Low you should reverse the output values.
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp

Mathniel

You are absolutely correct.
But if i'm cooling or heating at the moment doesnt really matter. I just want a reaction. For now, i can change the setpoint below and above the ambient temperature (which in my case is around 20 degrees C) without anything happening. The LED for PIN 13 is always on (and yes, i'm sure i'm looking at the right LED).

I just tried printing "Output" to my LCD. It says 0.00 no matter how i adjust the setpoint, which tells me that the PID is doing absolutely nothing.

Once again, did you just copy my sketch from the topic and pasted it in your IDE, and then it worked?

avr_fred

While I'm not familiar with the Arduino PID library, I'm am quite comfortable with PID in general.

My approach to troubleshooting a loop that doesn't behave properly is always first start with both I and D terms (the time based terms) set to zero. In this way, you should be dealing with only P portion and it is a simple matter to determine if the loop is working correctly since the output should be (actual - set point) * gain. If P is not gain and described as proportional, then the reciprocal of proportional is gain. The point is that you should be able to calculate what the output should be, given the actual, setpoint and gain. Once you have the correct output relationship to input, you've got want you need to use Z-N or other method to get in the ballpark tuning parameters.

wildbill

Once again, did you just copy my sketch from the topic and pasted it in your IDE, and then it worked?
All I changed was those debugging prints and the setpoint to 30. The LED on the Uno attached to pin 13 comes on for progressively less and less time until output reaches 5000 at which time it stays off.

Try an external LED on another pin.

Mathniel

Now i can get the PID responding through its 0-5000 value!

I wrote the program from scratch and now it works. Perhaps some syntax error..

But i still cant get the digital output on pin 13 to respond.

All this code does is to keep the output off(low) for 5000 msek (WinowSize) and then it goes on(high), and stays this way forever, even if i change the setpoint from 1 to 1000 and back again. I can also set the PID parameters as i wish, it changes nothing.

Code: [Select]

  /************************************************
     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(RELAY_PIN, HIGH);
  else digitalWrite(RELAY_PIN, LOW);


wildbill

But i still cant get the digital output on pin 13 to respond.
So load the blink example and see if the LED still works.

Mathniel

I already did. It works perfectly well when i load the blink example.

The output on PIN 13 is ON(high) even if i set the controller to REVERSE. And it doesnt matter if the SP is 1 or 1000.

Mathniel

I can also force the value "Output" to be either "0" or "5000". The digital output on pin 13 stays high.




Have you, by any chance, still got the working code open in your IDE and could you paste it below just to make 100% sure that we are doing the same thing?

Thanks a lot in advance..

wildbill

Oops, look at that, I lied - there's a serial.begin and println in setup too  ;)
Code: [Select]


/********************************************************
 * 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 <PID_v1.h>

// Libraries for the DS18B20 sensor
#include <OneWire.h>
#include <DallasTemperature.h>

// Temp. sensor on PIN 7 on the Arduino
#define ONE_WIRE_BUS 7

//Solid state relay on PIN 13 on the Arduino
#define RELAY_PIN 13

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

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

//Specify the links and initial tuning parameters
double Kp=2, Ki=5, Kd=1;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);

int WindowSize = 5000;
unsigned long windowStartTime;

void setup()
{
  Serial.begin(115200);
  Serial.println("Starting");
  windowStartTime = millis();

  //initialize the variables we're linked to
  Setpoint = 30;

  //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()
{
  sensors.requestTemperatures();
  Input = sensors.getTempCByIndex(0);
  Serial.print("Input: ");
  Serial.println(Input);
  myPID.Compute();
  Serial.print("Output: ");
  Serial.println(Output);

  /************************************************
   * 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(RELAY_PIN, HIGH);
  else
    digitalWrite(RELAY_PIN, LOW);

}

Go Up