Comandare più elettrovalvole con sensore prossimità

Ciao a tutti,
mio primo post qui...

vorrei utilizzare Arduino per controllare delle elettrovalvole tramite un sensore di prossimità.
Ho realizzato un prototipo con Arduino Nano, sensore di prossimità, e relè SSR per controllare le valvole. Sia gli ingressi del/dei sensori che le uscite per i relè SSR sono interfacciati tramite fotoaccoppiatori.
Questo sistema mi serve per lavare tramite getto d'acqua un attrezzo e successivamente asciugarlo tramite getto d'aria
Quando il sensore rileva la presenza dell'attrezzo attiva per 3 secondi il getto d'aqua e subito a seguire il getto di aria. Se l'attrezzo viene allontanato in qualunque momento la sequenza si deve interrompere.
Per verificare il principio di funzionamento ho realizzato un primo sketch molto banale con i famosi "Delay"...
Ora però vorrei realizzare un qualcosa di più serio e, grazie a questo forum ho capito che ero sulla strada completamente sbagliata ed ho riprovato con la funzione "Millis".

Purtroppo le mie conoscenze di programmazione sono molto basiche, direi primordiali, e mi sono arenato...

Vi allego lo sketch che con il quale sto provando, chiedendovi se potete darmi una mano su come impostare un corretto flusso e quali funzioni utilizzare per ottenere il mio scopo...
Grazie in anticipo per le dritte che vorrete darmi

PS: come vedete ho fatto un po' di prove e quindi forse è un pochino incasinato...
PS2: se la cosa può interessare ad altri posso poi postare circuito e PCB

Michele

// Attività da eseguire
// Quando si attiva il sensore Relè 1 va ON per 3 secondi poi OFF 
// e Relè 2 ON per 3 secondi poi off.
// se sensore va OFF relè 1 e relè 2 subito spenti

const int sens1Pin = 10; // Pin sensore prossimità
const int rel1Pin = 3;  // Pin relè elettrovalvola 1
const int rel2Pin = 5;  // Pin relè elettrovalvola 2
//const int rel3Pin = 6;  // Pin relè elettrovalvola 3 (in seguito servirà per riempire vasca di lavaggio)
 
unsigned long rel1OnTime;
unsigned long rel2OnTime;
//unsigned long rel3OnTime;
bool rel1On;
bool rel2On;
//bool rel3On;
bool statrel1;
bool statrel2;

 
void setup() {
 
  pinMode(rel1Pin, OUTPUT);
  pinMode(rel2Pin, OUTPUT);
// pinMode(rel3Pin, OUTPUT);
  pinMode(sens1Pin, INPUT);
  digitalWrite(sens1Pin, HIGH); //Abilita res.
  
 
  rel1On = false;
  rel2On = false;
//  rel3On = false;
  statrel1 = false;  // stato relè 1
  statrel2 = false;  // stato relè 2
}
 
void loop(){
 
  if (digitalRead(sens1Pin) == LOW) {    // Legge stato sensore
    digitalWrite(rel1Pin, HIGH);        // se sensore ON relè 1 ON 
    rel1On = true;                      // imposta varialbile stato relè 1 a TRUE
    rel1OnTime = millis();              // 
   }   
  else
 {  
  digitalWrite(rel1Pin, LOW);
 } 

  if (digitalRead(sens1Pin) == LOW && (statrel1 = false)) {
    digitalWrite(rel2Pin, HIGH);
     rel2On = true;
     rel2OnTime = millis();
}
else
 {  
  digitalWrite(rel2Pin, LOW);
 }
     
  
  if(rel1On) 
    if(millis() - rel1OnTime > 3000) {    // mantiene ON relè 1 per 3 secondi poi OFF
      digitalWrite(rel1Pin, LOW);
      rel1On = false;  
      if(statrel1 == false);
      statrel1 = true;
   }    
     
      else 
    {  statrel1 = false;
    }   
  
  if(rel2On) 
    if(millis() - rel2OnTime > 3000) {    // mantiene acceso relè 2 per 3 secondi poi OFF
      digitalWrite(rel2Pin, LOW);
      rel2On = false;  
      statrel2 = true;
    }  
 
}

