Ritardo fotocellule e funzione delay ridondante

Salutando e ringraziando anticipatamente per la cortesia, vi spiego il mio problema:
Ho creato un sistema composto da due motori stepper e due fotocellule che voglio definire "trasportatore". I due motori muovono due cinghie che devono portare una serie di oggetti da una parte all'altra di un nastro convogliatore, la prima fotocellula ha la funzione di attivare il trasportatore quando un oggetto si presenta davanti alla fotocellula stessa, mentre la seconda fotocellula, posizionata all'uscita del trasportatore, deve fermare il trasportatore nel caso in cui si formi una "coda" di oggetti in accumulo. A tutto questo ho aggiunto due pulsanti per incrementare e decrementare la velocità degli stepper, che girano in senso opposto uno all'altro, e ho montato un display a due righe per visualizzare la velocità impostata.
Il codice che ho scritto fa esattamente quello che vi ho appena descritto, ma il mio problema nasce dal fatto che, giunto fino a qui, dovrei anche impostare un ritardo dell'intervento delle fotocellule in quanto la loro azione immediata non è funzionale al sistema. Per esempio, nel momento in cui la fotocellula in ingresso è stata attivata da un oggetto in arrivo, nel momento in cui si libera devo attendere che l'oggetto stesso sia passato dall'atra parte del trasportatore, perché diversamente è un continuo di stop&go. Idem per quella in uscita.
E qui arriva il mio problema: il comando delay, che ho utilizzato (forse) in modo troppo esteso, non posso più utilizzarlo in quanto mi rallenta i motori fino a fermarli.
Allego il mio codice:

#include <Wire.h> 
#include <EEPROM.h> //libreria relativa alla lettura e scrittura sulla EEPROM
#include <PCF8574_HD44780_I2C.h> //Gestione del monitor LCD
PCF8574_HD44780_I2C lcd(0x27,16,2);

const int buttonUpPin = 8;  //numero pin a cui è collegato il pulsante di UP
const int buttonDownPin = 9;  //numero pin a cui è collegato il pulsante di DOWN
int buttonUpState;  //stato attuale del pulsante di UP
int buttonDownState;  //stato attuale del pulsante di Down
long UpDebounceTime;  //Variabilie di appoggio per calcolare il tempo di cambio di stato del pulsante di UP
long UpDebounceTimeF1;
long UpDebounceTimeF2;
long DownDebounceTime;  //Variabilie di appoggio per calcolare il tempo di cambio di stato del pulsante di Down
long DownDebounceTimeF1;
long DownDebounceTimeF2;
long timerButtonPushed; //tempo che indica da quanto è stato premuto il pulsante
long timerPauseRepeat;  //tempo che indica da quanto è stata fatta l'ultima ripetizione
long time_add_10 = 1000;  //costante per attivare ripetizione da +10
long time_add_100 = 5000; //costante per attivare ripetizione da +100
long time_pause = 250;  //costante che determina il tempo di ripetizione di UP e di DOWN
long debounceDelay = 80; //Tempo di debounce per i pulsanti UP e DOWN
boolean repeatEnable = LOW; //memoria che indica il repeat del pulsante attivo
unsigned int counter = 0; //dichiaro un contatore che mi servirà per il delay della fotocellula 1
int var = 0;  //variabile da aumentare o diminuire come valore
const int varMax = 100; //limite massimo valore della variabile
const int varMin = 0; //limite minimo valore della variabile

int readingUp = 0;  //Lettura ingresso digitale del pulsante di UP
int readingDown = 0;  //Lettura ingresso digitale del pulsante di Down
byte DatoEEprom; // dichiaro il dato che salverò sulla EEPROM


// Definisco i pin per lo stepper:

#define dirPin2 2 //definisco il pin che stabilisce la direzione del motore 1
#define stepPin3 3 //definisco il pin che stabilisce lo step del motore 1
#define dirPin4 4 //idem C.S.
#define stepPin5 5 //idem C.S.
#define pinsensor_1 6 //fotocellula in ingresso
#define pinsensor_2 7 //fotocellula in uscita

int val1 = 0;
int val2 = 0;

