Pilotaggio resistenza 220V e cali di potenza.

Salve a tutti.

Magari se ne è già parlato ma non sono riuscito a trovare nulla (mi sa che cerco con termini sbagliati).

Ho realizzato un termo regolatore PID a controllo di fase con zero crossing per una resistenza da 1200W a 220V AC (un fornetto) e tutto funziona alla perfezione ma (credo sia comune) ad ogni impulso le luci di casa hanno un piccolo abbassamento di tensione .
A parte il fatto che credo sia dannoso per le altre apparecchiature è anche molto fastidioso.

Come risolvo questo problema?

Condensatore tra fase e neutro a monte?

Un filtro di linea più complesso?

Un cero in chiesa?

Altro?

Chiedo aiuto :confused: .

Grazie a tutti in anticipo.

Ciao Van.

Non penso ci sia rimedio quando su 3kw ne succhi più della metà dato dallo spunto.

a controllo di fase con zero crossing per una resistenza da 1200W

secondo me il controllo di fase e il zero crossing si escludono a vicenda.

Prova a misurare la tensione dei 230V con e senza resistenza accesa fissa.

Ciao Uwe

uwefed:
secondo me il controllo di fase e il zero crossing si escludono a vicenda.
...

Infatti, o l'uno o l'altro, non puoi avere entrambi.

Ricordati anche che i filamenti metallici delle resistenze per riscaldamento (come quelle delle lampadine, ed altri simili, comunque), hanno una resistenza minore a bassa temperatura di quella che hanno una volta raggiunta la temperatura d'esercizio ... per cui la tua resistenza, quando accende da fredda, assorbira' di piu dei 1200W di targa, che sono probabilmente il valore di quando e' a remperatura d'esercizio.

Scusate ma perché a questo link (ed anche su altri) mi dice "AC Phase Control" ed usa lo zero crossing?

http://playground.arduino.cc/Main/ACPhaseControl

C'è qualcosa che non mi quadra o non ho capito bene alcune cose.

Mi ricordo anche di un vecchio post (credo scritto da Uwe) dove si spiegava nel dettaglio il pilotaggio a treno di impulsi e il pilotaggio a parsializzazione d'onda (<--- dho!!! credo di essermi risposto da solo.. confermate.)

parsializzazione d'onda = controllo di fase ?

Ciao Van.

Forse hai fatto un minimo di confusione :wink:

Parzializzazione d'onda (o parzializzazione di fase), e' cio che si usa normanlante nei regolatori dimmer o variatori per la 220 ... mentre zero crossing accende il triac SOLO al passaggio per lo zero della semionda (riducendo di molto i disturbi, ma rendendo impossibile la regolazione proporzionale) ... probabilmente il tuo sistema usa uno sketch (con o senza PID non importa) che fa da termostato, con un pilota per il triac (probabilmente un MOC) che ha gia lo zero-crossing all'interno ...

Nel link che hai postato lo "zero-crossing DETECTOR" e' riferito al fatto che il primo opto RILEVA il passaggio per lo zero della sinusoide, in modo da permettere ad Arduino di pilotare il triac come regolatore calcolando il ritardo degli impulsi di pilotaggio in base al trigger che riceve dal detector ... mentre invece il PILOTAGGIO di un triac in zero-crossing significa che viene acceso solo al passaggio per lo zero (in genere lo fa il circuitino gia presente nell'optotriac, alcuni modelli lo possiedono, altri no, in base all'uso che serve farne)

Ho capito "l'inghippo"!!! :smiley:

Credo di non essere stato specifico io fin dall'inizio .

Effettivamente uso lo zero crossing detector per avere la sincronia con i 50Hz della linea e quindi per avere un riferimento per l'accensione del triac (passando per il MOC3022 senza zerocrossing integrato).

