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 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.

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)

Where…..

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.

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.

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);

analogWrite(FB,62);

delay(500);

}void loop()

{

digitalWrite(ON,LOW);

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.

setPOINT = (1.2*0.1)/0.00107; //Amp Calculated here

in this how did you get the two terms 0.1 and 0.00107 from?

LikeLike

Hi,

1.2A is the ampere setpoint, 0.1 is the sense resistor across which the voltage will be measured by the arduino as a feedback.

For a 1.1v internal ADC reference on the arduino you get 1.1/1024 = 0.00107 (1024 since its a 10 bit ADC)

For better performance I highly encourage you to try out the ATtiny85 based design as the steady state error is reduced significantly with that variation.

LikeLike