Ciao, è più difficile capire il codice scritto da altri che scrivere uno proprio :slight_smile:

Io userei una macchina a stati finiti con una variabile che assume 3 valori.

Valore 0, spegne tutto

valore 1, avvia acqua temporizzata

valore 3, avvia aria temporizzata

================================

int stato=0;

void loop(){

//1 leggo il sensore

    if (digitalRead(sens1Pin) == LOW) {    // Legge stato sensore
        digitalWrite(rel1Pin, HIGH);        // se sensore ON relè 1 ON 
        stato=1;                   
        rel1OnTime = millis();              // 
    }   
   else if(digitalRead(sens1Pin) == HIGH){
        
         stato=0; //Spegne tutto

   }


 

 
     
  
  if(stato==1){
      if(millis() - rel1OnTime > 3000) {    // mantiene ON relè 1 per 3 secondi poi OFF
          digitalWrite(rel1Pin, LOW);
          digitalWrite(rel2Pin, HIGH);
          rel2OnTime = millis();
          stato=2; //Abilito aria temporizzata quando ha finito acqua
       }
   }    
     
   
  
  if(stato==2){
       if(millis() - rel2OnTime > 3000) {    // mantiene acceso relè 2 per 3 secondi poi OFF
           digitalWrite(rel2Pin, LOW);
          stato=0
       }  

  }


   if(stato==0){// se l'oggetto si allontana dal sensore spengo tutto
        digitalWrite(rel1Pin, LOW);
        digitalWrite(rel2Pin, LOW);
   }
}

Grazie mille per la risposta e l'aiuto
Ho provato lo sketch e rilevo che quando il sensore è ON il relè1 si attiva per un istante e poi subito OFF. Il relè 2 è sempre OFF

Se elimino l' else if i due relè funzionano correttamente tranne che, ovviamente, non vanno in OFF se il sensore si disattiva prima del tempo previsto....

Ho provato a capire il perchè, ma non capisco proprio come mai venga eseguito subito la parte di programma condizionata da else if

Prova a stampare il valore su seriale, in modo da capire se è il sensore che non funziona bene o il codice.

if (digitalRead(sens1Pin) == LOW) {    // Legge stato sensore
        digitalWrite(rel1Pin, HIGH);        // se sensore ON relè 1 ON 
        stato=1;                   
        rel1OnTime = millis();              // 
    }   
   else if(digitalRead(sens1Pin) == HIGH){
        
         stato=0; //Spegne tutto
         Serial.println(stato) ;// se stampa dopo poco tempo è la lettura del sensore che da HIGH

   }

