PID heater regulation. tuning problems

Hi guys,

I am very new to programming and arduino. I am using an Arduino Mega2560. I got the task to optimize a programm for a heater. I managed to find the right values for the PID parameters after a lot of struggle. But still I have some problems with the programm. Depending on the setpoint and the start temperatur I always have to adjust the Kp, Ki, Kd parameters. There is a big difference if I want to increase the temperature from 50-80C°,150-180C° or from 30-200C°.
So my question is: Is it normal, that I always have to adjust the parameters, or is there a solution, that I can use always the same parameters no matter what my heating rate is.

I would be really greatfull if you could help me to solve my problem.

By the way, this is my code:

#include <PID_v1.h>
#include <Wire.h>
#include <Adafruit_MCP4725.h>
#include <Adafruit_ADS1015.h>
#include <math.h>


Adafruit_MCP4725 DAC_strom;
Adafruit_MCP4725 DAC_spannung;
Adafruit_ADS1115 ADC_PT100(0x48);


double Setpoint = 0, Input, Output, Current;
double Kp = 5;
double Ki = 0.008;
double Kd = 15;   
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, P_ON_E, DIRECT);                                      //PID Objekt erzeugen, direct mode, proportional on error
double temp = 0;
long messzeit = 100300000;
  
void setup() {
  Serial.begin(9600);
  Serial.println("ClearRange,A,1,D,50000");
  Serial.println("LABEL,Zeit,Ist_Temperatur,Soll_Temperatur,Kp,Ki,Kd");

  Serial.println("CELL,GET,FROMSHEET,Simple Data,G,5"); Setpoint = Serial.readStringUntil(10).toFloat();
  Serial.println("CELL,GET,FROMSHEET,Simple Data,G,6"); Kp = Serial.readStringUntil(10).toFloat();
  Serial.println("CELL,GET,FROMSHEET,Simple Data,G,7"); Ki = Serial.readStringUntil(10).toFloat();
  Serial.println("CELL,GET,FROMSHEET,Simple Data,G,8"); Kd = Serial.readStringUntil(10).toFloat();
  
  ADC_PT100.begin();
  DAC_strom.begin(0x60);                                      //0x60 bei Adr auf GND
  DAC_spannung.begin(0x61);                                   //0x61 bei Adr auf Vdd

  DAC_spannung.setVoltage(2730,false);                       //Setzen der Spannung des Netzteils auf 24V (äquivalent 2730Bit / 3.333V)
  DAC_strom.setVoltage(0,false);
  
  //PID setzen

  Input = Temp_auslesen();
  myPID.SetOutputLimits(0, 500);                             //PID Limits setzen, SetOutputLimits(min,max)

  //PID SetTunings(Kp, Ki, Kd, POn), wenn die tuning paramter sich verändern.. evtl für verschiedene Temperturbereiche, schnellere Anfahrtszeiten
  //PID SetSampleTime(int>0 in ms), wie oft der alkorithmus ausgeführt wird. Default ist 200ms.
  //PID SetCOntrollerDirection(Direction:Direct/Reverse), DIRECT ist default

  myPID.SetMode(AUTOMATIC);                                   //PID SetMode(): AUTOMATIC - PID ein, MANUAL - PID aus
  delay(1000);
}

void loop() {
  if (millis() <= messzeit+1) 
  {
    Input = Temp_auslesen();

    myPID.Compute();
    
//    if (Output <= 0) 
//    {
//      Output = 0;
//    }
//    if (Output >= 3250) 
//    {                                       //evtl möglich wegzulassen, redundant
//      Output = 3250;
//    }

    Current=sqrt(1.3414*Output);                  // 1.3414 Berechneter Strom aus Leistung durch Kalibrationsfunktion 0.7455x^2=P
    
    DAC_strom.setVoltage((115.22*Current+100), false);                //Ausgabewert nach folgender Formel berechnet: y=115.22x+100

    Temp_ausgabe(Temp_auslesen(), 1000);                         //Temperaturausgabe über Funktion Temp_ausgabe mit float von Temp_auslesen alle 500ms


   // Pause 100 bis 1000 ms
  }
  else{
    DAC_strom.setVoltage(0,false);
  }
}


//----------------------Unterfunktionen-------------------------------

double Temp_auslesen() {                                         //Tempbereich 0-250°C
  int16_t Messwandler_spg_bit = 0;
  double Temperatur = 0 ;

  Messwandler_spg_bit = ADC_PT100.readADC_SingleEnded(1);
  Temperatur = Messwandler_spg_bit * (0.000187 * 50);           //0.187mV: bit->0-5V, 50: 0-5V->0-250°C

  return Temperatur;
}

void Temp_ausgabe(double temperatur, int Ausgabeintervall) {
  static long letzteAusgabe;

  if (millis() - letzteAusgabe >= Ausgabeintervall) {
    Serial.print("DATA,"); Serial.print((millis() / 1000)-2); Serial.print(","); Serial.print(temperatur); Serial.print(","); Serial.println(Setpoint);
    letzteAusgabe = millis();
    //Setpoint=Setpoint+1;
  }
}

If you pick the right parameters it should not matter to much. Although a PID isn't perfect. So if the system doe react very differently in different ranges a simple PID might not be perfect.

Keep in mind a PID is just a simplified / general form of a feedback system. if you want to have a better controller you have model your system and make a tailored controller. But that is a subject for multiple courses in itself.

What are you heating? Are you sure PID is necessary?

It's hard to give relevant suggestions without knowing specifics, but you might consider using PID only when you're close to the setpoint. If there's a long way to go, you may as well just ask for maximum heat and this way you'll avoid integral windup q.v.

Another similar alternative is to use different PID parameters depending on the error. One set to get you close to the setpoint, another to keep stability once the error is small. How critical is it to avoid overshoot and maintain an accurate temperature?