Plugin régulateur correcteur *PID* (proportionnel, intégral, dérivé)

Je confirme, le plugin Thermostat peut créer des thermostats PID.

1 « J'aime »

Non, je ne sais pas faire de plugin. Depuis, j’ai basculé mes scénarios sous Node-RED.

Bonjour,

Non, je ne sais pas faire de plugin. Depuis, j’ai basculé mes scénarios sous Node-RED.

C’est quelque chose que vous pourriez partager ou bien c’est trop compliqué ici? J’ai vu dans les nodes et flows sur node-red qu’il y a des trucs sur le PID (par ex. node-red-contrib-pid-controller), vous avez utilisé un de ceux-là?

Merci d’avance.

J’avais regardé à l’époque.
Il ne me parait pas être un vrai PID (aucun endroit pour rentrer les coeff Kp, Ki et Kd). J’ai l’impression qu’il correspond à ce que fait le plugin thermostat en jouant sur le rapport cyclique.

Le plus mature semble être celui-ci avec une fonction de filtrage sur la dérivée

Mais je n’ai pas vu d’endroit ou mettre de limites sur l’intégrateur pour borner la valeur de la sortie entre 0 et 100.

Nous, on a une vanne physique qui s’ouvre entre et 0% et 99%. Lors d’un abaissement de consigne, le régulateur ne peut rien faire au début (c’est comme pour le régulateur de vitesse), alors il essaie encore et encore de toujours fermer plus la vanne afin que la température descende plus vite. Sans limitation, il voudra fermer la vanne à -5000% :laughing: Même si je transformais le -5000% en 0%, la vanne mettrait des heures à se re ouvrir après un changement de consigne à la hausse car il va ouvrir à -4950% puis -4930%, etc

De manière générale, je ne sais pas trop ce qu’ils font exactement (un peu comme vous avec mon truc ;)), j’ai préféré reprendre mes formules décrites ici :slight_smile:

Je vais dire que c’est trop compliqué ici !

Bonjour,

D’après la doc du second, la sortie est bornée (entre 0 et 1). Donc je ne comprends pas trop ta remarque (qui est très intéressante au demeurant :wink: )

...the algorithm will generate a required power output between 0 and 1...

Effectivement, j’avais mal lu. :wink:

Ce module PID devrait pouvoir faire l’affaire.
A revoir l’hiver prochain…

Bonjour!

Désolé pour mon retour tardif, je pensais avoir activé les alertes sur réponse au fil, a priori je m’ai gourré…

Merci pour vos explications et votre temps.

Bonjour,
J’ai fait un régulateur PID pour piloter ma clim réversible :

Le fonctionnement :
Le plugin thermostat génère des température en fonction du temps (scénarios jour / nuit / WE).
Un autre scénario, fait office de régulateur PID pour contrôler la clim réversible, avec une sonde de température ambiante, et avec la consigne demandée par le thermostat.
On parvient à faire une régulation assez propre, et qui évite les ON/OFF de la PAC.
Le thermostat est paramétré en hysteresis positif avec un seuil à 5°C. Ainsi, la PAC n’est jamais réellement OFF, mais se gère via les ordres envoyé au split.

Si ca peut en aider certains…

1 « J'aime »

C’est toujours aussi compliqué, mais je mets à disposition le code de ma fonction Node-RED. Il reprend ce que j’avais fait pour Jeedom. Le petit changement : la variation de l’erreur ne prend plus en compte la consigne (on évite ainsi les problèmes de sauts de consigne).

var root = 'mqtt';
var piece = msg.topic;
var equipement = 'regulateur';

var prefixe = root+'.'+piece+'.'+equipement+'.';

// Ouverture min/max de la vanne thermostatique
var VALEUR_MIN =  0;
var VALEUR_MAX = 99;

// La période d'échantillonnage Te correspond à la période, exprimée en heure, où est lancé ce node
// Si ce node est exécuté toutes les 5 minutes, alors il faut que Te = 5/60
var Te = 10/60; 


//var Consigne            = global.get(prefixe+'consigne');
//var Mesure              = global.get(prefixe+'mesure');
var Kp                  = global.get(prefixe+'kp');
var Ki                  = global.get(prefixe+'ki');
var Kd                  = global.get(prefixe+'kd');
var N                   = global.get(prefixe+'filtrage');
var Offset              = global.get(prefixe+'offset');
var Regulation          = global.get(prefixe+'regulation');
var Erreur              = global.get(prefixe+'erreur_proportionnelle');
var Erreur_Integration  = global.get(prefixe+'erreur_integration');
var Erreur_Variation    = global.get(prefixe+'erreur_variation');
var Erreur_Saturation   = global.get(prefixe+'erreur_saturation');
var Correction              = global.get(prefixe+'correction');

