SD Card is not working (data logger) in a rocket

Hello everyone,

I've been developing a thrust vectoring controlled rocket since 7 months.
(To share thrust vectoring control code is illegal, therefore i'm not going to give you this part of the code)

I'm pretty advanced in my project, however my flight computer (image, PCB,
schematic below) encounters an issue with the data logging. In fact, the code is compiled and everything is working on the rocket except the SD Card.

Something that caught my attention is that it's working in the setup but not in the loop.

Here is the censured code:

/*

  Flight Software for Sprite's first launch
  Specifications: TIP120, 7.4v S-erc lipo battery

  Designed for Sprite's first flight computer

  Code written by Ethan D.
  No use permitted
*/

// --- Inertial unit and Accelerometer --- //

#include <Arduino_LSM6DS3.h>
#include "Wire.h"

float accelX,            accelY,             accelZ,            // units m/s/s i.e. accelZ if often 9.8 (gravity)
      gyroX,             gyroY,              gyroZ,             // units dps (degrees per second)
      gyroDriftX,        gyroDriftY,         gyroDriftZ,        // units dps
      gyroRoll,          gyroPitch,          gyroYaw,           // units degrees (expect major drift)
      gyroCorrectedRoll, gyroCorrectedPitch, gyroCorrectedYaw,  // units degrees (expect minor drift)
      accRoll,           accPitch,           accYaw,            // units degrees (roll and pitch noisy, yaw not possible)
      complementaryRoll, complementaryPitch, complementaryYaw;  // units degrees (excellent roll, pitch, yaw minor drift)

long lastTime;
long lastInterval;

// --- Bluetooth Low Energy unit --- //

#include <ArduinoBLE.h>

BLEService ledService("180A");
BLEByteCharacteristic switchCharacteristic("2A57", BLERead | BLEWrite);

// --- Barometer and temperature sensor --- //

#include <Adafruit_BMP085.h>

Adafruit_BMP085 bmp;
#define seaLevelPressure_hPa 1013.25

float altitude;
float temp;
float FirstAltitude;
float CurrentAltitude;

// --- Sd card and datalogging --- //

#include <SPI.h>
#include <SD.h>

//File dataFile;
char fileName[] = "data.txt";
const char Presets[] = "Roll, Pitch, Yaw, PIDX, PIDY, Altitude, Temperature, Flstate";

// --- Leds and RGB --- //

const int Red = A2, Green = A1, Blue = A0;
boolean sthwrong;
bool blinkl = LOW;

// --- Servomotors --- //

#include <Servo.h>

Servo AxeX;
Servo AxeY;
Servo Para;
float SmoothDecalX;
float SmoothDecalY;
float SmoothPrevX;
float SmoothPrevY;

// --- Timing, Pyro, Flight States --- //

unsigned long currentTime = 0;
unsigned long previousTime = 0;
unsigned long crt;
unsigned long prt;

const int Pyro_Channel = 2;

boolean Apogee;
boolean TVC_enabled;
int FlState;
int SDwrong;

//_______________________________________________SETUP_______________________________________________//

void setup(){

  analogWrite(Red, 255);
  Serial.begin(10000000);
  
  Serial.println("| --- Initialization --- |");
  Serial.println("");
  Serial.println("First, let's see if there is a component missing ! ");
  Serial.println("");
  
  if (!bmp.begin()) {
    Serial.println("Fatal error with the barometer !");
    sthwrong = 1;
  } else {
    Serial.println("Barometer is functionnal");
  }
  
  Serial.println("");
  
  if (!IMU.begin()) {
    Serial.println("Fatal error with the Inertial unit !");
    sthwrong = 1;
  } else {
    Serial.println("Inertial Unit is functionnal");
  }
  
  Serial.println("");
  
  if (!BLE.begin()) {
    Serial.println("Fatal error with the BLE !");
  } else {
    Serial.println("Bluetooth enabled !");
  }

  /*    Servos    */
  AxeX.attach(5);
  AxeY.attach(6);
  Para.attach(3);

  /*    IMU   */
  analogWrite(Blue, 255);
  analogWrite(Red, 0);
  Serial.println("");
  Serial.println("Now let's calibrate the Inertial Measurement Unit !, 5s long");
  lastTime = micros();
  calibrateIMU(1500, 3500);
  Serial.println("");
  analogWrite(Blue, 0);
  analogWrite(Red, 255);

  /*    BLE   */
  BLE.setLocalName("V8Software");
  BLE.setAdvertisedService(ledService);
  ledService.addCharacteristic(switchCharacteristic);
  BLE.addService(ledService);
  switchCharacteristic.writeValue(0);
  BLE.advertise();
  Serial.println("Bluetooth configuration done !");
  Serial.println("");

  /*    DATA    */
  Serial.println("Set reference altitude :");
  FirstAltitude = bmp.readAltitude(seaLevelPressure_hPa * 100);
  if (FirstAltitude == 30344.60) {
    Serial.println("No correct altitude available...");
  } else {
    Serial.println(FirstAltitude);
  }
  Serial.println("");

  /*    SD CARD   */
  //pinMode(4, OUTPUT);
  //digitalWrite(4,HIGH);
  Serial.print("Initializing SD card...");
  
  if (!SD.begin(4)) {
    Serial.print("");
    Serial.println("...Initialization failed!");
    sthwrong = 1;
    SDwrong = 1;
  } else {
    Serial.print("");
    Serial.println("...Initialization done.");
  }
  Serial.println("");
  Serial.println("Deleting old files...");
  SD.remove(fileName);
  Serial.println("Done");
  Serial.println("");

  File dataFile = SD.open(fileName, FILE_WRITE);
  if (!dataFile) {
    Serial.println("Fatal error with the Sd card, data recording not possible");
    sthwrong = 1;
  } else {
    Serial.println("Sd card connected !");
  }
  Serial.println("");
  Serial.println("Writing Assets on it if the card is present : ");
  dataFile.println();
  dataFile.println(Presets);
  dataFile.close();
  Serial.println("Finished");
  Serial.println("Now, let's move to the Loop function, rocket ready for flight ! (or not) ");
  analogWrite(Red, 0);
  delay(1000);

  /*    PYROpin   */
  pinMode(Pyro_Channel, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);
}

//_______________________________________________IMU Configuration_______________________________________________//

  void calibrateIMU(int delayMillis, int calibrationMillis) {

   int calibrationCount = 0;

   delay(delayMillis); 

   float sumX, sumY, sumZ;
   int startTime = millis();
   
   while (millis() < startTime + calibrationMillis) {
     if (readIMU()) {
      
       sumX += gyroX;
       sumY += gyroY;
       sumZ += gyroZ;

       calibrationCount++;
     }
   }
    if (calibrationCount == 0) {
      Serial.println("SERIOUS PROBLEMS AHEAD");
   } else {
     Serial.println("Inertial measurement Unit calibrated");
   }

    gyroDriftX = sumX / calibrationCount;
    gyroDriftY = sumY / calibrationCount;
    gyroDriftZ = sumZ / calibrationCount;
}

bool readIMU() {
    if (IMU.accelerationAvailable() && IMU.gyroscopeAvailable() ) {
     IMU.readAcceleration(accelX, accelY, accelZ);
     IMU.readGyroscope(gyroX, gyroY, gyroZ);
     return true;
    }
    return false;
}

//_______________________________________________LOOP_______________________________________________//