void setup() {

  lcd.init();           // Inizializzo LCD              
  lcd.backlight();      // Backlight ON
  lcd.clear();          // pulisce lo screen
  
  lcd.setCursor(0,0);   // porta il cursore a colonna 0, riga 0
  lcd.print("PROVA PROVA");   // Prima riga
  lcd.setCursor(0,1);   // porta il cursore a colonna 0, riga 0
  lcd.print("PROVA");
  delay(3000);
  lcd.clear();
  lcd.print("PROVA");   // Prima riga
  lcd.setCursor(0,1);   // porta il cursore a colonna 0, riga 0
  lcd.print("PROVA2");
  delay (2000);
  lcd.setCursor(0,0);   // porta il cursore a colonna 0, riga 0
  lcd.print("REGOLAZ.VELOCITA'");   // Prima riga
  lcd.setCursor(0,1);   // porta il cursore a colonna 0, riga 0
  lcd.print("-             +");
 

DatoEEprom = EEPROM.read(1); //Leggo il dato salvato sulla EEPROM nello slot 1
  var = EEPROM.read(1);
  
  Serial.begin(9600);  // impostazione baudrate seriale
  pinMode (buttonUpPin, INPUT); //impostazione buttonUpPin come ingresso
  pinMode (buttonDownPin, INPUT); //impostazione buttonDownPin come ingresso
  
   // Dichiaro i PIN di output:
  
  pinMode(stepPin3, OUTPUT);
  pinMode(dirPin2, OUTPUT);
  pinMode(stepPin5, OUTPUT);
  pinMode(dirPin4, OUTPUT);
  pinMode(pinsensor_1, INPUT);
  
  // imposto la direzione dei motori:
   digitalWrite(dirPin2, HIGH); //il motore 1 gira in senso ANTIORARIO
   digitalWrite(dirPin4, HIGH); //il motore 2 gira in senso ORARIO (Attenzione: nel caso dei NEMA13 non so perché ma in questo caso era LOW e non HIGH. Mistero).
}

void loop() {

readButtonState();  //Lettura stato buttons con controllo antirimbalzo
  if (buttonUpState == HIGH || buttonDownState == HIGH) {
    if ((repeatEnable == HIGH && ((millis() - timerPauseRepeat) > time_pause)) || repeatEnable == LOW) {
      if ((millis() - timerButtonPushed) > time_add_10) {
        if ((millis() - timerButtonPushed) > time_add_100) {
          if (buttonUpState == HIGH) var = var + 100;
          if (buttonDownState == HIGH) var = var - 100;
        } else {
          int resto = 0;
          if (buttonUpState == HIGH) resto = 10 - (var % 10);
          if (buttonDownState == HIGH) resto = (var % 10);
          if (resto == 0){
            if (buttonUpState == HIGH) var = var + 10;
            if (buttonDownState == HIGH) var = var - 10;
          } else{
            if (buttonUpState == HIGH) var = var + resto;
            if (buttonDownState == HIGH) var = var - resto; 
          }       
        }
      } else {
        if (buttonUpState == HIGH) var++;
        if (buttonDownState == HIGH) var--;
     
      }
      timerPauseRepeat = millis();
      repeatEnable = HIGH;
      if (var > varMax) var = varMax;
      if (var < varMin) var = varMin;
      Serial.println(var);
    
      EEPROM.write(1, var);

      //***qui inizia la procedura per lo screeen LCD***
        lcd.clear();
        lcd.setCursor(0,0);   // porta il cursore a colonna 0, riga 0
  lcd.print("   VELOCITA'");   // Prima riga
  lcd.setCursor(0,1);   // porta il cursore a colonna 0, riga 0   
   var = EEPROM.read(1);
    lcd.print(varMax - var); //questo mi serve per visualizzare la velocità correttamente, diversamente la vedrei decrescere invece che incrementarsi
    }

  } else {
    timerButtonPushed = millis();
    timerPauseRepeat = millis();
    repeatEnable = LOW;
  }
}

void readButtonState() {
  int readingUp = digitalRead(buttonUpPin); //Lettura ingresso digitale del pulsante di UP
  int readingDown = digitalRead(buttonDownPin); //Lettura ingresso digitale del pulsante di Down
  if (readingUp == HIGH) {
    if ((millis() - UpDebounceTime) > debounceDelay) {
      buttonUpState = HIGH;
    }
  } else {
    buttonUpState = LOW;
    UpDebounceTime = millis();
  }

  if (readingDown == HIGH) {
    if ((millis() - DownDebounceTime) > debounceDelay) {
      buttonDownState = HIGH;
    }
  } else {
    buttonDownState = LOW;
    DownDebounceTime = millis();
  }
  val1 = digitalRead(pinsensor_1);
  val2 = digitalRead(pinsensor_2);
  
  
  if (val1 == HIGH)
  if (val2 == LOW)

 { 
  digitalWrite(stepPin3, HIGH);
  digitalWrite(stepPin3, LOW);
  digitalWrite(stepPin5, HIGH);
  digitalWrite(stepPin5, LOW);
delayMicroseconds(var); //questo è il valore che determina la velocità

 }
}


