Following the bare bones Arduino power supply with LCD of my previous post, I wanted to fix the problem that the load voltage (V_load) will vary when the current varies, because of the voltage drop over the shunt resistor V_shunt, as the DC/DC converter supplies a constant V_out = V_shunt + V_load. The ultimate goal is to make a power supply that can ‘lock in’ a constant voltage independent of current drawn.

The obvious solution is to let the Arduino microcontroller control the potentiometer on the DC/DC converter, with a digital potentiometer. I got the MCP4151-103, a 10K digital potentiometer with 256 steps over SPI. The connection with Arduino is quite standard as described here. I found out in these schematics that the original trim pot on the DC/DC converter is actually not using its 3 legs independently, so that would call for a digital rheostat rather than a potentiometer, but the MCP4151 does the job too.

IMG_20150309_182332758
DC/DC converter on the left with digital potentiometer on breadboard connected to an Arduino in the back. Output voltage is divided over a shunt 5ohm resistor (to be able to measure current later) and a simulated load of 40ohm. The load voltage goes into a voltage divider ; 1/3 of the load voltage goes into an analog pin of the Arduino (Aref = 5V).

The DC/DC converter is quite stable, so if we would map the digital potentiometer values to the output voltages, we could just use a table to set the pot value corresponding with the target voltage. However, if we want to measure current (with a shunt resistor), then the voltage over the shunt resistor V_shunt will vary according to the current, and also V_load will vary (V_out remaining stable). If we try to keep V_load stable, we can use a typical PID controller setup. Arduino has an excellent PID library. It uses 3 variables:

  • input: output_voltage (in Volts)
  • setpoint: target_voltage (in Volts)
  • output: pot_level (to send to the digital potentiometer 0-255)

There are 3 parameters to tune the PID controller: Kp, Ki, Kd. The PID did work with the default values in the library example sketch, but it was very slow. I tried the PIDautotune library to find the optimal values for these 3 parameters, but couldn’t get that to work. To experiment with different values i really needed to see what was happening in a real-time graph. So i used a simple Processing sketch to visualise the output of the Arduino sketch (output_voltage).

PIDpowersupplytest2
Processing graph showing PID control at work to reach various random voltages under constant load

The Arduino sketch changes the target_voltage every 5 seconds to a random integer value between 3V and 9V. With a good set of K parameters the transitions are very short, less than 1 second. The graph shows that increasing the voltage goes a lot faster than decreasing it.

Next step is to see how the PID control reacts to a varrying load when we use a shunt resistor. To keep the V_load constant, the PID will need to adjust the V_out. I used a 5V target with a load of 40ohm, drawing a 130mA current, and switching this load on and off quickly, causing the spikes.

PIDpowersupplytest5ohmshunt40ohmloadonoff

And for reference the current version of the Fritzing schematics of the above project.

powersupply-digpot1_schem
Arduino based digital power supply with PID control

I used an Industruino PROTO to give this project a nice permanent home and i am using it frequently as my testing power supply.

proto-power

Below the code for the basic PID sketch (without shunt):

/* dig pot MCP4151
   create voltages of 0-1-2-3-4-5V over wiper-GND
   1: CS      D4
   2: SCLK    D13 (on leonardo use ICSP header!! SCK)
   3: SI      D11 (on leonardo use ICSP header!! MOSI)
   4: GND
   5: 5V
   6: wiper
   7: GND
   8: 5V
   Tom Tobback March 2015
*/   
#include <SPI.h>
#include <PID_v1.h>

// Set digital pin 4 as slave select for digital pot:
const int pot_pin = 4;
double pot_level = 0;    // between 0-255                PID OUTPUT  (default output is 0-255 = correct)
int read_voltage;       // analog read
double output_voltage;   // measured output voltage      PID INPUT
double target_voltage = 5;   // target output voltage        PID SETPOINT
long last_send = 0;      // for processing graph

// PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT);
PID myPID(&output_voltage, &pot_level, &target_voltage,2,5,1, DIRECT);

void setup()
{
//  analogReference(EXTERNAL);   // put 5V on AREF
  pinMode(pot_pin, OUTPUT);
  pinMode(3, INPUT);
  SPI.begin(); 
  Serial.begin(9600);
  myPID.SetMode(AUTOMATIC);
  myPID.SetSampleTime(50);
  myPID.SetTunings(10,200,0);
}
void loop()
{
    if (Serial.available() > 0) 
      {
        target_voltage = Serial.parseInt();
        Serial.println(target_voltage);
      }
      
    if (digitalRead(3) == HIGH)   // manual switch during processing graph
    { target_voltage = 5; }
    else 
    { target_voltage = 3; }
      
    read_voltage = analogRead(A0);
    output_voltage = 3 * 3.3 * float(read_voltage) / 1023;
    
    myPID.Compute();
    digitalPotWrite(pot_level);
    
    if (millis() - last_send > 50)   // don't send to often to Serial for processing graph
    {
    Serial.println(output_voltage);
    last_send = millis();
    }
//    Serial.print("V\t");
//    Serial.println(pot_level);
//    delay(100);
}
int digitalPotWrite(int value)
{
  // Take the SS/CS pin low to select the chip:
  digitalWrite(pot_pin, LOW);
  // Send in the address and value via SPI:
  SPI.transfer(0);
  SPI.transfer(value);
  // Take the SS/CS pin high to de-select the chip:
  digitalWrite(pot_pin, HIGH); 
} 


Digital power supply with PID control

4 thoughts on “Digital power supply with PID control

  • Pingback:Industruino digital power supply | Cassiopeia Ltd

  • 17/11/2016 at 01:26
    Permalink

    Hello!
    Are you willing to share your sketch?
    I am working on a very similar project and am having trouble getting the code to work the way I want it to.
    The PID library seems to need the input to be directly from an input pin, but I need it to do math to the value read from the input pin first and it just gives an output of 0 that way.

    Reply
    • 18/11/2016 at 08:17
      Permalink

      hi, i have included a basic sketch above, hope that helps.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *