Come caricare il buffer e salvare senza perdita di dati

di il
7 risposte

Come caricare il buffer e salvare senza perdita di dati

Salve a tutti, non ho grandissima esperienza in C++ in quanto è solo da un anno che lo sto utilizzando. Ho imparato a salvare i dati dei sensori che registravo tramite seriale o tramite sd. Ora ho integrato il wifi e vorrei sfruttarlo per farmi inviare i dati direttamente al computer. Ho bisogno di chiarimenti e/o dritte in quanto sono però confuso.
Sostanzialmente ho creato un applicazione che da remoto mi gestisce la board con i vari sensori, i cui dati voglio appunto salvare. Immaginando di accendere all'istante A i sensori, iniziare a registrare e spegnere al momento B i sensori, mi chiedo quanto debba essere grande il buffer. Ho notato che esiste anche il circularbuffer, forse meno computazionale, ma non capisco comunque la size del buffer nè quando inviare i dati e quando svuotare il buffer.
Gli output sono 10 in riga, separati da una virgola, e ognuno ha 1/2/3 cifre.
Il mio hardware: https://content.arduino.cc/assets/Datasheet-Portenta-H7.pdf https://cdn-learn.adafruit.com/downloads/pdf/adafruit-bno055-absolute-orientation-sensor.pdf


Lo sketch per testare il buffer è questo, dove voglio salvare phi e dove con più di 100 non sembrava funzionare. il problema aggiuntivo è che qui il valore di phi non cambia nonostante il movimento dell'imu bno055
/****  BNO055  ****/
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BNO055.h>
#include <utility/imumaths.h>

Adafruit_BNO055 bno = Adafruit_BNO055(55);   //(55);  //(-1, 0x28);
float q0, q1, q2, q3, gx, gy, gz, norm, phi, v0, v1, v2, linacc;
float radtodeg = 57296 / 1000;


int anArray[100];  
byte arrayIndex = 0;
int i=0;

void setup() {
  Serial.begin(57600);

   Wire.begin();

  /****  BNO055  ****/
  if (!bno.begin())
  {
    Serial.print("Ooops, no BNO055 detected ... Check your wiring or I2C ADDR!");
    while (1);
  }
  bno.setExtCrystalUse(true);
}

void loop() {

   imu::Quaternion quat = bno.getQuat();
  imu::Vector<3> lin = bno.getVector (Adafruit_BNO055::VECTOR_LINEARACCEL );
  q0 = quat.w(); q1 = quat.x(); q2 = quat.y(); q3 = quat.z();
  gx = q1 * q3 - q0 * q2; gy = q0 * q1 + q2 * q3; gz = q0 * q0 + q3 * q3 - 0.5f;
  norm = sqrt(gx * gx + gy * gy + gz * gz); norm = 1.0 / norm;
  gx *= norm; gy *= norm; gz *= norm;
  phi = acos(gx); phi = phi * radtodeg;
  v0 = lin.x(); v1 = lin.y(); v2 = lin.z();

  
  while (arrayIndex<99){
   anArray[arrayIndex] = phi;  //put a value in entry 0
  arrayIndex++;  //increment the array index
  i++;
  }
  
  Serial.println("array filled");
delay(3000);
for(int j = 0; j < 99; j++)
{
  Serial.println(anArray[j]);
 
}
   Serial.println();
   delay(1500);
 

}
Grazie a tutti per qualsiasi indicazione utile

