Saving IMU data to microSD

Hi, I am building a rocket flight computer and I would like to save the x,y, and z position along with a few other parameters to an sd card. I have a circuit that connects the sd card reader, an arduino nano, and a MPU6050 inertial measurement unit together. I have code that works for generating that position data and I would like to integrate the SD libraries datalogging.ino but I get an error that says "error opening flightdata.txt" even though the library example code works fine. Please let me know how to fix this!

// Libraries
  #include <Wire.h>
  #include <MPU6050.h> //includes intertial measurement library
  #include <SPI.h>
  #include <SD.h> //includes SD card reader library
  File dataFile;
//////////////////////////////////////////////////////////////////////////////////////////

  const int chipSelect = 4;

  MPU6050 mpu;
  
  // Timers
  unsigned long timer = 0;
  float timeStep = 0.01;
  
  // Pitch, Roll and Yaw starting values
  float pitch = 0;
  float roll = 0;
  float yaw = 0;
  float t = 0;

//////////////////////////////////////////////////////////////////////////////////////////
void setup() 
{
  Serial.begin(9600);
/////////////////////////////////////////////
  // Initialize SD Card Reader 
    while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  Serial.print("Initializing SD card...");

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");
/////////////////////////////////////////////
dataFile = SD.open("flightdata.txt", FILE_WRITE);  
/////////////////////////////////////////////
  // Initialize MPU6050
  Serial.println("Initialize MPU6050");
  while(!mpu.begin(MPU6050_SCALE_2000DPS, MPU6050_RANGE_2G))
  {
    Serial.println("Could not find a valid MPU6050 sensor, check wiring!");
    delay(500);
  }

  // Calibrate gyroscope. The calibration must be at rest.
  // If you don't want calibrate, comment this line.
  mpu.calibrateGyro();

  // Set threshold sensivty. Default 3.
  // If you don't want use threshold, comment this line or set 0.
  mpu.setThreshold(3);
  
  // Check settings
  checkSettings();
}
//////////////////////////////////////////////////////////////////////////////////////////
void checkSettings()
{
  Serial.println();
  
  Serial.print(" * Sleep Mode:        ");
  Serial.println(mpu.getSleepEnabled() ? "Enabled" : "Disabled");
  
  Serial.print(" * Clock Source:      ");
  switch(mpu.getClockSource())
  {
    case MPU6050_CLOCK_KEEP_RESET:     Serial.println("Stops the clock and keeps the timing generator in reset"); break;
    case MPU6050_CLOCK_EXTERNAL_19MHZ: Serial.println("PLL with external 19.2MHz reference"); break;
    case MPU6050_CLOCK_EXTERNAL_32KHZ: Serial.println("PLL with external 32.768kHz reference"); break;
    case MPU6050_CLOCK_PLL_ZGYRO:      Serial.println("PLL with Z axis gyroscope reference"); break;
    case MPU6050_CLOCK_PLL_YGYRO:      Serial.println("PLL with Y axis gyroscope reference"); break;
    case MPU6050_CLOCK_PLL_XGYRO:      Serial.println("PLL with X axis gyroscope reference"); break;
    case MPU6050_CLOCK_INTERNAL_8MHZ:  Serial.println("Internal 8MHz oscillator"); break;
  }
  
  Serial.print(" * Gyroscope:         ");
  switch(mpu.getScale())
  {
    case MPU6050_SCALE_2000DPS:        Serial.println("2000 dps"); break;
    case MPU6050_SCALE_1000DPS:        Serial.println("1000 dps"); break;
    case MPU6050_SCALE_500DPS:         Serial.println("500 dps"); break;
    case MPU6050_SCALE_250DPS:         Serial.println("250 dps"); break;
  } 
  
  Serial.print(" * Gyroscope offsets: ");
  Serial.print(mpu.getGyroOffsetX());
  Serial.print(" / ");
  Serial.print(mpu.getGyroOffsetY());
  Serial.print(" / ");
  Serial.println(mpu.getGyroOffsetZ());
  
  Serial.println();
}
//////////////////////////////////////////////////////////////////////////////////////////
void loop()
{  
  // Read normalized values
  Vector normGyro = mpu.readNormalizeGyro();

  // Calculate Pitch, Roll and Yaw
  pitch = pitch + normGyro.YAxis * timeStep;
  roll = roll + normGyro.XAxis * timeStep;
  yaw = yaw + normGyro.ZAxis * timeStep;

  // Output raw
  Serial.print(t);
  Serial.print(";");
  Serial.print(normGyro.XAxis);
  Serial.print(";");
  Serial.print(normGyro.YAxis);
  Serial.print(";");
  Serial.print(normGyro.ZAxis);
  Serial.print(";");
  Serial.print(pitch);
  Serial.print(";");
  Serial.print(roll);  
  Serial.print(";");
  Serial.print(yaw);
  Serial.print(";");  
  Serial.println(" "); 
  
  delay(10);
  t = t+1;
/////////////////////////////////////////////  
  float dataString = t + normGyro.XAxis + normGyro.YAxis + normGyro.ZAxis + pitch + roll + yaw;

  // if the file is available, write to it:
  dataFile = SD.open("flightdata.txt", FILE_WRITE);  
  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening flightdata.txt");
  }
  if(t > 32765){          //prevents issues related to integers rolling over at 32767
    t = 1;
  }
        
}

