Go Down

Topic: Irrigazione automatica (Read 4002 times) previous topic - next topic

karnhack

Dal post #11: «il valore associato ad ogni fase è naturalmente una convenzione»
Dal post #15: «Tra l'altro i valori sono del tutto convenzionali»
Mi fai paura, ma sei umano o un BOT?  :o
Che memoria! :smiley-surprise:

karnhack

#31
May 25, 2019, 07:33 pm Last Edit: May 25, 2019, 07:34 pm by karnhack
Lo switch deve funzionare in base al valore della variabile di fase, non del valore orario... Di fatto con lo switch hai scritto l'equivalente esatto di questo if... un sacco di condizioni che non risulteranno mai vere, o meglio, risulteranno vere solo a mezzanotte, a mezzanotte e un minuto, a mezzanotte e due minuti ecc, mentre per tutto il resto del tempo viene eseguito solo l'else
[/code]
Ok quindi se ho capito bene la tua indicazione il problema sta in
Code: [Select]
switch (ADESSO)
Quindi dovrei lavorare a cascata? cioè partire dalla fase1, verificarla e poi passare alla fase 2 ecc.

Dunque in poche parole dovrei partire dalla fase RIEMPIMENTO e interrogare la valvola se aperta o chiusa? è aperta, bene allora riempi e passa alla fase 2 RIPOSO.
Nella fase RIPOSO vado a interrogare l'RTC in attesa che la data o l'ora coincidano oppure solo l'orario per le operazioni quotidiane, etc. etc. fino alle fasi successive.

Ma quindi la X di "switch (x)" non deve essere un fattore comune a tutte le fasi? è questo che non capisco...
La X può essere legata solo alla lettura del sensore troppopieno della fase RIEMPIMENTO? Non so se mi sono spiegato.

Claudio_FF

#32
May 25, 2019, 08:13 pm Last Edit: May 25, 2019, 08:23 pm by Claudio_FF
Quindi dovrei lavorare a cascata? cioè partire dalla fase1, verificarla e poi passare alla fase 2 ecc.
Si, in ogni situazione esegui solo un pezzo del programma, quello relativo alla situazione corrente identificata dalla variabile fase. Quando ci sono le condizioni, ad esempio quando nella fase riempimento trovi che il sensore pieno si è chiuso, modifichi le uscite e passi alla situazione/fase seguente (seguente in senso logico, non necessariamente di numero). Al prossimo giro del programma verrà eseguito il nuovo pezzo di codice relativo alla nuova fase e così via.

Quote
Nella fase RIPOSO vado a interrogare l'RTC in attesa che la data o l'ora coincidano oppure solo l'orario per le operazioni quotidiane, etc. etc. fino alle fasi successive.
Esatto.

La variabile 'x' degli esempi del post #15 contiene il numero della fase corrente, e serve per eseguire solo il pezzo di codice di quella fase. Che poi lo fai con switch o con if poco importa.
Una domanda ben posta è già mezza risposta.

karnhack

#33
May 26, 2019, 01:12 am Last Edit: May 26, 2019, 01:18 am by karnhack
ci sto sbattendo la testa da un po ma non ne esco, forse ho dichiarato male le fasi
Code: [Select]
byte faseAttuale=RIEMPIMENTO;
int fase=0;


fatto sta che non riesco a passare da una fase all'altra. Per il momento stavo provando a passare dal RIEMPIMENTO ad IRRIGAZIONE giusto per capire, ma non va

Code: [Select]
switch (faseAttuale)
    {
      case RIEMPIMENTO:
      if(analogRead(pinTroppopieno) >= 1000) {
        digitalWrite(pinElettrovalvola,ACCESO);
      }
      else
      {
        digitalWrite(pinElettrovalvola,SPENTO);
        fase = IRRIGAZIONE;
      }
      delay(1000);
      //fase = IRRIGAZIONE; // ho provato anche qui
      break;

      case RIPOSO:  
       // istruzioni a  
      break;

      case CONCIMAZIONE:
      // istruzioni a
      break;

      case IRRIGAZIONE:
       digitalWrite(pinPompa,ACCESO);
      break;
      
      default:
      break;
    }
    }
}

Claudio_FF

#34
May 26, 2019, 01:20 am Last Edit: May 26, 2019, 10:24 am by Claudio_FF
Hai dichiarato due diverse variabili.
Lo switch (cioè quale caso viene eseguito) è controllato da 'faseAttuale' che rimane invariata, mentre tu modifichi 'fase' che non viene usata da nessuna parte.

La logica all'interno dei case può essere più semplice:


Per aggiungere la concimazione basta aggiungere un else if nella fase riposo, che avvia peristalsi e agitatore, e passa alla concimazione.
Una domanda ben posta è già mezza risposta.

karnhack

#35
May 26, 2019, 11:08 am Last Edit: May 26, 2019, 11:15 am by karnhack
Pero non mi spiego come mai una cosa che funzionava ieri non funziona oggi...
La lettura di A0 ieri oscillava tra 1023 e 1010 senza nessun voltaggio, oggi invece oscilla da tra i 310 e i 270 sempre a vuoto. Se invece gli do 5V simulando il contatto dell'acqua oscilla tra 0 e 1023. Ho bruciato qualcosa? ho provato anche un altro pin e fa uguale

Code: [Select]
case RIEMPIMENTO:
        if (analogRead(pinTroppopieno) >= 1000) {
          digitalWrite(pinElettrovalvola, ACCESO);
         
        }
        else
        {
          digitalWrite(pinElettrovalvola, SPENTO);
         
        }
        delay(500);
        fase = RIPOSO;
        break;


Oltre al mistero citato sopra, ho un altro problema, cioè appena viene fatta la lettura di A0 avviene la condizione pinTroppopieno >= 1000) e passa immediatamente all'altra fase senza attendere la condizione inversa, quindi in poche parole l'elettrovalvola rimane accesa. Ho provato ad inserire un delay senza successo, ho provato anche millis ma va in errore.

Claudio_FF

#36
May 26, 2019, 11:32 am Last Edit: May 26, 2019, 11:40 am by Claudio_FF
La lettura di A0 ieri oscillava tra 1023 e 1010 senza nessun voltaggio, oggi invece oscilla da tra i 310 e i 270 sempre a vuoto.
Nessun pin di ingresso deve restare scollegato, altrimenti leggendolo ottieni valori casuali. Il perché del ieri così e oggi pomì sta nel fatto che quell'ingresso ieri aveva accumulato più cariche elettrostatiche, e non essendo collegato a niente non potevano essere "smaltite" da nessuna parte.

Quote
appena viene fatta la lettura di A0 avviene la condizione pinTroppopieno >= 1000) e passa immediatamente all'altra fase senza attendere la condizione inversa
Certo, perché è esattamente quello che gli hai detto di fare, infatti la modifica alla variabile fase avviene al di fuori di ogni condizione, quindi sempre e subito alla prima esecuzione di quel case, invece dovrebbe avvenire solo nella condizione voluta.

Quote
Ho provato ad inserire un delay senza successo, ho provato anche millis ma va in errore.
I tentativi alla cieca non portano da nessuna parte. Se vuoi che un programma faccia quello che vuoi  bisogna imparare a pensare con la stessa logica di esecuzione di Arduino... fai finta di essere Arduino ed esegui tu il programma che hai scritto. Se tra la tua esecuzione mentale simulata e quella di Arduino qualcosa non coincide, vuol dire che c'è qualcosa di non compreso ed è inutile andare avanti se prima non ci si chiarisce le idee. Purtroppo non c'è altra strada (a parte farsi scrivere i programmi dagli altri).
Una domanda ben posta è già mezza risposta.

karnhack

#37
May 26, 2019, 11:47 am Last Edit: May 26, 2019, 11:49 am by karnhack
I tentativi alla cieca non portano da nessuna parte. Se vuoi che un programma faccia quello che vuoi  bisogna imparare a pensare con la stessa logica di esecuzione di Arduino... fai finta di essere Arduino ed esegui tu il programma che hai scritto. Se tra la tua esecuzione mentale simulata e quella di Arduino qualcosa non coincide, vuol dire che c'è qualcosa di non compreso ed è inutile andare avanti se prima non ci si chiarisce le idee. Purtroppo non c'è altra strada (a parte farsi scrivere i programmi dagli altri).
Credo di sapere come fare ma è l'ignoranza del linguaggio C che mi rende difficile l'attuazione.

Se potessi parlargli gli direi leggi il pin A0 che sarà < X , apri la valvola, attendi che diventi >X e poi passa la fase  Y

Claudio_FF

#38
May 26, 2019, 12:16 pm Last Edit: May 26, 2019, 12:49 pm by Claudio_FF
Se potessi parlargli gli direi leggi il pin A0 che sarà < X , apri la valvola, attendi che diventi >X e poi passa la fase  Y
Basta formalizzarlo con la logica disponibile (se, finché):

finchè pin A0 < X:

   apri valvola

chiudi valvola
fase Y