void loop(){

  /*    LEDBlink    */
  currentTime = millis();
  if ((currentTime - previousTime) > 500) {
    blinkl = !blinkl;
    previousTime = currentTime;
    if (blinkl == HIGH) {
      if (sthwrong == 1) {
        analogWrite(Green, 255);
        analogWrite(Red, 255);
      } else {
        analogWrite(Green, 255);
      }
    } else {
      analogWrite(Green, 0);
      analogWrite(Red, 0);
    }
  }

  /*    BLUETOOTH    */
  BLEDevice central = BLE.central();
  if (central) {
    if (switchCharacteristic.written()) {
      switch (switchCharacteristic.value()) {
        case 01:
          Serial.println("BLE 1 activated");
          ReadyForLaunch();
          break;
        case 02:
          Serial.println("BLE 2 activated");
          if (SDwrong == 1) {
           switchCharacteristic.writeValue(5);
          } else {
           switchCharacteristic.writeValue(3);
          }
          break;
      }
    }
  }

  /*     BAROMETER    */
   altitude = bmp.readAltitude(seaLevelPressure_hPa * 100);
  temp = bmp.readTemperature();
  CurrentAltitude = altitude - FirstAltitude;

  /*    IMUloop   */
   if (readIMU()) {
    long currentTime = micros();
    lastInterval = currentTime - lastTime; // expecting t-his to be ~104Hz +- 4%
    lastTime = currentTime;

    doCalculations();
  }

  /*    VOIDS   */
  ThrustVectoringControl();
  FindFFFS();

  /*    SD Card   */
  if(FlState >= 1){
    String dataString = "";

    dataString += String(complementaryRoll);
    dataString += String(",");
    dataString += String(complementaryYaw);
    dataString += String(",");
    dataString += String(complementaryPitch);
    dataString += String(",");
    dataString += String(PIDX);
    dataString += String(",");
    dataString += String(PIDY);
    dataString += String(",");
    dataString += String(CurrentAltitude);
    dataString += String(",");
    dataString += String(temp);
    dataString += String(",");
    dataString += String(FlState);

    crt = currentTime;

    File dataFile = SD.open(fileName, FILE_WRITE);

    if (crt >= (prt + 100)) {

     if (dataFile) {

      dataFile.print(dataString);
      dataFile.println(",");
      Serial.println("Writing...");

     }
    prt = crt;
  }
   
  dataFile.close();
 }
}

//_______________________________________________VOIDS_______________________________________________//

void doCalculations() {
  accRoll = atan2(accelY, accelZ) * 180 / M_PI;
  accPitch = atan2(-accelX, sqrt(accelY * accelY + accelZ * accelZ)) * 180 / M_PI;

  float lastFrequency = (float) 1000000.0 / lastInterval;
  gyroRoll = gyroRoll + (gyroX / lastFrequency);
  gyroPitch = gyroPitch + (gyroY / lastFrequency);
  gyroYaw = gyroYaw + (gyroZ / lastFrequency);

  gyroCorrectedRoll = gyroCorrectedRoll + ((gyroX - gyroDriftX) / lastFrequency);
  gyroCorrectedPitch = gyroCorrectedPitch + ((gyroY - gyroDriftY) / lastFrequency);
  gyroCorrectedYaw = gyroCorrectedYaw + ((gyroZ - gyroDriftZ) / lastFrequency);

  complementaryRoll = complementaryRoll + ((gyroX - gyroDriftX) / lastFrequency);
  complementaryPitch = complementaryPitch + ((gyroY - gyroDriftY) / lastFrequency);
  complementaryYaw = complementaryYaw + ((gyroZ - gyroDriftZ) / lastFrequency);

  complementaryRoll = 0.98 * complementaryRoll + 0.02 * accRoll;
  complementaryPitch = 0.98 * complementaryPitch + 0.02 * accPitch;
}

void ReadyForLaunch() {
  analogWrite(Red, 255);
  analogWrite(Green, 255);
  analogWrite(Blue, 255);
  Serial.println("Thrust Vectoring Mount activated !");
  delay(500);
  TVC_enabled = 1;
  FlState = 1;
}

void FindFFFS() {
  if (FlState >= 1) {
     if (complementaryYaw < -80 || complementaryYaw > 80 || complementaryPitch < 0) {
        if (FlState < 2) {
          FlState = 2; // APOGEE !
        }
       ParachuteSequence(); 
     }
  }
}

void ParachuteSequence() {
  boolean markup;
  if (markup == 0) {
    if (CurrentAltitude >= 80) {
      delay(2000);
      analogWrite(Red, 255);
      analogWrite(Green, 0);
      analogWrite(Blue, 0);
      digitalWrite(LED_BUILTIN, HIGH);
      digitalWrite(Pyro_Channel, LOW);
      delay(2000);
      analogWrite(Red, 0);
      digitalWrite(LED_BUILTIN, LOW);
      digitalWrite(Pyro_Channel, HIGH);
    } else {
      analogWrite(Red, 255);
      analogWrite(Green, 0);
      analogWrite(Blue, 0);
      digitalWrite(LED_BUILTIN, HIGH);
      digitalWrite(Pyro_Channel, LOW);
      delay(2000);
      analogWrite(Red, 0);
      digitalWrite(LED_BUILTIN, LOW);
      digitalWrite(Pyro_Channel, HIGH);
    }
    markup = 1;
    FlState = 3; // PARACHUTE !
  }
}

