Eccomi alla ribalta!!! 
Il software di arduino adesso funziona , i cali di potenza sono spariti ma sto diventando pazzo cercando di tarare il PID.
Per la taratura ho sempre usato il metodo Ziegler-Nichols e ha sempre funzionato egregiamente ma stavolta non ne vuole sapere di funzionare.
Non è il primo pid che configuro e non riesco a capire il perché di questa instabilità.
Ho provato anche con l'autotuning (PID_AutoTune_v0) ma ho ottenuto gli stessi risultati se non peggiori.
Specifiche tecniche del sistema:
- Termocoppia di tipo J dentro corpo metallico (l'ho usata decine di volte senza problemi).
-
AD594 dell'AnalogDevices (anche questo usato molte volte senza problemi)
- Le letture della termocoppia vengono effettuate ogni 100ms e poi viene fatta una media (100ms x 10 letture per un totale di 1 risultato ogni secondo)
- Per il pilotaggio della resistenza uso un triac BTA12-600 pilotato da un MOC3022 (senza zero crossing integrato)
- Per lo zero crossing detector uso un 4N35 (usato molte volte).
- Riguardo alla resistenza l'uniche specifiche che possiedo sono quelle della targhetta del forno e cioè:
1200W 230V AC della Tefal
Non conosco i vari coefficienti di temperatura.
Ho consultato già centinaia di pagine web inerenti all'argomento ma vengono sempre elencati i soliti 2 metodi (Ziegler-Nichols e CDHW Method) che conosco già.
C'è qualche esperto che possa indicarmi ,se esiste, qualche metodo/trucchetto per avere una taratura adhoc.
Premetto che non ho bisogno di molta precisione (è sempre un forno dove ci cuocio il pollo con le patate non un reattore nucleare ;D )
EDIT:
Posto anche lo sketch ne caso possa servire
(è un po' complicato perché c'è l'interfaccio che ho fatto con il software di monitoraggio.
Sarà mica quella che da fastidio?)
/*
Controllo_Forno
modified 26 Feb 2015
by Nicola Bruchi (van4dium)
This code is distribuited under the GPL v2 term.
*/
#include <TimerOne.h>
#include <PID_v1.h>
//Uncomment to enable tuning and debug
#define TUNING
#ifdef TUNING
#include <SerialCommand.h>
#endif
#define ZEROC_C_INTERRUPT 0
#define TRIAC_PIN 8
#define TC_PIN A0
#define POT_PIN A1
#define READ_INTERVAL 100 //ms
#define READ_NUMBER 10
unsigned long previousMillis = 0;
double temp = 0;
int counter = 0;
int dim = 256;
volatile int dimCounter = 0;
volatile boolean zero_cross = false;
int freqStep = 39;
double Setpoint, Input, Output;
//Valori non idonei
double Kp = 2.58;
double Ki = 0.1;
double Kd = 223.99;
PID myPID(&Input, &Output, &Setpoint,Kp,Ki,Kd, DIRECT);
#ifdef TUNING
SerialCommand sCmd;
int enabled = 0;
int aggressive = 0;
#endif
void setup()
{
pinMode(2, INPUT);
pinMode(TC_PIN,INPUT);
pinMode(POT_PIN,INPUT);
pinMode(TRIAC_PIN,OUTPUT);
digitalWrite(TRIAC_PIN,LOW);
Timer1.initialize(freqStep);
#ifndef TUNING
attachInterrupt(ZEROC_C_INTERRUPT, zero_cross_detect, RISING);
Timer1.attachInterrupt(dim_check, freqStep);
#else
Serial.begin(115200);
sCmd.addCommand("PG", getKp);
sCmd.addCommand("IG", getKi);
sCmd.addCommand("DG", getKd);
sCmd.addCommand("PS", setKp);
sCmd.addCommand("IS", setKi);
sCmd.addCommand("DS", setKd);
sCmd.addCommand("SS", setSetpoint);
sCmd.addCommand("SG", getSetpoint);
sCmd.addCommand("pid", getTuningP);
sCmd.addCommand("d", setEnabled);
#endif
// Serial.println("Staring program ....");
// wait for AD595 chip to stabilize
delay(500);
// Serial.println("Done.");
Input = ( 5.0 * analogRead(TC_PIN) * 100.0) / 1024.0;
Setpoint = 120;
myPID.SetOutputLimits(0,255);
// myPID.SetSampleTime(200);
#ifdef TUNING
myPID.SetMode(MANUAL);
Serial.println("R");
#else
myPID.SetMode(AUTOMATIC);
#endif
}
void loop()
{
#ifdef TUNING
sCmd.readSerial();
#endif
readThermocouple();
if(abs(Setpoint-Input) < 10)
{
myPID.SetOutputLimits(0.0,255.0);
myPID.SetTunings(Kp, Ki, Kd);
#ifdef TUNING
if(aggressive == 1)
{
aggressive = 0;
getTuningP();
}
#endif
}
else
{
myPID.SetOutputLimits(0.0,128.0);
myPID.SetTunings(10.0, 0.0, 0.0);
#ifdef TUNING
if(aggressive == 0)
{
aggressive = 1;
getTuningP();
}
#endif
}
myPID.Compute();
dim = 256 - int(Output);
delay(19);
}
void zero_cross_detect()
{
zero_cross = true; // set the boolean to true to tell our dimming function that a zero cross has occured
dimCounter = 0;
digitalWrite(TRIAC_PIN, LOW); // set low TRIAC_PIN
}
// Turn on the TRIAC at the appropriate time
void dim_check()
{
if(zero_cross == true)
{
if(dimCounter >= dim)
{
digitalWrite(TRIAC_PIN, HIGH); // turn on light
dimCounter = 0; // reset time step counter
zero_cross = false; //reset zero cross detection
}
else
{
dimCounter++; // increment time step counter
}
}
}
void readThermocouple()
{
//Serial.println("leggi temp");
unsigned long currentMillis = millis();
if(currentMillis - previousMillis >= READ_INTERVAL)
{
previousMillis = currentMillis;
temp += ( 5.0 * analogRead(TC_PIN) * 100.0) / 1024.0;
counter++;
if(counter == READ_NUMBER - 1)
{
temp /= READ_NUMBER;
Input = temp;
#ifdef TUNING
Serial.print("C");
Serial.println(temp,1);
#endif
counter = 0;
temp = 0;
}
#ifdef TUNING
if(enabled)
{
Serial.print("M");
Serial.println(int(Output));
}
#endif
}
}
#ifdef TUNING
void getKp()
{
Serial.print("KP");
Serial.println(myPID.GetKp());
}
void getKi()
{
Serial.print("KI");
Serial.println(myPID.GetKi());
}
void getKd()
{
Serial.print("KD");
Serial.println(myPID.GetKd());
}
void setKp()
{
char *arg;
arg = sCmd.next(); // Get the next argument from the SerialCommand object buffer
if (arg != NULL)
{
Kp = atof(arg);
myPID.SetTunings(Kp,Ki,Kd);
}
}
void setKi()
{
char *arg;
arg = sCmd.next(); // Get the next argument from the SerialCommand object buffer
if (arg != NULL)
{
Ki = atof(arg);
myPID.SetTunings(Kp,Ki,Kd);
}
}
void setKd()
{
char *arg;
arg = sCmd.next(); // Get the next argument from the SerialCommand object buffer
if (arg != NULL)
{
Kd = atof(arg);
myPID.SetTunings(Kp,Ki,Kd);
}
}
void setSetpoint()
{
char *arg;
arg = sCmd.next(); // Get the next argument from the SerialCommand object buffer
if (arg != NULL)
{
Setpoint = atof(arg);
getSetpoint();
}
}
void getSetpoint()
{
Serial.print("P");
Serial.println(Setpoint);
}
void getTuningP()
{
Serial.print("KP");
Serial.print(myPID.GetKp());
Serial.print(" ");
Serial.print("KI");
Serial.print(myPID.GetKi());
Serial.print(" ");
Serial.print("KD");
Serial.println(myPID.GetKd());
}
void setEnabled()
{
char *arg;
arg = sCmd.next(); // Get the next argument from the SerialCommand object buffer
if (arg != NULL)
{
int on = atoi(arg);
if(on == 1)
{
attachInterrupt(ZEROC_C_INTERRUPT, zero_cross_detect, RISING);
Timer1.attachInterrupt(dim_check, freqStep);
myPID.SetMode(AUTOMATIC);
enabled = 1;
Serial.println("DimON");
}
else
{
Timer1.detachInterrupt();
detachInterrupt(ZEROC_C_INTERRUPT);
digitalWrite(TRIAC_PIN,LOW);
myPID.SetMode(MANUAL);
enabled = 0;
Serial.println("DimOFF");
}
}
}
#endif
Grazie mille in anticipo.
Ciao Van.