Inserire solo dati "puliti" in un array e poi fare la media

Sto giocando con un sensore ad ultrasuoni (SR04) per misurare delle distanze.
Ho generato un ambiente pieno di disturbi per questo sensore creando una sorta di piccolo corridoio per puntualizzare la lettura.
Purtroppo questo mi genera dei valori uguali a 0 che vorrei eliminare dalla media che calcolo.
Questo è lo sketch che funziona ma è appunto affetto da letture errate (valori uguali a zero):

void loop() {
  distanza = ultrasuoni.ping_cm();
  readings[index] = distanza;
  if (index < (NUMREADINGS - 1)) index++;
  else index = 0;

  average = 0;
  for (int j = 0; j < NUMREADINGS; j++) {
    average += readings[j];
  }
  average = average / (NUMREADINGS);
  Serial.print(distanza); Serial.print(","); Serial.println(average);
  delay(10);
}

Questo il grafico che viene generato:

Come detto, vorrei eliminare i valori corrispondenti a zero, ho provato a mettere un if ma in questo modo non carico l'array correttamente (credo...) e la media (linea rossa) non è corretta:

void loop() {
  distanza = ultrasuoni.ping_cm();
    readings[index] = distanza;

    if (distanza != 0) {
    if (index < (NUMREADINGS - 1)) index++;
    else index = 0;
    }

  average = 0;
  for (int j = 0; j < NUMREADINGS; j++) {
    average += readings[j];
  }
  average = average / (NUMREADINGS);
  Serial.print(distanza); Serial.print(","); Serial.println(average);
  delay(10);
}

Dove sbaglio nell'escludere i valori uguali a zero dell'array che poi devono essere dati in pasto per generare la media? (media generata da 200 valori).

Grazie!

Fai il controllo di distanza != 0 ma l'inserimento del valore nell'array lo fai prima e poi incrementi comunque l'indice dell'array.

Prova cosi:

void loop() {
  distanza = ultrasuoni.ping_cm();
  if (distanza != 0) {
    readings[index] = distanza;
    index = (index + 1) % NUMREADINGS ;
  }

  average = 0;
  for (int j = 0; j < NUMREADINGS; j++) {
    average += readings[j];
  }
  average = average / (NUMREADINGS);
  Serial.print(distanza); Serial.print(","); Serial.println(average);
  delay(10);
}

Sinceramente avevo compreso il mio errore, perlomeno capivo che stavo aggiornando l'array anche con valori non desiderati, ma appunto non capivo come escluderli.
Il tuo suggerimento funziona, potresti però spiegarmi come "funziona"?

if (distanza != 0) {
    readings[index] = distanza;
    index = (index + 1) % NUMREADINGS ;
  }

-> verifico se il valore vale zero, se sì entro nella condizione
-> il valore della distanza è sicuramente diverso da zero ed inizio a scriverlo nell'array
-> incremento l'indice dell'array.... e poi? Non comprendo quel % NUMREADINGS
Ogni volta che la distanza é diversa da zero, scrivo il valore nell'array nell'indice successivo, ma se il mio numero di campioni (NUMREADINGS) è di 200, continuo ad aumentare e a popolare l'array all'infinito?
Il mio codice prevedeva di caricare l'array per il numero di campioni impostato (NUMREADINGS)

if (index < (NUMREADINGS - 1)) index++;
  else index = 0;

raggiunto il valore desiderato azzera l'indice e ricomincia a popolarlo di valori cancellando quelli più vecchi.

Sia chiaro, non sto dicendo che la tua soluzione non funziona, anzi, come detto testata e funzionante, ma non ne comprendo appunto il funzionamento.

Grazie mille!

khriss75:
-> incremento l'indice dell'array.... e poi? Non comprendo quel % NUMREADINGS

E' solo un modo più compatto ed efficiente per fare la stessa cosa che hai fatto tu con if/else.
L'operatore % è il cosiddetto modulo (lo trovi anche sulle calcolatrici), ovvero un operatore che da come risultato il resto di una divisione tra interi.
Esempio:

index = 0;
NUMREADINGS = 30;

index = (index +1 ) % NUMREADINGS  significa che index viene incrementato di 1 ed il risultato viene messo a modulo con 30.

(0 + 1) / 30 = 0 ->  resto 1   (ricorda che parliamo di divisione tra numeri INTERI) quindi index diventa  il risultato del modulo cioè 1
....
(10+1) / 30 = 0  -> resto 11 
(11+1) / 30 = 0  -> resto 12
...
(29 + 1) / 30 = 1 -> resto 0  quindi index diventa = 0

