PC Fan PID Cont

Hi all, I have been trying to tune a PID controller connected to a mini 12v low current computer fan with an in built hall effect sensor. I am just looking to control the rpm. When I connect the fan directly to 5v I can view the rpm using an interrupt which is great. The trouble is when the PID is used. The fan will oscillate up and down between an output value of either 0 or 255 every second. I feel like I have tried every Kp and Ki but still no luck.

Was seeing if I have missed anything?

double Setpoint, Input, Output;
double Kp = 1, Ki = 0, Kd = 0;
unsigned long last=0;
int pulseCount,RPM;

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

void setup() {
  Serial.begin(9600);
  pinMode(2,INPUT);
  attachInterrupt(0,encoderPulseInterrupt,FALLING);
  pulseCount=0;

  Setpoint = 4000;
  myPID.SetMode(AUTOMATIC);
  myPID.SetTunings(Kp, Ki, Kd);
  myPID.SetSampleTime(1);
}

void loop() {

if ((millis()-last)>=1000)
{
  last=millis();
  noInterrupts();
  RPM=pulseCount*60;
  Input = RPM;

  myPID.Compute();
  analogWrite(5, Output);
  Serial.println(RPM);
  
  interrupts();

  pulseCount=0;
}
}

void encoderPulseInterrupt()
{
  pulseCount++;
}

Alex.

Hi Alex,

Are you doing this to learn how to use PID control? Or do you believe it is absolutely needed in your project?

Tuning PID parameters is notoriously difficult. Would a simple linear relationship between temp and fan speed work well enough?

You should only disable interrupts for a short a time as possible, in order to avoid missing interrupts:

  noInterrupts();
  RPM=pulseCount*60;
  interrupts();
  Input = RPM;

  myPID.Compute();
  analogWrite(5, Output);
  Serial.println(RPM);
 

I ran an experiment to do something similar a while ago. This blog post may help https://arduinoplusplus.wordpress.com/2017/06/10/pid-control-experiment-making-the-testing-rig/

int pulseCount,RPM;

unsigned int would be safer.

 myPID.SetSampleTime(997);

Your PID window size is 1000ms, if you're using PID_v1.h there's no timer mode, so it would be better to make the PID sample time just less than the window size to ensure a computation each second. The PID library will account for the minuscule time difference.

Thanks for your help all. I was able to get something going that was somewhat stable after using a very small gain of 0.001 and an integral of 1.