Making the PID Controlled Current Source Better

Making the PID Controlled Current Source Better

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.

Programmable Switching Current Source Using Arduino as a PID Controller

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 modified circuit diagram incorporating the non-inverting gain amplifier (LM324 quad-opamp chip)

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.

PID two sets of constants

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.

Output limit

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;
void setup()
analogReference(INTERNAL); // set internal reference to 1.1 V
pinMode(ON,OUTPUT); // ON/OFF signal for LM2576
pinMode(FB, OUTPUT); //PWM for LM2576 Feedback
digitalWrite(ON, HIGH);
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;
void loop()
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;
analogWrite(FB, Output);
lastError = Error;

Final Words

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

Improving the beginners PID by Brett Beauregard

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.


Programmable Switching Current Source Using Arduino as a PID Controller

Programmable Switching Current Source Using Arduino as a PID Controller

Hope you guys are doing great!

In my last couple of posts concerning the NiMh battery charger I mentioned how I would like to make a programmable universal NiMh battery charger for a number of battery voltages and current levels, I was thinking of a contraption where the user would feed in the current output value or the level at which the battery is to be charged and the charger would magically maintain that desired output current through the charging process, since in my last iteration I had converted my original charging circuit to a formal switching regulator based one so it was obvious that I wanted to  implement the universal charger with a switching regulator as well.

The universal charger is nowhere near complete at the moment and this post, as the title suggests, won’t discuss just yet how to design one either, but instead this will cover a very important aspect which will be part of the final design, Since the whole point of the universal NiMh charger rests solely on realizing a current source where the user would be able to input a current value and get that exact same current output for the entire charge cycle of the battery.

I have made great progress on the issue and have finally  managed to implement a programmable current source based on the LM2576-ADJ controlled using an Arduino acting as a basic PID controller, now the name PID itself has its fair share of nostalgia associated with it, I learned it, in theory only while in engineering university and had a very basic to almost no idea of how it worked and why do we have these three proportional, integral and derivative terms in its equation anyway let alone knowing how it performed and what kind of stability it offered. Well when the time finally came to use a PID I realized how simple it was to implement in code on an Arduino and was surprised to see how stable and reliable it was as a controlling scheme. Apart from the PID controller implementation which sits at the heart of the design I also will be discussing the design schemes that I have followed to built this current source.

Understanding the LM2576-ADJ and how to control it

The LM2576-ADJ is a highly versatile buck DC-DC regulator, fortunately as I found out in order to get a desired current output from this regulator you don’t really have to know too much about the how the internal circuitry of the chip works.

The LM2576 can be treated as a black box that has some rules in order to regulate the current output from it. The LM2576-ADJ is a simple 5 pin chip, the pins are Vin, Vout, GND, Feedback and Inverted ON/ OFF

The LM2576-Adjustable

The 5th ON/OFF pin needs to be pulled up and a zero logic can enable the chip when needed, however in order to control the output of the chip one needs to know only one thing and that is whenever we put 1.2 volts on the Feedback pin the regulator stops changing it’s output and stays where it is as long as it gets the 1.2 volts required on the Feedback pin, say if you are not happy with the output and need to decrease it a little then you have to slightly increase the voltage on the Feedback pin, the LM2576-ADJ will think that the output has increased and will regulate it’s internal oscillator to bring down the output, the opposite holds true for when you are looking to increase your output current. So just to summarize it,

1- When you want to hold a certain output stable, put 1.2 Volts on FB (feedback) pin.

2- When you want to increase your output, put FB pin below 1.2 volts, when the desired output is reached again hold the output by applying 1.2 volts on the FB pin.

3- When you like to decrease your output, put a voltage greater than 1.2 volts on the FB pin and as soon as the desired output is reached again apply 1.2 volts on the FB pin to hold that output state.

This is what we will be basing our PID design on and will be constructing our simple circuit around these simple three requirements.

PID made simple, a basic review of concepts

Well the subheading is a trap really, no one can possibly make PID simple but if approached in the right way the PID is actually easy to understand and far more simpler to code in the Arduino.

The general PID equation

Well this is what they have scared you with so far, but you don’t need to know integration or derivative to implement a PID controller. The PID controller can be broken up into 3 simple parts and their functions are relatively easy to understand.

Proportional part deals with the errors that are present right now or errors that are in the “present” it does so by calculating an error which is typically,

Error = set point  – Actual value

The gain Kp is multiplied by the error term to generate an output which will work to minimize the error.

The integral term looks into the past and is a summation of all the error terms in the past, as time passes and the errors are summed up the integral term after being multiplied by the gain Ki boost the controller response to control the output. But why do we need integral past isn’t the proportional term enough? Well imagine a case where an error state occurs the proportional action moves to correct the error but as the actual value gets closer to set point the error decreases causing a weakly acting proportional part and since the proportional only acts on the current instantaneous error it never quite reaches the set point this is where the integral component comes into play, all the past errors are summed up over time (this is what the integral does summation over time) and then multiplied by a Ki gain to help the controller achieve its set point. For most processes this is enough as PI is probably the most widely used controller type.

The derivative component looks into the future and tries to determine what the output or actual value will be depending on its change rate and produces an output multiplied by a gain Kd, the derivative part of the PID helps to prevent overshoots, for example if the actual value is heading towards the set point very quickly then without the derivative part the actual value might overshoot the set point before eventually settling out this isn’t a desirable condition in most process so a derivative part is implemented to prevent overshoots, did I say I was going to make it simple? Well that didn’t work out as planned but you get the picture, my understanding at the moment is quite crude as well but it might help some of you struggling folks out there.

So the above equation can be simply written in programming terms as,

Output = Kp*(Error) + Ki*(Integral) + Kd*(Derivative)


Error = Set point – Actual Value

Integral = integral + Error

Derivative = Last value – Actual Value

Setting up The Circuit & Getting Analog Output from The Arduino

Well as discussed earlier the LM2576-ADJ needs 1.2 Volts on it’s feedback pin to hold the current output stable but we know that Arduino UNO being a micro-controller with no built-in DAC can only do zero and a logic high level, the answer lies in PWM and low pass filtering.

The Arduino has an 8 bit PWM output means it can go from 0- 255 varying the duty cycle of the PWM with 0 being the lowest and 255 being 5 volts.When you pass the PWM through a first order low pass filter you get fairly decent analog values that you can work with and that can reliably control the feedback pin of the LM2576-ADJ.

Through a simple comparison formula with analogWrite(x,0) being equal to 0 volts effectively and analogWrite(x,255) being equal to 5 volts I was able to deduce that analogWrite(x.62) passed through a low pass filter will give me close to 1.2 volts.

PID circuit
The programmed current source circuit

The circuit seems relatively simple, but that isn’t the simplest part about the design, the PID code is even simpler. Before getting to that let me just mention the feedback of the current into the battery that goes to the Arduino pin A0 is also being filtered, this gives better stability at low current values down in the range of 100 to 200 mA’s.

Setting up the PID equation

Well remember how I said that I need to have 1.2 volts on the LM2576-ADJ pin to hold the output stable?

From what we have learned so far we know that the proportional part of the equation can simply be written as,

Output = Kp*(Error)

So when the error is zero the output should be zero but what happens when you put zero volts on the FB pin of the LM2576? The output current increases until it reaches the maximum level of 3 Amps, so when the error is zero we don’t want zero volts on the output from the Arduino we want 1.2 volts or analogRead(x,62) like we discussed earlier so the proportional part is actually,

Output = – Kp*(Error) + 62,

Notice the negative sign in the equation above? that’s because the PID will be a reverse acting controller meaning in order to increase the current output the control output from the Arduino needs to be decreased and the opposite holds true to decrease the current output.

The final form of the PID equation should look something like this,

Output = -Kp*Error – Ki*Integral – Kd*Derivative + 62

The values for gain will be acquired through a manual loop tuning method that is very well documented on the wikipedia page of the PID controllers which we will also discuss briefly here.

Loop tuning, how to get suitable gain constants for your PID equation

Well in order to get reasonable gains for your PID we first set Ki and Kd gains to zero and slowly increase the Kp until we reach a point where the output current starts of with high amplitude oscillation and eventually settles not too far below the required set point and continues to oscillate at a reasonably slow pace between amplitudes close to each other, that value of Kp is halved and used as your Kp gain.

With the Kp gain set the Ki value is increased until the set point is acquired in reasonable time depending on the process you want to control. Note that too much Ki will make the loop unstable a it introduces a problem known as integral windup.

For the Derivative gain Kd, I settled for a value that gave me some stability at low set points in the milli amp ranges, before applying the derivative term my readings were fluctuating a lot.

Here is a cool little animated image from Wikipedia, helps to visualize and better understand all the gibberish

After a lot of trial and error and a lot of testing, this is the final equation that gives me the best results,

Output = -0.045*(Error) -0.0015*(Integral) -0.003*(Derivative)+ 62

I might still change these values as I go along but so far they seems to do the job pretty OK.

The Code

Remember how I said the code is the easiest part of the design? well I wasn’t joking.

int ON = 12;
int FB = 11;
float Actual, Last = 0, Error, Integral=0, Derivative, Output;
float setPOINT = (1.2*0.1)/0.00107; //Amp Calculated here
void setup() {
//setPOINT = ((setPOINT – 0.020)*0.1)/0.00107;
analogReference(INTERNAL); // set internal reference to 1.1 V
pinMode(ON,OUTPUT); // ON/OFF signal for LM2576
pinMode(FB, OUTPUT); //PWM for LM2576 Feedback
digitalWrite(ON, HIGH);

void loop()
Actual = analogRead(A0);
Error = setPOINT – Actual;
Integral = Integral + Error;
Derivative = Last – Actual;
Output = -0.045*(Error) -0.0015*(Integral) -0.003*(Derivative)+ 62; //PID control equation (0.09, 0.006, 0.1//old loop values -0.045 proportional oscillation// +62 corresponds to 1.2 V this
analogWrite(FB, Output);// is what keep the LM2576-ADJ stable when only proportional gain is used Output = -0.0225*(Error) -0.0015*(Integral) -0.001*(Derivative)+ 62;
Last = Actual;

That’s it, you’ve been running away all your life from a demon that didn’t exist in the first place! the PID code consists just of these few lines and that makes life incredibly easy!

Closing Remarks & Performance Check

Here is a video demonstrating the controller trying to achieve the 1.2 Amp set point, notice how a disturbance is introduced into the system as I am touching the exposed leads of the feedback capacitors and as soon as I remove my finger the controller again quickly maintains the output current to the set point. Seems pretty solid so far with very less variation. To be honest I wasn’t really hopeful when I started this out, I was actually looking for digital potentiometer chips that I can program to get a fixed current output value out of my LM2576-ADJ but wasn’t able to find any in the market, implementing a real time controlling scheme like the PID was my second choice but in the end I am kind of glad it got down to this.

Here’s a more recent LCD recent version of the same basic circuit with an added LCD interface and a keypad to input the current set point without having to change the code every time, just makes things a lot more convenient.