Go Down

Topic: aiuto gestione uscita a tempi ciclo diversi (ON=t1 OFF=t2 ON=t3 OFF=t2 ON=t3) (Read 2012 times) previous topic - next topic

megamarco83

Ciao, sono un principiante e non riesco a creare una funzione con arduino credo abbastanza banale, mi spiego
quello che vorrei fare è la seguente cosa: ho due relè esterni A e B (che saranno gli ingressi su arduino)
su arudiono vorrei collegare due relè  in uscita C e D (che saranno le uscite su arduino)
le uscite vorrei attivarle in questo modo:
se A=1 allora C=1
se A=0 C=0
se B=1 allora D=1
se B=0 allora D=0

inoltre la difficoltà (ed ecco perchè ho pensato di usare arduino) è la seguente
quando A si attiva, C deve attivarsi per 1,5ore e poi trascorso questo tempo, se A è ancora a 1, il relè C deve funzionare in modo discontinuo, cioè C=0 per 20minuti, poi (sempre se A è ancora a 1) C=1 per 30minuti e così via fino a che A=0 caso in cui si ferma tutto

stessa identica cosa per il relè B in ingresso

in poche parole vorrei che all'attivazione di un ingresso, la corrispondente uscita si attivi la prima volta per 1.5ore, poi si spegna per 20minuti, poi si riattivi per 30min, poi si spenga per 20min, poi si riattivi per 30min, e così via, fino a che l'ingresso corrispondente non torna a zero; in questo caso si disattivano tutti i cicli.....e nel caso in cui l'ingresso torno a 1 si riparte da capo: uscita ON x 1.5ore - OFF per 30min - ON per 20min - OFF per 30min - ON per 20min - OFF per 30min .....ecc ecc quando l'ingresso è 0 si spegne tutto continuando ad iterare il tutto all'infinito.

non ho idea di come fare, c'è qualche anima pia che avrebbe voglia di aiutarmi a realizzare un sistema del genere?
grazie mille!

PaoloP

Devi creare una macchina a stati finiti.
Lo stato sarà determinato dagli ingressi A e B e dal tempo di permanenza nello stesso stato. Scaduto il tempo passerai allo stato successivo oppure ricominci da capo.
Stato 0 condizione iniziale
Stato 1 attivazione per 90 minuti
Stato 2 disattivazione per 20 minuti
Stato 3 attivazione per 30 minuti
dallo stato 3 passi al nuovamente 2 se ci sono le condizioni, altrimenti torni all'1. Idem per i passaggi 1-2 e 2-3.
Questo per entrambi gli ingressi.

megamarco83

ciao e grazie, quindi con arduiono si può fare una cosa del genre....
penso di avere capito la logica con cui intendi operare....
dovrei concatenarli quindi in una serie di cicli for...
il problema è ....come lo scrivo il codice?
purtroppo progetti pronti non ne ho trovati....:(

nid69ita

Un esempio di macchina a stati finiti (non codice copia-e-incolla !! )
http://www.lucadentella.it/2013/04/30/macchina-a-stati-finiti-e-arduino/
my name is IGOR, not AIGOR

megamarco83

ciao e grazie, gli ho dato un occhio, ho più o meno capito cosa fa, anche se è associato ad un orario, mentre io lo voglio associare ad un ingresso, se l'ingresso è attivo fa partire il ciclo, altrimenti no.
Ad ogni modo come dicevo non sono per nulla un esperto...anzi, ho pensato di usare arduino perchè mi sembrava più versatile e perchè ho visto che ha una grossa comunità....magari veniva fuori qualche anima pia che mi sapesse guidare nel realizzarlo :)

SukkoPera

Mi pare che ti si stia appunto dando una mano a realizzarlo, il che però è diverso dal farlo al posto tuo...

Fai così: prendi carta e penna e cerca di individuare gli stati della tua macchina. Fai una serie di rettangoli, per ognuno scrivi quali condizioni ti ci portano e quali ti ci fanno uscire, oltre che cosa c'è da fare in quello stato (che potrebbe essere... niente!). Poi collega gli stati tra cui si può passare con delle frecce. Tipo:

  • INIZIO: -> Vai nello stato Attesa (senza se e senza ma, solo per capire come partire)
  • Attesa: Se A == 1 vai in AttesaB
  • AttesaB: Se A == 0 vai in Attesa. Se B == 1 vai in Accendi
  • Accendi: Accendi relé, se A == 0 vai in MezzoSpento
  • MezzoSpento: Se A == 1 vai in Accendi. Se B == 0 vai in Spento
  • Spento: Spegni relé. Vai in Attesa


