[RISOLTO] Segnapunti elettronico: testo lampeggiante e sensori ad ultrasuoni

Si ho provato con tre HC-SR04, e purtroppo non capisco perché mi danno tutti misurazioni sballate. Ad esempio uno appena l'ho collegato mi ha dato 179 cm poi 180cm poi 10 cm, 11 cm poi 0 cm e così via. Il tutto stando fermo senza mettere nessuno oggetto avanti.
A me non serve che misuri la distanza, ma che almeno mantenga la stessa lettura così che al diminuire possa mandare l'input ad un cicalino e al contatore sul display LCD.
Non ho aperto una nuova discussione perché è riferito allo stesso progetto dei messaggi precedenti. Magari provvederò a modificare il titolo

Ho risolto il discorso del sensore, però ho un problema con il buzzer attivo.
In pratica mi serve che al di sotto dei 3 cm deve suonare una volta sola, mentre al di sopra non deve suonare
questo è lo sketch (adattato uno preso in rete)

const int pinTrigger = 9;
const int pinEcho = 10;
const int cicalino = 7;

void setup() {

  pinMode(cicalino, OUTPUT);
  pinMode(pinTrigger, OUTPUT);
  pinMode(pinEcho, INPUT);
  Serial.begin(9600);
  Serial.print("Sensore Ultrasuoni: ");
}

void loop() {
  
  digitalWrite(pinTrigger, LOW);
  digitalWrite(pinTrigger, HIGH);
  delayMicroseconds(10);
  digitalWrite(pinTrigger, LOW);
  digitalWrite(cicalino, LOW);

  long durata = pulseIn(pinEcho, HIGH);
  long distanza = durata / 58;

  Serial.print("distanza: ");
  
  if (durata > 38000) {
    Serial.println("Fuori portata");
  } else {
    Serial.print(distanza);
    Serial.println(" cm");
  }
  if (distanza < 3) {
    digitalWrite(cicalino, HIGH);
    delay(500);
    digitalWrite(cicalino, LOW);
  } 
  delay(500);
}

Il problema è che al di sopra dei 3 cm emette un suono continuo, mentre al di sotto suona ad intervalli di 500 ms (come impostato nel delay), mentre a me occorre un singolo suono.
dove sbaglio?
premetto che a me non occorre il monitor seriale, l'ho inserito giusto in questa prova per capire meglio il funzionamento

Come è collegato il cicalino? Da quanto indichi sembra che si attivi con LOW. Pertanto è attivo fin dall'inizio e non si disattiva finché la distanza non è inferiore a 3 cm. In quel momento lo disattivi e dopo 500ms lo riattivi. E questo tante volte quante viene eseguito il loop e la distanza sia inferiore a 3 cm. Per tanto, sempre attivo meno quando distanza <3 che attivi per 500ms, per ogni volta nel loop.
Se attivato con HIGH, suonerà solo quando la distanza è < 3 cm (e anche per ogni passaggio del loop e distanza inferiore a 3 cm).
Puoi verificare se il buzzer si attiva con LOW?
comunque per far suonare una volta unicamente, devi avvere un "flag" come hai fatto con "GOAL". Ma occhio: adesso non attivi mai il cicalino quando distanza > 3cm.

Il cicalino l'ho collegato con il PIN positivo a 5v e il negativo al pin7..
Effettivamente sembra come dici tu, che si attivi a LOW e si disattivi a HIGH. Quindi funzionerebbe a comandi invertiti...
Ora che lo scrivo mi sa che ho invertito io i collegamenti :sweat_smile:
Si > a 3cm non mi serve che si attivi.

Ti riferisci alla variabile booleana se true o false?

Si; devi fare in modo simile.

sto facendo delle prove ed effettivamente per il cicalino avevo invertito io i collegamenti. Ora funziona bene.
Purtroppo però sto incontrando un nuovo problema con l'inserimento di un secondo sensore e annesso cicalino.
in pratica il sensore 1 funziona bene, mentre il sensore 2 misura sempre 0 cm.
sto leggendo online delle guide e tutti gli sketch sono uguali a quello che ho scritto io, quindi non capisco dov'è il problema..
riporto lo sketch

const int pinTrigger1 = 9;
const int pinEcho1 = 10;
byte cicalino1 = 7;

const int pinTrigger2 = 5;
const int pinEcho2 = 11;
byte cicalino2 = 3;

void setup() {

  pinMode(cicalino1, OUTPUT);
  pinMode(pinTrigger1, OUTPUT);
  pinMode(pinEcho1, INPUT);

  pinMode(cicalino2, OUTPUT);
  pinMode(pinTrigger2, OUTPUT);
  pinMode(pinEcho2, INPUT);

  Serial.begin(9600);
  Serial.print("Sensore Ultrasuoni: ");
}

