Régulation de chauffage par PID avec un Arduino

4.6
(35)

Dans ce tuto nous allons voir comment réguler un petit système de chauffage par PID avec un Arduino. Nous utiliserons une plaque chauffante PTC en aluminium que l’on va contrôler avec un relai statique SSR. Une sonde de température DS18B20 sera collée sur la plaque chauffante et permettra de mesurer sa température.

Liste du matériel utilisé

C’est quoi une régulation PID ?

Un régulateur PID est un système de contrôle en boucle fermée. PID est l’abréviation de Proportionnelle Intégrale et Dérivée, les trois actions effectuées par ce régulateur. Le PID peut très bien s’expliquer de façon intuitive. Le but de cet article est d’expliquer comment marche une régulation PID sans entrer dans les calculs ni sans utiliser les fonctions de transfert du système et autres équations.

Nous utiliserons la librairie PID disponible dans l’IDE Arduino. La version courante lors de la rédaction de ce tuto est le 1.2.0.

Librairie PID utilisée dans ce tutoriel

Notre tuto est basé sur l’exemple PID_RelayOutput fourni avec la librairie dont voici le code :

/********************************************************
 * PID RelayOutput Example
 * Same as basic example, except that this time, the output
 * is going to a digital pin which (we presume) is controlling
 * a relay.  the pid is designed to Output an analog value,
 * but the relay can only be On/Off.
 *
 *   to connect them together we use "time proportioning
 * control"  it's essentially a really slow version of PWM.
 * first we decide on a window size (5000mS say.) we then
 * set the pid to adjust its output between 0 and that window
 * size.  lastly, we add some logic that translates the PID
 * output into "Relay On Time" with the remainder of the
 * window being "Relay Off Time"
 ********************************************************/
#include <PID_v1.h>
#define PIN_INPUT 0
#define RELAY_PIN 6
//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);
int WindowSize = 5000;
unsigned long windowStartTime;
void setup()
{
  windowStartTime = millis();
  //initialize the variables we're linked to
  Setpoint = 100;
  //tell the PID to range between 0 and the full window size
  myPID.SetOutputLimits(0, WindowSize);
  //turn the PID on
  myPID.SetMode(AUTOMATIC);
}
void loop()
{
  Input = analogRead(PIN_INPUT);
  myPID.Compute();
  /************************************************
   * turn the output pin on/off based on pid output
   ************************************************/
  if (millis() - windowStartTime > WindowSize)
  { //time to shift the Relay Window
    windowStartTime += WindowSize;
  }
  if (Output < millis() - windowStartTime) digitalWrite(RELAY_PIN, HIGH);
  else digitalWrite(RELAY_PIN, LOW);
}

Attention toutefois, ce code fonctionne avec un relais NC (Normally Closed). Avec un relais NC la plaque chauffante est alimentée lorsque le relais est fermé et donc que lorsque la broche de sortie est à l’état bas (LOW). Dans mon tutoriel, le relai que j’utilise est un relai NO (Normally Opened). La broche de sortie doit donc être à l’état haut (HIGH) pour que la plaque chauffante soit alimentée.

Le bout de code à la fin du programme devra donc être modifié de la sorte :

if (Output < millis() - windowStartTime) 
    digitalWrite(RELAY_PIN, LOW);
else 
    digitalWrite(RELAY_PIN, HIGH);

Réglage des paramètres de la régulation PID

La régulation PID doit être paramétrée, elle dépend en effet du système qui est régulé. Il va donc falloir déterminer la valeur des coefficients Kp, Ki et Kd de notre régulateur.

Comme expliqué dans l’article mentionné plus haut le réglage peut s’effectuer en 2 étapes :

  • Il faut tout d’abord mettre en place un simple régulateur proportionnel (les coefficients Ki et Kd sont donc nuls). Par essais/erreurs, il faut régler le coefficient Kp afin d’améliorer le temps de réponse du système. C’est-à-dire qu’il faut trouver un Kp qui permette au système de se rapprocher très vite de la consigne tout en faisant attention de garder la stabilité du système : il ne faut pas que le système réponde très vite tout en oscillant beaucoup !
  • Une fois ce coefficient réglé, on peut passer au coefficient Ki. Celui-là va permettre d’annuler l’erreur statique finale du système afin que celui-ci respecte exactement la consigne. Il faut donc régler Ki pour avoir une réponse exacte en peu de temps tout en essayant de minimiser les oscillations apportées par l’intégrateur !
  • Enfin, si le système n’est pas stable, on peut passer au dernier coefficient Kd qui permet de rendre le système plus stable et permet de diminuer les oscillations.

