Consiglio HW per misurare distanza

Per un progettino sto utilizzando un modulo HC-SR04 (misuratore distanza ad ultrasuoni) che mi fa aumentale l'intensità luminosa di un led quando mi avvicino al sensore ed ovviamente fa diminuire la luminosità quando mi allontano.

Per ora sto testando il sensore leggendo su serial monitor la distanza misurata (con in vari sketch esempio) ma di tanto in tanto appaiono valori completamente sballati. Ad esempio 157 - 155 - 23 -157 ...
Di tanto in tanto c'è appunto un valore che non c'entra nulla.
La mia domanda: ci sono altri sensori per la misura della distanza magari più coerenti nella misura? Non ho assolutamente bisogno di precisione ma di coerenza nella misura.

In alternativa vedrò di ripulire quei valori non coerenti mediante software.

Ci possono essere altre soluzioni hardware per effettuare una misura evitando gli ultrasuoni (scarterei puntatori laser visto che vorrei misurare l'avvicinamento al sensore di una persona).

grazie!

Premetto che da alcuni anni ho bannato gli HC-SR04 perché mi hanno sempre dato problemi, in un modo o nell'altro, sostituiti felicemente dagli HY-SRF05 che costano un pochino di più ma sono ben più affidabili. Detto questo, diciamo che il problema nel tuo caso NON sia un SR04 bacato (ma non lo escludo).
Le letture non stabili possono dipendere da vari fattori.

Ad esempio se l'oggetto da rilevare ha una superficie più o meno riflettente (al suono intendo), se è regolare o quale angolazione ha. Ad esempio se metti una lastra liscia posta a 45 gradi rispetto al sensore, non la "vedi" quasi mai,

Poi se ci sono altre superfici od ostacoli nelle vicinanze: considera che "spara" un cono di ultrasuoni con ampiezza di circa 15 gradi, ed eventuali altri ostacoli presenti lateralmente potrebbero dare un "eco" di ritorno che alla lettura successiva viene interpretata come "qualcosa" di più vicino.

Poi dipende anche da con quale frequenza fai la misurazione: se leggi molto velocemente, il precedente probema viene amplificato notevolmente.

Insomma, posta lo sketch che hai usato per quella prova di cui hai riportato i valori, spiega meglio con quale ostacolo hai fatto la prova, ed in sostanza cosa devi rilevare e con quale "precisione".
A parte prendere un SRF05 intendo :wink:

Beh... Se i valori sono notevolmente diversi dagli altri, via software è semplice: fai una matrice circolare in cui hai costantemente gli ultimi 10 valori. Ogni volta che arriva un valore nuovo, leggi tutta la matrice, fai la media e la confronti con il nuovo valore. Se il rapporto è maggiore di 0,6 e minore di 1,7 lo visualizzi e lo scrivi nella matrice eliminando il più vecchio, altrimenti lo scarti.

Certo, rallenta la risposta in caso di variazioni rapide della distanza, ad esempio un oggetto che passa davanti. In alternativa, puoi fare il confronto solo con la lettura precedente: la da per buona solo se la lettura precedente è simile.

La misura viene fatta ogni ogni secondo (troppo veloce?), il “materiale” sono io :slight_smile:
In pratica mi interessa misurare la distanza tra il sensore (fisso) ed una persona che si avvicina (o allontana) al sensore stesso.

Questo è il codice:

#define TRIG_PIN 10
#define ECHO_PIN 9

void setup(){
  Serial.begin(9600);
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  digitalWrite(TRIG_PIN, LOW);
}

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

  unsigned long tempo = pulseIn(ECHO_PIN, HIGH);
  float distanza = 0.03438 * tempo / 2;

  Serial.println("Distanza: " + String(distanza) + "cm");
  delay(1000);
}

Non necessito di misure precise, mi bastano anche step da 10-20cm…
Distanza massima da rilevare circa un metro, distanza minima una trentina di centimetri.

Il sensore è posizionato su una parete del corridoio ed io mi muovo frontalmente al sensore. Forse sono i vestiti che creano queste false misure…

Certo, però, che gli schemi sono quasi uguali...
HC-SR04 (Adrirobot)
HY-SRF05 (Amazon)

Più semplicemente:

  int distanza = 0.0172*pulseIn(ECHO_PIN, HIGH);

Evita String!Serial.print("Distanza: "); Serial.print(distanza); Serial.println("cm");

Datman:
Evita String!Serial.print("Distanza: "); Serial.print(distanza); Serial.println("cm");

Ok grazie!
Come detto questo è solo uno sketch di prova.
Però sono curioso, perché è meglio evitare di utilizzare String? Per questioni di memoria di Arduino?

khriss75:
Però sono curioso, perché è meglio evitare di utilizzare String? Per questioni di memoria di Arduino?

Leggi QUI.

Guglielmo

Grazie Guglielmo, darò una lettura approfondita alla SafeString.

Dopo altre prove fatte, penso di aver trovato il "problema".
Sembra essere abbigliamento a generare problemi.
Materiali acrilici (filati lucidi delle tute ad esempio) sembrano riflettere meglio gli ultrasuoni, materiali più "porosi" come il cotone sembrano attenuare. Pieghe pieghine e pieghette rompono le scatole.
Se sto immobile davanti al sensore ho misure stabili e precise, se ruoto il tronco a DX e SX (rimanendo però alla stessa distanza) le misure sballano alla grande:

15:24:26.849 -> Distanza: 5.52cm
15:24:27.821 -> Distanza: 156.81cm
15:24:28.840 -> Distanza: 156.00cm
15:24:30.098 -> Distanza: 3868.35cm
15:24:31.077 -> Distanza: 5.62cm
15:24:32.103 -> Distanza: 71.77cm
15:24:33.315 -> Distanza: 3848.24cm
15:24:34.294 -> Distanza: 5.62cm
15:24:35.320 -> Distanza: 64.20cm
15:24:36.299 -> Distanza: 64.62cm
15:24:37.322 -> Distanza: 64.58cm
15:24:38.342 -> Distanza: 64.63cm
15:24:39.318 -> Distanza: 62.93cm
15:24:40.342 -> Distanza: 62.86cm
15:24:41.363 -> Distanza: 62.47cm
15:24:42.339 -> Distanza: 63.33cm
15:24:43.361 -> Distanza: 52.17cm
15:24:44.334 -> Distanza: 46.83cm
15:24:45.591 -> Distanza: 3825.62cm
15:24:46.570 -> Distanza: 5.62cm
15:24:47.826 -> Distanza: 3815.70cm
15:24:48.807 -> Distanza: 5.62cm
15:24:49.829 -> Distanza: 62.67cm
15:24:50.803 -> Distanza: 46.53cm
15:24:51.826 -> Distanza: 67.01cm
15:24:52.805 -> Distanza: 66.99cm
15:24:53.829 -> Distanza: 63.57cm
15:24:54.853 -> Distanza: 62.11cm
15:24:55.829 -> Distanza: 49.28cm

Il movimento del busto davanti al sensore crea problemi.

Considerando che il progetto sarebbe una sorta di gioco per il nipotino che avvicinandosi al sensore (bandierina) fa aumentare la luminosità di un led o la variazione di colori di un led rgb, pensavo di ripulire via software i valori sballati eliminando in primis quelli sopra un certo valore (magari maggiori di 2000) e poi eliminando quelli che si discostano troppo dal precedente.
Ribadisco che non ho la necessità di valori precisi, più il nipotino si avvicina alla "bandierina" più la luce del led aumenta o si colora.

Leggendo qui

io proverei con il vl53l0x

Grazie zoomx, appena ho un attimo verifico anche quel sensore (anche se come detto, si tratta di un gioco)

khriss75:
Se sto immobile davanti al sensore ho misure stabili e precise, se ruoto il tronco a DX e SX (rimanendo però alla stessa distanza) le misure sballano alla grande:

Che possano variare è normale, e l’ho pure descritto nel post #1. Che possano variare così tanto mi pare un poco strano, ma se usi gli HC-SR04 che a me hanno sempre dato problemi di stabilità (vedi sempre il post #1… ma lo hai letto?) e da anni uso solo gli HY-SRF05 per cui ti consiglierei di inizare da questo.

Io a suo tempo creai per me una libreria (se vuoi te la mando, l’chiamata “SRF05” indovina perché? :wink: ) nella quale facevo questo:

...
       digitalWrite( TrigPin, HIGH );
       delayMicroseconds(10); // Ping width
       digitalWrite( EchoPin, LOW );  
       long pulseDuration = pulseIn( EchoPin, HIGH, SRF_TIMEOUT);
       if ( Unlock && pulseDuration == 0 ) {
         // SR04 unlock
         pinMode(EchoPin, OUTPUT);
         digitalWrite(EchoPin, LOW);
         delay(50);
         pinMode(EchoPin, INPUT);
       }
       Distance = 0.034F * pulseDuration / 2;

A parte la if() per fare l’“unlock” (molti esemplari di SR04 ogni tanto si “bloccavano” dando sempre valori molto bassi fino a che non li si sbloccava resettandoli…), come vedi il codice ha prima dell’impulso da 10 us un “pull down” sul pin di trigger, che ti consiglio di aggiungere.

Poi alla pulseIn() ho aggiunto anche un timeout per “velocizzare” le letture quando non c’è alcun ostacolo entro il range prefissato (nel mio caso SRF_TIMEOUT vale 45000UL ossia 45 ms).

Detto questo, ho preso un sensore ed ho caricato il tuo sketch, ma non ho notato tutte le variazioni che hai mostrato tu.

