funzionamento strano del pid

salve a tutti, per un progettino ho implementato un codice del genere, tratto tra l'altro da una discussione qui su questo forum:

/*
Il programma misura la temperatura tramite il sensore DS18B20 e lo usa come ingresso al PID
L'uscita del PID pilota un circuito H-bridge

Vengono utilizzati i seguenti pin per DS18B20
Pin +5V         -> Alimentazione
Pin GND         -> Alimentazione
Pin Digital 2   -> Linea dati sensore DS18B20

*/

#include <OneWire.h>
#include <DallasTemperature.h>
#include <PID_v1.h>

/* Definizioni globali */

// Il terminale data del sensore è connesso alla porta 2 di Arduino
#define ONE_WIRE_BUS 2

// Imposta la comunicazione oneWire per comunicare
// con un dispositivo compatibile
OneWire oneWire(ONE_WIRE_BUS);

// Passaggio oneWire reference alla Dallas Temperature. 
DallasTemperature sensors(&oneWire);

double Setpoint, Input, Output;
	                   
int SNS_A   = A0; // current read
int LPWM = 9; // H-bridge leg 1 ->LPWM
int enL = 8; // H-bridge enable pin 1 -> L_EN
int RPWM = 6; // H-bridge leg 2 ->RPWM
int enR = 7; // H-bridge enable pin 2 -> R_EN

/* Impostazione dell'hardware */

//Inizializzazione del PID, impostazione a DIRECT (frigo)
PID myPID(&Input, &Output, &Setpoint,2,5,1, REVERSE);

void setup() 
{

  Setpoint = 15;          //definizione del set point
  Serial.begin(9600);
  Serial.println("Temperatura    PIDout    Corrente\n");

  //turn the PID on
  myPID.SetMode(AUTOMATIC);
  // Start up the OneWire library
  sensors.begin();
  // Configurazione PIN direzione e freno H-bridge

  pinMode(LPWM, OUTPUT); 
  pinMode(RPWM, OUTPUT); 
  pinMode(enL, OUTPUT);
  pinMode(enR, OUTPUT);
  digitalWrite(enL, HIGH);
  digitalWrite(enR, HIGH);

}

void loop()
{
  double temp = sensors.getTempCByIndex(0);  // legge il valore della temperatura e la memorizza nella var. temp.
  Input = temp;              //temperatura passata in ingresso a PID
  myPID.Compute(); 
  
  digitalWrite(LPWM, LOW);
  analogWrite(RPWM,Output); //PWM con segnale in uscita pari a uscita PID
    
  Serial.print( temp);    // invia i valori alla seriale
  Serial.print("\t");
  Serial.print((Output/255*100));
  Serial.print("\t");
  Serial.print(analogRead(SNS_A));
  Serial.print("\n");

delay (1000);
  
}

bene, "produce" caldo, riscaldando un lato di una cella di peltier e raffreddando il lato opposto, attraverso un ponte H. Quello che però ho notato è che l'output rimane al 100% fino a quando non viene superato il setpoint (nell'ipotesi che ci sia la necessità di scaldare), mentre l'output si alza quando la temperatura scende sotto al setpoint. Insomma, mi sembra che funzioni più come un termostato che come un pid. Ovviamente ho provato a variare i valori di Ki, Kp, Kd, (valori da 1 a 100) ma il comportamento rimane invariato. Ne consegue che ovviamente si hanno sovraelongazioni non trascurabili e la temperatura non si riesce a stabilizzare..

Per la parte software non saprei, ma ... la cella e' collegata a dei dissipatori ? ... ed hai tenuto in considerazione l'inerzia termica del tutto ?

Ricorda anche che una cella di Peltier e' in pratica una "pompa di calore", non produce freddo, si limita a spostare il calore da una faccia all'altra, e nel farlo produce altro calore, quindi il lato "caldo" va dissipato per bene ... se la cella supera la temperatura critica, si puo dannegiare ...

il box all'interno del quale sta funzionando è ancora i fase di predisposizione. Vorrei renderlo più efficiente possibile. Per quanto riguarda il lato caldo della cella, lo stesso raggiunge la temperatura massima di 45 gradi quando la cella è alimentata alla massima potenza (output 100%). Non riesco a capire perchè l'output non diminuisce man mano che si arriva alla temperatura target: inizia a calare solo dopo il superamento.

Modifica il codice così:

double Setpoint, Input, Output;
// aggiungi questi
#define KP 1.0
#define KI 1.0
#define KD 1.0


// modifica questo

//Inizializzazione del PID, impostazione a DIRECT (frigo)
PID myPID( &Input, &Output, &Setpoint, KP, KI, KD, REVERSE );

Verifica che con i coefficienti ad 1 le cose vadano meglio, se così sarà necessario potere modificare questi tre coefficienti da serial monitor senza dovere ad ogni modifica premere upload. I coefficienti possono anche avere valori con virgola, es:
0.2, 1.2 ecc.

In sostanza modificare i coefficienti durante l'esecuzione ti permette di fare il "tuning". Ricevuti da seriale i tre coefficienti devi chiamare la funzione

void PID::SetTunings(double Kp, double Ki, double Kd, int POn)

Ciao.

ilario:
il box all'interno del quale sta funzionando è ancora i fase di predisposizione. Vorrei renderlo più efficiente possibile....

l'efficienza non va d'accordo con le celle peltier che hanno un rendimento bassissimo

grazie per le risposte. Non avevo incluso il comando setTunings. L'ho inserito ad ogni ciclo perché ho nel frattempo implementato un sottomenù con la variazione dei parametri kp. ki, kd. La cosa che noto è che variando i parametri, l'output si riduce progressivamente anche prima del setpoint, ma ho ancora una sovraelongazione eccessiva. Proverò dei valori intermedi.
Per quanto riguarda l'efficienza ho comunque usato le celle di peltieri perchè la temperatura che voglio raggiungere si discosta da quella ambiente di 5/8 gradi sia in caldo che freddo. Per questo delta T credo che rimanga ancora una soluzione percorribile (la temperatura nella cella viene raggiunta in breve tempo per quanto riguarda il riscaldamento, mentre ho ancora molte difficoltà a raffreddare).

L'ho inserito ad ogni ciclo perché ho nel frattempo implementato un sottomenù con la variazione dei parametri kp. ki, kd.

Ok ma no ad ogni giro di loop, ma solo dopo avere ricevuto i nuovi coefficienti, comunque è influente per l risoluzione dello specifico problema.

In effetti con delta T di 8°C non vedo cos'altro usare al posto delle celle di peltier.

Per questo delta T credo che rimanga ancora una soluzione percorribile (la temperatura nella cella viene raggiunta in breve tempo per quanto riguarda il riscaldamento, mentre ho ancora molte difficoltà a raffreddare).

Strano, invertendo la polarità il comportamento dovrebbe essere molto simile. Non hai fornito info sul sistema di scambio se questo è statico, dinamico, misto ecc. Tanto per scrivere, magari ci pesco, ricordo che il sensore di temperatura che usi non eccelle in velocità, quanto influisca non lo so prevedere. Altra cosa aggiungendo due sensori di temperatura uno per ogni lato della cella si può calcolare il delta è il rendimento.

Riguardo al pid mi pare che si possa impostare il sampe time, come influisce al momento mi sfugge.

Ciao.

Cerco di essere più specifico riguardo l'hardware. Ho un box che sto coibentando in questi giorni, di dimensioni circa 40x40x40 cm. Uso due dissipatori arctic alpine 11 plus da 100w entrambi, una cella di peltier TEC da 15 Ampere alimentata a circa 13,8V e la velocità di rotazione delle ventole, al momento, è sempre al massimo, anche al raggiungimento del setpoint, sia lato freddo che caldo. Per evitare una repentina inversione di polarità quando il setpoint è vicino alla temperatura ambiente leggo sia la temperatura della stanza (ambiente esterno) con un DS18b20 che quella interna con un DHT22, che uso anche per leggere l'umidità (in futuro dovrò anche regolare la stessa). Sostanzialmente, lato software, ho implementato 2 pid, uno per il caldo (inverse) ed uno per il freddo (direct). Se il setpoint è grosso modo uguale alla temperatura ambiente (+/- un grado di tolleranza) la cella è spenta. Se il setpoint è maggiore della temperatura ambiente (setpoint > (t_amb+soglia)) entro in un if che attiva il pid "caldo", viceversa nel caso freddo. Sto aspettando un arduino mega per implementare anche il controllo della velocità di rotazione delle ventole, in quanto non ho più uscite/ingressi a disposizione su arduino uno. Ho su un altro pc il codice, appena possibile lo posto

Attenzione solo ad un dettaglio, se le tue temperature sono "critiche" ... soprattutto quando raffreddi ...

Le celle di Peltier NON sono isolanti termici quando non sono alimentate, anzi proprio l'opposto ... lo dico perche' tu parli di cella spenta ...

Faccio un'esempio, se raffreddi la faccia fredda a diciamo 0 gradi, e la faccia calda e relativo dissipatore vanno nel frattempo a 45 o 50 gradi, e spegni la cella del tutto, in pochi secondi il calore pompato verso la faccia calda torna indietro e la faccia fredda torna alla stessa temperatura di quella calda o poco meno ... se l'applicazione e' "critica", serve prevedere un minimo di "mantenimento" di tensione, appena al di sopra del limite minimo di funzionamento della cella, perche' questo non succeda ...

@Etemenanki
tiro ad indovinare: è una cella di lievitazione

si, è una cella di lievitazione. Per quanto riguarda la cella spenta, la stessa è appunto proprio spenta se la temperatura da "raggiungere" è quasi uguale a quella esterna. Nel caso invece di raggiungimento del setpoint ho un myPID_COLD.SetOutputLimits(15, 255) o myPID_HOT.SetOutputLimits(15, 255) facendo rimanere la cella circa al 5% del funzionamento. Comunque, giorni fa, con 28 gradi in casa, impostando tipo 20 gradi in cella ed alimentandola a 12v, non riusciva ad arrivare nemmeno a 24.. Overvoltando a 14V la cella ho un assorbimento di circa 5 ampere ed effettivamente il lato freddo raggiunge una temperatura un po' più bassa (rimane il dilemma dei fantomatici 15 ampere di una TEC12015...)

12015, oppure 12715 ? ... perche' di modelli 12015 non sono riuscito a trovarne ...

Comunque se con 12V sulla cella non hai un'assorbimento di quasi 15A, allora c'e' qualcosa che non funziona ... o il tuo sistema di pilotaggio della cella, o l'alimentazione, oppure la cella stessa (sono piu fragili di quello che si puo pensare, alle sollecitazioni meccaniche sbagliate ... il sistema di accoppiamento dovrebbe sempre prevedere delle molle, per sicurezza, perche' si fa presto a creparle senza volerlo tirando un po troppo una vite)

Cosa hai usato per distanziare i due dissipatori ? ... blocchetto di alluminio ? ... se si, le facce erano ben piane e con abbastanza grasso termico ?

si, la cella è la 12715, comandata da un ponte H BS7960B. Ho controllato l'assorbimento con un alimentatore stabilizzato variabile. A 12 v era appunto quasi 5 ampere. Per quanto riguarda il dissipatore non ho usato nessun distanziatore poichè i dissipatori arctic alpine 11 plus hanno una forma tale per cui la superficie a contatto della cella è sporgente rispetto alla superficie più larga del dissipatore stesso.. I due dissipatori, una volta fissati contrapposti, hanno una distanza di circa 2 cm..