(WARNING: Esempio assolutamente casuale e probabilmente non completamente corretto 8))

Prova tutti i vari percorsi per assicurarti che per qualunque variazione degli ingressi tutto rimanga sotto controllo e funzioni come intendi. Una volta fatto questo torna qua e ti aiuteremo ad implementarlo :).
"Code is read much more often than it is written, so plan accordingly. Design for readability."

Guida rapida a ESP8266: https://goo.gl/kzh62E

megamarco83

ho cercato su internet come funzionano i cicli for e come funziona il controllo if
poi ho provato guardando l'esempio a costruire il mio specifico programma....non ho capito però come incrementare il tempo del contatore del tempo, cioè proprio fisicamente come dire ad arduino di attendere tot secondi....ho messo un commento nel punto in cui non ho proprio idea di come dovrei scrivere l'istruzione.
potrebbe essere sensata una cosa di questo tipo?

Code: [Select]
#define RELAY_PIN_C 2
#define RELAY_PIN_D 3


#define START_TIME  5400 //1.5ore di prima attivazione
#define ON_TIME    1800 //30min di attivazione
#define OFF_TIME    1200 //20min di pausa

#define RELAY_PIN_INPUT_A 4
#define RELAY_PIN_INPUT_B 5

// variables

int fsm_state;

void setup() {
 

  pinMode(RELAY_PIN_C, OUTPUT);
  pinMode(RELAY_PIN_D, OUTPUT);
  pinMode(RELAY_PIN_INPUT_A, INPUT);
  pinMode(RELAY_PIN_INPUT_B, INPUT);
  fsm_state = STATE_OFF;
}