7 Risposte

  • Re: Come caricare il buffer e salvare senza perdita di dati

    Ci sono due approcci che puoi seguire.

    SOLUZIONE 1) Allocazione statica

    1) fare una valutazione di quanti byte ti servono per rappresentare il dato ""piu' grande"".
    Diciamo 3 difre decimali.
    Se il numero puo' essere negativo, serve un carattere per il segno. E siamo a 4.
    I numeri sono separati da una vrigola. Quindi 5 caratteri.
    I numeri sono 10, quindi 50 caratteri.

    2) ti serve sapere quanti "blocchetti" di 10 numeri vengono inviati ""al secondo"".
    Questo lo devi valututare tu facendo un po' di esperimenti.
    Supponiamo anche che il numero di bloccheti generati al secondo dipenda dalla lunghezza
    dei numeri. Quindi devi considerare il caso in di generazione ""piu' veloce"".
    Diciamo che, alla massima velocita' vengono generati 10 blocchetti di numeri.
    Quindi ti servono 500 caratteri.

    3) Poiche' queste sono ""stime"", devi assicurarti di avere spazio nel caso che le stime siano
    ""sottostimate"". Quindi abbondiamo un po': moltiplica la dimensione del buffer
    calcolato al punto 2 per 1.5 o meglio 2.
    Diciamo 2. Quindi ti servono 1000 caratteri al secondo.

    4) Ora ti serve sapere per quanto tempo vuoi bufferizzare i dati.
    Diciamo 1 minuto, cioe' 60 secondi. Quindi ti servono 60000 caratteri.
    Anche qui' abbondiamo un po', non si sa mai: diciamo che come limite massimo di tempo
    imposti 2 minuti, 120 secondi. Quindi ti servono 120000 caratteri.

    Quindi, secondo le ""stime"" fatte sopra (che tu dovrai riadattare secondo i TUOI calcoli),
    SE allochi un buffer di 120000 byte, hai abbastanza spazio per acquisire i dati per 2 minuti.


    SOLUZIONE 2) allocazione DINAMICA

    per questa soluzione devi usare l'allocazione dinamica della memoria.
    Cioe' usare le funzioni malloc/calloc/free della libreria standard C/C++.

    L'allocazione della memoria e' il ""tallone d'Achille"" del linguaggio C.

    Tutti pensano che sia un linguaggio ""semplice"" perche' ha pochi costrutti.
    MA la VERA difficolta' consiste nella CORRETTA GESTIONE della memoria.
    E' COMPLICATA ANCHE per gente che n-milioni di anni di esperienza.

    Spiegare come si fa da 0, mediante dei post, e' un'impresa impossibile.

    E' meglio che ti studi l'argomento su qualche buon libro di testo e solo DOPO
    fai le domande.

    Una delle soluzione e' appunto i buffer circolare, MA SOLO se ti e' PERFETTAMENTE
    CHIARO come funziona e quali sono i suoi limiti.
    Ad esempio: che fai se il buffer E' COMPLETAMENTE PIENO?
  • Re: Come caricare il buffer e salvare senza perdita di dati

    Ma nei casi embedded non è il SO a prevedere delle funzioni per l'allocazione?
  • Re: Come caricare il buffer e salvare senza perdita di dati

    
    while (arrayIndex<99){
       anArray[arrayIndex] = phi;  //put a value in entry 0
      arrayIndex++;  //increment the array index
      i++;
      }
    
    Beh è normale che non cambi l'angolo: hai lasciato fuori dal while acquisizione e calcoli... e poi i a che ti serve?

    Rimettili dentro al while e mettici un delay di un secondo o di quanto vuoi tu, oppure non mettere proprio il while e usa il delay del loop() (il loop è già il while infinito del main() in Arduino). Comincia a sistemare questo, che tanto hai megabyte di RAM: non credo che ci arrivi in fondo se ci metti un array abbastanza grande e non penso che tu stia facendo un drive dove devi leggere la posizione di continuo
  • Re: Come caricare il buffer e salvare senza perdita di dati

    migliorabile ha scritto:



    SOLUZIONE 1) Allocazione statica
    Grazie delle tue spiegazioni. Il mio sistema lavora a 100Hz. Ad ogni instate di campionamento il mio output, inserendo tutti i digit possibili, avrebbe una forma del genere ##### , ##.## , ##.## , ### , # , +-### , ## con 37 caratteri. Espandendo il calcolo al secondo e raddoppiando per avere la soglia di sicurezza arrivo a 740caratteri/sec. I 2 minuti dovrebbero bastare. Quindi il finale fa 88800.
    Online non ci sono tanti esempi pratici. Io vorrei capire come si inizializza un buffer del genere e come converto ad ogni loop gli int, i float e le virgole da inserirci dentro. Non voglio la soluzione sia chiaro, ma una ragionamento che possa condurmi alla soluzione e magari qualche piccolo esempio.
    Cio che ho fatto, ingenuamente, è stato:
    
    /******STORING********/
    const unsigned int BUFFER_SIZE = 15;
    int buffer[BUFFER_SIZE];
    e nel loop caricavo ad ogni elemento i-esimo il corrispondente valore. Spero di non avere scritto una balasfemia, anche se ne dubito.
    Se con l'allocazione statica ho il tempo di 2 minuti di registrazione, significa che non ho necessità di svuotare il buffer, e che lo invio al server una sola volta. Anche qui, dico bene?
    Grazie mille della pazienza
  • Re: Come caricare il buffer e salvare senza perdita di dati

    Alexv ha scritto:


    Ma nei casi embedded non è il SO a prevedere delle funzioni per l'allocazione?
    Non ho ben capito se mi serve una carrier per accedere alla sdram. Nella pagina officiale Arduino trovo solo questo esempio https://docs.arduino.cc/tutorials/portenta-h7/reading-writing-flash-memory e non credo faccia al caso mio in quanto dice che per la lettura di un sensore potrebbe rovinare la scheda. Tu che ne pensi?
  • Re: Come caricare il buffer e salvare senza perdita di dati

    Weierstrass ha scritto:



    Rimettili dentro al while e mettici un delay di un secondo o di quanto vuoi tu, oppure non mettere proprio il while e usa il delay del loop() (il loop è già il while infinito del main() in Arduino). Comincia a sistemare questo, che tanto hai megabyte di RAM: non credo che ci arrivi in fondo se ci metti un array abbastanza grande e non penso che tu stia facendo un drive dove devi leggere la posizione di continuo
    Pensi bene, non voglio collezionare solo la posizione. Questo era un test per iniziare a capire il buffer dato che non ne ho mai utilizzato uno. Grazie in ogni caso della dritta.
  • Re: Come caricare il buffer e salvare senza perdita di dati

    Lascia perdere la scrittura in flash, ci manca pure fare una cosa del genere per i dati di un sensore.

    Non so se ci arrivi alle letture ogni 10 ms. Comincia a usare i 100 ms a lettura in polling consigliati, poi si vedrà.

    Per dire, se vuoi fare 600 letture (1 minuto) ogni 5 minuti (più o meno, perché se vuoi i tempi esatti devi usare i timer e non il polling):
    
    /****  BNO055  ****/
    #include <Wire.h>
    #include <Adafruit_Sensor.h>
    #include <Adafruit_BNO055.h>
    #include <utility/imumaths.h>
    
    Adafruit_BNO055 bno = Adafruit_BNO055(55);   //(55);  //(-1, 0x28);
    float q0, q1, q2, q3, gx, gy, gz, norm, phi, v0, v1, v2, linacc;
    float radtodeg = 57296.0 / 1000.0;
    
    float anArray[600];  
    int arrayIndex = 0;
    
    int clock = 0;
    
    void setup() {
      Serial.begin(57600);
    
      Wire.begin();
    
      /****  BNO055  ****/
      if (!bno.begin()){
        Serial.print("Ooops, no BNO055 detected ... Check your wiring or I2C ADDR!");
        while(1);
      }
      bno.setExtCrystalUse(true);
      delay(1000);
    }
    
    void loop() {
       if(clock < 600){
       	imu::Quaternion quat = bno.getQuat();
       	imu::Vector<3> lin = bno.getVector (Adafruit_BNO055::VECTOR_LINEARACCEL );
       	q0 = quat.w(); q1 = quat.x(); q2 = quat.y(); q3 = quat.z();
       	gx = q1 * q3 - q0 * q2; gy = q0 * q1 + q2 * q3; gz = q0 * q0 + q3 * q3 - 0.5f;
       	norm = sqrt(gx * gx + gy * gy + gz * gz); norm = 1.0 / norm;
       	gx *= norm; gy *= norm; gz *= norm;
       	phi = acos(gx); phi = phi * radtodeg;
       	v0 = lin.x(); v1 = lin.y(); v2 = lin.z();
       	
       	anArray[arrayIndex] = phi; 
       	Serial.print(anArray[arrayIndex], 6);
            Serial.println();   	
       	arrayIndex++;
       }
    
       delay(100);
       if(++clock >= 3000){
          Serial.println();
          clock = 0;
          arrayIndex = 0;
       }
    }
    
Devi accedere o registrarti per scrivere nel forum
7 risposte