Buongiorno e benvenuto, :slight_smile:
essendo il tuo primo post, nel rispetto del regolamento della sezione Italiana del forum (… punto 13, primo capoverso), ti chiedo cortesemente di presentarti IN QUESTO THREAD (spiegando bene quali conoscenze hai di elettronica e di programmazione ... possibilmente evitando di scrivere solo una riga di saluto) e di leggere con molta attenzione tutto il succitato REGOLAMENTO ... Grazie. :slight_smile:

Guglielmo

P.S.: Ti ricordo che, purtroppo, fino a quando non sarà fatta la presentazione nell’apposito thread, nel rispetto del suddetto regolamento nessuno ti risponderà (eventuali risposte verrebbero cancellate), quindi ti consiglio di farla al più presto. :wink:

Grazie per il suggerimento, mi era sfuggito. Ho fatto le dovute presentazioni.
Buona giornata,
Aldo

Benvenuto, Aldo! :slight_smile:

Copia millis() in una variabile unsigned long, p.e.
unsigned long t_usc_1=millis();
ogni volta che un oggetto libera la prima fotocellula: in questo modo nella variabile avrai il momento in cui l'ultimo oggetto è transitato; poi, con
if (millis()-t_usc_1 > tempo_di_transito_in_ms)
potresti fermare il nastro senza usare l'altra fotocellula, perché in quel tempo l'ultimo oggetto deve essere uscito.

Grazie mille DATman per il tuo consiglio! In effetti la funzione millis() era entrata nel raggio d'azione delle mie attenzioni, ma per ignoranza l'avevo utilizzata in modo pedissequo e non con cognizione di causa.
P.S.
Mi piace il nickname DATman... se avessi seguito la tua stessa logica, avrei dovuto chiamarmi BOBIN, visto che ho iniziato coi registratori a bobina. Avremmo fatto DATMAN e BOBIN.
Chiedo perdono per la battutaccia.
Saluti e grazie

1 Like

Stupenda!!!
Mi piace :slight_smile:

Disgressione sul tema:
Ad ogni modo, caro Datman, la seconda fotocellula in uscita mi serve comunque (a meno che tu non abbia una soluzione più smart della mia, cosa che non escludo assolutamente): se nel nastro di uscita viene a formarsi una "coda" di oggetti fermi, io ho bisogno di fermare il nastro anche se la fotocellula in ingresso è temporaneamente libera, perché non devo fare in modo che in uscita si venga a formare un accumulo... non so se mi sono spiegato.

Datman e Bobin... Ancora rido... Grande

Tornando al problema, provo a dire la mia.
Hai 2 fotocellule, quindi in tutto 4 possibilità:
A - F1=0 - F2=0
B - F1=1 - F2=0
C - F1=0 - F2=1
D - F1=1 - F2=1
Dove 0 sta per libero e 1 per occupato.
Puoi definire una serie di azioni per ogni stato. Tipo (sparo a caso):
A = tutto libero, avanti nastro
B = uscita libera, avanti nastro
C = uscita occupata, nastro fermo
Ecc...

1 Like

Esatto, il flusso è quello, Fratt.
La mia problematica, e la soluzione suggeritami dal mio capo Datman (ormai sono entrato nella parte), è quella di utilizzare la funzione millis() per aggiungere un ritardo nell'azione delle fotocellule qualora venissero fatte intervenire dal passaggio di un oggetto, in quanto, per dare un senso anche a quello che tu mi hai gentilmente descritto, il funzionamento normale del mio nastro di collegamento è un passaggio continuo di oggetti che provengono da un nastro di trasporto 1 che deve essere collegato, tramite la mia soluzione, ad un nastro di trasporto 2, i quali sono indipendenti. Se il nastro 1 manda oggetti con continuità (immagina delle bottiglie che scorrono su un nastro trasportatore) la mia fotocellula interviene in continuazione e fa girare con continuità il nastro SOLO se ho impostato dei ritardi sia sulla fotocellula in ingresso, sia su quella in uscita. Se quella in ingresso rimane occupata per lungo tempo, non mi interessa più di tanto, io faccio girare comunque il mio nastro. Se invece la fotocellula in uscita rimane occupata, ecco che ho una occlusione in uscita e devo fermare il mio nastro sennò ingolferò l'uscita.
That's the case.
Saluti carissimi anche a te, e grazie per l'interessamento.
Aldo

1 Like

Ho provato a dare uno sguardo al software, ma al terzo if concatenato mi viene il mal di testa..

Scherzi a parte, come ha ben sintetizzato @fratt ti conviene usare una piccola macchina a stati finiti, ovviamente NON bloccante e quindi l'utilizzo di millis() per le temporizzazioni è d'obbligo.

Il discorso della fotocellula con segnale di uscita ritardato è secondario a quel punto: può essere definito come uno stato distinto oppure "integrato" nel codice che gestisce la ftc.

Se dovessi farlo io ad esempio (che preferisco l'approccio alla C++ :sweat_smile:), definirei un oggetto generico che descrive il comportamento della fotocellula prevedendo tutte le casistiche che possono essere utili da usare poi nella FSM come e dove serve.
Tipo cosi:
image

Io farei una cosa molto più semplice.

Il tuo scopo è non verificare l'intasamento giusto?

long tempomassimo = 10000; // tempo massimo di permanenza dell'oggetto
long tempoultimopassaggio = 0;
bool ultimo_stato = LOW;
vodi loop() {
  if(digitalRead(fotocellula) == HIGH && ultimo_stato == LOW) { // passaggio dell'oggetto
    tempoultimopassaggio = millis();
    ultimo_stato = HIGH;
  }
  if(digitalRead(fotocellula) == LOW && ultimo_stato == HIGH) {  // oggetto passato (o non arrivato)
    tempoultimopassaggio = millis();
    ultimo_stato = LOW;
  }

  if(tempoultimopassaggio-millis() >= tempomassimo) {
    // CODA FERMA!
    // esegui qui il tuo codice di coda ferma!
  }
}

puoi anche aggiungerla ad un altro modo implementando un piccolo contaoggetti

int oggettisulnastro = 0;
bool dacontare_ingresso = false;
bool dacontare_uscita = false;
void loop() {
  if(digitalRead(fotocellula_ingresso) == HIGH && !dacontare_ingresso) {
    dacontare_ingresso = true;
    oggettisulnastro++;
  }
  
  if(digitalRead(fotocellula_ingresso) == LOW && dacontare_ingresso) {
    dacontare_ingresso = false;
  }

  // ora sappiamo quanti oggetti entrano, vediamo quanti escono
  if(digitalRead(fotocellula_uscita) == HIGH && !dacontare_uscita) {
    dacontare_uscita = true;
    oggettisulnastro--;
  }
  
  if(digitalRead(fotocellula_uscita) == LOW && dacontare_uscita) {
    dacontare_uscita = false;
  }

  // ora possiamo fare alcune verifiche tipo massimo elementi sul nastro:
 if(oggettisulnastro >= oggetti_massimi) {
    // ERRORE: troppi oggetti sul nastro
  }

}

Questi 2 metodi possono ovviamente essere uniti :wink:

Ho scritto in fretta quindi è possibile che nel codice ci siano errori, verifica e chiedi in caso

Grazie mille a tutti per le risposte,
Scusate l'assenza ma nel frattempo ho avuto da fare con una azienda cinese con sede in Sudafrica, che ultimamente ha parecchi clienti anche da queste parti, me compreso. Appena mi passa il mal di testa, spero domani, andrò a fare un test sulla soluzione passatami da Superlol, che ringrazio.
La "serie di IF" è dovuta al fastidioso bouncing dei pulsanti. Senza quella serie di IF ho dei fastidiosi "saltellamenti" dei dati di incremento/decremento dei pulsanti.

Grazie mille per la risposta, la provo al più presto, gentilissimo!

Come sempre, basta un condensatore da circa 100nF in parallelo a ciascun pulsante.

Lo provo subito... grazie.

In realtà sarebbe meglio una rete RC ...

@Aldus68 : segui questi possibili schemi in funzione di come sono collegati i tuoi pulsanti:

Guglielmo

Grazie infinite, con tutti questi contributi sarà un progetto perfetto!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.