void loop() {

 
  // FSM states
  switch(fsm_state) {
   
    case STATE_OFF:
      if(RELAY_PIN_INPUT_A=1 OR RELAY_PIN_INPUT_B=1) {
        for(X=0; X<START_TIME,X++){
          //QUI MI MANCA DI  AGGIUNGERE L'ATTESA DI UN SECONDO....
          digitalWrite(RELAY_PIN_C, HIGH);
          digitalWrite(RELAY_PIN_d, HIGH);
          if(RELAY_PIN_INPUT_A=1 RELAY_PIN_INPUT_B=1) {
            for(X=0; X<OFF_TIME,X++){
              //QUI MI MANCA DI AGGIUNGERE L'ATTESA DI UN SECONDO....
              digitalWrite(RELAY_PIN_C, LOW);
              digitalWrite(RELAY_PIN_D, LOW);
               if(RELAY_PIN_INPUT_A=1 RELAY_PIN_INPUT_B=1) {
                for(X=0; X<ON_TIME,X++){
                  //QUI MI MANCA DI  AGGIUNGERE L'ATTESA DI UN SECONDO....
                    digitalWrite(RELAY_PIN_C, HIGH);
                    digitalWrite(RELAY_PIN_d, HIGH);
                   
             
            }
          }
        fsm_state = STATE_ON;
      }
      break;
   
    case STATE_ON:
      if(RELAY_PIN_INPUT_A=0) {
        digitalWrite(RELAY_PIN_C, LOW);
        fsm_state = STATE_OFF;
      }   
      break;
  }
}

}

CoreZilla

http://www.leonardomiliani.com/2013/programmiamo-i-compiti-con-millis/

megamarco83

Fai così: prendi carta e penna e cerca di individuare gli stati della tua macchina. Fai una serie di rettangoli, per ognuno scrivi quali condizioni ti ci portano e quali ti ci fanno uscire, oltre che cosa c'è da fare in quello stato (che potrebbe essere... niente!). Poi collega gli stati tra cui si può passare con delle frecce. Tipo:

http://it.tinypic.com/r/igmfk6/8
se ho capito bene....questo sopra è lo schema a blocchi che ho pensato per la logica del programma
scusa la qualità...ed il mezzo discutibile su cui lo ho fatto...ma credo funzioni...
come faccio a scriverlo ora? :D

p.s. ho dimenticato di scrivrere, che nello schema a blocchi sopra volevo definire
#define START_TIME  5400 //1.5ore di prima attivazione
#define ON_TIME    1800 //30min di attivazione
#define OFF_TIME    1200 //20min di pausa
e che non ho capito come dare la pausa ad arduino



megamarco83

http://it.tinypic.com/r/igmfk6/8
seguendo il mio schema a blocchi, e leggendo un po' come si programma arduino, penso che dovrò utilizzare dei cicli while
non capisco e non ne vengo a capo di come far in modo che arduino faccia trascorrere il tempo
la mia idea di usare il contatore tempo, è quella appunto di contare fino al valore dichiarato nelle variabili
START_TIME OFF_TIME ON_TIME e poi di rendere ciclica la cosa...
ma non ho capito come posso far si che arduino lasci accesa o spenta l'uscita per effettivamente quel tempo
essendo il tempo di calcolo dell'iterazione diverso dal trascorrere del tempo reale

Code: [Select]
#define OUT_C 2
#define OUT_D 3
#define START_TIME  5400 //1.5ore di prima attivazione
#define ON_TIME    1800 //30min di attivazione
#define OFF_TIME    1200 //20min di pausa
#define IN_A 4
#define IN_B 5
int tempo = 0

int fsm_state;
void setup() {
  pinMode(OUT_C, OUTPUT);
  pinMode(OUT_D, OUTPUT);
  pinMode(IN_A, INPUT);
  pinMode(IN_B, INPUT);
  fsm_state = STATE_OFF;
}

void loop() {

  switch(fsm_state) {
   
    case STATE_OFF:
      while(IN_A=1){
        digitalWrite(OUT_C, HIGH);
        tempo=tempo+1; //in questo modo aumento il contatore del tempo fino ad arrivare ai valori impostati...ma come posso fare affinchè arduino mantenga l'uscita attiva per i secondi effettivi??
        while(tempo>=START_TIME){
            tempo=0;
            digitalWrite(OUT_C, LOW);
         
          while(IN_A=1){
            tempo=tempo+1;
         
          wile(tempo>=OFF_TIME)
          tempo=0;
          while(ING_A=1){
            digitalWrite(OUT_C, HIGH);
            tempo=tempo+1;
            while(tempo>=ON_TIME)
          }
             
      tempo=0;
      while(IN_A=1)
         
          }         
digitalWrite(OUT_C, LOW);
tempo=0


fsm_state = STATE_ON;
      }
      break;
   
    case STATE_ON:
     
      }   
      break;
  }
}

}


ovviamente sono lontanissimo dal risultato finale immagino... :(

SukkoPera

Appena riesco guardo lo schema, da qua non riesco a vederlo.

Fare trascorrere il tempo è facile: la funzione millis() ti dice quanti millisecondi sono passati dall'accesione e viene aggiornata automaticamente. Basta che salvi il suo valore all'inizio dell'intervallo da misurare e poi, a ogni iterazione del ciclo verifichi che sia passato abbastanza tempo. Dai un'occhiata all'esempio BlinkWithoutDelay.
"Code is read much more often than it is written, so plan accordingly. Design for readability."

Guida rapida a ESP8266: https://goo.gl/kzh62E

megamarco83

Apena riesco guardo lo schema, da qua non riesco a vederlo.

Fare trascorrere il tempo è facile: la funzione millis() ti dice quanti millisecondi sono passati dall'accesione e viene aggiornata automaticamente. Basta che salvi il suo valore all'inizio dell'intervallo da misurare e poi, a ogni iterazione del ciclo verifichi che sia passato abbastanza tempo. Dai un'occhiata all'esempio BlinkWithoutDelay.
grazie sei molto getile!!
....l'esempio lo ho guardato, ma ci ho capito davvero poco....
cercando in rete le informaizioni sui vari if e while e for, ho provato a mettere già il secondo codice...ma con la semplificazione di usare un solo ingresso: IN_A e una sola uscita OUT_C
già doverci inserire il secondo ingresso IN_B e OUT_D mi si complicava tutto...
infine....sarebbe interessante usare mills() se posso passagli come valore di attesa quello che calcolo con l amia variabile incrementale che ho definito come tempo
però forse, pensando ci ora....così c'è un errore...poichè farebbe un conto del tipo:
0secondi+1secondo=1secnodo di attesa
1secondo+1secondo=2secondi di attesa (sommati a quello di prima)
2secondi+1secondo=3 secondi di attesa (che sommati ai due di prima e quelo iniziale fa già 6)....
però come funziona mills dall'esempio nn lo ho proprio capito:(
grazie per l'aiuto!

SukkoPera

Ho guardato lo schema, ma hai fatto un flowchart, non quel che ti ho detto io :smiley-confuse:.
"Code is read much more often than it is written, so plan accordingly. Design for readability."

Guida rapida a ESP8266: https://goo.gl/kzh62E

megamarco83

ci sto provando ora...ma scrivere tutti gli stati, mi porta ad un loop infinito....ma credo di non avere capito come fare il tuo schema....
io ho fatto così: ingressi A, B       uscite: C, D

START
con A=0 B=0 -> C=0 D=0
con A=1 B=0 -> C=1 per 1,5ore D=0 (e qui mi incasino a rappresentarlo perchè dovrei fare: C=1 per 1,5ore...ma se dopo 10min A=0 allora C=0 anche se l'ora e mezza non è passata...interropo tutto e torno a START
(infatti nel mio flowchart facevo sempre il controllo relativo all'ingresso A prima di aumentare il tempo, così che non appena A=0 uscisse)

proseguendo...se trascorrono le 1,5ore ed ho ancora A=1 B=0 -> C=0 per 30min e D=0 (anche qui il controllo sugli ingressi deve essere continuo, se dovesse verificarsi A=0 interrompo tutto e torno allo START)
se dopo i 30min A=1 B=0 -> C=1 per 20min e D=0 (anche qui solito controllo sugli ingressi, se A=0 si torna a START
trascorsi i 20minuti se A è ancora = 1 e B=0 allora devo continuare a ciclare ripartendo però dalla sosta di 30min e così via.

il resto delle combinazioni A=0 B=1 è identico solo che accendo l'uscita D

se A=0 e B=0 -> C=0 e D=0
se A=1 e B=1 identico alla descrizione con il ciclo sopra, solo che accendo sia D che C....ovviamente le uscite sono slegate, cioè ognuna segue il suo ingresso, quando il relativo ingresso si spegne la relativa uscita torna a condizione di START

grazie!

vittorio68

Ciao,

come ti hanno già suggerito, questo tipo di problemi si risolve molto bene utilizzando la millis() che ti restituisce il numero di millisecondi trascorsi dall'accensione di Arduino. Tipicamente puoi utilizzarla in questo modo:

Code: [Select]

unsigned long lastMillis;

void setup()
{
   lastMillis = millis();
}

void loop()
{
   unsigned long now = millis();
   if (now - lastMillis > 1000)
   {
      // qui entri una volta al secondo
      // inserisci qui il codice che vuoi eseguire una volta al secondo
      // per esempio incrementa una variabile che conta i secondi trascorsi da un certo evento

     lastMillis = now;   // questo inizializza la variabile lastMillis per il prossimo periodo
   }
}



Con il codice di esempio precedente puoi gestire una variabile che conta 5400 secondi per il periodo di 1,5 ore oppure 1200 secondi per i 20 minuti e così via.

Ottimo il suggerimento dell'utilizzo di un automa a stati finiti. Io ti suggerirei di riflettere innanzitutto su un automa che gestisce solo A e C. Risolto quello per gestire B e D ti basterà soltanto duplicarlo utilizzando variabili diverse in modo da gestire cicli autonomi.

Proviamo a pensare insieme agli stati:

- Stato ATTESA: se A = 0 non succede nulla; se A = 1 metti C = 1 e passi nello stato TIME90 (90 minuti = 1,5 ore)

- Stato TIME90: Se A = 0 metti C = 0 e torni nello stato ATTESA; se A = 1 incrementi la variabile secondiTrascorsi; se secondiTrascorsi < 5400 non fai nulla, se secondiTrascorsi >= 5400 metti C = 0 e passi nello stato TIME20

- Stato TIME20: Se A = 0 metti C = 0 e torni nello stato ATTESA;  se A = 1 incrementi la variabile secondiTrascorsi; se secondiTrascorsi < 1200 non fai nulla, se secondiTrascorsi >= 1200 metti C = 1 e passi nello stato TIME30

- Stato TIME30: Se A = 0 metti C = 0 e torni nello stato ATTESA;  se A = 1 incrementi la variabile secondiTrascorsi; se secondiTrascorsi < 1800 non fai nulla, se secondiTrascorsi >= 1800 metti C = 0 e passi nello stato TIME20

Lo stato in cui sei lo gestisci con una variabile (la chiamiamo stato???) che assumerà quattro valori: ATTESA, TIME90, TIME20, TIME30. Per questo puoi usare una enum.

Nella loop userai uno switch per decidere cosa fare ad ogni ciclo in base allo stato in cui sei.

Si tratta solo dell'idea di base, adesso riflettici e prova a buttare giù il codice, poi postalo e lo guardiamo insieme. Se invece hai ancora dubbi chiedi pure.

Ciao.
Vittorio.

Go Up