equipement = 'radiateur';
prefixe = root+'.'+piece+'.'+equipement+'.';

var Consigne            = global.get(prefixe+'consigne');
var Mesure              = global.get(prefixe+'temperature');


var debug = {};

debug.topic = msg.topic;
debug.payload = {
    "Consigne" : Consigne,
    "Mesure" : Mesure,
    "Kp" : Kp,
    "Ki":Ki,
    "Kd":Kd,
    "N":N,
    "Offset":Offset,
    "Regulation":Regulation,
    "Erreur":Erreur,
    "Erreur_Integration":Erreur_Integration,
    "Erreur_Variation":Erreur_Variation,
    "Erreur_Saturation":Erreur_Saturation,
    "Correction":Correction
}



if (Consigne == undefined) {
  Consigne = 19;
}
if (Mesure == undefined) {
  Mesure = 19;
}
if (Kp == undefined) {
  Kp = 20;
}
if (Ki == undefined) {
  Ki = 5;
}
if (Kd == undefined) {
  Kd = 10;
}
if (N == undefined) {
  N = 0;
}
if (Offset == undefined) {
  Offset = 25; // 25% d'ouverture lorsque la consigne est atteinte si pas d'intégrateur dans la régulation
}
if (Regulation == undefined) {
  Regulation = "P";
}
if (Erreur == undefined) {
  Erreur = 0;
}
if (Erreur_Integration == undefined) {
  Erreur_Integration = 0;
}
if (Erreur_Variation == undefined) {
  Erreur_Variation = 0;
}
if (Erreur_Saturation == undefined) {
  Erreur_Saturation = 0;
}
if (Correction == undefined) {
  Correction = 0;
}


var Td = Kd/Kp;
var Ti = Kp/Ki;
// Ts : periode d'integration de l'erreur de saturation
// Ts = [0.1 Ti, Ti]
// Ts = Ti pour un PI
var Ts = Ti;
// Ts = sqrt(Ti*Td) pour un PID
//var Ts = sqrt(Ti*Td); // Ts = Ti/2 si Td=Ti/4


// Valeurs precedentes
var Ki_Precedent                    = Ki;
var Mesure_Precedente               = Mesure;
var Erreur_Precedente               = Erreur;
var Erreur_Integration_Precedente   = Erreur_Integration;
var Erreur_Variation_Precedente     = Erreur_Variation;
var Erreur_saturation_Precedente    = Erreur_Saturation;
//var Correction_Precedente               = Correction;


// Erreur proportionnelle
Erreur = Consigne - Mesure;

// Recalcul de l'erreur d'integration précédente car le % d'ouverture de vanne due a l'integration doit rester constant lors d'un changement de Ki
Erreur_Integration_Precedente = Ki_Precedent*Erreur_Precedente/Ki;

// La methode des trapezes pour le calcul de l’integration permet un calcul plus precis
Erreur_Integration = Erreur_Integration_Precedente + Te*(Erreur + Erreur_Precedente)/2;


// Erreur derivee
// Pas de dérivation des changements de consigne (comme si la consigne était constante)
// Ainsi, il n'y a pas de discontinuité de la dérivée (variation de l'erreur)
// La variation d'une constante vaut toujours 0 donc la constante peut prendre n'importe quelle valeur : 0 pour simplifier
Erreur = 0 - Mesure;
Erreur_Precedente = 0 - Mesure_Precedente;


// Filtrage
if (N == 0) {
    // pas de filtrage
    Erreur_Variation = (Erreur - Erreur_Precedente)/Te;
} else {
    Erreur_Variation = (Td*Erreur_Variation_Precedente + N*(Erreur - Erreur_Precedente))/(Td+N*Te);
}


// Type de regulation
if (Regulation == "P" || Regulation == "PI" || Regulation == "PD" || Regulation == "PID") {
    Terme_Proportionnel = Kp*Erreur;
} else {
    Terme_Proportionnel = 0;
}

if (Regulation == "I" || Regulation == "PI" || Regulation == "ID" || Regulation == "PID") {
    Terme_Integration = Ki*Erreur_Integration;
    Terme_Constant = 0;
} else {
    Terme_Integration = 0;
    Terme_Constant = Offset;
}

if (Regulation == "D" || Regulation == "PD" || Regulation == "ID" || Regulation == "PID") {
    Terme_Derive = Kd*Erreur_Variation;
} else {
    Terme_Derive = 0;
}

Correction = Terme_Constant + Terme_Proportionnel + Terme_Integration + Terme_Derive;


