Extensive testing leads to many problems that are not revealed initially, during the time I spent tinkering and tweaking the PID code I was confronted with some problems that had to be addressed in order to make the final code reliable. By the end of this article we’ll be improving the code through logical reasoning and the simple circuit I built in the original article for a PID controlled current source using arduino as the PID controller and the LM2576-ADJ switching regulator as the current source.
Here’s a link to the previous post for your quick reference, before you go further it is absolutely necessary to read the original post in order to understand where we stand at this point.
The problems I faced with the previous setup are briefly listed below,
1- Instability of current output at lower current set points.
2- The steady state error increased with increase in set point, the output current settled at as high as 70mA’s above the desired value.
3- Wild random oscillations when power source is turned ON after a small delay, the output current oscillates and settles down randomly and at times need a restart.
4- High current spikes at the start.
Instability of Low Current Outputs
During my initial implementation I found out that current fluctuation became more and more pronounced at low set points, secondly the output once it settled deviated quite a bit from the required value, say for a set point of 100 mA the output settled at around 150 mA, this condition was undesirable from my view point.
Since I am using a 0.1 ohm current sense therefore for a current of 100mA’s the voltage feedback going to the Arduino UNO for digital conversion will be only 0.01 volts. Using an internal reference of 1.1 volts the Arduino will read this voltage as almost 9 steps on the ADC, from a noise immunity point of view these low values of voltages are easily corruptible and cause wide deviations from the original set point, although I used a low pass filter in my initial design and it did settle out the voltage fluctuation to some extent but the desired value still deviated far from the required current.
Since I have designed this current source for a maximum of 2.2Amps which translates into a feedback voltage of 0.22 volts for the Arduino therefore a good portion of the range of the 1.1 Volts ADC reference is being wasted, amplifying the voltage will not only utilize the full range of the 1.1 volts reference but will also give the ADC reasonable amount of steps to work with at low current values which will be less susceptible to noise and give better stability at low currents.
At this point it seemed like a good idea to amplify the feedback voltage from the current sense resistor before it goes to the arduino, I am going to utilize the LM324 that’s already on board to amplify my voltage feedback from the current sense resistor by an amplification factor of 4.4 (Although the amplifier is designed for a 4.4gain factor but multiplying by a gain factor of 4.3 in the final code gives the best results, upon measuring the resistances by a multi-meter I got readings in the range of 4.32, this might be the underlying problem but things will become clear once I use precision resistors), here are the changes I have made in the circuit,
The increase in the number of steps specially at low current values and better utilization of the ADC reference range helps improve stability at lower down the scale. From a 50mA deviation previously I was able to reduce the deviation down to 15mA, this is reasonable improvement.
But this is not it, through experimentation I found out the that a single set of proportional, integral and derivative constants won’t work, with a single equation the current values lower down the scale, although had less of an error than last time but showed rapid fluctuations, there is always some ripple when working with switching regulators and even if the digital multi-meter can’t display it the effect becomes obvious once you use a sensitive equipment like an oscilloscope, however for my case I settled for two different sets of constants approach since it works best and produces desirable results.
Increasing Steady State Error With Increasing Set Point Values
The use of a gain amplifier to produce stability at low current values offered an added advantage and served to reduce the high but steady deviation at high current values, however before I accidentally stumbled upon this I did try to use a mathematical method to push back my output currents closer to the set point and it was based on a very simple idea, if I knew the deviation from set point for a particular set point I can control the situation by passing on a modified set point to the controller, for e.g if I knew the deviation for a set point of 1.9 Amps is 0.07 Amps then I can simple tell the controller to achieve a set point of 1.85 Amps giving me a value closer to 1.9 Amps and since the error increased with increasing set point the smell of a linear relationship between the steady state error and the set point was always there, however I ended up dropping this approach since my search for elegance got the best of me in this case.
For any of you who might be interested here the mathematical expression for the set point modification I used before implying the gain amplifier.
Subtraction Factor from set point = 0.01047*Set Point + 0.0529
Random Oscillations At High Set Points Which Would Settle Out Randomly or Needed a Restart
Above is the definition for a very common PID related problem known as integral windup, however I never knew how it looked like in practice up until very recently, say for example if you leave your controller running and turn off your power source, the integral term will go on summing up the errors endlessly, since the controller never reaches the set point, if at this point you put your voltmeter on the PWM output pin from the Arduino you’ll see your voltages fluctuating, that’s not a good sign, what we need it to clamp the integral term and put limits to it, I got best results by limiting my integral term in between 5000 and -5000,
These limits were achieved through test and trial, once this is done it’s probably best to limit your PID outputs as well since the output of a PWM can’t go above 255 and below 0 for an arduino so it is only logical to clamp the output of the PID to these values, but putting zero volts on the LM2576-ADJ feedback pin pushes up the current drastically to the maximum current capacity of 3Amp for the LM2576-ADJ, so we can safely assume a PID output value of 0 volts is an undesirable situation in itself and should be avoided, since any value below 1.25 volts on the LM2576-ADJ feedback pin will eventually serve to increase the current, however the smaller and the farther away the voltage is from the 1.25V threshold the sharper the current rise hence resulting in unwanted peaks at times, therefore after testing out a few values I settled for a minimum PWM output of 10, it is important to state at this point that selecting a high value for the minimum output of the PID is going to affect it’s performance so since you are basically limiting PID’s ability to increase the current output from the LM2576-ADJ.
Current Spikes At The Start
The unusual current peaks at the start might not be a problem for certain PID controlled processes but for me it could have a deteriorating affect on the battery life, this situation can however be controlled by changing the derivative equation slightly, in my previous code my derivative factor was computed by subtracting the present current value from the last current value, however when the PID starts the last and present current values will both be zero and a strong derivative action won’t kick in until a high current flows so this almost always guarantee’s a current spike at the beginning, what we can do to counter this is to compute the derivative using the below scheme,
Derivative = Last Error – Present Error
Say for a set point of 1.2 Amps which equates to 480 ADC steps the PID will get to the derivative computation part with an Error of at most 480, since the last error at this stage will be zero therefore the derivative term in the PID equation will become positive and will act to decrease the starting instantaneous current from the LM2576-ADJ
This change guarantees that there will always be a respectable derivative action present at the start of a control cycle to dampen out the current spikes that would have otherwise resulted without this approach.
The Complete Code
Here is what the complete code looks like,
int ON = 12;
int FB = 5;
float Actual, lastError = 0.0, Error = 0.0, Integral = 0.0, Derivative;
float Amp = 0.5;
float Output, Kp, Ki, Kd;
float setPOINT = 0.0;
analogReference(INTERNAL); // set internal reference to 1.1 V
pinMode(ON,OUTPUT); // ON/OFF signal for LM2576
pinMode(FB, OUTPUT); //PWM for LM2576 Feedback
setPOINT = Amp*0.1*1024*4.3; // with the amplification factor included
setPOINT = setPOINT/1.1;
if(Amp <= 0.5)
Kp = 0.07;
Ki = 0.00075;
Kd = 0.07;
if(Amp > 0.5)
Kp = 0.2;//was 0.1
Ki = 0.0025;
Kd = 0.04;
Actual = analogRead(A1);
Error = setPOINT – Actual;
Integral = Integral + Error;
if(Integral > 5000)
Integral = 5000;
if(Integral < – 5000)
Integral = -5000;
Derivative = lastError – Error;
Output = -Kp*(Error) -Ki*(Integral) – Kd*(Derivative)+ 62;
if(Output > 255)
Output = 255;
if(Output < 0)
Output = 10;
lastError = Error;
There’s an excellent article online written by Brett Beauregard who is the authority on PID controllers and arduino based PID in particular, I highly recommend anyone who’s struggling with PID’s or wishes to write his or hers own PID to go check out his blog, there’s tons of priceless information there
For me this would not have been possible without Brett’s article, so all credit to the guy who’s behind the Arduino’s PID library and is doing much more amazing projects.
As for the PID one can never be completely happy, it’s just the way PID is it leaves you wondering, “can I do it any better than this?” the result is countless hours of chair warming and head scratching but it all pay’s up well in the end, once again this is leading up to my universal charger design and the more I get closer to finalizing the design in my mind the more I realize that I can’t work with a single controller alone to act as a PID and monitor the battery voltage as well, the PID block needs to be separate with a dedicated chip just taking care of the PID control process and nothing else, since I was originally hoping to base my design around an Atmega328 chip and which I still am, I have started to wonder if I can have an Attiny85 in the design functioning as a separate PID block independent of the the Atmega chip and only receives the set point before it goes about doing it’s work, at this stage I am wondering how I can communicate the set point from the Atmega328 to Attiny85, I am thinking about developing a custom communication two wire protocol to simply transmit pulses to the Attiny85 and counting those pulses the tiny would be coded to compute the set point, Morris code comes to mind for a second, I have to see where I go with this though. If you like my article please share it with your friends, leave a like or a comment, your suggestions are more than welcome.
Update: The design is quiet sensitive to loose connections, using a breadboard might introduce errors in the current output, use bypass capacitors for the opamp supply, make sure voltage doesn’t fluctuate.