Azzeramento lettura altitudine con sensore BMP280

Buonasera/notte a tutti.

Sono un paio di giorni che mi arrovello sul come settare uno zero relativo per il sensore BMP280.
In pratica vorrei utilizzare questo sensore come parte di un datalogger molto basilare.
Vorrei avere modo di settare uno zero fittizio a mio piacere premendo un tasto e facendogli settare la pressione di quell’istante come altezza zero. E da lì creare il profilo altimetrico del percorso successivo.

Ho provato, partendo dall’esempio incluso con le librerie per il sensore in oggetto, ad elaborarlo per fargli inserire un valore in una float alla pressione di un bottone attraverso un ciclo if, ma ogni volta che riparte si azzera, anche usando lo static.

Ho la netta sensazione di essere particolarmente duro io, e che la soluzione è più semplice di quanto possa sembrare… Però provo a chiedere a voi…

Allego ciò che ho scritto per ora…

#include <Wire.h>
#include <SPI.h>
#include <Adafruit_BMP280.h>

#define BMP_SCK  (13)
#define BMP_MISO (12)
#define BMP_MOSI (11)
#define BMP_CS   (10)

Adafruit_BMP280 bmp; // I2C

#define BUTTON 7
int val = 0;
int Check_Start=0;
float relAlt;
float alt;