// Limitation de l'ouverture de la vanne pour que la vanne ne sorte pas de l'intervalle de 0% à 100%.
if (Correction < VALEUR_MIN) {
    Correction_limitee = VALEUR_MIN;
} else if (Correction > VALEUR_MAX) {
    Correction_limitee = VALEUR_MAX;
} else {
    Correction_limitee = Correction;
}


// Erreur de saturation
Erreur_Saturation = (Correction - Correction_limitee)/Kp;
//Si le régulateur possède une composante intégrale, alors on recalcule l'erreur d'intégration en lui retranchant une fraction (>=1) de l’intégration de l'erreur de saturation
//Avec un Ts=0.5*Ti, Ti/Ts=2, l'erreur d'intégration diminue 2 fois plus avec l'erreur de saturation qu'elle augmente avec l'erreur, ainsi la vanne idéale revient vers les limites physiques de la vanne réelle
Erreur_Integration = Erreur_Integration - (Ti/Ts)*Te*Erreur_Saturation;
// Methode trapeze
//Erreur_Integration = Erreur_Integration - (Ti/Ts)*Te*(Erreur_Saturation + Erreur_Saturation_Precedente)/2;

/*
// Mise a jour des variable globales
global.set(prefixe+'ki',Ki);
global.set(prefixe+'erreur',Erreur);
global.set(prefixe+'erreur_integration',Erreur_Integration);
global.set(prefixe+'erreur_variation',Erreur_Variation);
global.set(prefixe+'erreur_saturation',Erreur_Saturation);


//msg.payload = Correction_limitee;
*/

msg.payload = {
    //'consigne' : Consigne,
    //'mesure' : Mesure,
    'kp' : Kp,
    'ki' : Ki,
    'kd' : Kd,
    'filtrage' : N,
    'offset' : Offset,
    'regulation' : Regulation,
    'erreur_proportionnelle' : Erreur,
    'erreur_integration' : Erreur_Integration,
    'erreur_variation' : Erreur_Variation,
    'erreur_saturation' : Erreur_Saturation,
    'correction' : Correction
}


debug.payload.sortie = msg.payload;
return [msg, debug];

Code à adapter selon vos besoins.

2 « J'aime »

Dans une régulation PID la difficulté est de choisir les différents coefficients de chaque action P, I et D.
Sur du chauffage, régulation lente une régulation PI suffit généralement, l’action dérivé est plus adaptée pour les régulations rapides comme de la régulation de vitesse. En plus l’action dérivé peut ajouter de l’instabilité à la régulation si le coefficient est mal choisi. Une méthode que j’ai appliqué sur le terrain pour piloter des vannes 3 voies est la méthode de Ziegler-Nichols. On supprime les actions dérivée et intégrale puis on augmente le coefficient du gain sur l’action proportionnelle jusqu’à ce que le système oscille. cette oscillation doit être entretenue. On note le coefficient du gain de l’action proportionnelle et la période de l’oscillation puis on applique aux différentes actions les coefficients de la méthode. Une très bonne explication : Méthode de Ziegler-Nichols — Wikipédia

Après avoir appliqué les coefficients on observe les résultats obtenus, puis on les ajuste en fonction.

1 « J'aime »

Tout à fait.

:+1: Bravo
J’avais régarder les différentes méthodes pour ajuster les coefficients à l’époque. Mais, je n’avais pas vraiment réussi à faire osciller mon chauffage !

Les régulations que j’ai réglé était sur la température de l’eau chaude en sortie de vannes 3 voies. Effectivement faire osciller une température dans une pièce est plus difficile. Il faut déjà en premier lieu avoir une eau chaude à température constante élevée pour fournir la puissance nécessaire, les chaudières ont des automatismes de sécurité par exemple la pompe est mise à l’arrêt après une temporisation si la consigne de température de l’eau n’est pas atteinte. Le brûleur est arrêté si la température de consigne est atteinte etc… La période d’oscillation est grande de plusieurs dizaines de minutes et pendant ce temps des éléments perturbateurs comme la variation de la température extérieure par exemple surviennent. En tout cas j’ai eu grand plaisir à suivre ta démarche. Moi je n’en suis pas encore à réguler mes radiateurs. Je me suis battu pendant 3 ans pour comprendre pourquoi je n’arrivait pas à chauffer ma maison, les radiateurs du rez de chaussée ne chauffaient pas du tout. Nettoyage des radiateurs, suppression des robinets thermostatiques, j’ai eu la chance de tomber sur un technicien qui faisait des concours de dépannage, il a tout de suite diagnostiqué que la vanne 3 voies de la chaudière ne s’ouvrait pas complètement.

Oui, pour le gagnant du concours, sinon le perdant t’aurais fait changer de chaudière ! :laughing:

Et oui tous les techniciens non pas le même degré d’expertise. :smiley: