How to use PID_AutoTune_v0?

Hi,

I am working on a pwm constant current LED driver.
I use an acs712 hall sensor to measure current. I would like to use a PID setup my code but unfortunately I can not find the appropriate PID values. After several trial and error I decided to use auto tune PID in my code. I have implemented it in my code but I can not figure out how to use it.
How can I get the auto tuned PID values?

Here is my code:

#include <PID_AutoTune_v0.h>
#include <PID_v1.h>


const int analogIn = A0;    // Sensor connected to analog pin A0
int ledPin = 9;      // LED connected to digital pin 9
int mVperAmp = 64; // use 100 for 20A Module and 66 for 30A Module
double RawValue= 0;  //value read by the current sensor
double pwmValue= 0;  //pwm value 0-255
int ACSoffset = 2500;   //offset value of the current sensor, for more info see the datasheet
double Voltage = 0;     //calculated voltage read by the sensor
double Amps = 0;        //measured current
double SetAmp = 2;      //desired current

//Modified Moving Avarege method used to smooth sensor data

// Let's compare an average of 100
const byte averageCount = 100;

// Variables for the Modified Moving Average
double movingAverage = 0;
double movingAverageSum = 0;

// Timer variables
unsigned long previousMillis = 0;
unsigned int printInterval = 50;
unsigned long startTime = 0;
unsigned long stopTime = 0;

//Specify the links and initial PID tuning parameters
byte ATuneModeRemember=2;
double Kp=3, Ki=5, Kd=2;
double kpmodel=1.5, taup=100, theta[50];
double outputStart=5;
double aTuneStep=50, aTuneNoise=1, aTuneStartValue=100;
unsigned int aTuneLookBack=20;

boolean tuning = true;
unsigned long  modelTime, serialTime;

PID myPID(&Amps, &pwmValue, &SetAmp, Kp, Ki, Kd, DIRECT);
PID_ATune aTune(&Amps, &pwmValue);

//set to false to connect to the real world
boolean useSimulation = false;

void setup()
{
 pinMode(ledPin, OUTPUT);   // sets the pin as output



   if(useSimulation)
  {
    for(byte i=0;i<50;i++)
    {
      theta[i]=outputStart;
    }
    modelTime = 0;
  }
  //Setup the pid 
  myPID.SetMode(AUTOMATIC);

  if(tuning)
  {
    tuning=false;
    changeAutoTune();
    tuning=true;
  }
  
  serialTime = 0;
  Serial.begin(9600);

// Pre-load MMA
  for (int x=0; x < averageCount; x++)
  movingAverageSum = movingAverageSum + analogRead(analogIn);
     
// Calculate inital average
  movingAverage = movingAverageSum / averageCount;

    
//Set the PWM frequency of the arduino board

//TCCR1B = TCCR1B & B11111000 | B00000001;    // set timer 1 divisor to     1 for PWM frequency of 31372.55 Hz
//TCCR1B = TCCR1B & B11111000 | B00000010;    // set timer 1 divisor to     8 for PWM frequency of  3921.16 Hz
TCCR1B = TCCR1B & B11111000 | B00000011;    // set timer 1 divisor to    64 for PWM frequency of   490.20 Hz (The DEFAULT)
//TCCR1B = TCCR1B & B11111000 | B00000100;    // set timer 1 divisor to   256 for PWM frequency of   122.55 Hz
//TCCR1B = TCCR1B & B11111000 | B00000101;    // set timer 1 divisor to  1024 for PWM frequency of    30.64 Hz

}


void loop()
{

  unsigned long now = millis();

  if(!useSimulation)
  { //pull the input in from the real world
    RawValue = analogRead(analogIn);
  }
  
  if(tuning)
  {
    byte val = (aTune.Runtime());
    if (val!=0)
    {
      tuning = false;
    }
    if(!tuning)
    { //we're done, set the tuning parameters
      Kp = aTune.GetKp();
      Ki = aTune.GetKi();
      Kd = aTune.GetKd();
      myPID.SetTunings(Kp,Ki,Kd);
      AutoTuneHelper(false);
    }
  }
  else myPID.Compute();
  
  if(useSimulation)
  {
    theta[30]=pwmValue;
    if(now>=modelTime)
    {
      modelTime +=100; 
      DoModel();
    }
  }
  else
  {
     analogWrite(ledPin,pwmValue);
  }
  
  //send-receive with processing if it's time
  if(millis()>serialTime)
  {
    SerialReceive();
    SerialSend();
    serialTime+=500;
  }
  
 



 
// each interation of loop, update moving average
// Get a new sample
// unsigned int currentValue = analogRead(analogPin);
 
  startTime = micros();
  // Remove previous movingAverage from the sum
  movingAverageSum = movingAverageSum - movingAverage;
  // Replace it with the current sample
  movingAverageSum = movingAverageSum + RawValue;
  // Recalculate movingAverage
  movingAverage = movingAverageSum / averageCount;
  stopTime = micros();

// analogRead values go from 0 to 1023, analogWrite values from 0 to 255 
Voltage = (movingAverage / 1024.0) * 5000; // Gets you mV
Amps = ((Voltage - ACSoffset) / mVperAmp);




  /*if (millis() - previousMillis >= printInterval) {
    /*Serial.print(F("RawValue: "));
    Serial.println(RawValue);
    Serial.print(F("PWM Value: "));
    Serial.println(pwmValue);
    /*Serial.print(F("Moving Average: "));
    Serial.println(movingAverage);
    Serial.print("Calculation time: ");
    Serial.print(stopTime - startTime);
    Serial.println(" us");
    Serial.print(F("Amps: "));
    Serial.print(Amps);
    Serial.println(" A");
    Serial.print(F("Voltage: "));
    Serial.print(Voltage);
    Serial.println(" mV");
    Serial.println();
    Serial.flush();*/
 
// reset the millis clock
previousMillis = millis();

}