void setup() {
  pinMode(BUTTON, INPUT);
  Serial.begin(9600);
  Serial.println(F("BMP280 test"));
  

  if (!bmp.begin()) {
    Serial.println(F("Could not find a valid BMP280 sensor, check wiring!"));
    while (1);
  }

  /* Default settings from datasheet. */
  bmp.setSampling(Adafruit_BMP280::MODE_NORMAL,     /* Operating Mode. */
                  Adafruit_BMP280::SAMPLING_X2,     /* Temp. oversampling */
                  Adafruit_BMP280::SAMPLING_X16,    /* Pressure oversampling */
                  Adafruit_BMP280::FILTER_X16,      /* Filtering. */
                  Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */
}

void loop() {

  val = digitalRead(BUTTON);
  if (val ==HIGH) {

    Check_Start++;
  }
  if (Check_Start==0) {
    Serial.println ("Premere per settare altezza");
  }
  else {

  if (val == HIGH) {
      static float relAlt = (bmp.readPressure()/100); 
      Serial.println(relAlt);
        }
  }

    static float alt=relAlt;
  
    Serial.print(F("Temperature = "));
    Serial.print(bmp.readTemperature());
    Serial.println(" *C");

    Serial.print(F("Pressure = "));
    Serial.print(bmp.readPressure());
    Serial.println(" Pa");

    Serial.print(F("Approx altitude = "));
    Serial.print(bmp.readAltitude(relAlt));
    Serial.println(" m");

    Serial.println(Check_Start);
    Serial.println(alt);

    Serial.println();
    delay(1000);
    
  }

Come posso far restare memorizzato il valore relAlt per poterlo utilizzare successivamente per i cicli successivi finché non azzero nuovamente o resetto l’unità?

ciao a te,
ma che intendi con

Vaglio:
[...] ma ogni volta che riparte si azzera, anche usando lo static.

ogni volta che riparte cosa?
cmq ho notato che dichiari due volte alt (all'inizio e dopo gli if) e che
alt = relAlt è fuori dalla condizionale if(si aggiorna ad ogni ciclo e nn solo quando premi il tasto)

poi questa è piu una domanda che altro perche scrivi
val = digitalRead e poi if (val == HIGH)invece di
if(digitalRead(7) == high){}
??

Mi sa che hai fatto un po' un misto fritto di cose.
Cerco di spiegarmi meglio:
All'inizio scrivi:

float relAlt;

e quindi dichiari una variabile relAlt come global, quindi accessibile sempre.

poi dentro il loop scrivi:

static float relAlt = (bmp.readPressure()/100);

e quindi dichiari una nuova variabile relAlt, questa volta statica.
Ora hai due variabili con lo stesso nome e accessibili sempre.
Stessa cosa per la variabile alt.
Poi scrivi:

static float alt=relAlt;

a parte la dichiarazione di alt, ma tra le due relAlt viste sopra, qui, secondo te, quale viene presa? quella globale o quella statica?
E qui?

Serial.println(alt);

quale delle due variabili alt viene stampata? quella globale o quella statica?

Ho reso un po' l'idea del misto fritto?

Ciao, grazie ad entrambi per le risposte.

Diciamo che chiaro non è, ma ho capito d'aver fatto del casino. :slight_smile:

Il fatto è che ho preso stand alone i due codici per la pressione bottone e quello di esempio del BMP280 e ho provato ad unirli.
Facendo chiaramente un bordello.

La variabile alt l'avevo inserita in un momento di prove.
La escluderei a priori dal codice. Ieri avevo sono e mi sono scordato di farlo...

Sul ripartire intendevo il loop, ogni volta che si esegue sembra che la variabile relAlt si azzeri. E non memorizza il valore letto.
È legato alla doppia definizione?
Come posso fare in modo che quando sente il bottone in HIGH legga il valore di pressione, lo memorizzi in una variabile e finche non premo nuovamente usa quel valore come riferimento per il calcolo dell'altezza?

Scusatemi ma sulla programmazione sono ancora parecchio durino...

mixmax122:
poi questa è piu una domanda che altro perche scrivi
val = digitalRead e poi if (val == HIGH)invece di
if(digitalRead(7) == high){}
??

Si in effetti potevo usare direttamente quello.
Ma nella voglia di provare mi sono ripreso il vecchio esercizio di test per provare il bottone e non ho corretto.

Ho la netta sensazione che devo ripartire da zero e ripassarmi bene la programmazione…

inizia ad eliminare i vari

static float

in modo da riutilizzare le variabili globali definita in testa senza definirne di nuove.
Poi rivedi un po' se tutto fila provando ad eseguirlo a mente come se fossi tu il processore. Dovresti poter vedere se ci sono ulteriori cose strane.

Vaglio:
Si in effetti potevo usare direttamente quello.

Questo non è un problema, fai solo un doppio passaggio ma non è necessariamente sbagliato, è solo un'ottimizzazione.

Vaglio:
Ho la netta sensazione che devo ripartire da zero e ripassarmi bene la programmazione...

Questo non farebbe male a prescindere :wink:

Vaglio:
...
Vorrei avere modo di settare uno zero fittizio a mio piacere premendo un tasto e facendogli settare la pressione di quell'istante come altezza zero. E da lì creare il profilo altimetrico del percorso successivo.
...

Sai, vero, che la pressione atmosferica (QNH) non è sempre quella? E che, di conseguenza, il tuo zero (QFE) potrebbe essere diverso da un giorno con l'altro? (ma anche dopo poche ore). Quindi se tracci un profilo altimetrico vedi di completarlo nel più breve tempo possibile, altrimenti una isobara diversa di quella che hai settato "passa di li" e ti ritrovi con un lavoro fatto male.
Comunque se la giornata è stabile non dovresti avere problemi...

Ovvio,
Sarebbe un oggetto da utilizzare su moto o auto, più lanprima della seconda per registrare un percorso fatto.
So che può variare anche in questo modo, poiché andando da A a B potrei passare in zone di diversa pressione. Però è anche vero che non è così facile fare unabcosa che funzioni perfettamente sempre.
Per correre ho un Garmin da Trial, il Fenix 3. Ogetto fatto bene e dedicato proprio anche al rilevamento delle ascese e discese. Ed anche lui spesso, si corse su circuito chiuso o in andata e ritorno si sbaglia di qualche metro. Spesso scende di più di quanto è salito. E da un giorno all'altro mi varia l'altezza a cui mi trovo. Per via di quelle oscillazioni.
Quindi se sbaglia quello che è pensato industrialmente pernquel compito, posso accettare di avere delle letture non perfette con un oggetto fatto da me.

Poi spero anche che in eventuali uscite in pista o su percorsi che si articolano attorno ad un passo l'errore sia minimo.

Grazie mille maubarzi, tolti gli static float adesso funziona perfettamente.
Tende una volta azzerato a oscillare e andare leggermente verso valori appena negativ, tipo 10/20cm in negativo.
Ma va benissimo.
Ora devo vedere di aggiungere la parte che salva i dati su scheda SD.

Il mio suggerimento risolveva solo l'omonimia :wink:
Ora va riverificato ed eventualmente risistemato tutto il resto.

Ti crei una variabile globale, chiamiamola Zero e all'inizio la poni proprio uguale a zero.

Nel ciclo di acquisizione e stampa della quota, prima della stampa sottrai la variabile Zero alla quota.

Quando premi il pulsante, fai un'acquisizione della quota attuale e la metti nella variabile Zero.

Salve a tutti , sono nuovo nel forum….

per mettere l'altimetro a ZERO basterebbe inserire la pressione locale in questa riga al posto di 1013.25.

 Serial.print(bme.readAltitude(1013.25)); // this should be adjusted to your local forcase

ciao

>Elesoft: Buongiorno, 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 su citato REGOLAMENTO ... Grazie. :slight_smile:

Guglielmo

maubarzi:
Il mio suggerimento risolveva solo l'omonimia :wink:
Ora va riverificato ed eventualmente risistemato tutto il resto.

Era proprio l'omonimia delle variabili a far si che non riuscisse ad aggiornare la pressione di riferimento.
Adesso funziona correttamente.
L'errore verso il negativo credo sia legato semplicemente alla lettura del sensore. Si azzera memorizza il valore ma lanlettura è molto oscillante e basta pochissimo per perdere o guadagnare qualche cm sull'altezza. Temo ci sia poco da fare su quel fronte.

zoomx:
Ti crei una variabile globale, chiamiamola Zero e all'inizio la poni proprio uguale a zero.

Nel ciclo di acquisizione e stampa della quota, prima della stampa sottrai la variabile Zero alla quota.

Quando premi il pulsante, fai un'acquisizione della quota attuale e la metti nella variabile Zero.

Riuscendo a memorizzare in una variabile globale la pressione al momento del click sul bottone, tutto il calcolo tra altezza reale meno lo zero relativo lo fa in automatico il sensore attraverso il comando "bmp.readAltitude". Poiché gli dico che la pressione al livello del mare è la pressione che ha appena memorizzato.
Il mio problema è che avevo fatto del casino con la definizione delle variabili...

Non credo sia esattamente la stessa cosa.
La variazione di pressione con la quota non è lineare. Se la libreria usa la legge non lineare o la approssima con più leggi lineari a secoda della quota il risultato mi sa che non sarà lo stesso.
Significa che la variazione di 100mb al livello del mare significa una certa variazione di quota ma a 2000 metri un'altra, superiore. Di quanto non lo so ma si può fare il calcolo.
Però dipende dalla libreria.
Quella che usi tu usa una legge non lineare

/*!
 * @brief Calculates the approximate altitude using barometric pressure and the
 * supplied sea level hPa as a reference.
 * @param seaLevelhPa
 *        The current hPa at sea level.
 * @return The approximate altitude above sea level in meters.
 */
float Adafruit_BMP280::readAltitude(float seaLevelhPa) {
  float altitude;

  float pressure = readPressure(); // in Si units for Pascal
  pressure /= 100;

  altitude = 44330 * (1.0 - pow(pressure / seaLevelhPa, 0.1903));

  return altitude;
}

Edit: ho fatto i calcoli usando questa pagina

A 101325 hPa siamo a quota zero.
Sottraggo 100mb

A 91325 hPa siamo a circa 868 m che sarebbe il nostro dislivello

Se mettiamo a zero alla pressione di 1950 m 80000 hPa e poi togliamo 100mb, cioè andiamo a 70000 abbiamo una quota di 1112m che sarebbe il nostro dislivello.

Se invece lascio invariata la pressione del mare, parto da parto da 80000 (quindi 1950m) e tolgo 100Mb arrivando a 70000 mi ritrovo ad una quota di 3012, cioè un dislivello di 1062m

Quindi il dislivello, azzerando usando la pressione al livello del mare, risulta sovrastimato.

Salendo di quota le cose dovrebbero peggiorare.

Guardando il grafico indicato sembra sufficientemente lineare e regolare fino ai circa 5000m.
Facendo un paio di prove.
Se setto lo zero a circa 1000m, scalando lo stesso delta di pressione usato per salire da zero a 1000m si ottiene una quota teorica di 2106m, ho uindi un errore di circa 106m senza considerare che comunque un minimo la curva di calcolo interna si corregge in parte da sola.
Si avrebbe quindi un errore di circa il 10%.
Ma considerando che circuiti sopra i 100/200m di altezza non ce ne sono, e che se faccio un giro in moto o simili, partirei da una quota molto più bassa dei 1000m presi ad esempio prima... Direi che l'errore è trascurabile.
Inoltre per fare un azzeramento corretto servirebbe avere arduino collegato ad internet, o inserire manualmente la Pressione di riferimento di una superficie aeroportuale vicina.

Beh, certo, la misura non è proprio lineare perché l'atmosfera non è stabile e la massa d'aria non ha tutta la stessa temperatura (gradiente termico verticale) e la stessa umidità. A temperatura minore corrisponde una densità maggiore dell'aria, quindi salendo hai anche quella variabile da calcolare oltre a quella della sua umidità
Però se mi faccio queste torte quando decollo e atterro col mio aereo, non ci salgo nemmeno più :smiley:
Nel tuo caso non hai grandi variazioni di altitudine e la cosa dovrebbe essere abbastanza precisa.

Ma non puoi fare anche una lettura gps con un app sul tuo cellulare? Ci sono delle app che prevedono anche il profilo della terra con le correzioni del caso.