Con questa tecnica posso usare la parzializzazione di fase? (scritto corretto stavolta :-[ )
Se non erro gli impulsi devono arrivare a multipli di 20ms ,oppure ho detto un altra cavolata?

Ciao Van.

In quel modo piloti il triac come regolatore ... gli impulsi devono avere un ritardo rispetto al trigger (quello dato dallo zero crossing detector) proporzionale alla potenza a cui vuoi far lavorare la resistenza (piu sono in ritardo, piu tardi il triac innesca, meno potenza arriva alla resistenza), con un ritardo massimo di 10mS (in realta' un po meno, con un ritardo di esattamente 10ms non dovrebbe accendersi nulla ;))

Ovviamente ti servira' anche una sonda termica, per vedere che temperatura hai e regolarci la potenza in conseguenza di quella che vuoi ... ed allo stesso tempo potrai prevedere una "rampa" di accensione in modo che non ti faccia il "salto" dell'abbassamento impulsivo quando si accende ...

Ciao a Tutti.

Non credo che l'abbassamento delle luci dipenda dal sincronismo, ma solo dall'impianto di casa....
Parlo come Elettricista, Probabile che dove hai attaccato il fonetto non sia una presa cosidetta di calore, ma luce, che ha la sezione dei fili piu' piccola e che ti fa' calare la luce.

Etemenanki:
Infatti, o l'uno o l'altro, non puoi avere entrambi.

Ricordati anche che i filamenti metallici delle resistenze per riscaldamento (come quelle delle lampadine, ed altri simili, comunque), hanno una resistenza minore a bassa temperatura di quella che hanno una volta raggiunta la temperatura d'esercizio ... per cui la tua resistenza, quando accende da fredda, assorbira' di piu dei 1200W di targa, che sono probabilmente il valore di quando e' a remperatura d'esercizio.

Questo non mi risulta. In una lampadina é importante che la temperatura del filamento sia piú alto possibile perché la resa cromatica e quella della luce é migliore piú alta é la temperatura. percui si usano metalli con temperatura di fusione alta.
Nelle resistenze di riscaldamento non si deve arrivare a temperature cosí alte. Percui si usa constantanio come lega per fare le resistenze.

Ciao Uwe

Ehm, uwe, scusa ma no ... le resistenze per riscaldamento in genere sono di leghe nichel-cromo o di Kanthal, non di costantana, quella la si usa per le resistenze di precisione che in genere vengono montate per misurare la corrente :wink:

Comunque la variazione non e' molta, anche per quelle leghe ... per il tungsteno delle lampadine in effetti e' piu alta ...

diodo157:
Ciao a Tutti.

Non credo che l'abbassamento delle luci dipenda dal sincronismo, ma solo dall'impianto di casa....
Parlo come Elettricista, Probabile che dove hai attaccato il fonetto non sia una presa cosidetta di calore, ma luce, che ha la sezione dei fili piu' piccola e che ti fa' calare la luce.

No no, la sezione dei fili e di 2.5 sono sicuro e la derivazione principale è di 4 (l'ho fatto io l'impianto essendo elettricista anche io) mentre le prese sono tutte 10/16/schuko (ora non sono più a norma ma ai tempi lo erano)

Grazie cmq.

Facendo delle misurazione con l'oscilloscopio mi sono reso conto che ci sono come dei doppi impulsi sul pilotaggio del triac, non ho avuto tempo di approfondire ma appena posso faccio i test del caso e posto i risultati.

Ciao Van.

Ho risolto ragazzi!!!

I problemi erano il tempo tra un impulso e l'altro (ritardo), il quale avveniva troppo presto,
e la funzione collegata all'interrupt dello zero crossing che , ancora non ho capito il perché visto che era settato su RISING, veniva eseguita il doppio delle volte , bloccandomi quasi il sistema.

Ho risolto cambiando il modo di pilotare il triac ,usando la libreria TimerOne invece di usare dei delayMicroseconds nella callback dell'interrupt (credo che il quasi blocco del sistema possa dipendere da questo).

Cmq adesso la cucina è ritornata tale e non è più una sala da ballo con le strobo che flashiano a palla. ;D

Appena ripulisco lo sketch lo posto, potrebbe servire a qualcun altro e magari possiamo anche migliorarlo.

Grazie a tutti per il tempo e le idee spese.

Ciao Van.

P.S. : Metto Risolto nel titolo? o lo metto dopo che posto lo sketch?

Ciao,
anch'io ho in programma di costruirmi un forno non ventilato per la mia pasticceria amatoriale (non ditmi che sono goloso, lo so da tempo), in muratura e ben coibentato e resistenze da controllare con arduino che gestisce la curva di riscaldmento. Sarei felice di guardare il tuo schema e lo schetch
Franco

Eccomi alla ribalta!!! :smiley:

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.

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);       // turn off TRIAC (and AC)
}

Dal contenuto della funzione sopra, sembra tu voglia spegnere il triac, purtroppo il triac si può solo accendere (triggerare) e si spegne da solo al passaggio per lo zero della tensione "main".
Guardando il resto del codice mi sembra di capire che alimenti continuamente il led del moc, invece basta solo un impulso alto basso largo 50uS o poco più.

