Aiuto per il mio primo sketch

Buongiorno a tutti,
seguendo il consiglio di Guglielmo, ma essendo novizio nel mondo di Arduino, mi sono letto tutte le pubblicazioni consigliate, però so che qualcosa mi manca, per far funzionare come vorrei il tutto, posso chiedervi se potete darmi una mano? Grazie mille
`

// FUNZIONAMENTO
// 1. Il treno viene rilevato da uno dei sensori IR
// 2. Inizia il suono della campanella e si accendono i led rossi 2 per lato in modo alternato.
// 3. Dopo 5 sec. iniziano a scendere le barriere e continua il suono della campanella ed i led restano accesi.
// 4. A barriere abbassate dopo 5 sec. si ferma la campanella e restano i led accesi fissi.
// 5. Rimane questa condizione fin quando il treno impegna ancora il secondo IR dello stesso binario.
// 6. Liberato il secondo IR le sbarre si alzano i led rimango accesi
// 7. A barriere completamente alzate i led si spengono dopo 2 sec.

#include <Servo.h>

#define servoPin 2
#define IR1 3
#define IR2 4
#define ledSemaf_int_1 5
#define ledSemaf_int_2 6
#define ledSemaf_est_1 7
#define ledSemaf_est_2 8
#define campanella 9

#define posMin 0
#define posMax 20
#define timePL 10

boolean statoPL = false;
int currentGrad = posMax;

Servo myservo;

void setup() {

  pinMode(servoPin, OUTPUT);
  pinMode(IR1, INPUT);
  pinMode(IR2, INPUT);
  pinMode(ledSemaf_int_1, OUTPUT);
  pinMode(ledSemaf_int_2, OUTPUT);
  pinMode(ledSemaf_est_1, OUTPUT);
  pinMode(ledSemaf_est_2, OUTPUT);
  pinMode(campanella, OUTPUT);

  myservo.attach(servoPin);
  myservo.write(currentGrad);
}

void loop() {
  digitalRead(IR1);                                  //legge lo stato del sensore IR1
  digitalRead(IR2);                                  //legge lo stato del sensore IR2
  if (digitalRead(IR1) == HIGH) { statoPL = true; }  //se il sensore è alto presenza treno
  if (digitalRead(IR2) == HIGH) { statoPL = true; }  //se il sensore è alto presenza treno
  digitalWrite( campanella, HIGH ); 
  digitalWrite(ledSemaf_int_1, HIGH); // se la condizione degli IR è HIGH (quindi con il treno) si accendono i led 
  digitalWrite(ledSemaf_int_2, LOW);
  digitalWrite(ledSemaf_est_1, HIGH);
  digitalWrite(ledSemaf_est_2, LOW);
  delay(1000);// attesa di un secondo per altenare i led
  digitalWrite(ledSemaf_int_1, LOW);
  digitalWrite(ledSemaf_int_2, HIGH);
  digitalWrite(ledSemaf_est_1, LOW);
  digitalWrite(ledSemaf_est_2, HIGH);
  delay(1000);// attesa di un secondo per altenare i led
if ( statoPL == true && currentGrad > posMin) 
while (currentGrad > posMin) {
currentGrad--;
myservo.write(currentGrad);
delay(timePL);
}
if ( statoPL == false && currentGrad < posMax) {
while (currentGrad < posMax) {
currentGrad++;
myservo.write(currentGrad);
delay(timePL);
}
}
}

`

grazie mille per l'aiuto

Per evitarci di dover ricostruire i tuoi passati messaggi, potresti dire se per "funzionare come vorrei" intendi le prime righe con i commenti? Ed in realtà cosa succede invece?

Grazie DOC, succede che, se mi metto davanti ai sensori , parte la campanella i led lampeggiano in modo alternato, ma il servo non si muove, questo è il primo problema.

Potrebbe essere un problema di cablaggio più che di codice.
Puoi postare uno schema dei collegamenti (anche fatto a mano e fotografato, basta che sia leggibile) ed eventualmente anche una foto? Come hai alimentato il servo?

Ok, ma in quello schema non si vede l'alimentazione del servo (ed anche del resto), non c'è nessun alimentatore o batteria disegnata che porti i +5V ai servo. Quindi, ripeto: come alimenti i servo? Hai un alimentatore separato? Usi lo stesso di Arduino? Batterie? E come è connesso?

Perdona non lo messa ,è alimanta da Arduinio con il filo rosso sulla basetta, aggiorno foto, comunque il servo non parte dopo due secondi ed i led si accendono anche se i rilevatori (che nel mio caso sono due sensori IR emittente/ricevente sulla stessa shield) non hanno nulla davanti

Ok, ora è un po' più chiaro. Io generalmente alimento separatamente i servo (Arduino non è in grado di erogare molta corrente), comunque con uno solo potrebbe anche funzionare.

Ma questa cosa te la fa anche sull'emulatore? Se usi Wokwi o Tinkercad, condividi qui anche il link al progetto così vediamo direttamente e possiamo provare lo sketch.