I can give more informations about the rocket and my project to help you.

Thanks in advance,
Ethan D.
by the way i'm only 15yo.
Please answer me to use my work (actually this one isn't working).

The Arduino appears to be a Nano. Is that right?

Can you tell us in what way the logging isn't working in the loop()? What does it write to the SD card?

If it is a Nano, then you are powering the SD card from the Nano's 5V regulator. I'm not sure that regulator will provide enough current for the card. Have you monitored the 5V pin during SD card writing to see if it stays steady?

Have you tried writing dummy data to the card instead of all the strings, just to see if that works? I ask because I've been advised not to use strings in Arduino sketches. I don't really know why, But try commenting out all the string buildup, and just write "EthanD" each time.

A link to the SD card module might be helpful.

Hi ShermanP,

I use an arduino 33 IOT https://store-usa.arduino.cc/products/arduino-nano-33-iot). (sorry i forgot to mention what type of card it was).

About the way it isn't working, when i check the corresponding file on the card there is only presets are printed (result below)

data

This part is printed in void setup,

const char Presets[] = "Roll, Pitch, Yaw, PIDX, PIDY, Altitude, Temperature, Flstate";
Serial.println("");
  Serial.println("Writing Assets on it if the card is present : ");
  dataFile.println();
  dataFile.println(Presets);
  dataFile.close();

You must notice that this arduino does not have a 5v regulator. The micro SD card is powered by the battery (7.4v 900mah) using resistors. It seems to work because when i use examples sketchs it works very well.

Thanks for your idea, i'll try right away !

Concerning the microSD module i use, here it is : https://www.amazon.fr/gp/product/B06XHJTGGC/ref=ppx_yo_dt_b_search_asin_image?ie=UTF8&psc=1

Finally,

i'm going to do some tests and i will bring back to you the results of them.

Here is the pcb : (i can't add 2 images in the same post)

I haven't had a chance to study your code. I would just suggest that you make sure the IF statement conditions are met to write in the loop().

I don't see anything in your schematic or the PCB image showing that. The SD module is powered from physical pin 12 of the Nano module. That pin receives power from USB only if the jumper blob on the Nano is shorted with solder, which connects pin 12 to VBUS. According to the schematic provided by Aduino for the 33 IOT, pin 12 is connected to Vin through a diode. So unless USB is connected and powered up, your SD module will not be powered. So it will not work in flight.

But at the moment it appears your SD module is being powered by USB, which is certainly capable of doing that. So it's unlikely that the original problem is a hardware problem. So let's find out why it writes successfully in setup(), but not in loop(). Can you add some serial debugging lines in loop() to show that it has opened the file, and the values of the IF conditions? Does it ever say "Writing..."? And maybe send dataString to serial so you can see what it looks like.

Did you remember to close the file before turning off your 33 IOT?

I think the problem is PRT. You define it, but never assign a value to it. So it appears the IF statement:

    if (crt >= (prt + 100)) {

     if (dataFile) {

      dataFile.print(dataString);
      dataFile.println(",");
      Serial.println("Writing...");

     }
    prt = crt;
  }

is never executed because prt is always zero.

Ok, it looks like I got that one backwards. Well, programming was never my strong point. Anyway, just make sure the SD write commands are actually executing.

No problem, thanks for your help.
Then, I modify the code to glow up the blue led when the loop where the arduino is writing on the SD card. Thus, this loop is executing (loop start by connecting my phone with BLE)

Well, we can observe that at each end of the loop the file close.

    crt = currentTime;

    File dataFile = SD.open(fileName, FILE_WRITE);

    if (crt >= (prt + 100)) {

     if (dataFile) {

      dataFile.print(dataString);
      dataFile.println(",");
      Serial.println("Writing...");

     }
    prt = crt;
  }
   
  dataFile.close();
 }
}