void loop() {

  digitalWrite(pinTrigger1, LOW);
  digitalWrite(pinTrigger1, HIGH);
  delayMicroseconds(10);
  digitalWrite(pinTrigger1, LOW);
  digitalWrite(cicalino1, LOW);

  digitalWrite(pinTrigger2, LOW);
  digitalWrite(pinTrigger2, HIGH);
  delayMicroseconds(10);
  digitalWrite(pinTrigger2, LOW);
  digitalWrite(cicalino2, LOW);

  long durata1 = pulseIn(pinEcho1, HIGH);
  long distanza1 = durata1 / 58;

  long durata2 = pulseIn(pinEcho2, HIGH);
  long distanza2 = durata2 / 58;

  Serial.print("distanza1: ");

  if (durata1 > 38000) {
    Serial.println("Fuori portata");
  } else {
    Serial.print(distanza1);
    Serial.println(" cm");
  }
  if (distanza1 < 3) {
    digitalWrite(cicalino1, HIGH);
  } else {
    digitalWrite(cicalino1, LOW);
  }
 
  Serial.print("distanza2: ");

  if (durata2 > 38000) {
    Serial.println("Fuori portata");
  } else {
    Serial.print(distanza2);
    Serial.println(" cm");
  }
  if (distanza2 < 3) {
    digitalWrite(cicalino2, HIGH);
  } else {
    digitalWrite(cicalino2, LOW);
  }
  delay(10);
}

Oltretutto con l'inserimento del secondo sensore, le misurazioni del primo non sono più tanto precise, ma questo credo che, come ho letto qui sul forum, dipenda dal fatto che questi sensori non sono cosi affidabili come pensavo

Per forza! Non puoi leggerli contemporaneamente! Per leggere il secondo devi attendere la fine della lettura del primo.

