Ciao, sto cercando di realizzare un sistema in grado di automatizzare una fase del processo di cottura del malto per fare la birra. Spiegato in poche parole ciò che serve è che vengano mantenuti valori di temperatura per determinati tempi, un esempio 55° C per 10 minuti, poi salita fino a 63°C, pausa a questa temperatura, salita a 72°C, altra pausa di mezz'ora e poi salita a 78 e relativa pausa di 15 minuti.
La base con la quale intendo realizzare tutto ciò è arduino mega 2560 con lcd 16x2, sonde di temperatura ds18b20 e un relè ssr che comanda una resistenza elettrica.
Essendo alle prime armi l'idea è di creare inizialmente uno sketch con tutti i valori di temperature e pause a pc, caricarlo su arduino e far eseguire le istruzioni, per poi in un secondo momento fare in modo di poter variare i parametri con un tastierino direttamente su arduino senza passare dal pc, ma questo verrà poi...
Per ora ho iniziato a fare lo sketch di misura della T e ho inserito il controllo PID, il problema grosso col quale mi sono scontrato è che non ho idea di come far conteggiare i tempi ad arduino. O meglio ho letto di usare millis per tenere conto del tempo, ma non saprei come implementare una funzione che, quando raggiunta una data temperatura (ipotizziamo i 55° C di cui sopra), mi tenga conto dei 10 minuti di questo step e che terminati questi mi permetta di impostare il nuovo setpoint alla successiva T. Qualche idea?
Potresti usare un codice tipo questo:
float Soglia[4] = {
55.0, 63.0, 72.0, 78.0};
unsigned long Tempo[4] = { // 10', 20', 30', 15'
600000, 1200000, 1800000, 900000};
unsigned long Timer;
byte Fase;
float Temp = 0.0;
void setup() {
Fase = 0; // fase iniziale
Timer = millis(); // start timer
}
void loop() {
if (millis() - Timer > Tempo[Fase]) {
Fase ++; // fase successiva
Timer = millis(); // restart timer
}
else {
if (Temp < Soglia[Fase]) {
// accendi riscaldatore
}
else {
// spegni riscaldatore
}
}
}
cyberhs:
Potresti usare un codice tipo questo:float Soglia[4] = {
55.0, 63.0, 72.0, 78.0};
unsigned long Tempo[4] = { // 10', 20', 30', 15'
600000, 1200000, 1800000, 900000};
unsigned long Timer;
byte Fase;
float Temp = 0.0;
void setup() {
Fase = 0; // fase iniziale
Timer = millis(); // start timer
}
void loop() {
if (millis() - Timer > Tempo[Fase]) {
Fase ++; // fase successiva
Timer = millis(); // restart timer
}
else {
if (Temp < Soglia[Fase]) {
// accendi riscaldatore
}
else {
// spegni riscaldatore
}
}
}
Se non ho interpretato male il codice questo mi permette di fare le varie soste ma all'interno della sosta tiene conto anche della rampa per giungere alla temperatura di set point. Mi spiego meglio con un esempio, sono a 55° C e ho appena finito la fase da 10 minuti di attesa, prossima fase a 63° C. A me serve che la pausa da 30 minuti venga calcolata dal momento in cui il sistema raggiunge per la prima volta i 63 gradi e non che essa venga conteggiata da quando parto a scaldare da 55° C...
ho provato a scrivere questo codice sfruttando la libreria simpletimer ma non sono sicuro faccia ciò che voglio e non ho la possibilità di provare il tutto non avendo ancora il relè SSR che comanda la resistenza elettrica e non avendo nemmeno ancora pronto il pcb sul quale montare l'elettronica. Comunque qui sotto c'è il codice, in particolare non sono sicuro sulle ultime due righe, se veramente fanno ciò che è mia intenzione fare, ovvero far andare il timer della sosta in questione solo se la temperatura è in un range di +/- 0,5° C rispetto al setpoint
#include <SimpleTimer.h>
// the timer object
SimpleTimer sacc_1;
//define mash profile Temperature
double T_prot, T_sacc_1, T_sacc_2, T_mash_out;
//define mash profile time
long t_prot, t_sacc_1, t_sacc_2; //t in minuti
float T_actual;
//Define Variables we'll be connecting to
double Setpoint, Input, Output;
//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT);
int WindowSize = 5000;
unsigned long windowStartTime;
//repetition for Proteasi
void fase_prot(){
Setpoint = T_prot;
myPID.Compute();
/************************************************
* turn the output pin on/off based on pid output
************************************************/
if(millis() - windowStartTime>WindowSize)
{ //time to shift the Relay Window
windowStartTime += WindowSize; //come dire windowStartTime = windowStartTime + WindowSize
}
if(Output < millis() - windowStartTime) digitalWrite(RelayPin,HIGH);
else digitalWrite(RelayPin,LOW);
}
//repetition for Sacc_1
void fase_sacc_1(){
Setpoint = T_sacc_1;
myPID.Compute();
/************************************************
* turn the output pin on/off based on pid output
************************************************/
if(millis() - windowStartTime>WindowSize)
{ //time to shift the Relay Window
windowStartTime += WindowSize; //come dire windowStartTime = windowStartTime + WindowSize
}
if(Output < millis() - windowStartTime) digitalWrite(RelayPin,HIGH);
else digitalWrite(RelayPin,LOW);
}
void setup(void)
{
windowStartTime = millis();
//Mash times
t_prot = 10;
t_sacc_1 = 30;
t_sacc_2 = 30;
//initialize the variables we're linked to
Setpoint = T_prot;
//tell the PID to range between 0 and the full window size
myPID.SetOutputLimits(0, WindowSize);
//turn the PID on
myPID.SetMode(AUTOMATIC);
sensors.begin();
lcd.begin(16,2);
prot.setInterval(1000*t_prot*60, fase_prot); //duration of proteasi phase
}
void loop(void)
{
sensors.requestTemperatures(); // Send the command to get temperatures
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Temperatura di:");
lcd.setCursor(0,1);
lcd.print(sensors.getTempCByIndex(0));
lcd.print(" C");
Input = sensors.getTempCByIndex(0);
T_actual=sensors.getTempCByIndex(0);
if(sensors.getTempCByIndex(0)<T_prot)
{myPID.Compute();
/************************************************
* turn the output pin on/off based on pid output
************************************************/
if(millis() - windowStartTime>WindowSize)
{ //time to shift the Relay Window
windowStartTime += WindowSize; //come dire windowStartTime = windowStartTime + WindowSize
}
if(Output < millis() - windowStartTime) digitalWrite(RelayPin,HIGH);
else digitalWrite(RelayPin,LOW);
}
if(T_actual>=(T_prot-0,5) && T_actual<=(T_prot+0,5))
{prot.run();
}
}
ho fatto altre prove e sono giunto a qualcosa, il setpoint ora viene aggiornato, il punto è che non riesco a capire quando faccia partire il timer per l'aggiornamento del setpoint.
Nelle mie intenzioni era far partire il timer quando la T raggiunge l'intervallo +/- 0,5° C rispetto al setpoint1.
Ho provato il codice qui sotto (non ho messo tutto ma solo le parti che mi sembravano salienti) con semplicemente la sonda di temperatura e mettendo il setpoint1 a 36,5° C in modo da poterli raggiungere tenendo la sonda addosso. Se la sonda è già ad una temperatura nel range prefissato lo shift verso il nuovo setpoint lo fa dopo circa 1' 04" nonostante il timer fosse impostato su 1', ma questo errore ci può anche stare, a patto che dilatando l'intervallo di tempo, l'errore non cresca di conseguenza.
I problemi più grossi li ho invece avuti quando avvio arduino con la sonda che rileva una T più bassa del range, ad esempio 35,2 gradi. Tenendo la sonda addosso la T letta piano piano inizia a salire e mi aspettavo che lo shift verso il nuovo setpoint avvenisse dopo 1'4" che viene visualizzata la T di 36,00 o superiore, ma non è così. Lo shift avviene decisamente prima.... Nell'ultima prova fatta ad esempio è avvenuto circa 45" dopo che era stata visualizzata per la prima volta la T di 35,9°C.
Credo ci sia qualche problema con l'intervallo di T.... Sapete darmi una mano???
#include <SimpleTimer.h>
// the timer object
SimpleTimer sacc_1;
//define mash profile Temperature
double T_prot, T_sacc_1, T_sacc_2, T_mash_out;
//define mash profile time
long t_prot, t_sacc_1, t_sacc_2; //t in minuti
float T_actual;
//Define Variables we'll be connecting to
double Setpoint, Input, Output;
//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT);
int WindowSize = 5000;
unsigned long windowStartTime;
//repetition for Proteasi
void fase_prot(){
Setpoint = T_prot;
myPID.Compute();
/************************************************
* turn the output pin on/off based on pid output
************************************************/
if(millis() - windowStartTime>WindowSize)
{ //time to shift the Relay Window
windowStartTime += WindowSize; //come dire windowStartTime = windowStartTime + WindowSize
}
if(Output < millis() - windowStartTime) digitalWrite(RelayPin,HIGH);
else digitalWrite(RelayPin,LOW);
}
//repetition for Sacc_1
void fase_sacc_1(){
Setpoint = T_sacc_1;
myPID.Compute();
/************************************************
* turn the output pin on/off based on pid output
************************************************/
if(millis() - windowStartTime>WindowSize)
{ //time to shift the Relay Window
windowStartTime += WindowSize; //come dire windowStartTime = windowStartTime + WindowSize
}
if(Output < millis() - windowStartTime) digitalWrite(RelayPin,HIGH);
else digitalWrite(RelayPin,LOW);
}
void gotosacc_1(){
Setpoint = T_sacc_1;
}
void setup(void)
{
windowStartTime = millis();
//Mash times
t_prot = 1;
t_sacc_1 = 30;
t_sacc_2 = 30;
//initialize the variables we're linked to
Setpoint = T_prot;
//tell the PID to range between 0 and the full window size
myPID.SetOutputLimits(0, WindowSize);
//turn the PID on
myPID.SetMode(AUTOMATIC);
sensors.begin();
lcd.begin(16,2);
// prot.setInterval(1000*t_prot*60, fase_prot); //duration of proteasi phase
}
void loop(void)
{
sensors.requestTemperatures(); // Send the command to get temperatures
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Temperatura di:");
lcd.setCursor(0,1);
lcd.print(sensors.getTempCByIndex(0));
lcd.print(" C");
Input = sensors.getTempCByIndex(0);
T_actual=sensors.getTempCByIndex(0);
if(sensors.getTempCByIndex(0)<T_prot)
{myPID.Compute();
/************************************************
* turn the output pin on/off based on pid output
************************************************/
if(millis() - windowStartTime>WindowSize)
{ //time to shift the Relay Window
windowStartTime += WindowSize; //come dire windowStartTime = windowStartTime + WindowSize
}
if(Output < millis() - windowStartTime) digitalWrite(RelayPin,HIGH);
else digitalWrite(RelayPin,LOW);
}
if(T_actual>=(T_prot-0,5) && T_actual<=(T_prot+0,5))
{prot.run();
}
prot.setTimeout(1000*t_prot*60, gotosacc_1);
}
Ho letto tutto più volte e non ci ho capito nulla.
Primo punto:
Non cambiare le carte in tavola prima di aver raggiunto un risultato.
Cosa deve fare?
Accendi lo strumento, premi il pulsante di partenza e dopo cosa deve accadere:
Il pid inizia a lavorare con Setpoint 55.0°C.
Il pid ci mettere t tempo a raggiungere i 55°C, appena li raggiunge cosa deve accadere:
Il pid continua a lavorare con il Setpoint = 55°C e parte un timer che conta 10 minuti e alla
scadenza il Setpoint passa a 63°C, raggiunti parte un timer che conta o no?
Chiarisci questo punto: Il timer parte sempre raggiunto un valore di temperatura?
Se fosse così, il codice che ha scritto cyberhs è riutilizzabile.
float Setpoints[4] = {
55.0, // raggiunge 55 °C e parte il timer e alla scadenza il setpoint è quello seguente
63.0, // Il timer è scaduto ora il questo è il setpoint e parte il timer
72.0, // Il timer è scaduto ora questo è il setpoint e parte il timer
78.0}; // Il timer è scaduto ora questo è il setpoint.
Per ricavare il setpoint da passare al pid bisogna scrivere:
Setpoint = Setpoints[indice];
Indice deve stare nel range 0 to 3.
Anche l'array dei tempi di cyberhs è riutilizzabile:
unsigned long Tempo[4] = { // 10', 20', 30', 15'
600000, // timer che parte dopo aver raggiunto la t di Setpoints[0]
1200000, // timer che parte dopo aver raggiunto la t di Setpoints[1]
1800000, // timer che parte dopo aver raggiunto la t di Setpoints[2]
900000 // Fase finale, per quanto tempo deve rimanere a Setpoints[3]?
};
Da minuti a millesimi di secondo
minuti * 60000 = 60000 millesimi di secondo equivalgono ad 1 minuto
Spero ti possa essere di aiuto, eventualmente posta una descrizione lunga e dettagliata di cosa deve fare e i dati momentaneamente fissi.
Ciao.
Provo a rispiegare nuovamente ciò che ho in testa di fare in modo semplice
1- accendo l'apparecchio, il setpoint del riscaldatore è a 55°C
2- al raggiungimento dei 55°C il PID mantiene questa temperatura e parte un timer da 10 minuti
3- allo scadere del timer il setpoint passa a 63° C
4- al raggiungimento dei 63°C il PID mantiene questa temperatura eparte un timer da 30 minuti
5- allo scadere del timer il setpoint passa a 72° C
6- al raggiungimento dei 72°C il PID mantiene questa temperatura eparte un timer da 30 minuti
7- allo scadere del timer il setpoint passa a 78° C
8- arrivato ai 78° C si spegne
Avevo visto anche io che il codice di cyberhs va bene (ed è anche decisamente più pulito del mio) ma non capisco proprio in quale parte del suo codice ci sia l'istruzione che fa partire il timer una volta raggiunti i fatidici 55, 63, 72°C. Purtroppo ho iniziato a trafficare con arduino da 2 settimane e la mia esperienza è quindi molto limitata...
potresti illuminarmi?
Il codice di @cyber usa intelligentemente 2 vettori/array di 4 elementi e la variabile "Fase", che va da 0-3 per sapere in quale "stato" è il programma. Quella variabile Fase viene anche usata per prendere dai 2 vettori il limite e il tempo.
Il primo if all'interno del loop determina se la fase corrente ha raggiunto il Tempo[Fase].
All'inizio Fase = 0 e quindi il sistema attende Tempo[0] = 600000 (10 minuti).
Se il tempo è scaduto, la Fase è incrementata di 1 (fase successiva) ed il Timer riparte.
Il secondo if, invece, determina l'attivazione o lo spegnimento del riscaldatore in funzione di Temp confrontata con il set point Soglia[Fase].
Ovviamente se vuoi usare un PID (ma secondo me non è necessario) devo inserire qui i comandi.
Il fatto che la Fase 0 deve far partire il Timer solo al raggiungimento del primo set point è facilmente risolvibile...
Il codice che posto devi trovare tu il modo di integrarlo al tuo pid.
Questo pezzo lo devi inserire all'inizio fuori da ogni funzione.
// macro che definisce il numero massimo di step uguale a 4
#define N_MAX_STEPS 4
// macro che converte da minuti a millisecondi
#define minutesToMillis(m) (m * 60000UL)
/* setpoint con la s finale indica una lista, lo preferisco a soglie
le variabili le nomino sempre in camel case es: firstSetpoint (primo setpoint) */
float setpoints[N_MAX_STEPS] = {
55.0 // setpoint da raggiungere dopo la pressione del pulsante start
, 63.0 // setpoint da raggiungere dopo
, 72.0
, 78.0
};
unsigned long timeStep[N_MAX_STEPS] = {
minutesToMillis(10) // 10 minuti
, minutesToMillis(30) // 30 minuti
, minutesToMillis(30) // 30 minuti
, 0
};
unsigned long timer;
byte nStep;
bool trigger;
Quello che segue richiede maggiore impegno:
void setup() {
nStep = 0; // first step
timer = millis(); // save timer
Setpoint = setpoints[nStep];
trigger = false;
}
void loop() {
if (trigger == false) {
if (Input > setpoints[nStep] - 0.5) {
trigger = true;
timer = millis(); // save timer
}
} else {
if (nStep < N_MAX_STEPS - 1) {
if (millis() - timer > timeStep[nStep]) {
nStep++; // next step
Setpoint = setpoints[nStep]; // set Setpoint
trigger = false; // reset trigger
}
} else {
trigger = true; // block trigger
// spegni qui tutto
}
}
}
Dove c'è scritto "spegni tutto" devi inserire del codice per fermare il PID.
Per fare ripartire tutto da capo, devi azzerare nStep e impostare trigger a false.
Ciao.
Grazie mille!!!! Ora provo subito ad implementare, poi vi do un feedback sui risultati!
Comunque a mio avviso serve un PID in quanto avrei un pentolone (con 70/80 litri di mosto) dal quale prelevo tramite pompa parte del mosto, lo faccio passare per la resistenza elettrica e lo rimando nel pentolone. Le inerzie termiche sono decisamente elevate e il PID mi serve appunto per combatterle...
dunque ho inserito il codice e fatto alcune prove (con solo la sonda sempre) e pare che funzioni decisamente meglio, il codice è incollato qui sotto. Ora attendo l'arrivo dell'SSR per fare test veri e propri!!
#include <PID_v1.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <LiquidCrystal.h>
// Data wire is plugged into pin 53 on the Arduino
#define ONE_WIRE_BUS 53
//Relay connected
#define RelayPin 6
// macro che definisce il numero massimo di step uguale a 4
#define N_MAX_STEPS 4
// macro che converte da minuti a millisecondi
#define minutesToMillis(m) (m * 60000UL)
OneWire oneWire(ONE_WIRE_BUS);
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
DallasTemperature sensors(&oneWire);
/* setpoint con la s finale indica una lista, lo preferisco a soglie
le variabili le nomino sempre in CamelCase es: firstSetpoint (primo setpoint) */
float setpoints[N_MAX_STEPS] = {
55.0 // setpoint da raggiungere dopo la pressione del pulsante start
, 63.0 // setpoint da raggiungere dopo
, 72.0
, 78.0
};
unsigned long timeStep[N_MAX_STEPS] = {
minutesToMillis(10) // 10 minuti
, minutesToMillis(30) // 30 minuti
, minutesToMillis(30) // 30 minuti
, 0
};
unsigned long timer;
byte nStep;
bool trigger;
//Define Variables we'll be connecting to
double Setpoint, Input, Output;
//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT);
int WindowSize = 3500;
unsigned long windowStartTime;
void setup() {
nStep = 0; // first step
timer = millis(); // save timer
Setpoint = setpoints[nStep];
trigger = false;
windowStartTime = millis(); //per PID
//tell the PID to range between 0 and the full window size
myPID.SetOutputLimits(0, WindowSize);
//turn the PID on
myPID.SetMode(AUTOMATIC);
sensors.begin(); // IC Default 9 bit. If you have troubles consider upping it 12. Ups the delay giving the IC more time to process the temperature measurement
lcd.begin(16,2);
}
void loop() {
// call sensors.requestTemperatures() to issue a global temperature
// request to all devices on the bus
sensors.requestTemperatures(); // Send the command to get temperatures
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Temp:");
lcd.print(sensors.getTempCByIndex(0));
lcd.print(" C");
lcd.setCursor(0,1);
lcd.print("T_setpoint:");
lcd.print(Setpoint);
lcd.print(" C");
Input = sensors.getTempCByIndex(0);
float DeltaPID=5.0;
if((Setpoint - Input) < DeltaPID) myPID.Compute();//was 6, getting close, start feeding the PID -mdw
if ((Setpoint - Input) > DeltaPID) Output=WindowSize; // was 5, ignore PID and go full speed -mdw // set the output to full on
/************************************************
* turn the output pin on/off based on pid output
************************************************/
if(millis() - windowStartTime>WindowSize)
{ //time to shift the Relay Window
windowStartTime += WindowSize; //come dire windowStartTime = windowStartTime + WindowSize
}
if(Output < millis() - windowStartTime) digitalWrite(RelayPin,HIGH);
else digitalWrite(RelayPin,LOW);
if (trigger == false) {
if (Input > setpoints[nStep] - 0.5) {
trigger = true;
timer = millis(); // save timer
}
} else {
if (nStep < N_MAX_STEPS - 1) {
if (millis() - timer > timeStep[nStep]) {
nStep++; // next step
Setpoint = setpoints[nStep]; // set Setpoint
trigger = false; // reset trigger
}
} else {
trigger = true; // block trigger
myPID.SetMode(MANUAL); //Tutto off
}
}
}
Scusate il necroposting ma volevo sapere se questo codice poi ha funzionato? è quello che sto cercando forse...
ho bisogno di un pid che però non abbia i famosi spikes una volta raggiunto il target!
Calamaro:
Scusate il necroposting ma volevo sapere se questo codice poi ha funzionato? è quello che sto cercando forse...ho bisogno di un pid che però non abbia i famosi spikes una volta raggiunto il target!
I fattori del IPD devono essere sempre adeguati alla lentezza/velocitá del ristema in uso. Inoltre cambiano i fattori ottimali in funzione della quantitá di liquido da riscaldare.
Se non usi gli stessi materiali del esempio devi definirti i fattori Tu stesso per il Tuo sistema riscaldante.
Ciao Uwe
si si lo so, a me il pid serve per la stessa cosa di nnc6 solo che io ho bisogno che si adatti da solo al sistema in cui è inserito...
ad esempio
pentola da 18lt, settato il target lo raggiunge e lo mantiene
pentola da 30lt, settato il target lo raggiunge e lo mantiene
pentola da 100lt, settato il target lo raggiunge e lo mantiene
col PID cinese che vendono su ebay (REX C100) oltre ad avere un aspetto misero ha anche un algoritmo stupido che ha bisogno di 6-10 ore per fare un tuning dei parametri del sistema in cui è inserito!
quello che sto cercando io è un algoritmo che da solo si setti i parametri imparando dal sistema in cui è inserito.
esempio:
Il target è 66 gradi, lo stato iniziale è 52 gradi -> si crea un sotto step a 64° vede quanto tempo ci mette a raggiungerlo e in base a quello si calcola l'inerzia della pentola per arrivare a 66...
I sistemi in homebrewing sono inerziali con una massa enorme e quindi un'enorme lentezza, se sgarri di un grado la temperatura si conserva per mezz'ore senza scendere!
per questo, se il mio sistema mi fa uno spike di 4-5 gradi, non posso tornare indietro così rapidamente!
quello che sto cercando io è un algoritmo che da solo si setti i parametri imparando dal sistema in cui è inserito.
Bello se esistesse, ma io penso che è già tanto che il PID funzioni su Arduino.
In pratica la gobba che si vede nei grafici può essere limata, ma il PID ci impiegherà più tempo a raggiungere il setpoint, questo comportamento è tipico del PID senza ID, introducendo I aumenti la rapidità e D dovrebbe poi smorzare l'oscillazione che si viene a creare intorno al setpoint, tuttavia come ha detto tu, c'è da fare i conti con il l'inerzia o accumulo di energia termica, per questo motivo ID (specie I) devono essere ridotti quanto più possibile.
Mantenendo il PID attuale potresti pensare di fare 3 tarature, uno per contenitore, ma tieni conto che il PID nulla sa circa la temperatura ambiente e altre cose che normalmente consideriamo trascurabili, ma nel caso si voglia un comportamento più preciso forse c'è da rivalutare ciò che abbiamo trascurato prima.
Smontando il PID attuale si potrebbe pensare di farlo lavorare con dei parametri autoadattativi ma la vedo durà. Dotare il PID di approssimazione successive potrebbe essere una idea da sperimentare ma prima di passare al codice ci vuole un analisi. Considera che se alimenti un riscaldatore elettrico e ne misuri la temperatura all'istante T0 e togli la corrente, all'istante T1 anche senza corrente rileverai un aumento di temperatura, a cosa è dovuto ciò sarebbe da analizzare.
Uno dei motivi sicuramente è legato alla velocità di risposta del sensore di temperatura e a questa ci aggiungiamo anche il tempo impiegato dal micro per avere il dato numerico che si riferisce ad una situazione vecchia di Tn tempo.
Quella di impostare un setpoint anticipato non elimina la necessità di tarare il PID che per inseguire il setpoint conta su kp, ki, kd. In sostanza risolvi solo l'avvicinamento al setpoint.
Ciao.
http://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/
Da lì e nelle pagine a seguire trovi analizzato un PID base e come applicare delle modifiche per migliorarlo. Ad oggi mi pare uno dei migliori articoli perché spiega in modo semplice come funziona un PID, quali sono i problemi che lo affliggono e come ottimizzarlo, tutto in salsa Arduinica.
Sarebbe bello poter discutere con voi di queste cose davanti a una birra...
Comunque ho usato il software di opern ArdBid e tra un po' farò qualche prova!
Leo72, quell'articolo me lo sono proprio stampato perchè secondo me è fatto benissimo! E' spiegato veramente bene e con i disegni aiuta tantissimo a capire il funzionamento!