0

In my recent project, I'm working with Peltier module. And I tried out to adjust manually to set the value of Kp, Ki, and Kd. But it not so convenient to control the desired temperature. So for the solution of this, I found one Arduino library named Arduino-PID-AutoTune. And after using this library I got my desired output but there is one problem occurred. My output Peltier module not driven. I'm using DC Motor driver to drive Peltier module.

Autotune Library:

Arduino-PID-AutoTune-Library

My code is below:

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

int thermoDO = 3;
int thermoCS = 4;
int thermoCLK = 5;
Adafruit_MAX31855 thermocouple(thermoCLK, thermoCS, thermoDO);

#define PIN_OUTPUT 6

//Define Variables we'll be connecting to
//double Setpoint, Input, Output;

//Specify the links and initial tuning parameters
//double kp = 180, ki = 30, kd =1;

byte ATuneModeRemember=2;
double input, output, setpoint = 10;
double kp = 2,ki = 0.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 = false;
unsigned long  modelTime, serialTime;

PID myPID(&input, &output, &setpoint, kp, ki, kd, DIRECT);
PID_ATune aTune(&input, &output);

int IN1 = 8;
int IN2 = 9;

boolean useSimulation = true;

void setup()
{ 
  //initialize the variables we're linked to
  input = thermocouple.readCelsius();

  if(useSimulation)
  {
    for(byte i = 0; i  < 50; i++)
    {
      theta[i] = outputStart;
    }
    modelTime = 0;
  }

  //turn the PID on
  myPID.SetMode(AUTOMATIC);

  if(tuning)
  {
    tuning = false;
    changeAutoTune();
    tuning = true;
  }

  serialTime = 0;
  Serial.begin(9600);

  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
}

void loop()
{
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);

  unsigned long now = millis();

  if(!useSimulation)
  { //pull the input in from the real world
    input = thermocouple.readCelsius();
  }

  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] = output;
    if(now >= modelTime)
    {
      modelTime += 100; 
      DoModel();
    }
  }
  else
  {
     analogWrite(PIN_OUTPUT, output); 
  }

  //send-receive with processing if it's time
  if(millis() > serialTime)
  {
    SerialReceive();
    SerialSend();
    serialTime += 500;
  }
}

void changeAutoTune()
{
 if(!tuning)
  {
    //Set the output to the desired starting frequency.
    output = 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("setpoint: ");Serial.print(setpoint); Serial.print(" ");
  Serial.print("input: ");Serial.print(input); Serial.print(" ");
  Serial.print("output: ");Serial.print(output); 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
  input = (kpmodel / taup) *(theta[0]-outputStart) + input*(1-1/taup) + ((float)random(-10,10))/100;
}

My output is below:

setpoint: 10.00 input: 10.04 output: 12.20 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.13 output: 14.76 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.09 output: 14.70 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.30 output: 13.52 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.41 output: 12.30 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.23 output: 13.99 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.22 output: 11.64 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.31 output: 11.60 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.37 output: 11.70 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.10 output: 13.24 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.02 output: 13.97 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.05 output: 10.68 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 9.90 output: 13.46 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 9.79 output: 13.84 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 9.82 output: 11.34 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 9.75 output: 12.23 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.02 output: 10.23 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.07 output: 13.03 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.20 output: 11.90 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.14 output: 10.50 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.17 output: 12.47 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.37 output: 10.33 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.41 output: 10.85 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.53 output: 8.74 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.59 output: 10.84 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.62 output: 11.36 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.59 output: 10.42 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.62 output: 9.18 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.57 output: 11.08 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.64 output: 9.92 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.40 output: 9.69 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.35 output: 8.91 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.31 output: 12.12 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.32 output: 12.44 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.03 output: 11.91 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 9.72 output: 11.55 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 9.75 output: 11.12 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 9.54 output: 13.52 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 9.59 output: 10.28 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 9.40 output: 12.16 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 9.29 output: 13.12 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 9.58 output: 12.31 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 9.55 output: 11.78 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 9.69 output: 10.03 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 9.83 output: 10.69 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 9.87 output: 13.55 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.03 output: 11.28 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 9.81 output: 13.29 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.07 output: 9.85 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.30 output: 11.59 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.29 output: 11.26 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.38 output: 9.52 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.16 output: 11.14 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.06 output: 10.09 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 10.06 output: 10.43 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 9.68 output: 13.66 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 9.84 output: 12.71 kp: 2.00 ki: 0.50 kd: 2.00
setpoint: 10.00 input: 9.84 output: 12.61 kp: 2.00 ki: 0.50 kd: 2.00

I don't understand why my Peltier not driven even if all things seem right. Suggest me.

EDIT:1

One thing I noticed during testing that when I put the manual value of PID parameters then the temperature(means Input) will set according to Setpoint when I start my power supply. But when I use PID AutoTune library then temperature(means Input) set according to Setpoint even if there is no power supply there. I don't understand without power supply how can it possible to set the temperature(means Input) according to Setpoint?

Hasan
  • 1,468
  • 13
  • 27
  • If the problem isn't that `analogWrite(PIN_OUTPUT, output) ` doesn't happen when `useSimulation=true`, then it might be a difference between the PID's dT and the reporting dT. The timestep of the myPID.compute() and doModel() look like they might be as fast as it can loop(), but the reporting cycle is 500ms. If the code can run lots of iterations per 500ms, what you will see in the log is aliased noise. I'd suggest controlling the sampling time of the PID process (and simulation and reporting) so that the simulation happens more physically realistically. – Dave X Dec 20 '17 at 18:03
  • If you don't have a dT of the control process on the order of 1/10 of the time constant of the process under control, the kI and kD terms of the PID can produce unstable behavior. – Dave X Dec 20 '17 at 18:08
  • Please explain why you are using "DIRECT" instead of "REVERSE" again? – AltAir Dec 20 '17 at 22:49
  • @DaveX I can't understand what you are trying to say! Sorry !!! – Hasan Dec 21 '17 at 12:46
  • @AltAir Because I already tried out that thing means writing "REVERSE" then my input constantly increasing. That's why I write "DIRECT" for this autotune. But for manual adjustment of the parameter, I used "REVERSE". – Hasan Dec 21 '17 at 12:49
  • 1
    Can PID_AutoTune_v0 work when output growth leads to lower temperatures? Unlike the heater. – AltAir Dec 21 '17 at 12:59
  • @AltAir Yes, this code is perfectly working. It leads to lower temperatures when we set the low value of temperature. Only not driven Peltier module. – Hasan Dec 21 '17 at 13:02
  • First, do you mean that pin 6 doesn't change even though the simulation is working perfectly? If so, take the `analogWrite(...)` out of the `else{}` clause. – Dave X Dec 21 '17 at 19:23
  • Second, your output control is a 0-255 duty cycle that is fed into analogWrite(). The approximately 10 value you are feeding your Peltier driver might not be enough to be detectable. You may need to adjust your simulation consider inputs in the range 0-255, or alternately, scale whatever output/input your simulation is using to the controlled output. I like thinking of the units of kP, -- it could, for example, be mapping degrees of temperature error into counts of the PWM duty cycle. – Dave X Dec 21 '17 at 19:37
  • @DaveX I think I have to edit my detail more. Wait for that. I will update soon. Becuase I forget to mention one thing which can't be able to explain in this comment. I think it is better to update my details. – Hasan Dec 23 '17 at 07:39

0 Answers0