The problem is almost certainly the length of the filename which is limited to the 8.3 format

1 Like

If you want to write data quickly, this is the worst approach you can possibly take. Opening the file, writing a speck of data and then closing it again slows down the process to a crawl, and vastly increases the error rate.

Open the file once in setup(), and close it again when you are done collecting data.

This won't work, either:

float dataString = t + normGyro.XAxis + normGyro.YAxis + normGyro.ZAxis + pitch + roll + yaw;

Thanks for the reply. I changed the text file name to "data.txt" and I am getting the same problem. Is there something I am still doing wrong there?

Hi thanks for the reply! Is there a better way to make that string? Also, when I close the file with data.close(); after the void loop, I get an error that says "data does not name a type"

Don't even try to make a string, or a String.

Just write to the file using dataFile.print() statements, similar to this series (replace "Serial" with "dataFile"):

  Serial.print(t);
  Serial.print(";");
  Serial.print(normGyro.XAxis);
  Serial.print(";");
  Serial.print(normGyro.YAxis);
  Serial.print(";");
  Serial.print(normGyro.ZAxis);
...
  Serial.println();

I changed the text file name to "data.txt" and I am getting the same problem.

Post the revised code (using code tags) and the error message.

  if (data) {
    data.print(t);
    data.print(";");
    data.print(normGyro.XAxis);
    data.print(";");
    data.print(normGyro.YAxis);
    data.print(";");
    data.print(normGyro.ZAxis);
    data.print(";");
    data.print(pitch);
    data.print(";");
    data.print(roll);
    data.print(";");
    data.print(yaw);
    data.print(";");
    data.println(" ");
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening data.txt");

Then I added this line after the loop()

data.close();

Which gives the error 'data' does not name a type.

post whole sketch, not instruction how to create one

1 Like
void setup() {}
void loop() {}
data.close(); // here?

Post ALL the code.

// Libraries
#include <Wire.h>
#include <MPU6050.h> //includes intertial measurement library
#include <SPI.h>
#include <SD.h> //includes SD card reader library
File data;
//////////////////////////////////////////////////////////////////////////////////////////

const int chipSelect = 4;

MPU6050 mpu;

// Timers
unsigned long timer = 0;
float timeStep = 0.01;

// Pitch, Roll and Yaw starting values
float pitch = 0;
float roll = 0;
float yaw = 0;
float t = 0;

//////////////////////////////////////////////////////////////////////////////////////////
void setup()
{
  Serial.begin(9600);
  /////////////////////////////////////////////
  // Initialize SD Card Reader
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  Serial.print("Initializing SD card...");

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");

  data = SD.open("data.txt", FILE_WRITE);
  data.println("New Run");
  data.close();
  /////////////////////////////////////////////
  // Initialize MPU6050
  Serial.println("Initialize MPU6050");
  while (!mpu.begin(MPU6050_SCALE_2000DPS, MPU6050_RANGE_2G))
  {
    Serial.println("Could not find a valid MPU6050 sensor, check wiring!");
    delay(500);
  }

  // Calibrate gyroscope. The calibration must be at rest.
  // If you don't want calibrate, comment this line.
  mpu.calibrateGyro();

  // Set threshold sensivty. Default 3.
  // If you don't want use threshold, comment this line or set 0.
  mpu.setThreshold(3);

  // Check settings
  checkSettings();
}
//////////////////////////////////////////////////////////////////////////////////////////
void checkSettings()
{
  Serial.println();

  Serial.print(" * Sleep Mode:        ");
  Serial.println(mpu.getSleepEnabled() ? "Enabled" : "Disabled");

  Serial.print(" * Clock Source:      ");
  switch (mpu.getClockSource())
  {
    case MPU6050_CLOCK_KEEP_RESET:     Serial.println("Stops the clock and keeps the timing generator in reset"); break;
    case MPU6050_CLOCK_EXTERNAL_19MHZ: Serial.println("PLL with external 19.2MHz reference"); break;
    case MPU6050_CLOCK_EXTERNAL_32KHZ: Serial.println("PLL with external 32.768kHz reference"); break;
    case MPU6050_CLOCK_PLL_ZGYRO:      Serial.println("PLL with Z axis gyroscope reference"); break;
    case MPU6050_CLOCK_PLL_YGYRO:      Serial.println("PLL with Y axis gyroscope reference"); break;
    case MPU6050_CLOCK_PLL_XGYRO:      Serial.println("PLL with X axis gyroscope reference"); break;
    case MPU6050_CLOCK_INTERNAL_8MHZ:  Serial.println("Internal 8MHz oscillator"); break;
  }

  Serial.print(" * Gyroscope:         ");
  switch (mpu.getScale())
  {
    case MPU6050_SCALE_2000DPS:        Serial.println("2000 dps"); break;
    case MPU6050_SCALE_1000DPS:        Serial.println("1000 dps"); break;
    case MPU6050_SCALE_500DPS:         Serial.println("500 dps"); break;
    case MPU6050_SCALE_250DPS:         Serial.println("250 dps"); break;
  }

  Serial.print(" * Gyroscope offsets: ");
  Serial.print(mpu.getGyroOffsetX());
  Serial.print(" / ");
  Serial.print(mpu.getGyroOffsetY());
  Serial.print(" / ");
  Serial.println(mpu.getGyroOffsetZ());

  Serial.println();
}
//////////////////////////////////////////////////////////////////////////////////////////
void loop()
{
  // Read normalized values
  Vector normGyro = mpu.readNormalizeGyro();

  // Calculate Pitch, Roll and Yaw
  pitch = pitch + normGyro.YAxis * timeStep;
  roll = roll + normGyro.XAxis * timeStep;
  yaw = yaw + normGyro.ZAxis * timeStep;

  // Output raw
  Serial.print(t);
  Serial.print(";");
  Serial.print(normGyro.XAxis);
  Serial.print(";");
  Serial.print(normGyro.YAxis);
  Serial.print(";");
  Serial.print(normGyro.ZAxis);
  Serial.print(";");
  Serial.print(pitch);
  Serial.print(";");
  Serial.print(roll);
  Serial.print(";");
  Serial.print(yaw);
  Serial.print(";");
  Serial.println(" ");

  data = SD.open("data.txt", FILE_WRITE);
  data.print(t);
  data.print(";");
  data.print(normGyro.XAxis);
  data.print(";");
  data.print(normGyro.YAxis);
  data.print(";");
  data.print(normGyro.ZAxis);
  data.print(";");
  data.print(pitch);
  data.print(";");
  data.print(roll);
  data.print(";");
  data.print(yaw);
  data.print(";");
  data.println(" ");
  data.close();

  delay(10);

  /////////////////////////////////////////////
  t = t + 1;
  if (t > 32765) {
    t = 1;
  }
}

I tried what you said about just opening the file in the setup() and it just generates a blank txt file

You open the file and define "data" in setup(), so it is a local variable and is invisible to the loop function.

The "data" variable needs to be declared as a global variable of type File.

Spend some more time studying the documentation and examples that come with the SD library.

I used an example to make this simplified code which just prints the variable t and saves it to the txt file and that works no problem.

// Libraries

#include <SPI.h>
#include <SD.h> //includes SD card reader library
File data;
//////////////////////////////////////////////////////////////////////////////////////////
const int chipSelect = 4;
float t = 0;
//////////////////////////////////////////////////////////////////////////////////////////
void setup()
{
  Serial.begin(9600);
  /////////////////////////////////////////////
  // Initialize SD Card Reader
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  Serial.print("Initializing SD card...");

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");
  data = SD.open("data.txt", FILE_WRITE);
  data.println("New Run");
  data.close();
}
//////////////////////////////////////////////////////////////////////////////////////////
void loop()
{
  // Output raw
  Serial.println(t);
  data = SD.open("data.txt", FILE_WRITE);
  data.println(t);
  data.close();
  t = t + 1;
  delay(1000);
}

But I tired the exact same method for my larger code and nothing saves.

// Libraries
#include <Wire.h>
#include <MPU6050.h> //includes intertial measurement library
#include <SPI.h>
#include <SD.h> //includes SD card reader library
File data;
//////////////////////////////////////////////////////////////////////////////////////////

const int chipSelect = 4;

MPU6050 mpu;

// Timers
unsigned long timer = 0;
float timeStep = 0.01;

// Pitch, Roll and Yaw starting values
float pitch = 0;
float roll = 0;
float yaw = 0;
float t = 0;

//////////////////////////////////////////////////////////////////////////////////////////
void setup()
{
  Serial.begin(9600);
  /////////////////////////////////////////////
  // Initialize SD Card Reader
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  Serial.print("Initializing SD card...");

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");

  data = SD.open("data.txt", FILE_WRITE);
  data.println("New Run");
  data.close();
  /////////////////////////////////////////////
  // Initialize MPU6050
  Serial.println("Initialize MPU6050");
  while (!mpu.begin(MPU6050_SCALE_2000DPS, MPU6050_RANGE_2G))
  {
    Serial.println("Could not find a valid MPU6050 sensor, check wiring!");
    delay(500);
  }

  // Calibrate gyroscope. The calibration must be at rest.
  // If you don't want calibrate, comment this line.
  mpu.calibrateGyro();

  // Set threshold sensivty. Default 3.
  // If you don't want use threshold, comment this line or set 0.
  mpu.setThreshold(3);

  // Check settings
  checkSettings();
}
//////////////////////////////////////////////////////////////////////////////////////////
void checkSettings()
{
  Serial.println();

  Serial.print(" * Sleep Mode:        ");
  Serial.println(mpu.getSleepEnabled() ? "Enabled" : "Disabled");

  Serial.print(" * Clock Source:      ");
  switch (mpu.getClockSource())
  {
    case MPU6050_CLOCK_KEEP_RESET:     Serial.println("Stops the clock and keeps the timing generator in reset"); break;
    case MPU6050_CLOCK_EXTERNAL_19MHZ: Serial.println("PLL with external 19.2MHz reference"); break;
    case MPU6050_CLOCK_EXTERNAL_32KHZ: Serial.println("PLL with external 32.768kHz reference"); break;
    case MPU6050_CLOCK_PLL_ZGYRO:      Serial.println("PLL with Z axis gyroscope reference"); break;
    case MPU6050_CLOCK_PLL_YGYRO:      Serial.println("PLL with Y axis gyroscope reference"); break;
    case MPU6050_CLOCK_PLL_XGYRO:      Serial.println("PLL with X axis gyroscope reference"); break;
    case MPU6050_CLOCK_INTERNAL_8MHZ:  Serial.println("Internal 8MHz oscillator"); break;
  }

  Serial.print(" * Gyroscope:         ");
  switch (mpu.getScale())
  {
    case MPU6050_SCALE_2000DPS:        Serial.println("2000 dps"); break;
    case MPU6050_SCALE_1000DPS:        Serial.println("1000 dps"); break;
    case MPU6050_SCALE_500DPS:         Serial.println("500 dps"); break;
    case MPU6050_SCALE_250DPS:         Serial.println("250 dps"); break;
  }

  Serial.print(" * Gyroscope offsets: ");
  Serial.print(mpu.getGyroOffsetX());
  Serial.print(" / ");
  Serial.print(mpu.getGyroOffsetY());
  Serial.print(" / ");
  Serial.println(mpu.getGyroOffsetZ());

  Serial.println();
}
//////////////////////////////////////////////////////////////////////////////////////////
void loop()
{
  data = SD.open("data.txt", FILE_WRITE);
  // Read normalized values
  Vector normGyro = mpu.readNormalizeGyro();

  // Calculate Pitch, Roll and Yaw
  pitch = pitch + normGyro.YAxis * timeStep;
  roll = roll + normGyro.XAxis * timeStep;
  yaw = yaw + normGyro.ZAxis * timeStep;

  // Output raw
  Serial.print(t);
  Serial.print(";");
  Serial.print(normGyro.XAxis);
  Serial.print(";");
  Serial.print(normGyro.YAxis);
  Serial.print(";");
  Serial.print(normGyro.ZAxis);
  Serial.print(";");
  Serial.print(pitch);
  Serial.print(";");
  Serial.print(roll);
  Serial.print(";");
  Serial.print(yaw);
  Serial.print(";");
  Serial.println(" ");

  data.print(t);
  data.print(";");
  data.print(normGyro.XAxis);
  data.print(";");
  data.print(normGyro.YAxis);
  data.print(";");
  data.print(normGyro.ZAxis);
  data.print(";");
  data.print(pitch);
  data.print(";");
  data.print(roll);
  data.print(";");
  data.print(yaw);
  data.print(";");
  data.println(" ");

  data.close();
  delay(10);

  /////////////////////////////////////////////
  t = t + 1;
  if (t > 32765) {
    t = 1;
  }
}

No, you did not. Reread post #13.

You are still making the mistake of opening the file in loop(), writing a bit of data, then closing it.

filename has to be DOS FAT 8.3.

flightdata.txt

is 10.3, invalid filename

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