La traduzione è uno a uno (mi rifaccio al codice postato prima perché non so cosa significano i valori letti da A0... una funzioncina chiamata 'troppo_pieno' che ritorna vero o falso sarebbe molto più chiara sempre per il fatto che i numeri sparsi qua e la non è immediatamente evidente cosa rappresentano):
Code: [Select]
while (analogRead(pinTroppopieno) >= 1000)
{
    digitalWrite(pinElettrovalvola, ACCESO);
}
digitalWrite(pinElettrovalvola, SPENTO);
fase = RIPOSO;

Certo questo snatura un po' lo schema del post #34, perché con la struttura a fasi le attese sono già contemplate nel fatto che una fase rimane attiva finché non avviene un evento che la fa cambiare:

Se fase RIEMPIMENTO:
    Se troppopieno:
        chiudi valvola
        fase RIPOSO


Che si traduce sempre uno a uno:
Code: [Select]
case RIEMPIMENTO:
    if (analogRead(pinTroppopieno) < 1000)
    {
        digitalWrite(pinElettrovalvola, SPENTO);
        fase = RIPOSO;
    }
break;


La funzioncina per il troppo pieno può essere semplicemente:
Code: [Select]
bool troppo_pieno()
{
    if (.....) { return true; }
    return false;
}

E quindi le condizioni dei due esempi sopra si semplificano e diventano chiare:
Code: [Select]
while (!troppo_pieno()) // finche' non e` troppo pieno

if (troppo_pieno())     // se e` troppo pieno
Una domanda ben posta è già mezza risposta.

karnhack

Al momento ho risolto così e sembra funzionare

Code: [Select]
switch (fase)
    {
      case RIEMPIMENTO:
      if (analogRead(pinTroppopieno) >= 50) {  //soglia di prova
          digitalWrite(pinElettrovalvola, ACCESO);
          delay(1000);
        }
        while (analogRead(pinTroppopieno) <= 5) //soglia di prova
        {
        digitalWrite(pinElettrovalvola, SPENTO);
        }
        fase = RIPOSO;
        break;


tralasciano per ora le soglie del voltaggio in ingresso che sto tenendo molto basse per il problema esposto nel post #36 (cariche elettrostatiche) e che spero di risolvere acquistando un sensore di livello acqua (per ora sto facendo le prove con i cavetti dupont simulando contatto e apertura).
Colgo l'occasione per ringraziarti dell'aiuto anche perchè stamattina ho avuto un calo di autostima e stavo per buttare tutto dalla finestra  :smiley-mr-green:

Maurotec

La fase di riempimento può essere divisa in più fasi.
1° Controlla se la vasca è vuota, se lo è passa alla fase successiva il cui nome potrebbe essere RIEMPIMENTO_START. Mentre se la vasca è piena si salta RIEMPIMENTO_START.

La fase RIEMPIMENTO_START si limita ad alimentare l'elettrovalvola e passa alla fase successiva che ha il compito di verificare quando la vasca è piena, quando lo è si va alla fase successiva, fintanto che non lo è si rimane in questa fase.

Le fasi o stati possono statiche o dinamiche, tutto ciò che è statico lo si sa prima e lo si può definire ad esempio tramite un array.  Lo switch case è solo un modo di implementare la macchina a stati finiti ma noi per semplificare lo riteniamo essere l'unico modo. Quando una applicazione richiede due macchine a stati una dinamica e una statica servono ad esempio due switch case e quindi due variabili indipendenti.

La suddivisione evita ad esempio la necessità di questo while
Code: [Select]

while (analogRead(pinTroppopieno) <= 5) //soglia di prova
        {
        digitalWrite(pinElettrovalvola, SPENTO);
        }


Hai serial.print usalo, per evitare che stampi sempre sempre la stessa stringa serve una variabile che mantiene il valore della fase precedente.

Quote
fai finta di essere Arduino ed esegui tu il programma che hai scritto.
Non ti calare troppo nella parte altrimenti rischi di non uscirne e rimarrai arduino per sempre. :)

Ciao.

Claudio_FF

#41
May 26, 2019, 06:54 pm Last Edit: May 26, 2019, 07:54 pm by Claudio_FF
Quote
il problema esposto nel post #36 (cariche elettrostatiche) e che spero di risolvere acquistando un sensore di livello acqua (per ora sto facendo le prove con i cavetti dupont simulando contatto e apertura).
Il problema si risolve con una normalissima resistenza di pull-up o pull-down da 1..10k come per leggere qualsiasi pulsante. Non ho però ancora capito se il contatto di troppo pieno deve dare un livello alto o basso, e neppure perché lo vuoi leggere con analogRead invece di digitalRead... devi leggere un contatto o un potenziometro?

Quote
Al momento ho risolto così e sembra funzionare
Il codice che hai scritto secondo me fa questo:



Giusto degli esempi... cosa succede se la lettura vale 2?
Cosa succede se  dopo un secondo lettura vale 40?
Cosa succede se dopo un secondo lettura vale 100?

Il programma prima che su Arduino deve funzionare correttamente su carta... e naturalmente le prove reali non si possono fare con ingressi fluttuanti di cui non si è sicuri che livello abbiano.

Quote
stamattina ho avuto un calo di autostima e stavo per buttare tutto dalla finestra  :smiley-mr-green:
Hai detto tu: «Vi prego dunque di aiutarmi a capire cosa non capisco», quindi nessun errore verrà abbonato  ;D  :smiley-twist:





Quote
La suddivisione evita ad esempio la necessità di questo while
È quello che ho cercato di evidenziare con lo schema post #34, la valvola viene già aperta nella fase precedente, e rimane solo da controllare se è stato raggiunto il troppo pieno, senza bisogno di nessun while di attesa... la struttura a fasi è fatta proprio per questo, ma ammetto che inizialmente può essere difficile capire l'ordine in cui avvengono le cose per cui si cerca di procedere nel solito modo sequenziale scrivendo codice bloccante (che in questo specifico caso comunque problemi non ne da).

Quote
Non ti calare troppo nella parte altrimenti rischi di non uscirne e rimarrai arduino per sempre.
:smiley-mr-green:  :smiley-mr-green:  :smiley-mr-green:
Una domanda ben posta è già mezza risposta.

karnhack

#42
May 26, 2019, 07:46 pm Last Edit: May 26, 2019, 07:50 pm by karnhack
Il problema si risolve con una normalissima resistenza di pull-up o pull-down da 1..10k come per leggere qualsiasi pulsante. Non ho però ancora capito se il contatto di troppo pieno deve dare un livello alto o basso, e neppure perché lo vuoi leggere con analogRead invece di digitalRead... devi leggere un contatto o un potenziometro?
 :smiley-mr-green:  :smiley-mr-green:  :smiley-mr-green:
All'inizio pensavo di fare una cosa semplicissima e cioè due fili d'acciaio posti uno di fianco all'altro, uno preleva i 5v da arduino l'altro va a finire in A0, quindi l'acqua avrebbe fatto da contatto aperto/chiuso... ma non sapevo delle cariche elettrostatiche. Come infatti le prime "quote" che avevo messo erano 0 e 1023 quindi:

Code: [Select]
case RIEMPIMENTO:
      if (analogRead(pinTroppopieno) = 1023) {   
          digitalWrite(pinElettrovalvola, ACCESO);
          delay(2000);
        }
        while (analogRead(pinTroppopieno) <= 0)
        {
        digitalWrite(pinElettrovalvola, SPENTO);
        }


Poi dopo aver constatato che il mondo ideale non è quello reale, ho pensato di andare a controllare i valori aggiungendo la riga:

Code: [Select]
int sensorValue = analogRead(A0);
      Serial.println(sensorValue, DEC);


Fatto questo mi sono accorto che con i contatti aperti c'erano delle oscillazioni notevoli da 100 a 1023 circa ed ho inserito un valore di "sicurezza" cioè >=50 per verificare che la variabile funzionasse. Stessa cosa ho fatto con i contatti chiusi... mi sono tenuto largo ed invece di mettere 0 ho messo <=5. Ma li ho messi solo come valore di prova pensando che i sensori di pioggia/acqua (che non ho è che dovrò comprare) abbiano la resistenza che li protegge dalle cariche elettrostatiche e che quindi, successivamente, col sensore in mano avrei poi stabilito i valori di soglia reali.

Il codice che hai scritto secondo me fa questo:



Mi sa che hai ragione

Hai detto tu: «Vi prego dunque di aiutarmi a capire cosa non capisco», quindi nessun errore verrà abbonato  ;D  :smiley-twist: 
La mia condizione attuale è che per la prima volta sto maneggiando codice C o arduinese, non so neanche se c'è una vera differenza. La pazienza e la buona volontà c'è, però mi trovo difronte a diverse difficoltà:
- Non conosco l'elettronca
- Non conosco gli operatori Arduino
- Se vado a leggermi le guide ho comunque difficoltà a capirle a causa di terminologie che per me indicano tutt'altra cosa se non addirittura nulla (array, macro, boolean ecc). Dunque per comprendere una spiegazione impiego il doppio del tempo  perchè non ho riferimenti e tutto i nomi usati sono per lo più sconosciuti.