However, i don't know if this way is correct. Maybe I can try to close it by hand (with a BLE message)

I'm also going to try to print raw values to sd card instead of using a string.

BUT, with all the "if" does it really get executed?

 dataFile.close();

This part of the code is contained in " Flstate == 1" if statement.

As i just verify that if (datafile){} was executing, which is also in this if statement, it really gets executed.

Ok, then it might be instructive to Serial.print() something from the last data that was written to the card, just before the close.

I tried to modify the code but i just noticed that if (dataFile) {} isn't executing. In fact, my code is so complicated that I forgot that the blue led was on because of another part of the code.

I also removed the Serial.println(); for safeties reasons.

We know where's the problem now. (but i don't know how to fix it)

Another example of writing programs that are not tested at each small step.

Well, it worked before the code was this size but i don't even see where is the problem.
I'm going to isolate all code in relation to the sd card and watch if it's working.

Have you tried to serial print the outputs on every step on the sd card coding? This way probably you will see which step doesn't work.

The system is working on a battery, therefore i just can't do that. I'm using leds and bluetooth instead.

So I did a lot of experiments and I figured out that the SD card is only working if I use the Data logger example (SD library).

Even if I add a led blink (without delay of course) it's not working for example. I really don't understand why is this happening...

I can't add something in the loop but in the setup too, for example this is working :

#include <SPI.h>
#include <SD.h>

char fileName[] = "datalog.txt";
const char Presets[] = "Roll, Pitch, Yaw, PIDX, PIDY, Altitude, Temperature, Flstate";



void setup() {

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

  if (!SD.begin(4)) {
    Serial.println("...Initialization failed!");

  } else {
    Serial.println("...Initialization done.");
  }
}

void loop() {

  /* SD CARD */


  String dataString = "";

  for (int analogPin = 0; analogPin < 3; analogPin++) {
    int sensor = analogRead(analogPin);
    dataString += String(sensor);
    if (analogPin < 2) {
      dataString += ",";
    }
  }

  File dataFile = SD.open(fileName, FILE_WRITE);

  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
    digitalWrite(LED_BUILTIN, HIGH);
  }
}

And this isn't working : (the file is created but nothing is written)

#include <SPI.h>
#include <SD.h>

char fileName[] = "datalog.txt";
const char Presets[] = "Roll, Pitch, Yaw, PIDX, PIDY, Altitude, Temperature, Flstate";

//ADDED PART//

const int Red = A2, Green = A0, Blue = A1;
bool led_blink = LOW;
unsigned long currentTime = 0;
unsigned long previousTime = 0;
boolean component_error;

void setup() {

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

  if (!SD.begin(4)) {
    Serial.println("...Initialization failed!");
    component_error = 1;
  } else {
    Serial.println("...Initialization done.");
  }
}

void loop() {

  //ADDED PART//
  currentTime = millis();
  if ((currentTime - previousTime) > 333) {
    led_blink = !led_blink;
    previousTime = currentTime;
  }
  if (led_blink == HIGH) {

    if (component_error == 0) {
      analogWrite(Blue, 255);
    } else {
      analogWrite(Red, 255);
    }
  } else {
    analogWrite(Red, 0);
    analogWrite(Green, 0);
    analogWrite(Blue, 0);
  }

  String dataString = "";

  for (int analogPin = 0; analogPin < 3; analogPin++) {
    int sensor = analogRead(analogPin);
    dataString += String(sensor);
    if (analogPin < 2) {
      dataString += ",";
    }
  }

  File dataFile = SD.open(fileName, FILE_WRITE);

  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
    digitalWrite(LED_BUILTIN, HIGH);
  }
}

The only difference between theses two is the blink program in the loop, and it doesn't contain any errors.

Two guesses:

To make sure it isn't a power problem, try running the second sketch with the LEDs not connected, and see if that makes any difference.

Could there be a conflict between analogWrite and SPI? Do they use the same timer? Try changing the analog writes to digital writes.

Just a thought and it does not explain your observation in post #18.

Your use of LED_BUILTIN might be interfering with your SD card; LED_BUILTIN is connected to the SCK pin which is used in the SPI interface with your SD card reader.