Après plusieurs essais, les paramètres Kp=65, Ki=0.71 et Kd=0 semblent plutôt corrects. La montée est assez rapide, le dépassement acceptable (3°C au dessus de la consigne) et le régime stationnaire est atteint rapidement avec une température stable de 40° au bout de 3 minutes environ.

Régulation PID avec une consigne de 40°C et les paramètres Kp=65, Ki=0.71, Kd=0

Voici quelques exemples de réglages PID qui ne conviennent pas aux caractéristiques du système.

Avec les paramètres Kp=10, Ki=0, Kd=0 le système n’arrive pas à atteindre la consigne de 40°C ; le paramètre Kp est trop faible
Avec les paramètres Kp=100, Ki=0, Kd=0 le système se stabilise à 39°C ; le paramètre Ki doit être augmenté pour compenser l’erreur statique
Avec les paramètres Kp=100, Ki=1, Kd=0 le système se stabilise à 40°C au bout d’environ 210 secondes et le dépassement (3°C de plus que la consigne) reste acceptable pour mon système
Autre réglage de paramètres avec Kp=55, Ki=0.8, Kd=0.3

Visualisation de la consigne de sortie de la régulation PID

Dans le graphique suivant, vous pouvez visualiser deux courbes :

  • La courbe bleue représente l’entrée de la boucle de régulation PID. Elle correspond à la valeur retournée par le capteur de température.
  • La courbe rouge représente l’état du relais. Lorsque cette valeur est à 0, cela signifie que le relai est ouvert (la plaque ne chauffe pas). Lorsque cette valeur est différente de 0, cela signifie que le relai est fermé (la plaque chauffe).

On voit que les impulsions sont plus rapprochées et plus longues dans la phase de montée en température. Après une pause qui permet d’atteindre la température de consigne, ces impulsions deviennent brèves et leur fréquence permet de maintenir le système à une température constante.

A t-on vraiment besoin d’une régulation PID ?

Vous vous posez sûrement la question de savoir si une simple régulation par seuil pourrait convenir. En allumant la plaque chauffante dès que la température est inférieure à 40°C et l’éteignant dès que la température est supérieure ou égale à 40°C. Comme ce simple code par exemple :

if (temp >= 40) {
    commande_relai(LOW);
} else {
    commande_relai(HIGH);
}

Et bien le résultat est clairement visible sur la courbe suivante. Le dépassement est élevé, la température monte à 50°C soit 10 °C de plus que la consigne de 40°C. La régulation ne se stabilise pas, elle oscille continuellement entre 39°C et 45°C…

Exemple de régulation basique avec un déclenchement sur seuil

Relai statique SSR

Un relai statique SSR nécessite peu de courant pour être contrôlé (10mA à 5V pour le mien). Il peut dont être alimenté directement par une broche de l’Arduino. Je vous invite à lire cet article qui explique le contrôle par relais.

Le relais que j’utilise permet de contrôler un courant de 10 A sous une tension continue comprise entre 12 V et 220 V. La tension de contrôle est également continue et comprise entre 3 V et 32 V. Il s’agit de la référence SSR-10 DD.

Le capteur de température DS18B20

Ce capteur de température permet de mesurer des températures comprises entre -55 °C et +125 °C. Il est équipé d’un boîtier en acier inoxydable que l’on peut facilement coller sur la plaque chauffante grâce à de la colle thermique.

Ne pas oublier de rajouter une résistance de rappel “pull-up” de 4,7 kΩ comme indiqué dans la documentation du capteur.

Schéma de branchement du capteur DS18B20 sur l’Arduino Uno