void changeAutoTune()
{
 if(!tuning)
  {
    //Set the output to the desired starting frequency.
    pwmValue=aTuneStartValue;
    aTune.SetNoiseBand(aTuneNoise);
    aTune.SetOutputStep(aTuneStep);
    aTune.SetLookbackSec((int)aTuneLookBack);
    AutoTuneHelper(true);
    tuning = true;
  }
  else
  { //cancel autotune
    aTune.Cancel();
    tuning = false;
    AutoTuneHelper(false);
  }
}

void AutoTuneHelper(boolean start)
{
  if(start)
    ATuneModeRemember = myPID.GetMode();
  else
    myPID.SetMode(ATuneModeRemember);
}


void SerialSend()
{
  Serial.print("SetAmp: ");Serial.print(SetAmp); Serial.print(" ");
  Serial.print("RawValue: ");Serial.print(RawValue); Serial.print(" ");
  Serial.print("pwmValue: ");Serial.print(pwmValue); Serial.print(" ");
  if(tuning){
    Serial.println("tuning mode");
  } else {
    Serial.print("kp: ");Serial.print(myPID.GetKp());Serial.print(" ");
    Serial.print("ki: ");Serial.print(myPID.GetKi());Serial.print(" ");
    Serial.print("kd: ");Serial.print(myPID.GetKd());Serial.println();
  }
}

void SerialReceive()
{
  if(Serial.available())
  {
   char b = Serial.read(); 
   Serial.flush(); 
   if((b=='1' && !tuning) || (b!='1' && tuning))changeAutoTune();
  }
}

void DoModel()
{
  //cycle the dead time
  for(byte i=0;i<49;i++)
  {
    theta[i] = theta[i+1];
  }
  //compute the input
  RawValue = (kpmodel / taup) *(theta[0]-outputStart) + RawValue*(1-1/taup) + ((float)random(-10,10))/100;

}

Thank you in advance.

Moderator edit:
</mark> <mark>[code]</mark> <mark>

</mark> <mark>[/code]</mark> <mark>
tags added.

Sounds like a classic x-y problem

Why do you need PID for an led driver? That doesn’t make much sense.

Putting that aside assuming you really need the PID loop, if the input is unstable, no tuning will make it stable. Have you loroked at the input value with a scope or plotted it with the serial plotter? Is there any noise on the signal? If you’re reading current of a PWM signal, are you sampling the input of the acs712 only when the output is high?

I would like to make a high power led driver. The power source would be a battery. As the battery discharged it's voltage changes but I want to keep the current constant so I need to change the pwm signal automatically.

I also need different outputs, for example low, mid, high... I can also do it by changing the pwm duty cycle. High power leds can be very hot and their "resistance" changes significantly with temperature, and I want to keep the light output constant. If the current constant the output also will be constant regardless of the temperature.

If I change between light modes the temperature difference can cause problem, but I am not sure. What happens if the led, pcb and pill is hot and than you change for a lower mode?... I do not know.

So that is why I wanted to use a PID control and control the current. But if there is a better soulution I can accept it.

The current is measured always not just at the peaks of the pwm signal, that is why a moving average calculation is used and this avereged value is used for the PID control.

PWM does not regulate current, it only controls the average voltage over time. You might think you’re controlling current but you’re not and such a scheme could cause to led failures due to overvoltage.

Have you Googled “constant current led driver”? You drive high powered led’s with hardware, not software based solutions. The changing battery voltage is irrelevant, so long as it meets the driver (and led) minimum voltage requirements.

If you want more detailed help, please post the specs of the LED’s and the battery you’d like to use.

My idea was to make a "general" programmable constant current driver.
But now I would like to use an XHP70.2 led and the power source is a 2s lipo battery.

I know that pwm regulate voltage and not current. That is why I used an ACS712 current sensor and I wanted to adjust the pwm signal based on the measured current.