Greetings community,
so I would like to give you a short introduction to my problem and thanks for taking your time!
I am using an IMU (BNO055) with an MKR Zero Board.
I want to store data on that card. The data can look like this: 359,22114,-6,2,-6,0,2,-6,,2225,-40,-159,0,0,0,0
I want to store it column per column. And the data output should be around 100 hz (every 10ms).
At first i was working with a buffer, but now, I would like to store every column on its one. Because the sensor delivers new data every 10 ms, we got time in between to store the data, without missing any data.
Without any optimization, it takes about 25ms to store the data on the SD-Card.
I tried to implement the SD-Fat library by adding something like :
if (!myFile.open("test.txt", O_RDWR | O_CREAT | O_AT_END)) {
But its now even slower?
My guess is, that it is not done right, and I need to add more. I already looked into some examples and the documentation, but i am still not sure what steps I need to take to make this a success. If you got some time and wisdom, i would be very pleased if you can share it with me. I also think, that my code atm isn't that quick because of some "if's" in it, which are maybe unnecessary.
In the end i would like to combine the different outputs of the sensor to a column like:
359,22114,-6,2,-6,0,2,-6,,2225,-40,-159,0,0,0,0
And store every time this column separately to the sd-card as fast as possible to use the 100 hz the sensor is having.
Yeah i know, saving the information binary is also a good thing, which I am already trying to add. In addition, I am also trying a faster SD-Card.
Here my code, auto formatted. It may look quite long, but most of it is just configuring the data from the sensor.
I would be glad if you could explain my how to use the SD-Fat library and further opitmize my code for speed.
Thanks for your help and time!
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BNO055.h>
#include <utility/imumaths.h>
#include <SPI.h>
#include <SD.h>
#include <SPI.h>
#include "SdFat.h"
#include <avr/dtostrf.h>
#include "BNO055_support.h"
// Check I2C device address and correct line below (by default address is 0x29 or 0x28)
// id, address
Adafruit_BNO055 bno = Adafruit_BNO055(55, 0x28);
const int SAMPLE_RATE = 100; //100 Hz
const int SAMPLE_TIME = 1000 / SAMPLE_RATE; // Milisekunde
const char dataFileName[] = "test20.txt";
const int SAVE_TO_SD_TIME = 0.01; //Sekunden
const int NUMBER_OF_SAMPLES = SAMPLE_RATE * SAVE_TO_SD_TIME; //Wie viele Daten eingelesen werde bevor auf SD gespeichert
File file;
const int chipSelect = 28; // CS Pin für SD
int last_data_read = 0; //Speichert letztes Dateneinlesen
char dataString[16384]; //Buffert/Speichert Daten
int counter = 0; //Zählt wie oft Daten eingelesen
struct bno055_euler myEulerData; //Structure to hold the Euler data
struct bno055_t myBNO;
// ------------------ initializeSD&Sensor ----------------------------------
void setup(void)
{
//Initialize I2C communication
Wire.begin();
//Initialization of the BNO055
BNO_Init(&myBNO); //Assigning the structure to hold information about the device
//Configuration to NDoF mode
bno055_set_operation_mode(OPERATION_MODE_NDOF);
delay(1);
Serial.begin(19200);
//Wartet dass Serialer Monitor geöffnet wird
//Lösch mich für Feldmessungen
while (!Serial) {}
file = SD.open(dataFileName, O_CREAT | O_WRITE);
Serial.print("Number of Samples:");
Serial.println(NUMBER_OF_SAMPLES);
// SD-Card Initialise
Serial.print("Initializing SD card...");
if (!SD.begin(28)) {
Serial.println("initialization failed!");
while (1);
}
Serial.println("initialization done.");
}
void loop(void)
{
// Sensor Calibration
uint8_t system, gyro, accel, mag = 0;
bno.getCalibration(&system, &gyro, &accel, &mag);
//Wenn die System-Kalibration auf 3 ist leuchtet eine LED
if (system == 3) {
digitalWrite(LED_BUILTIN, HIGH);
delay(500);
digitalWrite(LED_BUILTIN, LOW);
delay(500);
} else {
digitalWrite(LED_BUILTIN, LOW);
}
//Einlesen und speichern
if (millis() - last_data_read >= SAMPLE_TIME) {
last_data_read = millis();
storeValues();
}
}
//Ließt Werte ein und speichert alle x Werte nach y auf die SD
void storeValues() {
sensors_event_t orientationData , angVelocityData , linearAccelData, magnetometerData, accelerometerData, gravityData;
bno.getEvent(&orientationData, Adafruit_BNO055::VECTOR_EULER);
bno.getEvent(&angVelocityData, Adafruit_BNO055::VECTOR_GYROSCOPE);
bno.getEvent(&linearAccelData, Adafruit_BNO055::VECTOR_LINEARACCEL);
bno.getEvent(&magnetometerData, Adafruit_BNO055::VECTOR_MAGNETOMETER);
bno.getEvent(&accelerometerData, Adafruit_BNO055::VECTOR_ACCELEROMETER);
bno.getEvent(&gravityData, Adafruit_BNO055::VECTOR_GRAVITY);
counter = counter + 1;
//--------------------add to the array-----------------------------------
// setting up the struct
// struct datastore {
// uint16_t count_c;
// struct datastore myData;
// uint16_t timestamp;
// uint16_t accelerometerX;
// uint16_t accelerometerY;
// uint16_t accelerometerZ;
// uint16_t gyroscopeX;
// uint16_t gyroscopeY;
// uint16_t gyroscopeZ;
// };
//Speichert count
char count_c[16];
itoa(counter, count_c, 10);
strcat(dataString, count_c);
strcat(dataString, ",");
//Speichert Zeit
int t = millis();
char timestamp[16];
itoa(t, timestamp, 10); //Konvertiert int to char[]
strcat(dataString, timestamp);
strcat(dataString, ",");
/*______ACCELEROMETER_____*/
imu::Vector<3> acc = bno.getVector(Adafruit_BNO055::VECTOR_ACCELEROMETER);
int ax = int(acc.x());
char accelerometerX[8];
itoa(ax, accelerometerX, 10); //Konvertiert int to char[]
int ay = int(acc.y());
char accelerometerY[8];
itoa(ay, accelerometerY, 10); //Konvertiert int to char[]
int az = int(acc.z());
char accelerometerZ[8];
itoa(az, accelerometerZ, 10); //Konvertiert int to char[]
strcat(dataString, accelerometerX);
strcat(dataString, ",");
strcat(dataString, accelerometerY);
strcat(dataString, ",");
strcat(dataString, accelerometerZ);
strcat(dataString, ",");
/*______GYROSCOPE_____*/
imu::Vector<3> gyr = bno.getVector(Adafruit_BNO055::VECTOR_GYROSCOPE);
int gx = int(gyr.x());
char gyroscopeX[8];
itoa(gx, gyroscopeX, 10); //Konvertiert int to char[]
int gy = int(acc.y());
char gyroscopeY[8];
itoa(gy, gyroscopeY, 10); //Konvertiert int to char[]
int gz = int(acc.z());
char gyroscopeZ[8];
itoa(gz, gyroscopeZ, 10); //Konvertiert int to char[]
strcat(dataString, gyroscopeX);
strcat(dataString, ",");
strcat(dataString, gyroscopeY);
strcat(dataString, ",");
strcat(dataString, gyroscopeZ);
strcat(dataString, ",");
/*______System Calibration_____*/
uint8_t system, gyro, accel, mag = 0;
bno.getCalibration(&system, &gyro, &accel, &mag);
int systemcali = int(system);
char systemcalibration[10];
itoa(systemcali, systemcalibration, 10); //Konvertiert int to char[]
strcat(dataString, ",");
strcat(dataString, systemcalibration);
Serial.print (systemcalibration);
/*______VECTOR_EULER_____*/
imu::Vector<3> euler = bno.getVector(Adafruit_BNO055::VECTOR_EULER);
int ex = int(euler.x());
char eulerX[8];
itoa(ex, eulerX, 10); //Konvertiert int to char[]
int ey = int(euler.y());
char eulerY[8];
itoa(ey, eulerY, 10); //Konvertiert int to char[]
int ez = int(euler.z());
char eulerZ[8];
itoa(ez, eulerZ, 10); //Konvertiert int to char[]
strcat(dataString, eulerX);
strcat(dataString, ",");
strcat(dataString, eulerY);
strcat(dataString, ",");
strcat(dataString, eulerZ);
strcat(dataString, ",");
/*______Quaternion_____*/
imu::Quaternion quat = bno.getQuat();
int qw = int(quat.w());
char quaternionW[8];
itoa(qw, quaternionW, 10); //Konvertiert int to char[]
int qx = int(quat.y());
char quaternionX[8];
itoa(qx, quaternionX, 10); //Konvertiert int to char[]
int qy = int(quat.x());
char quaternionY[8];
itoa(qy, quaternionY, 10); //Konvertiert int to char[]
int qz = int(quat.z());
char quaternionZ[6];
itoa(qz, quaternionZ, 10); //Konvertiert int to char[]
strcat(dataString, quaternionW);
strcat(dataString, ",");
strcat(dataString, quaternionX);
strcat(dataString, ",");
strcat(dataString, quaternionY);
strcat(dataString, ",");
strcat(dataString, quaternionZ);
strcat(dataString, "\n");
//Abspeichern auf SD nach NUMBER_OF_SAMPLES eingelesenen Daten
// if (counter >= NUMBER_OF_SAMPLES) {
writeStringToSD(dataString, dataFileName); //Speichert auf SD
Serial.println("DONE ");
//Zurücksetzen der Variablen
memset(dataString, 0, sizeof(dataString)); //Speichert 0er in Datenarray
// }
}
// ------------------ writeStringToSD ----------------------------------
//Ein belibiger String wird in ein belibiges Files geschrieben
boolean writeStringToSD(const char *data, const char *filename) {
stopWatch(); //Startet Stoppuhr
Serial.print("Writing to: ");
Serial.println(filename);
file = SD.open(filename, FILE_WRITE); //Öffnet file zum Lesen
if (file) { //Wenn File erfolgreich geöffnet wurde
file.println(data); //Schreibt Datenstring ans Ende des Files
}
else {
Serial.println("Error while opening the file!");
return false;
}
file.close(); //Schließt File (Daten werden gesichert)
stopWatch(); //Beendet Stoppuhr
return true;
}
// ------------------ Stoppuhr ----------------------------------
boolean stopWatch_started = false;
int stopWatch_time;
void stopWatch() {
if (stopWatch_started == false) {
stopWatch_time = millis();
stopWatch_started = true;
}
else {
int duration = millis() - stopWatch_time;
Serial.print("Duartion: ");
Serial.print(duration);
Serial.println(" ms");
stopWatch_started = false;
}
}
//Systemcalibration aufzeichnen geht nicht und aufnahmefrequenz ist bei etwa 35ms