Come diceva DocDoc i servi vanno alimentati a parte, non con arduino, neanche se sono microservi, e per muoverli da una posizione al prossimo step, non mi ricordo bene ma 10 millisecondi mi sembrano pochi.
E cmq l'attesa che si completi il ciclo ti ferma il resto del loop,devi togliere while (currentGrad < posMax) {
E la massa dell'alimentatore deve essere in comune con la massa di Arduino

Sono pochi

Il ciclo PPM dei servo dura 20ms

Ah ecco, cmq gli blocca il loop se non toglie quel while (currentGrad < posMax) {.
Poi se gli dai anche 6V con l'alimentatore i servi sono + contenti

Vi ringrazio per l'aiuto, e sicuramente alimenterò il servo con un altra alimentazione , ora non capisco come mai si accendono i led e si muove il sevo anche se non ce ostacoli davanti gli IR.
io vorrei:

  • che gli ir vedano l'ostacolo
  • partono i led e la campanella
  • 2 sec dopo si muove il servo .
    questo è il link:

grazie ancora

Che è esattamente quello che gli fai fare tu

Le prime due if sono tutte su una riga sola

Suoneria e led NON sono sotto if

Inoltre tu metti alta la variabile statopl
Ma non la riabbassi mai

Rileggiti bene il tuo programma, perche non è ben studiato

Scusami ma non ho capito è la prima volta che faccio un programma, mi sono letto 10 libri in una settimana . Mi puoi spiegare grazie

Pretendi troppo da te. Comunque considera che questo problema lo hanno tutti i principianti, infatti di post simili al tuo il forum è pieno. Il problema è nell'uso della funzione delay(). Questa funzione in gergo diciamo che è "bloccante", detta in termini più sofisticati si dice "monopolizzare l'uso della CPU", semplificando: la funzione delay(t) detiene il controllo per t tempo.

L'effetto di detenere il controllo per t tempo è quello di ritardare l'esecuzione della prossima "istruzione" e tutte quelle a seguire.

Nessun programma che legge l'input e reagisce in breve tempo è compatibile con l'uso della funzione delay().

La soluzione è che invece di ritardare l'esecuzione della prossima "istruzione", si seleziona una porzione di codice quando la si vuole eseguire. La selezione è fatta con l'uso della funzione millis() in combinazione di if.

Per mostrarti un esempio in breve tempo, uso il seguente pseudocodice:

IF (IL_TEMPO_E_SCADUTO) {
    IF (SERVO.pos < maxPos)     
         SERVO.pos++
}

Ti lascio alcuni link:

Da cui puoi prendere spunto per l'uso di millis(). Dovresti anche notare che nessuno di quei programmi fa uso della funzione delay().

Ciao.

Il problema li non è millis

O almeno non ancora

Beh, intanto per rendere il codice più leggibile devi usare una indentazione quantomeno quella "standard". Se premi Ctrl-T nell'IDE te lo fa lui, poi usa sempre quella impostazione.

Poi quando si affrontano algoritmi da implementare (quindi anche programmini come questo), specialmente se non si ha ancora molta esperienza, è sempre utile partire dai commenti per descrivere il processo (indentando anche questi), e quando vedi che "funziona" provandolo a mente o su carta, allora ogni commento lo "traduci" nel relativo codice.

Nel tuo caso quindi, come già ti hanno giustamente sottolineato, tu nel loop() fai subito suonare la campanella e tutto il resto. Devi invece far lavorare il codice solo quando il sistema rileva la presenza del treno, quindi tutto va messo quantomeno dentro ad una "if()".
Chiaramente ci sono vari modi di affrontare la cosa, compresa l'implementazione di una "macchina a stati finiti" o FSM ma per ora tralasciamo questo argomento visto che il tuo processo è praticamente sequenziale e non deve far altro nel frattempo (ma sappi che dovrai alla fine studiarti anche le FSM perché utilizzatissime in sistemi di controllo).

Tu hai fatto già una certa descrizione del funzionamento (quindi del solo loop()), per cui traducendola in commenti "stile Arduino" diventerebbero una cosa del tipo (occhio all'indentazione che mostra quali step fanno parte di if() o cicli while()):

// loop:
// ----------------------
  // Il treno viene rilevato da uno dei sensori IR? (è la "if()")
    // SI
    // inizia il suono della campanella 
    // ciclo per 5 secondi:
      // si accendono i led rossi 2 per lato in modo alternato.
    // ciclo di attesa discesa delle barriere:
      // Iniziano a scendere le barriere (continua il suono della campanella)
      // i led restano accesi.
    // Le barriere sono abbassate, attendi 5 sec
    // si ferma la campanella e restano i led accesi fissi.
    // ciclo attesa che il treno passi oltre il secondo IR
      // pausa (es. 500 ms)
    // Liberato il secondo IR, ciclo di attesa che le sbarre si alzino (i led rimango accesi)
      // pausa (es. 500 ms)
    // Le barriere sono ora completamente alzate!
    // pausa 2 secondi
    // spegni i led
  // fine if()
// ----------------------
// fine loop

Prova a d inserire questi commenti in un loop() vuoto, quindi "tradurre" in codice ogni step.

PS; quando la cosa funzionerà, potremo iniziare a spiegarti le FSM che nonostante possano inizialmente sembrarti una inutile complicazione, semplificano la logica e la rendono facilmente gestibile ed estensibile...

Grazie:
MaurotecTesla : ho compreso benissimo ed ora approfondisco l'argomento, e molto volentieri guardo ciò che hai linkato.

DatmanDATman quello lo letto su un manuale suggerito da Guglielmo, e non mi era molto chiaro, ora lo è di più; Ci provo a fare come avete detto.

docdocTesla: ciao uso la formattazione che è presente in arduino ma a volte non me la modifca .
Ti ringrazio per lo svolgimento utile, e sicuramente faro lo sviluppo di un loop nuovo per provare, per quanto rifuarda gli FSM non so cosa siamo, ma se ci sarà impararli.... Studiare non è un problema visto che la mia professione implica uno studio continuo.

Per il momento vi ringrazio provo a sistemare il tutto cogliendo i vostri consigli, e sicuramente vi rompero di nuovo le :grimacing:scatole :grimacing: su cosa accadrà.

Grazie

Ma anche no... Nello sketch puoi scrivere tutto come ti pare, non forza ad avere intendazioni particolari, potresti anche scrivere tutto a partire dalla prima colonna di ogni riga, non è importante per il compilatore perché sintatticamente è tutto corretto. Per farti capire, il loop del tuo sketch è così:

  if ( statoPL == true && currentGrad > posMin) 
    while (currentGrad > posMin) {
    currentGrad--;
    myservo.write(currentGrad);
    delay(timePL);
    }
  if (digitalRead(IR1) == LOW) { statoPL = false; }  //se il sensore è alto presenza treno
  if (digitalRead(IR2) == LOW) { statoPL = false; }
if ( statoPL == false && currentGrad < posMax) {
while (currentGrad < posMax) {
currentGrad++;
myservo.write(currentGrad);
delay(timePL);
}
}
}

Quelle tre graffe finali cosa chiudono? Messe così non si capisce nulla, e devi cercare ad ogghio (o a mano) a ritroso contando le graffe. Se premi Ctrl-T nell'IDE Arduino, te le riformatta lui e diventano così:

void loop() {
  digitalRead(IR1);                                  //legge lo stato del sensore IR1
  digitalRead(IR2);                                  //legge lo stato del sensore IR2
  if (digitalRead(IR1) == HIGH) { statoPL = true; }  //se il sensore è alto presenza treno
  if (digitalRead(IR2) == HIGH) { statoPL = true; }  //se il sensore è alto presenza treno
  digitalWrite(campanella, HIGH);
  digitalWrite(ledSemaf_int_1, HIGH);  // se la condizione degli IR è HIGH (quindi con il treno) si accendono i led
  digitalWrite(ledSemaf_int_2, LOW);
  digitalWrite(ledSemaf_est_1, HIGH);
  digitalWrite(ledSemaf_est_2, LOW);
  delay(500);  // attesa di un secondo per altenare i led
  digitalWrite(ledSemaf_int_1, LOW);
  digitalWrite(ledSemaf_int_2, HIGH);
  digitalWrite(ledSemaf_est_1, LOW);
  digitalWrite(ledSemaf_est_2, HIGH);
  delay(500);  // attesa di un secondo per altenare i led

  if (statoPL == true && currentGrad > posMin)
    while (currentGrad > posMin) {
      currentGrad--;
      myservo.write(currentGrad);
      delay(timePL);
    }
  if (digitalRead(IR1) == LOW) { statoPL = false; }  //se il sensore è alto presenza treno
  if (digitalRead(IR2) == LOW) { statoPL = false; }
  if (statoPL == false && currentGrad < posMax) {
    while (currentGrad < posMax) {
      currentGrad++;
      myservo.write(currentGrad);
      delay(timePL);
    }
  }
}

Ora ad occhio è tutto più chiaro, basta un'occhiata per capire la struttura.
Poi ci sono alcune ottimizzazioni possibili (che non influenzano il tuo codice, è solo un esempio, non entro nella logica, e ricorda che devi sempre rivedere il programma per implementare correttamente la sequenza) come ad esempio invece di:

  if (digitalRead(IR1) == LOW) { statoPL = false; }  //se il sensore è alto presenza treno
  if (digitalRead(IR2) == LOW) { statoPL = false; }

che contiene delle inutili graffe, puoi ad esempio scrivere un più leggibile e commentato:

  // Lo stato è "true" se almeno uno dei due IR è LOV
  statoPL = (digitalRead(IR1) == LOW) || (digitalRead(IR2) == LOW);

Bene, quindi ora prova a fare come ti ho consigliato, parti dai commenti ed inizia a scrivere il codice sotto. E se hai problemi, posta quello che hai scritto e dicci cos'è che non ti convince, non capisci, o non riesci a fare.

Sicuro, ma tranquillo, ti si spiegherà tutto appena avrai fatto almeno questa prima parte (non vogliamo darti la "pappa pronta" perché altrimenti non si capisce), e con qualche esempio dovresti riuscire a capire rapidamente il concetto delle macchine a stati finiti.