Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Arduino Discussion :

Régulation de température avec PID


Sujet :

Arduino

  1. #1
    Membre actif
    Régulation de température avec PID
    Bonsoir,

    Pour les besoins d'une expérience (propagation de la chaleur dans une barre), je dois mettre une source chaude à une extrémité d'une barre métallique : pour cela, j'ai mis une résistance. Le problème est qu'en l'alimentant en permanence, je n'obtiens jamais de température constante or j'ai besoin que la source chaude soit à une température constante, il me faut donc une régulation de la température.
    Je pensais utiliser une carte arduino avec un capteur de température (par exemple LM35) comme circuit de mesure et dans le circuit de régulation un relais qui commande le générateur d'alimentation de la résistance.
    Pour améliorer la régulation de la température, j'ai vu qu'il était possible d'utiliser un PID mais je n'ai jamais utilisé un tel dispositif : de ce que j'ai pu glaner comme information, une bibliothèque PID permet de le mettre en oeuvre avec un Arduino.
    D'emblée, j'ai quelques questions qui me viennent à l'esprit :
    - comment le résultat peut être transmis au relais ?
    - comment faire pour déterminer les meilleurs paramètres (Kp, Ki et Kd) ?

    Merci pour votre retour
    Pour créer une belle table des matières sur LibreOffice - N'oubliez pas de consulter les FAQ en cas de question !
    Envie de se lancer dans l'aventure Arduino : allez faire un tour sur ce cours.

  2. #2
    Responsable Arduino et Systèmes Embarqués

    Salut,

    La loi de commande pourrait être le pourcentage de temps où le relais est fermé sur une période fixe (par exemple, 1 minute).

    Il existe des bibliothèques, mais si le système est lent, un simple correcteur P devrait déjà donner de bons résultats et reste facile à programmer.

  3. #3
    Membre actif
    Bonjour

    Je reviens sur mon problème après l'avoir laissé un peu de côté.
    J'ai essayé dans un premier temps une régulation par hystérésis mais qui ne me donne pas une régulation suffisamment bonne pour mon utilisation.
    Par rapport à la réponse, je ne comprends pas comment je pourrais utiliser comme loi de commande le pourcentage de temps où le relais est fermé pendant une période fixe ou plus exactement comment je programme un pourcentage de temps car les seuls exemples que j'ai trouvé dans la régulation de type PID (notamment le fichier exemple fourni avec la bibliothèque PID_v1) est (puisque j'utilise un relais pour alimenter ou non la résistance chauffante) une instruction du type
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    digitalWrite(RELAY_PIN, LOW)
    .

    Merci pour l'aide.
    Pour créer une belle table des matières sur LibreOffice - N'oubliez pas de consulter les FAQ en cas de question !
    Envie de se lancer dans l'aventure Arduino : allez faire un tour sur ce cours.

  4. #4
    Responsable Arduino et Systèmes Embarqués

    Salut,

    Tu ne peux pas faire une régulation avec une commande qui vaut seulement HIGH ou LOW.

    Exemple en pseudo-code, sans doute à améliorer :

    Boucle infinie
    ....erreur = consigne - température réelle
    ....Si erreur>0 // il faut chauffer
    ........duree_activation = Kp*Erreur + Ki*integrale_erreur + Kd*derivée_erreur
    ........Si duree_activation > 60
    ............duree_activation = 60
    ........Sinon si duree_activation <0
    ............duree_activation = 0
    ....Sinon
    ........duree_activation = 0

    ....Si duree_activation > 0
    ........Activer_relais = Vrai //activer le relais==>chauffage allumé
    ........temporiser(duree_activation)
    ........Activer_relais = Faux //couper le chauffage
    ........temporiser(60 - duree_activation)
    ....Sinon
    ........temporiser(60) // on temporise 1min chauffage coupé.
    Fin boucle infinie

  5. #5
    Membre actif
    La temporisation de 60 secondes est arbitraire ?
    Pour créer une belle table des matières sur LibreOffice - N'oubliez pas de consulter les FAQ en cas de question !
    Envie de se lancer dans l'aventure Arduino : allez faire un tour sur ce cours.

  6. #6

  7. #7
    Membre actif
    Salut

    J'ai essayé de mettre en oeuvre ta proposition avec le code suivant
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    //chargement des librairires nécessaires
    #include <OneWire.h>
    #include <DallasTemperature.h>
    #include <PID_v1.h>
     
     
    //définition des constantes du programme
    const unsigned long baud = 115200; //débit de la liaison série
    #define ONE_WIRE_BUS  7  //#define PIN_INPUT 0
     
     
    //déclaration de l'objet one wire qui permet de gérer le bus one wire
    OneWire oneWire(ONE_WIRE_BUS);
    DallasTemperature sensors(&oneWire);
     
    //température de consigne
    const double tempConsigne = 50 ; //Setpoint
     
    double temperature, duree_activation;
     
    //broche connexion relais
    byte relais = 2; //#define PIN_OUTPUT 3
     
    //Specify the links and initial tuning parameters
    double Kp = 50, Ki = 0, Kd = 0;
    PID myPID(&temperature, &duree_activation, &tempConsigne, Kp, Ki, Kd, DIRECT);
     
    void setup()
    {
      Serial.begin(baud);
      pinMode(relais, OUTPUT);
      sensors.begin();
     
      //turn the PID on
      myPID.SetMode(AUTOMATIC);
    }
     
    void loop()
    {
      sensors.requestTemperatures();
      float temperature = sensors.getTempCByIndex(0);
      Serial.println(temperature);
      myPID.Compute();
      if (duree_activation  > 60000)
      {
        duree_activation = 60000;
      }
      else if (duree_activation < 0)
      {
        duree_activation = 0;
      }
     
      if (duree_activation > 0)
      {
        digitalWrite(relais, HIGH);
        delay(duree_activation);
        digitalWrite(relais, LOW);
        delay(60000 - duree_activation);
      }
      else
      {
        delay(60000);
      }
     
    }


    mais mon relais ne se met jamais en position "haute" et donc la résistance ne chauffe pas
    Pour créer une belle table des matières sur LibreOffice - N'oubliez pas de consulter les FAQ en cas de question !
    Envie de se lancer dans l'aventure Arduino : allez faire un tour sur ce cours.

  8. #8
    Modérateur

    Salut,
    Quelques petites remarques :
    Dans ton programme je vois que tu déclares deux fois la variable temperature, d'abord en globale double temperature, duree_activation; puis plus bas dans la fonction principale float temperature = sensors.getTempCByIndex(0); et je pense que ça doit mettre le bazar.

    Pour ta solution à hystérésis :
    Comme tu l'as compris, un système bouclé tend a osciller en passant au dessus puis en dessous de la consigne. C'est d'ailleurs de cette manière qu'on créait un oscillateur en électronique. Avec un hystérésis il faudrait abaisser les seuils de passage au dessus et en dessous de la consigne en même temps qu'on ralenti la fréquence d'oscillation en ajoutant du temps entre le passage tantôt au dessus puis en dessous de la consigne.

    Sur les coefficients kP, kI et kD :

    Le tableau ci dessous résume ce qui se passe si tu augmentes un les paramètres k. A titre d'exemple, en augmentant kI ; le temps de monté diminue et on est donc plus rapide, malheureusement le dépassement de la consigne augmente ainsi que le temps de stabilisation du système de régulation ce qui est problématique si on veut quelque chose de stable rapidement ou si le dépassement peut casser quelque chose. Enfin l'erreur global de la mesure par rapport à ce qu'on voulait en consigne est nettement amélioré. Tout ceci se met au point à la main, il n'y a pas vraiment de formule magique permettant de trouver la combinaison gagnante. C'est un compromis de tout.



    Code Pseudo code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Tous les x secondes, faire :
        erreur = consigne - mesure_temperature;
        somme_erreurs += erreur; // possibilté de débordement si trop long a stabiliser
        variation_erreur = erreur - erreur_précédente;
        commande_courant = Kp * erreur + Ki * somme_erreurs + Kd * variation_erreur;
        erreur_précédente = erreur
    
       generateur_courant = commande_courant


    A propos de la solution avec le relai :
    Si tu commandes un relai, je ne pense pas que tu puisses réellement faire un PID car celui-ci donne une réponse analogique et pas tout ou rien comme le relai. Peux être qu'il faudrait contrôler, à l'aide du signal de sortie issu du PID, la valeur du courant - avec un générateur de courant - qui passe dans la résistance afin de la faire chauffer.



    Je me demandais si tu as fait quelques estimations du courant nécessaire pour maintenir à température constante un élément chauffant relié à un dissipateur de type barre de métallique ? La barre de métallique étant un excellent conducteur thermique, et si elle est grande elle dissipera assez facilement la chaleur, tu pourrais vite arriver à des courants incroyablement forts.
    La science ne nous apprend rien : c'est l'expérience qui nous apprend quelque chose.
    Richard Feynman

  9. #9
    Membre expérimenté
    La conception d'une régulation de température demande de connaitre beaucoup de paramètres physiques. Quelle est la précision requise, quel est le système de commande ( ajustable ou TOR, relais ou transistor ), quel est le temps de réaction de la sonde à un chauffage, quelle est l'inertie du système, etc.
    J'ai longtemps travaillé avec çà, on peut en discuter.
    C'est moins drôle, mais si c'est le résultat qui t'intéresse, on trouve pour une vingtaine d'euros des régulateurs autoadaptatifs qui marchent très bien.
    Ce qui s'énonce clairement se conçoit bien ( Le hautbois)

  10. #10
    Membre actif
    Salut

    Citation Envoyé par Vincent PETIT Voir le message

    Dans ton programme je vois que tu déclares deux fois la variable temperature, d'abord en globale double temperature, duree_activation; puis plus bas dans la fonction principale float temperature = sensors.getTempCByIndex(0); et je pense que ça doit mettre le bazar.
    En supprimant le "float", cela ne change rien.


    Citation Envoyé par Vincent PETIT Voir le message

    Je me demandais si tu as fait quelques estimations du courant nécessaire pour maintenir à température constante un élément chauffant relié à un dissipateur de type barre de métallique ? La barre de métallique étant un excellent conducteur thermique, et si elle est grande elle dissipera assez facilement la chaleur, tu pourrais vite arriver à des courants incroyablement forts.
    J'alimente la résistance avec 40W (20V, 2A) : avec ces valeurs, j'arrive à obtenir une valeur thermostatée à la température ambiante en bout de barre. Je ne dispose pas de générateur de courant "puissant" me permettant d'alimenter suffisamment la résistance : c'est pour cette raison que j'ai opté pour un générateur de tension commandé par un relais.
    Pour créer une belle table des matières sur LibreOffice - N'oubliez pas de consulter les FAQ en cas de question !
    Envie de se lancer dans l'aventure Arduino : allez faire un tour sur ce cours.

  11. #11
    Modérateur

    Salut,
    @Nebulix, nous t'invitons à détailler ta pensée

    Il y a truc qui me semble chaud patate à calculer (sans jeu de mots ) dans cette histoire. Si on veut maintenir une température constante de la source de chaleur malgré la présence du dissipateur thermique qu'est la barre métallique, je ne vois pas comment faire sans connaître au préalable sa résistance thermique ?
    La science ne nous apprend rien : c'est l'expérience qui nous apprend quelque chose.
    Richard Feynman

  12. #12
    Membre actif
    Citation Envoyé par Vincent PETIT Voir le message
    Il y a truc qui me semble chaud patate à calculer (sans jeu de mots ) dans cette histoire. Si on veut maintenir une température constante de la source de chaleur malgré la présence du dissipateur thermique qu'est la barre métallique, je ne vois pas comment faire sans connaître au préalable sa résistance thermique ?
    Ce qui m'intérèsse est en fait d'avoir 2 thermostats sur la barre : un point chaud (résistance) et un point froid (l'autre bout de la barre qui est à l'air libre que l'on peut supposer à température constante).
    Je cherche donc à avoir une température constante au côté de la résistance : comme il y a effectivement propagation de la chaleur le long de la barre, il faut une puissance pour maintenir constante la température plus une pour propager la chaleur !
    Pour créer une belle table des matières sur LibreOffice - N'oubliez pas de consulter les FAQ en cas de question !
    Envie de se lancer dans l'aventure Arduino : allez faire un tour sur ce cours.

  13. #13
    Membre expérimenté
    Citation Envoyé par Vincent PETIT Voir le message
    Salut,
    @Nebulix, nous t'invitons à détailler ta pensée

    Il y a truc qui me semble chaud patate à calculer (sans jeu de mots ) dans cette histoire. Si on veut maintenir une température constante de la source de chaleur malgré la présence du dissipateur thermique qu'est la barre métallique, je ne vois pas comment faire sans connaître au préalable sa résistance thermique ?
    Tous les thermostats fonctionnent en boucle fermée selon le même principe : une sonde mesure la température, si c'est trop froid on chauffe, si c'est trop chaud on refroidit. Les réalisations pratiques sont évidemment très diversifiées et dépendent de tous ces points que j'ai cités.
    Pour pouvoir conseiller utilement, il faudrait que j'en sache plus sur le projet initial.
    Ce qui s'énonce clairement se conçoit bien ( Le hautbois)

  14. #14
    Modérateur

    Mais ici dans le projet, si je l'ai bien compris, je ne vois pas comment avec un simple relais et une résistance de 40W faire pour réguler la température ?

    Imaginons qu'on alimente cette résistance de 40W pendant 5 secondes et qu'elle atteint la température de 150°C (c'est un exemple de résistance thermique, élévation de température de 3.75°C/Watt dissipé). Je pose la résistance sur la barre métallique. La présence de la barre métallique va absorber la chaleur à l'intérieur de celle ci, et faisant baisser sur la température de la résistance qui est toujours alimentée et produit toujours 40W. L'idée est donc, non pas de continuer à l'alimenter la résistance sous 40W, cela produirait simplement une montée progressive en température, mais de produire beaucoup plus de puissance pour compenser la chaleur qui part dans la barre métallique.

    Je ne suis pas sur que l'exemple du thermostat de maison soit le bon exemple. Chez moi ma chaudière a sa température d'eau qui est fixe et pour atteindre la consigne elle reste en route plus ou moins longtemps. Si, et je dis bien si j'ai bien compris nlbmoi avec mon exemple de chaudière, il faudrait que ma chaudière monte l'eau en température pour rester au niveau de la consigne.

    C'est peut être moi qui me trompe mais le problème ici me paraît un peu plus complexe.
    La science ne nous apprend rien : c'est l'expérience qui nous apprend quelque chose.
    Richard Feynman

  15. #15
    Membre actif
    La résistance est intégrée à la barre (vissée dedans) donc elle transmet "instantanément" à une extrémité de la barre une certaine puissance : je mesure la température à ~2cm de la résistance et c'est cette distance que je prends comme extrémité de la barre thermostatée.
    Je suis parti dans l'idée d'utiliser un relais pour la régulation car initialement c'est la première idée qui m'est venue pour gérer la température : comme le dit Nebulix, si la température est trop froide, le relais est "ON" ; si c'est trop chaud, il est en "OFF".
    Mais peut-être que la solution du relais n'est pas adaptée.
    Pour créer une belle table des matières sur LibreOffice - N'oubliez pas de consulter les FAQ en cas de question !
    Envie de se lancer dans l'aventure Arduino : allez faire un tour sur ce cours.

  16. #16
    Membre expérimenté
    @Vincent : L'exemple de la chaudière est plus complexe parce qu'elle peut jouer sur 2 paramètres : la température de l'eau et sa vitesse de circulation.
    @nlbmoi : Il faut commencer par le plus simple, mais c'est à toi de voir si le résultat convient ou doit être amélioré. Avec ce système, la température varie en dents de scie. Son amplitude est-elle trop grande ? Si c'est non, tout va bien. Si c'est oui, tu peux essayer de diminuer la puissance de chauffe ou rapprocher la sonde de la résistance. Si les commutations sont trop rapides pour ton relais,tu peux le remplacer par un transistor ou un relais statique.
    etc. etc.
    Ce qui s'énonce clairement se conçoit bien ( Le hautbois)

  17. #17
    Membre actif
    Citation Envoyé par Nebulix Voir le message
    @nlbmoi : Il faut commencer par le plus simple, mais c'est à toi de voir si le résultat convient ou doit être amélioré. Avec ce système, la température varie en dents de scie. Son amplitude est-elle trop grande ? Si c'est non, tout va bien. Si c'est oui, tu peux essayer de diminuer la puissance de chauffe ou rapprocher la sonde de la résistance. Si les commutations sont trop rapides pour ton relais,tu peux le remplacer par un transistor ou un relais statique.
    etc. etc.
    J'ai essayé au préalable avec une régulation avec hystérésis mais les amplitudes d'oscillation sont trop grandes.
    Je ne peux pas rapprocher plus la sonde de la résistance.
    Je vais essayer de diminuer la puissance de chauffe mais cela risque d'augmenter le temps de la manipulation et pas sûr qu'in fine cela tienne dans le temps imparti de la manipulation.
    Si je remplace le relais pas un transistor, lequel me conseilles-tu ?
    Pour créer une belle table des matières sur LibreOffice - N'oubliez pas de consulter les FAQ en cas de question !
    Envie de se lancer dans l'aventure Arduino : allez faire un tour sur ce cours.

  18. #18
    Modérateur

    Tu souhaites atteindre quelle température ?
    La science ne nous apprend rien : c'est l'expérience qui nous apprend quelque chose.
    Richard Feynman

  19. #19
    Membre expérimenté
    https://fr.rs-online.com/web/p/trans...osfet/7545480/ (par exemple,sous toute réserve)
    Ton hystérésis était peut être trop grand ?
    Ce qui s'énonce clairement se conçoit bien ( Le hautbois)

  20. #20
    Responsable Arduino et Systèmes Embarqués

    Salut à tous,

    Citation Envoyé par nlbmoi Voir le message
    Salut

    J'ai essayé de mettre en oeuvre ta proposition avec le code suivant
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    //chargement des librairires nécessaires
    #include <OneWire.h>
    #include <DallasTemperature.h>
    #include <PID_v1.h>
     
     
    //définition des constantes du programme
    const unsigned long baud = 115200; //débit de la liaison série
    #define ONE_WIRE_BUS  7  //#define PIN_INPUT 0
     
     
    //déclaration de l'objet one wire qui permet de gérer le bus one wire
    OneWire oneWire(ONE_WIRE_BUS);
    DallasTemperature sensors(&oneWire);
     
    //température de consigne
    const double tempConsigne = 50 ; //Setpoint
     
    double temperature, duree_activation;
     
    //broche connexion relais
    byte relais = 2; //#define PIN_OUTPUT 3
     
    //Specify the links and initial tuning parameters
    double Kp = 50, Ki = 0, Kd = 0;
    PID myPID(&temperature, &duree_activation, &tempConsigne, Kp, Ki, Kd, DIRECT);
     
    void setup()
    {
      Serial.begin(baud);
      pinMode(relais, OUTPUT);
      sensors.begin();
     
      //turn the PID on
      myPID.SetMode(AUTOMATIC);
    }
     
    void loop()
    {
      sensors.requestTemperatures();
      float temperature = sensors.getTempCByIndex(0);
      Serial.println(temperature);
      myPID.Compute();
      if (duree_activation  > 60000)
      {
        duree_activation = 60000;
      }
      else if (duree_activation < 0)
      {
        duree_activation = 0;
      }
     
      if (duree_activation > 0)
      {
        digitalWrite(relais, HIGH);
        delay(duree_activation);
        digitalWrite(relais, LOW);
        delay(60000 - duree_activation);
      }
      else
      {
        delay(60000);
      }
     
    }


    mais mon relais ne se met jamais en position "haute" et donc la résistance ne chauffe pas
    Je reste avec un relais, avec l'idée de produire une commande de durée d'activation sur une période. Par exemple 8s d'activation du relais dans une fenêtre de 10s. Avec cette bibliothèque PID, je suppose de toute façon que ça ne peut pas fonctionner avec des delay() bloquants, et qu'il faut programmer ça sous la forme d'une machine à états (avec millis()).

    Tu as un exemple suivant ce principe ici https://gist.github.com/nobodyguy/ac...7a604f6a0f8af9

    La fenêtre de temps, ici 10s
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    int WindowSize = 10000;


    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    //tell the PID to range between 0 and the full window size
      myPID.SetOutputLimits(0, WindowSize);

    La commande qui produit une durée d'activation du relais entre 0 et 10s

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
      /************************************************
       * 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);

    L'activation ou non du relais en fonction de la sortie. Si par exemple, la commande de sortie Output vaut 8s (c-à-d sur les 10 prochaines secondes, il faut chauffer pendant 8s), pendant les deux premières secondes le relais est éteint, puis reste allumé pendant 8s.
    Et on réévalue la sortie Output pour recommencer sur les 10 prochaines secondes.

###raw>template_hook.ano_emploi###