existing problems
The purpose of this adjustment is to eliminate a phenomenon known as "Derivative Kick".
The picture above reflects this problem. Since error=Setpoint-Input, any change in Setpoint will cause error to change instantaneously. The derivative of this change is infinite (actually, since dt is not 0, it just computes to a very large number). This number is fed into the pid equation, which outputs an undesired peak. Fortunately there is an easy way to get rid of this.
solution
The derivative error is equal to the negative derivative of the input, except when the Setpoint is changed. This is not a perfect solution, instead of adding (Kd *derivative of error), we subtract (Kd *derivative of input). This is called using a "derivative measure".
The Code
/*working variables*/ unsigned long lastTime; double Input, Output, Setpoint; double errSum, lastInput; double kp, ki, kd; int SampleTime = 1000; //1 sec void Compute() { unsigned long now = millis(); int timeChange = (now - lastTime); if(timeChange>=SampleTime) { /*Compute all the working error variables*/ double error = Setpoint - Input; errSum += error; double dInput = (Input - lastInput); /*Technical PID output, Compute PID Output*/ Output = kp * error + ki * errSum - kd * dInput; /*Remember some variables for next time*/ lastInput = Input; lastTime = now; } } void SetTunings(double Kp, double Ki, double Kd) { double SampleTimeInSec = ((double)SampleTime)/1000; kp = Kp; ki = Ki * SampleTimeInSec; kd = Kd / SampleTimeInSec; } void SetSampleTime(int NewSampleTime) { if (NewSampleTime > 0) { double ratio = (double)NewSampleTime / (double)SampleTime; to *= ratio; kd /= ratio; SampleTime = (unsigned long)NewSampleTime; } }
Modifications here are very easy. We replace the error derivative and the input derivative. Remember the last input not the last error.
The Result
Here is the modified result, notice that the input still looks the same. So we get the same performance, but without outputting huge spikes every time the Setpoint changes.
This may or may not be a big problem. It depends on how sensitive your program is to output peaks.