180.62
192.44
181.41
192.42
85.92   <-- qui sono entrato per mettermi davanti al sensore
80.98
72.71
72.30
74.11
73.78
73.26
74.97
72.75  <-- qui ho iniziato a ruotare sul posto
74.93
82.58
83.49
181.34 <-- qui sono andato via
180.89
182.68
181.85
183.09
180.96
72.32  <-- qui ho messo un cuscino alla stessa distanza
70.70
71.42
70.70
68.30
80.60 <-- qui ho un poco ruotato il cuscino
85.30
69.52
71.91
59.67
31.25 <-- qui ho avvicinato il cuscino
28.16
28.95
92.33 <-- l'ho allontanato
75.21
34.53 <-- e riavvicinato
193.25 <-- poi ho tolto il cuscino
182.13
195.00

Come si vede, non ho particolari “salti” di misurazione, ed anche se le distanze variano un poco anche stando fermi (la precisione della misurazione non è assoluta soprattutot in ambiente aperto, considera sempre una variazione di almeno un paio di cm) e muovendomi o ruotando sul posto variano un po’ di più.

Ma come detto, dipende dal materiale e dalla sua inclinazione: se metti un foglio o uno specchio a 45 gradi è come se non ci fosse. Se parliamo di una persona, allora si, potresti fare una “media” delle letture scartando quelle maggiori del limite che vuoi considerare, ma aumentando il numero di campioni al secondo e realizzando una media mobile ossia degli ultimi “n” valori acquisiti. Ovviamente l’intervallo tra letture moltiplicato per il numero di valori della media ti darà la “latenza”.

Una cosa di questo tipo:

#define TRIG_PIN 10
#define ECHO_PIN 9

unsigned long tempo;
// Valori in centimetri
int distanza, media;
// Intervallo in ms tra letture
#define INTLETTURE 100
// Numero di letture per la media mobile
#define NUMLETTURE 10
int lettura[NUMLETTURE];
byte pos = 0;

void setup(){
  Serial.begin(115200);
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  digitalWrite(TRIG_PIN, LOW);
  Serial.println("Started.");
}

void loop(){
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);
  tempo = pulseIn(ECHO_PIN, HIGH);
  distanza = 0.03438F * tempo / 2.0;
  if ( distanza <= 300 && distanza > 3 ) {
    lettura[pos] = distanza; // Memorizzo la lettura
    // Se sono all'ultima posizione
    if ( pos == NUMLETTURE-1 ) {
      // Calcolo la media
      media = 0;
      for (int i=0; i<NUMLETTURE; ++i) {
        media += lettura[i];
        if ( i>0 ) // Rotazione valori
          lettura[i-1] = lettura[i];
      }
      media /= NUMLETTURE;
      Serial.println(media);
    } else
      ++pos;
  }
  delay(INTLETTURE);
}

Puoi giocare sul delay (INTLETTURE) e sul numero di campioni (NUMLETTURE).

PS: le capsule hanno una ampiezza dell’apertura del segnale di circa 15 gradi, se vuoi limitare eventuali “rumori” di altri oggetti e rendere più direzionale la rilevazione, puoi mettere le capsule, o almeno la capsula di ricezione, dentro a due tubetti in cartoncino di qualche centimetro. Dico in cartoncino perché è meglio se non sono superfici riflettenti, rende il tutto più direzionale.

Trovi tutto su GitHub compresa documentazione ed esempi:

nid69ita:
@docdoc, ho ordinato un SRF05, mi puoi mandare la libreria ? ;D

Mi unisco anch'io ai ringraziamenti.
Inizio a pensare che il mio sensore sia... troppo farlocco.
Non ricordo nemmeno dove lo avevo preso, era in un cassettino tra le mille e mille cose...

docdoc:
Trovi tutto su GitHub compresa documentazione ed esempi:
GitHub - dotto59/SRF05: Libreria Arduino per la gestione del sensore ad ultrasuoni

@docdoc, ti segnalo alcune cosette:

  1. la lib mi da degli errori in compilazione (li ho corretti ma ho anche cambiato alcune cose).
  2. ci sono le variabili membro anche come variabili globali nel cpp
  3. l'indentazione nella read() è un pò strana
  4. nel file .h ti segnalo che la costante del timeout nel commento dice millisecondi ma sono microsecondi.
  5. se l'esempio non è in sottocartella, non lo carica poi da esempi lib.

Dovresti fare un fork su github, eseguire le correzioni su quello (oppure copiarci sopra i file corretti) e quindi una pull request.
Questo perché il sistema evidenzia i cambiamenti effettuati ed è quindi più facile valutarli.

nid69ita:
@docdoc, ti segnalo alcune cosette:

  1. la lib mi da degli errori in compilazione (li ho corretti ma ho anche cambiato alcune cose).
  2. ci sono le variabili membro anche come variabili globali nel cpp
  3. l'indentazione nella read() è un pò strana
  4. nel file .h ti segnalo che la costante del timeout nel commento dice millisecondi ma sono microsecondi.
  5. se l'esempio non è in sottocartella, non lo carica poi da esempi lib.

Grazie, è una libreria fatta qualche anno fa, poi l'ho usata solo un'altra volta ma effettivamente rilasciandola come libreria su GitHub meglio correggere.

Segnalameli come issue su GitHub, poi ci penso io in questo fine settimana.