Beh intanto basterebbe ignorare tutte le letture a zero direi. Ma soprattutto butta l'SR04 ed usa solo SRF05. Costano qualche centesimo in più ma sono più affidabili, soprattutto non soffrono del problema dei "blocchi" e degli "zeri spuri" che a prima vista hai anche tu su quell'SR04 e con il quale ho "litigato" parecchio.

Se vuoi saperne di più vedi QUI (è una libreria che feci qualche anno fa proprio per "colpa" degli SR04, e che oltre agli SRF05 funziona anche con i 04 o almeno tenta di "recuperarne" gli errori...;)).

docdoc:
Beh intanto basterebbe ignorare tutte le letture a zero direi. Ma soprattutto butta l'SR04 ed usa solo SRF05. Costano qualche centesimo in più ma sono più affidabili, soprattutto non soffrono del problema dei "blocchi" e degli "zeri spuri" che a prima vista hai anche tu su quell'SR04 e con il quale ho "litigato" parecchio.

Se vuoi saperne di più vedi QUI (è una libreria che feci qualche anno fa proprio per "colpa" degli SR04, e che oltre agli SRF05 funziona anche con i 04 o almeno tenta di "recuperarne" gli errori...;)).

Grazie Doc, in effetti sembra fare un poco schifo il mioSR04, oltre ai picchi a zero, oltre i 130cm non misura.
Punto sui SRF05. Pensi vadano bene quelli acquistati sul mega sito online che consegna il giorno dopo? Ho visto alcuni store online proporli anche a 45 euro mentre sul mega sito di vendita online costa appunto poco piu' sei sr04.
Non ho bisogno di precisione ma di misurare io che mi muovo lungo un corridodio (circa 4 metri, e mi serve di capire se sono all'iizio, meta' e fine oltre ai quarti...)
Ancora grazie!
(provero' sicuramente la tua libreria)

45 Euro? L'uno? Ma dove? Spero che sia almeno per una confezione da 10 (o più)...

Puoi trovarne QUI tre sensori a 9 Euro spedizione inclusa (in 1 giorno), oppure QUI a meno di 3 Euro l'uno (ma più spedizione).

Costano quindi poco meno di 2 SR04 ma io ho risolto molti problemi abbandonando gli SR04 ed usando sempre SRF05. Poi vedi tu :wink:

Il primo link è proprio quello che volevo prendere, mi hai dato conferma.
Ordino, li provo e ti faccio sapere.
Ho provato la tua libreria con il mio sr04 e rallenta tantissimo (per la miriade di valori a zero che deve tagliare).
Ancora grazie!

Doc, ho provato gli SRF05 e sono sicuramente migliori dei 4. Purtroppo posizionandoli in un corridoio vuoi i vari rimbalzi vuoi che ci sia altro ma leggono le misure delle pareti e non mi permettono di fare una misura pulita già ad un paio di metri. In campo aperto funzionano invece bene.
No problem, come detto era una prova.
Dovrei magari privare a stampare dei coni con la stampante 3d e metterli su tx ed rx per chiudere un pò il cono.

Ci giocherò su un poco.

Potresti anche provare a lasciare perdere gli ultrasuoni e cambiare tecnologia...

paulus1969:
Potresti anche provare a lasciare perdere gli ultrasuoni e cambiare tecnologia...

SI, dovrei passare ad un misuratore di distanza laser, ma oltre al costo, consapevole che le potenze in gioco sono comunque molto basse, non mi va di lanciare fasci più o meno collimati. Nel corridoio ci passano persone (io, moglie ed eventuali ospiti) e sebbene possa attuare tutte le misure di sicurezza del caso, come detto, preferirei non far girare per casa fasci laser.
Tra l'altro era una banale idea per accendere mezzo metro di strip led ed aumentare la luminosità all'avvicinarsi di una persona. Era comunque un progettino a cui non sto dando alcuna importanza.
Grazie comunque per l'info!

khriss75:
Nel corridoio ci passano persone (io, moglie ed eventuali ospiti) e sebbene possa attuare tutte le misure di sicurezza del caso, come detto, preferirei non far girare per casa fasci laser.

Un sensore tipo il VL53L0X usa un laser di classe 1 quindi sicuro per l'uomo in qualsiasi condizione di utilizzo.

cotestatnt:
Un sensore tipo il VL53L0X usa un laser di classe 1 quindi sicuro per l'uomo in qualsiasi condizione di utilizzo.

Come detto, avevo pensato ad una soluzione laser poi scartata per i motivi (probabilmente infondati) che ho descritto sopra.
Il "problema" è che dovrei misurare circa 4 metri e quei modulini arrivano fino a 2 metri. Beh, potrei metterne uno ad inizio corridoio ed uno a fine corridoio ed interpolare le misure con Arduino in modo da capire dove la persona si trova (inizio, metà, tre quarti, un quarto... del corridoio).
Visto che li utilizzi, potresti togliermi un paio di dubbi?

  1. Sono abbastanza selettivi? Intendo, quelli ad ultrasuoni mi leggevano i muri generando un cono ampio (sulla lunghezza).
  2. Potrebbero esserci problemi a metterne uno di fronte all'altro (inizio e fine corridoio)? Anche in questo caso dipende dal cono generato.
  3. (domanda bonus :wink: ) L'irregolarità dei vestiti/corpo umano, potrebbe compromettere la riflessione e quindi la misura della distanza?
    Come detto, il mio giochetto, sarebbe quello di gestire la luminosità di un pezzetto di strip led avvicinandomi o allontanandomi da essa.
    Ti chiedo questo, perché il costo rispetto agli ultrasuoni è sicuramente maggiore e vorrei evitare di buttare 30 euro per qualcosa che poi mi rimarrebbe nel cassetto (e ne ho già molta :roll_eyes: ).

Fino a 4 metri ci sono i VL53L1X.
La selettività è sicuramente migliore rispetto agli ultrasuoni, il cono dovrebbe essere di circa 25/30°. Probabilmente nel datasheet trovi tutte queste informazioni molto più dettagliate.

Per quanto riguarda la domanda bonus, essendo un sensore Time Of Fligh ottico, la superficie dell'oggetto colpito non influenza in modo significativo il risultato (a meno che non sia trasparente, in questo caso non funzionano proprio).

Il costo è sicuramente maggiore rispetto agli ultrasuoni, ma 30€ mi sembrano davvero troppo...
Nel grande store online (che accetta resi :wink: ) del Sig. Bezos si trovano anche a 10/15€ mentre in quelli cinesi per 6/7€.

Anche rimanendo su distributori "seri" con poco più di 20 euro si acquistano 2 breakout board originali ST, con level shifter integrato.

Ciao, Ale.

khriss75:
Doc, ho provato gli SRF05 e sono sicuramente migliori dei 4. Purtroppo posizionandoli in un corridoio vuoi i vari rimbalzi vuoi che ci sia altro ma leggono le misure delle pareti e non mi permettono di fare una misura pulita già ad un paio di metri. In campo aperto funzionano invece bene.

Hm, allora secondo me per poterti aiutare dovresti spiegare un po' meglio l'ambito di utilizzo.

Per dire, quei sensori non hanno solo 2 metri di range ma arrivano a 4 o 5 metri circa, però maggiore è la distanza minore è la precisione per via di vari fattori, iniziando da quello "fisico" (maggiore è la distanza minore il livello del segnale ricevuto, secondo legge quadratica) a quello più "geometrico" (come per un sensore ottico, un oggetto a 10 centimetri si "vede" molto più grande dello stesso a 2 metri, il che significa necessariamente minore eco), all'ampiezza del cono di rlevazione (vedi allegato, e per ridurlo potresti provare come hai anticipato con una maschera, basta anche un cartoncino di pochi cm, e neanche necessariamente a cono, basta anche un "tubicino"), ed infine ad altri fattori come il materiale dell'oggetto da rilevare (prova a fargli rilevare una spugna..), la sua inclinazione (prova a fargli rilevare una superficie ruotata di 45 gradi...) e la presenza di eventuali altri ostacoli che generano echi (il sensore "sente" e misura solo il PRIMO eco ricevuto).

Detto questo, è possibile che se parli di un "corridoio", ovviamente non sarà un tubo con pareti lisce ma ci saranno magari altri oggetti ed ostacoli, per cui potrebbero essere questi a dare fastidio in quanto oltre 2 metri c'è qualche altro ostacolo che restituisce un eco prima del vero obiettivo. Inoltre sarebbe utile sapere "cosa" sia quello che vuoi misurare, se è una persona, un cane, un robot, un drone, un alieno, o cosa? E poi in realtà "cosa" vuoi rilevare, la sola presenza (si/no) o proprio la distanza? Perché ad esempio se parliamo di una persona che attraversa il corridoio e vuoi sapere solo se "qualcuno" occupa il corridoio potresti pensare ad un normalissimo PIR.

beam.gif

beam.gif

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