Per essere sicuro del corretto funzionamento del sensore ho anche provato con un pulsante al suo posto.
Ho fatto un piccolo sketch di test e sul monitor leggo correttamente 0 a pulsante rilasciato e 1 a pulsante premuto.
(ho utilizzato una resistenza esterna di Pulldown per questo nel listato ho sostituito LOW con HIGH

void loop() {
 
  if (digitalRead(sens1Pin) == HIGH) {    // Legge stato sensore
        digitalWrite(rel1Pin, HIGH);        // se sensore ON relè 1 ON 
        stato=1;                   
            
    
    }   
   else if(digitalRead(sens1Pin) == LOW){
        digitalWrite(rel1Pin, LOW); 
        stato=0; //Spegne tutto
              
 }

Serial.println(stato);

}

Ricapitolando:
con il codice completo sul monitor leggo sempre 0 sia a sensore attivo che non attivo, ma a sensore attivo si attiva il relè 1 e si disattiva a sensore disattivato
Se elimino else if a sensore attivo leggo 1 e lo stato non cambia se non a sensore disattivo dove a questo punto inizia la sequenza che fa spegnere 1, accendere 2 spegnere 2

Serial print l'ho spostato fuori da else if altrimenti a sensore attivo non invia più dati

lo scketch che vuoi fare tu è molto semplice
mancano i "flag" che segnalano di proseguire se tutto "fila liscio"

e le poche situazioni possibili (compresa una mancanza momentanea di alimentazione) vanno previste
e ordinare allo scketch come comportarsi

ricordare che se mandi qualcosa HIGH/true rimarrà sempre HIGH/true se non prendi provvevimenti

Ho aggiunto un flag alla lettura del sensore, secondo me la logica è quella che ti posto, ma non riesco a trovare l'errore, else if del sensore dovrebbe essere eseguito solo se allontani il pezzo dal sensore, quindi zero solo se allontani il pezzo o finisci la lavorazione.

Codice modificato, Non trovo l'errore logico, a me pare che dovrebbe funzionare :frowning:

int stato=0;
byte flag=1; // flag che mi stabilisce se deve eseguire le operazioni, al termine del lavaggio il sensore è ancora 
             // attivo, senza un flag ripeterebbe le operazioni 
void loop(){

//1 leggo il sensore

    if (digitalRead(sens1Pin) == LOW && flag) {    // Legge stato sensore
        digitalWrite(rel1Pin, HIGH);        // se sensore ON relè 1 ON 
        stato=1;   
        flag=0;// ripete il lavaggio solo una volta fino allo scattare del sensore		
        rel1OnTime = millis();              // 
    }   
   else if(digitalRead(sens1Pin) == HIGH){ // il pezzo si è allontanato dal sensore
        
         stato=0; //Spegne tutto
         flag=1;
   }


 

 
     
  
  if(stato==1){
      if(millis() - rel1OnTime > 3000) {    // mantiene ON relè 1 per 3 secondi poi OFF
          digitalWrite(rel1Pin, LOW);
          digitalWrite(rel2Pin, HIGH);
          rel2OnTime = millis();
          stato=2; //Abilito aria temporizzata quando ha finito acqua
       }
   }    
  
  else if(stato==2){// Ho messo un else if, in modo che l'if è valutato solo se diverso da uno
                          // mentre con un un if, è valutato sempre anche quando non necessario

       if(millis() - rel2OnTime > 3000) {    // mantiene acceso relè 2 per 3 secondi poi OFF
           digitalWrite(rel2Pin, LOW);
           stato=0
       }  

  }


   if(stato==0){// terminato aria spegne tutto
        digitalWrite(rel1Pin, LOW);
        digitalWrite(rel2Pin, LOW);
   }
}

torn24:
Ho aggiunto un flag alla lettura del sensore, secondo me la logica è quella che ti posto, ma non riesco a trovare l'errore, else if del sensore dovrebbe essere eseguito solo se allontani il pezzo dal sensore, quindi zero solo se allontani il pezzo o finisci la lavorazione.

Codice modificato, Non trovo l'errore logico, a me pare che dovrebbe funzionare :frowning:

Grazie mille torn24, così come è impostato ora funziona perfettamente.
Non mi resta che testarlo sul campo...

Un paio di domande:
Volendo aggiungere il controllo di un terzo relè, che controlla il riempimento della vaschetta, è sufficiente inserire un terzo stato ?
La gestione del ritardo di spegnimento dei relè può essere gestita con dei potenziometri? Si complica troppo ?

Dipende da come vuoi gestire la vaschetta, SECONDO ME, se devi riempire la vaschetta ad ogni lavaggio all'ora userei un terzo stato, se invece devi riempirla dopo x lavaggi, userei una variabile contatore che arrivata a x lavaggi attiva il relè della vaschetta, questo con un codice a parte all'interno della funzione loop().

Mentre per stabilire la pausa con un potenziometro, ti basta leggere il potenziometro con analogRead() e usare la funzione map() per avere i valori voluti inseriti in una variabile, e poi usare la variabile al posto del tempo.