Trouble with PID library and fan control

Hi,

I am working with the PID library (PID_v1.h) I am trying to maintain the temperature of a DS18B20 sensor at a setpoint by varying the speed of a PWM fan (4 pin type). I've read that PWM fans need a frequency of around 25kHz to operate properly and have adjusted so in my sketch below. Individually, I have tested the fan and temperature sensor individually and they work just fine. I can ramp the fan from PWM values 0-100 and the sensor gives me temperature readings. When I try to integrate the PID library, it no longer works. I am stumped as to what is wrong, I have followed and read the playground notes on the library and used the example provided as reference and cannot come up with a working solution. I am hoping someone can see what I am doing wrong.

Also, physically, I tried connecting the fan through an n-channel MOSFET and without and both method work just fine for testing just the PWM fan without the PID library.

#include <DallasTemperature.h>
#include <OneWire.h>
#include <PID_v1.h>

int fanPinREG = 3;

double Setpoint, Input, Output;

//Tuning Parameters
float Kp=2;    //Proportional Gain
float Ki=5;    //Integral Gain
float Kd=1;    //Differential Gain

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

// Data wire is plugged into port D6 on the Arduino
#define ONE_WIRE_BUS 6

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);

void setup()
{
Serial.begin(9600);
// Start up the library (DS18B20 DallasTemperature)
sensors.begin();

////////////////////////////////////// PWM BY REGISTRY CHANGE ////////////////////////
pinMode(fanPinREG, OUTPUT);
  
  TCCR2A = _BV(COM2B1) | _BV(WGM21) | _BV(WGM20); // COM2B1: clear OC2B on Compare Match; WGM21/20/22 (latter in TCCR2B below): count from 0 to OCR2A
  TCCR2B = _BV(WGM22) | _BV(CS21); // CS20: prescaler 8
  OCR2A = 80;
  OCR2B = 40; // for 50% duty cycle
////////////////////////////////////////////////////////////////////////////////////

  sensors.requestTemperatures();
  Input = sensors.getTempCByIndex(0);//analogRead(0);     /**************  TEMPERATURE  **********************/
  Setpoint = 15;            /***********  TEMPERATURE SETPOINT (CELCIUS)  ******/

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

void loop(void)
{

  sensors.requestTemperatures();
  Input = sensors.getTempCByIndex(0);    //Temperature from DS18B20
  myPID.Compute();
  analogWrite(fanPinREG,Output);
  Serial.print("Temperature C = ");
  Serial.println(Input);

}
//Tuning Parameters
float Kp=2;    //Proportional Gain
float Ki=5;    //Integral Gain
float Kd=1;    //Differential Gain

A D-term. An I-term of five. I suspect you made those up. Did you?

void loop(void)
{
...
  Serial.print("Temperature C = ");
  Serial.println(Input);
  Serial.print("Output = "); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  Serial.println(Output); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
}

Those were just the stock values that came with the example sketch in the PID library.

Moderator edit: unnecessary over-quoting removed

Ah yes, I get zero as the value of Output from the readings. I played around with the tuning parameters to see if there was any change, but none, still an Output of zero. Unless the frequency adjustment is hindering the PID library from working or my sketch is just flawed.

Moderator edit: unnecessary over-quoting removed

madsci:
I played around with the tuning parameters...

That the word "parameter" includes an "s" indicates you are making a mistake. You should only be working with the Proportional parameter at this point.

Ok, adjusted only the proportional gain and still no change to Output.

Moderator edit: unnecessary over-quoting removed

I assume the fan is meant to cool.

PID myPID(&Input, &Output, &Setpoint,Kp,Ki,Kd, DIRECT);

If Setpoint is 15 and Input is 17 then the error is Setpoint - Input = -2. In this situation, the fan should be on to bring the Input down to 15.

This is from the header file...

DIRECT means the output will increase when error is positive. REVERSE means the opposite.

The error is negative and you specified DIRECT. The PID algorithm will try to drive the output more negative. The opposite of what you want.

Yes, the fan is meant to cool.

Oh right, thank you for pointing that out, I should have read the document more carefully. With Reverse, I get an Output reading of 255 and that makes sense since the temperature in my room is 31 celcius (summer heat) right now, at least according to the sensor.

I will further test the electronics tomorrow morning in my office as I do not have a power supply unit here with me at home. The 12V 0.7Amp fan does not seem to power on through the arduinos 5V power supply, not even a little bit.

Moderator edit: unnecessary over-quoting removed

The 12V 0.7Amp fan does not seem to power on through the arduinos 5V power supply, not even a little bit.

Well, I'm not surprised. Not even a little bit.

First of all, I'd like to say thank you for everyone that has helped me so far. The controller operates however, the PWM control portion of the code for that adjusts the fan is from 0-255 while the setpoint of the temperature sensor is set to 23 (for celcius). So when I initiate the code, the fan would ramp all the way up to max speed. I assume that this is because the two data types are not the same, one being a digital temperature reading and the other being a PWM range value.

I am thinking of converting the temperature sensor reading (range -55 to 125 Celcius according to data sheet) to be proportional to a PWM (0-255) value so that the two values would be somewhat compatible. Unless that is the wrong method to go about this problem. Suggestions?

From the examples that I have read, the PID controller seems to interact between two PWM (0-255) type controls. The temperature sensor isn't within that PWM range, however, the fan control is PWM controlled. Would I have to modify or map the temperature sensor values to the range of 0-255 or would the PID library not care if these two data types aren't the same?

Edit: I don't think I was clear in my last post. The situation is that the controller either ramps up the fan to max PWM speed setting if the temperature input is greater than the setpoint, even when the input is only 1 or 2 degrees higher than setpoint. How would one adjust the output of the PWM fan speed to slow down when the temperature input is close to the setpoint and then increase the fan speed when the temperature input is far from the setpoint?

The reason for the outputs in the 0-255 range is that that is the range that analogWrite gives you to vary the power on the PMW'd device between zero and max.

There is no need to transform the temperature reading into the same range; you can continue to work in Celsius. The PID simply looks at the difference between set point and current temp to help calculate how much power it needs to give to the fan. The units don't matter.

You may get better insight by serial.printing the set point, input and output values each time the PID computes.

Also, are you sure your fan is having a cooling effect? If you're just blowing ambient temperature air around, it may feel cooler to you due to evaporative effects on your skin, but the DS18B20 won't see any difference.

I have printed out the temperature readings and they are dropping however, the fan itself continues to spin at the same high speed even when the temperature difference is small. Could it be that my PID setting is incorrect? I have used REVERSE instead of DIRECT as suggested. I now feel that REVERSE should be used as the output (PWM fan) should decrease when my error (setpoint - input) is low.

it sounds like you haven't tuned your PID??
to do that you set the integral and derivative to 0, and get the P controlling and no ocsilating.
then you add I and d back in, though why you need I and D for a CPU fan I have no idea