Sono d'accordo e non voglio abbonato nessun errore, però quello che ti chiedo ovviamente ringraziandoti per la cortesia e la pazienza, è di non darmi tutti gli strumenti in mano perché altrimenti mi perdo e mi scoraggio. Dammi quello che è strettamente necessario per ora e lavoriamo su quelli perché se mentre cerco di padroneggiare l' IF entra lo SWICH col CASE, poi entra BOOL non ne esco... ovviamente non è una pretesa, ci mancherebbe altro, quello che ho capito in due giorni non l'avevo capito in due anni di copia e incolla.

@Maurotec questo è anche il motivo per cui non ti ho fatto la domanda:
PS: lo so, la domanda è; da dove spuntano fuori uint8_t, uint16_t ecc?

Vi ringrazio ancora

Claudio_FF

#43
May 26, 2019, 08:24 pm Last Edit: May 26, 2019, 11:12 pm by Claudio_FF
All'inizio pensavo di fare una cosa semplicissima e cioè due fili d'acciaio posti uno di fianco all'altro, uno preleva i 5v da arduino l'altro va a finire in A0, quindi l'acqua avrebbe fatto da contatto aperto/chiuso... ma non sapevo delle cariche elettrostatiche.
Come detto nel post #41 il problema c'è solo se l'ingresso è lasciato scollegato, metti una R da 10k verso massa e hai risolto. Con i due fili di acciaio piuttosto avresti il problema dell'elettrolisi, basta mettere nell'acqua i poli di una batteria 9V per vederla. Vediamo come sono questi sensori.

Per quanto riguarda gli strumenti ho cercato di proporre la struttura minima base generale per risolvere tutti i problemi una volta per sempre. Se seguivi paro paro lo schema post #34 avevi già finito ;) Ogni rettangolo è un case, e dentro ai case una o due righe di programma (non credo si possa fare molto di meno e soprattutto così flessibile e modificabile). Il case RIEMPIMENTO l'ho già scritto completo nel post #38. Se non piace lo switch c'è sempre la corrispondente forma a soli 'if' nel post #15.



Quote
PS: lo so, la domanda è; da dove spuntano fuori uint8_t, uint16_t ecc?
https://forum.arduino.cc/index.php?topic=583927.msg3980712#msg3980712
Una domanda ben posta è già mezza risposta.

Maurotec

Quote
Dammi quello che è strettamente necessario per ora e lavoriamo su quelli perché se mentre cerco di padroneggiare l' IF entra lo SWICH col CASE, poi entra BOOL non ne esco... ovviamente non è una pretesa, ci mancherebbe altro, quello che ho capito in due giorni non l'avevo capito in due anni di copia e incolla.
Mi metto nei tuoi panni, so perfettamente cosa intendi, purtroppo noi abbiamo conoscenza di tutti gli strumenti offerti dal linguaggio e inevitabilmente tendiamo ad usare il martello per piantare e la pinza per afferrare.
Però è anche vero che se al momento disponi del solo cacciavite se serve lo usi pure a mo di martello. :)

Le conseguenze al momento non sono evidenti, ti voglio a capirci qualche cosa quando il numero delle variabili arriva a 50, più le costanti, più le funzioni, più gli switch, più gli if ecc, se poi usiamo pure i tipi di variabile a caso non sarà più possibile introdurre modifiche al codice senza comprometterne il funzionamento.

Quote
- Non conosco l'elettronca
- Non conosco gli operatori Arduino
- Se vado a leggermi le guide ho comunque difficoltà a capirle a causa di terminologie che per me indicano tutt'altra cosa se non addirittura nulla (array, macro, boolean ecc). Dunque per comprendere una spiegazione impiego il doppio del tempo  perchè non ho riferimenti e tutto i nomi usati sono per lo più sconosciuti.
Quote
quello che ho capito in due giorni non l'avevo capito in due anni di copia e incolla.
Posso girare la frittata, dicendo che hai perso due anni a copiare ed incollare senza ottenere quello che desideravi. Rigirandola nuovamente dico che è andata così solo perché non hai trovato un programma che con poche modifiche si adattava alle tue necessità. :)

Ma ora la situazione (STATO corrente) è questa: sei disposto a studiare quello che serve al fine di crearti la tua applicazione, nonostante alle volte tu possa trovarti nello stato "CARENZA_DI_AUTOSTIMA", in conseguenza di ciò hai anche previsto un CASE  BUTTARE_TUTTO_DALLA_FINESTRA, CASE che fino a questo momento non hai deciso di eseguire. :) 

Ciao.

Go Up