void loop() {

  digitalWrite(pinTrigger1, HIGH);
  delayMicroseconds(10);
  digitalWrite(pinTrigger1, LOW);
  digitalWrite(cicalino1, LOW);

  long durata1 = pulseIn(pinEcho1, HIGH);
  long distanza1 = durata1 / 58;

  digitalWrite(pinTrigger2, HIGH);
  delayMicroseconds(10);
  digitalWrite(pinTrigger2, LOW);
  digitalWrite(cicalino2, LOW);

  long durata2 = pulseIn(pinEcho2, HIGH);
  long distanza2 = durata2 / 58;

Poi anche semplificare, risparmiando le variabili della durata:

  long distanza1 = pulseIn(pinEcho1, HIGH)/58;

e poi:

  Serial.print("distanza1: ");

  if (distanza1 > 655) {
    Serial.println("Fuori portata");
  } else {
    Serial.print(distanza1);
    Serial.println(" cm");

ok quindi il codice è scritto bene (semplificazioni a parte), ho solo invertito una parte del codice.... Grazie

Puoi anche inserire il timeout:
long distanza1 = pulseIn(pinEcho1, HIGH, 40000)/58;
Potrebbe essere utile.

E questo come influisce sulle letture del sensore? Nei vari sketch che ho visto e analizzato online non mi è mai capitato di trovarlo

Ho completato lo sketch e funziona bene. C'è solo una cosa che non mi è chiara. Quando uno dei 2 sensori si attivano per lettura della distanza impostata, per 5/6 secondi entrambi i sensori smettono di leggere (almeno stando al monitor seriale).

  • Può essere un problema di codice (in tal caso appena riesco lo scrivo perché ora sono dal telefono e non ce l'ho sottomano)?
  • Oppure può essere che dovendo nel frattempo fare altro (suono del cicalino, aggiornamento testo su LCD) si fermi per un po' la lettura fino al termine delle altre operazioni?
  • Oppure è il normale funzionamento dei sensori HC-SR04?

Probabile, ma ovviamente dovresti postare il codice, perché con quello si può capire se il problema sia nel programma o nelle altre due cause che hai ipotizzato.

Resta per me il fatto che ho sempre avuto problemi con gli HC-SR04 che da anni ho bandito dai miei progetti perché sono spesso difettosi ed inaffidabili sostituendoli con gli HY-SRF05 che costano qualche cent in più ma non mi hanno mai dato problemi.
A parte la scarsa precisione degli SR04, mi capitava spesso che da un certo momento in poi iniziavano a dare distanza 0 o 3 cm, e l'unico modo di riprendere a farli funzionare era o togliere e rimettere l'alimentazione oppure fare via software una operazione per tentare di forzarli ossia mettere in OUTPUT il pin Echo, portarlo LOW per 50 ms, poi reimpostarlo ad INPUT. Capisci che (almeno secondo la mia opinione) non è propriamente una buona cosa usare gli SR04... :wink:

Senza vedere tutto il programma, è impossibile dirlo.

Ok se oggi mi metto un attimo al PC posto il codice.

Diciamo che ho letto dei SRF05 solo dopo aver comprato gli SR04. purtroppo tutti i tutorial che ho visto online parlavano di questi ultimi e sembravano affidabili, però devo dire che in effetti non sono così precisi. Sto facendo un po' di prove per vedere la stabilità e valutare eventualmente la sostituzione.

Se questo può ovviare il problema, vorrei capire meglio in quale punto dello sketch inserirlo

Io lo faccio (facevo) quando vedo che ho una lettura a 0 o 3 cm (segno che si è "impallato"). A suo tempo feci anche una piccola libreria per gestire i sensori SRF05 con opzione per "autocorrezione" degli errori degli SR04 ma, anche se di fatto non la uso più, se vuoi dargli un'occhiata la trovi ancora QUI su Github.

Ma comunque, anche se anni fa per mancanza di fiducia buttai tutti i miei SR04 passando agli SRF05, non è detto che sia questo il problema: facci prima vedere il codice poi possiamo cercare di indirizzarti.

Riporto il codice (traendo spunti dai precedenti suggerimenti dati)

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

//configurazione LCD cinese
#define I2C_ADDR 0x27
#define BACKLIGHT_PIN 3
#define En_pin 2
#define Rw_pin 1
#define Rs_pin 0
#define D4_pin 4
#define D5_pin 5
#define D6_pin 6
#define D7_pin 7

LiquidCrystal_I2C lcd(I2C_ADDR, En_pin, Rw_pin, Rs_pin, D4_pin, D5_pin, D6_pin, D7_pin);
int x = 0;

int contatoreR = 0;  // contatore punteggio squadra rossa
int contatoreB = 0;  // contatore punteggio squadra blu

const int pinTrigger1 = 10;
const int pinEcho1 = 9;
byte cicalino = 7;

const int pinTrigger2 = 12;
const int pinEcho2 = 11;

byte LT[8] = {
  B00111,
  B01111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111
};
byte UB[8] = {
  B11111,
  B11111,
  B11111,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000
};
byte RT[8] = {
  B11100,
  B11110,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111
};
byte LL[8] = {
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B01111,
  B00111
};
byte LB[8] = {
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B11111,
  B11111,
  B11111
};
byte LR[8] = {
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11110,
  B11100
};
byte UMB[8] = {
  B11111,
  B11111,
  B11111,
  B00000,
  B00000,
  B00000,
  B11111,
  B11111
};
byte LMB[8] = {
  B11111,
  B00000,
  B00000,
  B00000,
  B00000,
  B11111,
  B11111,
  B11111
};

void setup() {

  pinMode(cicalino, OUTPUT);
  pinMode(pinTrigger1, OUTPUT);
  pinMode(pinEcho1, INPUT);

  pinMode(pinTrigger2, OUTPUT);
  pinMode(pinEcho2, INPUT);

  Serial.begin(9600);
  Serial.print("Sensore Ultrasuoni: ");

  lcd.begin(16, 2);
  lcd.setBacklightPin(BACKLIGHT_PIN, POSITIVE);
  lcd.setBacklight(HIGH);

  lcd.createChar(8, LT);
  lcd.createChar(1, UB);
  lcd.createChar(2, RT);
  lcd.createChar(3, LL);
  lcd.createChar(4, LB);
  lcd.createChar(5, LR);
  lcd.createChar(6, UMB);
  lcd.createChar(7, LMB);

  TestoFisso();
  Punteggio();
}

bool segna = true;

void loop() {

  digitalWrite(pinTrigger1, LOW);
  digitalWrite(pinTrigger1, HIGH);
  delayMicroseconds(10);
  digitalWrite(pinTrigger1, LOW);
  digitalWrite(cicalino, LOW);

  long durata1 = pulseIn(pinEcho1, HIGH);
  long distanza1 = durata1 / 58;

  digitalWrite(pinTrigger2, LOW);
  digitalWrite(pinTrigger2, HIGH);
  delayMicroseconds(10);
  digitalWrite(pinTrigger2, LOW);

  long durata2 = pulseIn(pinEcho2, HIGH);
  long distanza2 = durata2 / 58;

  Serial.print("distanza1: ");

  if (durata1 > 38000) {
    Serial.println("Fuori portata");
  } else {
    Serial.print(distanza1);
    Serial.println(" cm");
  };
  if (distanza1 < 3) {
    digitalWrite(cicalino, HIGH);
    delay(1000);
    digitalWrite(cicalino, LOW);
    contatoreR++;
    lcd.setCursor(0, 0);
    lcd.print("Squadra rossa  ");
    lcd.print(contatoreR);
    segna = true;
    if (segna) {
      for (int n = 1; n <= 3; ++n)
        GOAL();
      segna = false;
      TestoFisso();
      Punteggio();
    };
  };

  Serial.print("distanza2: ");

  if (durata2 > 38000) {
    Serial.println("Fuori portata");
  } else {
    Serial.print(distanza2);
    Serial.println(" cm");
  };
  if (distanza2 < 3) {
    digitalWrite(cicalino, HIGH);
    delay(1000);
    digitalWrite(cicalino, LOW);
    contatoreB++;
    lcd.setCursor(0, 1);
    lcd.print("Squadra blu    ");
    lcd.print(contatoreB);
    segna = true;
    if (segna) {
      for (int n = 1; n <= 3; ++n)
        GOAL();
      segna = false;
      TestoFisso();
      Punteggio();
    };
  };

  delay(50);
}


void TestoFisso() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Squadra rossa  ");
  lcd.print(contatoreR);
  lcd.setCursor(0, 1);
  lcd.print("Squadra blu    ");
  lcd.print(contatoreB);
}

void GOAL() {
  scrivi("GOAL");
  delay(1000);
  lcd.clear();
  delay(500);
}

void scrivi(const char* stringa) {
  x = 0;  // posizione iniziale
  lcd.clear();
  for (int i = 0; i < strlen(stringa); ++i)
    lettera(stringa[i]);
}

void lettera(char lettera) {
  switch (lettera) {
    case 'G':
      lcd.setCursor(x, 0);
      lcd.write(8);
      lcd.write(1);
      lcd.write(1);
      lcd.setCursor(x, 1);
      lcd.write(3);
      lcd.write(4);
      lcd.write(2);
      break;
    case 'O':
      lcd.setCursor(x, 0);
      lcd.write(8);
      lcd.write(1);
      lcd.write(2);
      lcd.setCursor(x, 1);
      lcd.write(3);
      lcd.write(4);
      lcd.write(5);
      break;
    case 'A':
      lcd.setCursor(x, 0);
      lcd.write(8);
      lcd.write(6);
      lcd.write(2);
      lcd.setCursor(x, 1);
      lcd.write(255);
      lcd.write(254);
      lcd.write(255);
      break;
    case 'L':
      lcd.setCursor(x, 0);
      lcd.write(255);
      lcd.setCursor(x, 1);
      lcd.write(255);
      lcd.write(4);
      lcd.write(4);
      break;
  }
  x = x + 4;
}
void Punteggio() {

  lcd.setCursor(0, 0);
  lcd.print("Squadra rossa  ");
  lcd.print(contatoreR);

  lcd.setCursor(0, 1);
  lcd.print("Squadra blu    ");
  lcd.print(contatoreB);

  if (contatoreR == 9 || contatoreB == 9) {  //condizione da verificare (se il contatore arriva a 9)

    digitalWrite(cicalino, HIGH);
    delay(100);
    digitalWrite(cicalino, LOW);
    delay(100);

    digitalWrite(cicalino, HIGH);
    delay(100);
    digitalWrite(cicalino, LOW);
    delay(100);

    digitalWrite(cicalino, HIGH);
    delay(100);
    digitalWrite(cicalino, LOW);
    delay(100);

    lcd.setCursor(0, 0);
    lcd.print("Squadra rossa  ");
    lcd.print(contatoreR = 0);
    lcd.setCursor(0, 1);
    lcd.print("Squadra blu    ");
    lcd.print(contatoreB = 0);  // riporta il contatore a 0 quando si verifica la condizione dell'if
  };
}

In pratica sul monitor seriale riporta tutte le letture dei 2 sensori, però nel momento in cui uno dei due scende sotto i 3 cm (dando input alle cose da fare), sul monitor non riporta le letture di nessuno dei 2, per circa 5/6 secondi dopodichè riprende regolarmente.
In questo progetto potrebbe anche non rappresentare un problema in quanto dal momento in cui uno dei 2 sensori legge il passaggio della pallina, passano alcuni secondi per riprendere il gioco, però sarei curioso di sapere da cosa dipende, nel caso possa tornarmi utile in futuro.
Come sempre grazie

Sono tutti quei delay
Oltretutto contenuti in un ciclo ripetuto

Quelli del loop o quelli del Punteggio (che poi vengono richiamati nel loop)?
Nel punteggio l'ho scritto velocemente per fare suonare il cicalino tre volte al raggiungimento di una condizione?
Meglio se uso una variabile booleana quindi, giusto?

Hai delay(1000); poi tre volte GOAL() che sono altri 4,5 secondi e punteggio, che in un una particolare condizione introduce altri 600ms di attesa!

Ok quindi magari riduco il tempo dei delay. Grazie

P. S. Poiché i delay li uso per indicare il tempo di esecuzione di un qualcosa, ma ho capito che al tempo stesso ferma le altre operazioni dei componenti connessi alla scheda, può essere sostituito da qualcos'altro che permetta di continuare le altre operazioni contemporaneamente a quelle richiamate ad una determinata condizione?