Control transitorio y estacionario de temperatura

Hola, estoy desarrollando un codigo para controlar la temperatura en estado transitorio de una resistencia calefactora. Estoy usando sensores pt1000, con su librería y combinado con una librería PID, donde el input del PID es el valor en ºC del pt1000.

A partir de aqui no se como continuar, necesito poder controlar el tiempo en el que tarda a llegar a una cierta temperatura, por ejemplo, de 20ºC a 80ºC en 10 minutos. Luego pedir que se quede estable durante por ejemplo 2 minutos y otra vez, que suba de 80 a 100 por ejemplo en 10 minutos más.

Para la resistencia calefactora estoy usando un módulo mosfet.

Este es el código que tengo hasta ahora:

/*************************************************** 
 This is a library for the Adafruit PT100/P1000 RTD Sensor w/MAX31865
****************************************************/

#include <Adafruit_MAX31865.h>

// Use software SPI: CS, DI, DO, CLK
Adafruit_MAX31865 max = Adafruit_MAX31865(10, 11, 12, 13);

// The value of the Rref resistor. Use 430.0 for PT100 and 4300.0 for PT1000
#define RREF      4300.0
// The 'nominal' 0-degrees-C resistance of the sensor
// 100.0 for PT100, 1000.0 for PT1000
#define RNOMINAL  1000.0

/*************************************************** 
 This is a library for the PID
****************************************************/
#include <PID_v1.h>

#define PIN_OUTPUT 1

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

//Specify the links and initial tuning parameters
double Kp=2, Ki=5, Kd=1;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);

void setup()
/*************************************************** 
 P1000
****************************************************/
{
 Serial.begin(115200);

 max.begin(MAX31865_3WIRE);  // set to 2WIRE or 4WIRE as necessary


/*************************************************** 
 PID
****************************************************/

 //initialize the variables we're linked to
 Input = max.temperature(RNOMINAL, RREF);
 Setpoint = 100;

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

void loop() 
/*************************************************** 
 P1000
****************************************************/
{
 Serial.print("Temperature = "); Serial.println(max.temperature(RNOMINAL, RREF));
 Serial.println();
 delay(1000);

/*************************************************** 
 PID
****************************************************/
 Input = max.temperature(RNOMINAL, RREF);
 myPID.Compute();
 digitalWrite(PIN_OUTPUT, Output);
}

No es lo mismo @ArduMyth.
No puedes con millis() hacer que una masa de agua (supongo) que se esta calentando alcance una temperatura determinada cuando esta siendo controlada por un PID.

No tiene nada que ver millis() o delay() con lo que el plantea.

Tienes dos caminos para encontrar tu solución:

  1. Un camino implica dominar tu planta, conocerla, saber como reacciona desde la teoría de control pero si estas consultando es porque no lo sabes.

  2. hago pruebas fijando determinados setpoints como por ejemplo 80°C y mido el tiempo que demora en llegar.
    Si no son 10 minutos intento modificando los K para ajustarlo a la respuesta deseada.
    Prueba/Error debería salir.

Bueno esto ultimo que puse

  1. hago pruebas fijando determinados setpoints como por ejemplo 80°C y mido el tiempo que demora en llegar.
    Si no son 10 minutos intento modificando los K para ajustarlo a la respuesta deseada.
    Prueba/Error debería salir.

Fue de lo mas horrible que he sugerido en este foro. OLVIDALO!!!

Si un sistema tiene un Kp Ki Kd no se puede andar cambiandolo!!!

Lo que si puedes hacer es cambiar el enfoque
Ya que lo que buscas es que suba determina cantidad de grados/min porque no cambiar el setpoint y en lugar de fijar una temperatura hacerlo con la dTemp/dT donde

dTemp es variacion de Temperatura
dT es la variación de tiempo

Entonces si tu sistema funciona bien, fijas una pendiente tal que (80°C-20°C)/10 min te da 60/10 = 6 °C/min
Entonces on un setpoint de 6°C/min tu alcanzas los 80 al cabo de 10 minutos.

Y luego que este estable implica un setpoint de 0°C/min

Hola Surbyte, muchas gracias por contestar y tan rapido. Tu comentario me ha servido de inspiracion para seguir buscando, he encontrado un tutorial de un PID donde rampear temperaturas. Mi objetivo es subir temperatura de manera controlada, luego unos minutos estacionarios, luego volver a subir, otra vez estacionarios y finalmente bajar de manera controlada a temp. ambiente.

Con la libreria PID, MAX31865 y el tutorial que menciono, he escrito este codigo, que aun no he probado pero se complia correctamente:

/*************************************************** 
  This is a library for the Adafruit PT100/P1000 RTD Sensor w/MAX31865
 ****************************************************/

#include <Adafruit_MAX31865.h>

// Use software SPI: CS, DI, DO, CLK
Adafruit_MAX31865 max = Adafruit_MAX31865(10, 11, 12, 13);//PINS ON ES CONECTA L'AMPLIFICADOR

// The value of the Rref resistor. Use 430.0 for PT100 and 4300.0 for PT1000
#define RREF      4300.0
// The 'nominal' 0-degrees-C resistance of the sensor
// 100.0 for PT100, 1000.0 for PT1000
#define RNOMINAL  1000.0


/*************************************************** 
  This is a library for the PID
 ****************************************************/
#include <PID_v1.h>


//Arduino Pins
 uint8_t SSR_PIN = 4;// PIN OUTPUT DIGITAL DEL PID
//Temperature Cycle Settings
uint8_t state = 0;
uint16_t max_temp1 = 95; //in degrees C
uint16_t max_temp2 = 95; //in degrees C
uint8_t soak_time1 = 10; //in minutes
uint8_t soak_time2 = 10; //in minutes
uint8_t ramp_rate1 = 10; //in degrees C/min
uint8_t ramp_rate2 = 10; //in degrees C/min
uint8_t cool_down = 10; //in degrees C/min
 
//PID parameters
double init_temp;
double Input, Output, Setpoint;
uint8_t init_read = 1; //flag to prevent 2 temp reads on first PID pass
uint32_t PID_interval = 5000; //time in ms to run PID interval
 
//Object Instantiation
double Kp=2, Ki=5, Kd=1;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
 
void setup()
{
pinMode(SSR_PIN, OUTPUT);
/*************************************************** 
  P1000
 ****************************************************/

    Serial.begin(115200);

  max.begin(MAX31865_3WIRE);  // set to 2WIRE or 4WIRE as necessary
}
 
void loop()
{
   switch (state) {
      case 0: //Ramp Up
         run_cycle_time();
         state = state + 1;
         break;
      case 1: //Soak Time
         run_cycle_time();
         state = state + 1;
         break;
      case 2: //Ramp Up
         run_cycle_time();
         state = state + 1;
         break;
      case 3: //Soak Time
         run_cycle_time();
         state = state + 1;
         break;
      case 4: //Cool Down
         run_cycle_time();
         state = state + 1;
         break;
      case 5: //Finished
         while(1);
    }
}
 
void run_PID(double Kp, double Ki, double Kd, uint16_t WindowSize, uint32_t time_interval)
{
   double ratio;
   uint32_t windowStartTime;
 
   //Specify the links and initial tuning parameters
   myPID.SetOutputLimits(0, WindowSize);
   myPID.SetTunings(Kp, Ki, Kd);
   myPID.SetMode(AUTOMATIC);
 
   windowStartTime = millis();
 
   Input = max.temperature(RNOMINAL, RREF);
   myPID.Compute();
 
   ratio = Output / WindowSize;
 
   digitalWrite(SSR_PIN, 1);
   while(millis() - windowStartTime < time_interval * ratio);
 
   digitalWrite(SSR_PIN, 0);
   while(millis() - windowStartTime < time_interval);
}
 
void run_cycle_time(void)
{
   uint32_t initial_time = millis();
   uint32_t elapsed_time;
   double diff_time_min;
   double cycle_time;
 
   //This set of statements calculates time of cycle phase
   if(state == 0) //rising ramp, increasing temperature
   {
      //Calculate time remaining in rise phase based on temperature and rate
      init_temp = max.temperature(RNOMINAL, RREF);
      cycle_time = (max_temp1 - init_temp)/ramp_rate1;
   }
   else if(state == 1) //soak time
   {
      //Soak time is already determined
      cycle_time = soak_time1;
   }
   else if(state == 2) //rising ramp 2, increasing temperature
   {
      //Calculate time remaining in rise phase based on temperature and rate
      init_temp = max.temperature(RNOMINAL, RREF);
      cycle_time = (max_temp2 - init_temp)/ramp_rate2;
   }
     else if(state == 3) //soak time
   {
      //Soak time is already determined
      cycle_time = soak_time2;
   }
   else if(state == 4) //falling ramp, decreasing temperature
   {
      //Calculate time remaining in fall phase based on temperature and rate each cycle
      cycle_time = (max.temperature(RNOMINAL, RREF) - init_temp)/cool_down;
   }
 
   //Determine time left in current phase
   elapsed_time = millis();
   diff_time_min = float(elapsed_time - initial_time) / 60000;
 
   {
      if(state == 0) //rising ramp, increasing temperature
      {
          //While increasing, Setpoint increases based on elapsed time
          Setpoint = (diff_time_min * ramp_rate1) + init_temp;
      }
      else if(state == 1) //soak time
      {
          Setpoint = max_temp1;
      }
      else if(state == 2) //rising ramp, increasing temperature
      {
          //While increasing, Setpoint increases based on elapsed time
          Setpoint = (diff_time_min * ramp_rate2) + init_temp;
      }
      else if(state == 3) //soak time
      {
          Setpoint = max_temp2;
      }
      else if(state == 4) //falling ramp, decreasing temperature
      {
          //While decreasing, Setpoint increases based on elapsed time
          Setpoint = max_temp2 - (diff_time_min * cool_down);
      }
      //Determine PID response based on current temp
      run_PID(2, 5, 1, 500, PID_interval);
 
      //Determine time left in current phase
      elapsed_time = millis();
      diff_time_min = float(elapsed_time - initial_time) / 60000;
   }
}

Podrias haberlo explicado en lugar de tener que investigar a ver que has hecho?