J’ai utilisé la librairie DallasTemperature pour ce tuto.

Librairie DallasTemperature utilisée dans ce tutoriel

Cette librairie inclus de nombreux programmes d’exemple pour ce capteur. Le tuto se base sur le programme Simple dont voici le code :

// Include the libraries we need
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);
/*
 * The setup function. We only start the sensors here
 */
void setup(void)
{
  // start serial port
  Serial.begin(9600);
  Serial.println("Dallas Temperature IC Control Library Demo");
  // Start up the library
  sensors.begin();
}
/*
 * Main function, get and show the temperature
 */
void loop(void)
{ 
  // call sensors.requestTemperatures() to issue a global temperature 
  // request to all devices on the bus
  Serial.print("Requesting temperatures...");
  sensors.requestTemperatures(); // Send the command to get temperatures
  Serial.println("DONE");
  // After we got the temperatures, we can print them here.
  // We use the function ByIndex, and as an example get the temperature from the first sensor only.
  float tempC = sensors.getTempCByIndex(0);
  // Check if reading was successful
  if(tempC != DEVICE_DISCONNECTED_C) 
  {
    Serial.print("Temperature for the device 1 (index 0) is: ");
    Serial.println(tempC);
  } 
  else
  {
    Serial.println("Error: Could not read temperature data");
  }
}

Le programme complet

Voici le programme utilisé pour la régulation. Il utilise la librairie PID pour la régulation ainsi que la librairie DallasTemperature pour la mesure du capteur de température.

/*
  PID regulation
 
  Created March 2022
  by Tutoduino
*/
// For PID regulation
#include <PID_v1.h>
// For DS18B20 sensor
#include <OneWire.h>
#include <DallasTemperature.h>
// DS18B20 sensor is on PIN 2 of the Arduino
#define ONE_WIRE_BUS 2
// Solid state relay is on PIN 4 of the Arduino
#define RELAY_PIN 4
// Sensor objects
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
// PID variables
double Setpoint, Input, Output;
int WindowSize = 5000;
unsigned long windowStartTime, lastPrintTime;
// PID tuning parameters
double Kp=65, Ki=0.71, Kd=0;
// PID object
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
// Function that controls activation or deactivation
// of the relay. The LED built into the Arduino is on when
// the relay is active, otherwise it is off.
void relay_state(bool state) {
    digitalWrite(RELAY_PIN, state);
    digitalWrite(LED_BUILTIN, state);
}
// Function that print temperature each second
void printTemperatureEverySec(double temp) {
  if ((millis()-lastPrintTime) > 1000) {
    lastPrintTime = millis();
    Serial.println(temp);
  }
}
// Setup function that runs once at startup
void setup()
{
  // Define relay and led pins as output
  pinMode(RELAY_PIN, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);
    
  // Set the relay to low state
  relay_state(LOW);
  Serial.begin(115200);
  // Store current time in variables used by PID
  // and display functions
  windowStartTime = millis();
  lastPrintTime = millis();
  
  // Setpoint for the PID temperature control 40 degrees Celcius
  Setpoint = 40;
  // Tell the PID to range between 0 and the full window size
  myPID.SetOutputLimits(0, WindowSize);
  // Turn the PID on
  myPID.SetMode(AUTOMATIC);
}
// Main loop function
void loop()
{
  // Get the temperature from the sensor
  sensors.requestTemperatures();
  Input = sensors.getTempCByIndex(0);
  printTemperatureEverySec(Input);
  // Compute the PID
  myPID.Compute();
  /************************************************
   * turn the output pin on/off based on pid output
   ************************************************/
  if (millis() - windowStartTime > WindowSize)
  {
    //time to shift the Relay Window
    windowStartTime += WindowSize;
  }
  if (Output < millis() - windowStartTime) {
    relay_state(LOW);
  }
  else 
    relay_state(HIGH);
}

Votre avis compte !

Note moyenne : 4.6 / 5. Nombre de votes : 35

Pas encore de vote pour ce tutoriel

Désolé si cet article ne vous a pas intéressé

Merci de commenter afin que je puisse l’améliorer.

Dites-moi comment améliorer cette page.