Il problema della taratura invece è legato al fatto che la funzione di trasferimento non è lineare, ti spiego alla carlona, con un tempo di trigger di 5ms ottieni il 50% della energia, con 2.5ms non ottieni il 75% dell'energia. Ciò è facile dedurlo ad intuito, con tempo di 2.5ms hai piena conduzione per 7.5ms prima dello zero, rispetto al tempo di trigger di 5ms hai aggiunto un pezzo di sinusoide di 2.5ms di larghezza, in questo tempo la tensione (o d.d.p) non è costante ma differente ad ogni istante T. Puoi ottenere l'energia reale dividendo la sinusoide in tanti punti T e campionando il valore istantaneo e sommandoli tutti per poi fare la media.

Ciao.

Grazie MauroTec per la risposta.

la funzione:

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);       // turn off TRIAC (and AC)
}

L'ho presa da un esempio trovato in rete.
In realtà il digitalWrite(TRIAC_PIN, LOW); non prova a spegnere il triac (anche se c'è scritto così, il commento non è mio , lo correggo subito) ma mette a livello logico basso il pin per permettere alla funzione di callback di TimerOne , void dim_check(), di riaccendere il triac al giusto clock.

il metodo che mi indichi tu è a treno di impulsi (giusto?) io invece sto usando (provando ad usare) la parzializzazione di fase.

Ma a l'atto pratico quale di queste 2 tecniche è migliore?

Ciao Van.

Ma se volessi pilotare il forno usando un SSR zero-crossing ed i treni di impulsi ,eliminando del tutto il il PID,termocoppia e ammenicoli vari un schetch così potrebbe andare?

#define SSR_PIN 8
#define POT_PIN A0

void setup() 
{
        pinMode(SSR_PIN,OUTPUT);
        pinMode(POT_PIN,INPUT);

        digitalWrite(SSR_PIN,LOW);
}

void loop() 
{
        int val = map(analogRead(POT_PIN),0,1023,10,1);
        digitalWrite(SSR_PIN,HIGH);
        delay(20);
        digitalWrite(SSR_PIN,LOW);
        delay(val * 20);
}

Per impostare le temperature uso un potenziometro facendo prima dei test con un termometro da laboratorio, e poi mi segno le varie posizioni sulla manopola.

Credo di essermi complicato la vita un po' troppo per cuocere le lasagne ;D .
Come si dice dalle mie parti:
Uso un cannone per sparare ad i fringuelli. ;D

Ciao Van.

Credo ci sia ancora una certa confusione nei termini impiegati al fine di identificare un determinato circuito e sistema di regolazione.

La parzializzazione della onda è l'unica soluzione economica in molte applicazioni, come:
1 - Regolazione velocità di un motore
2 - Regolazione intensità luminosa di una lampada

La tecnica della modulazione dell'onda è invece adatta a qualunque applicazione e fornisce funzione di trasferimento lineare, proporzionale alla percentuale della modulazione, ma è un poco più costosa.

L'altra tecnica a cui credo ti riferisci, io non so come chiamarla, comunque è impiegabile solo nel caso in cui il carico ha una inerzia a favore. Questo è il caso delle resistenza elettriche impiegate come generatore di calore. Sostanzialmente si basa su un PWM applicato su un intervallo di tempo ampio, come ad esempio 1 minuto. In 1 Secondo abbiamo 50 sinusoidi, in un minuto abbiamo 60*50 = 3000 sinusoidi, con un PWM del 50% avremo 1500 sinusoidi in un minuto.

Quindi il PWM deve avere un periodo di 60 secondi.

Con questa tecnica ci sono dei vantaggi nei riguardi delle emissioni EMI, perché sarà premura dello sviluppatore assicurarsi di sincronizzare il PWM con il passaggio dello zero. Quindi inserendo il carico nel momento in cui la tensione passa per lo zero avremo corrente zero e quindi niente transitorio sulla linea "main", stessa cosa avverrà per lo spegnimento.

Ti serve precisione per cuocere le lasagne? non credo si tratti di precisione alta, si può benissimo tollerare una sovra-elongazione della risposta iniziale del PID del 30%, c'è da vedere quanto dura ma penso possa essere tollerato. Se il setpoint vale 220°C e per 5 minuti ti ritrovi con 280°C, che via via si avvicinano sempre più al setpoint man mano che passa il tempo io penso che può andare, tra l'altro prima porterai a temperatura il forno e solo dopo inserisci la teglia e il pid è già stabile.

Puoi anche realizzare questa tecnica con il triac, visto che già ai il circuito non resta che provare.

Edit: Non so perché ho sbagliato questi calcoli
abbiamo 60*50 = 300 sinusoidi
avremo 150 sinusoidi in un minuto.

Ciao.

MauroTec:
... inserendo il carico nel momento in cui la tensione passa per lo zero ...

Ci pensa gia l'optotriac, a quello (basta usare la versione con lo zero-crossing) ... quindi alla fine tutto quello che serve e' un termostato on-off :wink: