Arduino Nano Data Logger

Hello,

I am new to arduino and decided to pick up an Arduino Nano to create a data logger for my motorcycle. I would like to record angles and acceleration in the x, y, and z directions. I would also like to record GPS data and inputs from two potentiometers. I am saving all of this into an array and writing it to an SD card in a .CSV file.

Currently i am having issues recording the data onto an SD card when it is being powered from a 5V phone charger through USB. It will either record for 20 seconds at ~5-10Hz then stop or it will record one array but the data appears to be corrupted (rather than a number its a bunch of ?я). It records fine when it is powered by my computer.

I went through and tried to minimize the RAM usage and program size by using integers instead of floats and moved the decimal by 100 for some of the variables (post processing to fix). I also used a for loop instead of a delay to keep calculating the angles before it outputted an array to the SD card. Lastly i used char’s instead of strings but this still has not helped.

What can i do to make write the arrays to the SD card reliably at 5-10Hz for a few hours at a time?

Hardware:

  • Nano V3.0, Nano Board ATmega328P (I think its a knock off)
  • DaFuRui GY-521 MPU-6050 Accelerometer Gyroscope Sensor Module
  • NEO-6M GPS Module Receiver
  • HiLetgo Micro SD TF Card Adater Reader Module
#include <math.h>
#include <SD.h>
#include <Wire.h>
#include <TinyGPS.h>

byte i=0;
float lat,lon;
TinyGPS gps; // create gps object
File testfile;
char* fileName = "Riding.csv";
int accelX, accelY, accelZ;
int gForceX, gForceY, gForceZ;

int gyroXCalli = 0, gyroYCalli = 0, gyroZCalli = 0;
int gyroXPresent = 0, gyroYPresent = 0, gyroZPresent = 0;
int gyroXPast = 0, gyroYPast = 0, gyroZPast = 0;
float angelX = 0, angelY = 0, angelZ = 0; 
float angelXold=0, angelZold=0, angelYold=0; 

word n=1; // for counters in if statements
float ZeroAngleX=0, ZeroAngleY=0, ZeroAngleZ=0; 
long int timer=0;
double timer2=0;
double timePast = 0;
double timePresent = 0;

void setup() {
  Serial.begin(115200);
  Wire.begin();
  setUpMPU();
  readAndProcessAccelData();
  callibrateGyroValues();
  timePresent = millis();

  if (!SD.begin(10)) {
    //Serial.println("No SD Module Detected");
  }
  if (SD.exists(fileName)){
    //Serial.println("File exists, deleting and starting new");
    SD.remove(fileName);
  }
  testfile = SD.open(fileName, FILE_WRITE);
  if (testfile) {
    testfile.println("Time,Pitch,Yaw,Lean,Lateral-G's,Veritcal-G's,Longitudinal-G's,Front Height (mm),Rear Height (mm),Lat,Lon");
    testfile.close();
  } else {
    //Serial.println("error opening file");
  }
    
}

void loop() {
  for (int i=0; i<80; i++){
  readAndProcessAccelData();
  readAndProcessGyroData();
   }
    while(Serial.available()){ // check for gps data
       if(gps.encode(Serial.read())){ // encode gps data
         gps.f_get_position(&lat,&lon); // get latitude and longitude
  }
 } 
   printData();
}

void setUpMPU() {
  // power management
  Wire.beginTransmission(0x68);          // Start the communication by using address of MPU
  Wire.write(0x6B);                           // Access the power management register
  Wire.write(0x00);                     // Set sleep = 0
  Wire.endTransmission();                     // End the communication

  // configure gyro
  Wire.beginTransmission(0x68);
  Wire.write(0x1B);                           // Access the gyro configuration register
  Wire.write(0x08);
  Wire.endTransmission();

  // configure accelerometer
  Wire.beginTransmission(0x68);
  Wire.write(0x1C);                           // Access the accelerometer configuration register
  Wire.write(0x10);
  Wire.endTransmission(); 
}

void callibrateGyroValues() {
    for (int i=0; i<5000; i++) {
      getGyroValues();
      gyroXCalli = gyroXCalli + gyroXPresent;
      gyroYCalli = gyroYCalli + gyroYPresent;
      gyroZCalli = gyroZCalli + gyroZPresent;
    }
    gyroXCalli = gyroXCalli/5000;
    gyroYCalli = gyroYCalli/5000;
    gyroZCalli = gyroZCalli/5000;
}

void readAndProcessAccelData() {
  Wire.beginTransmission(0b1101000); 
  Wire.write(0x3B); 
  Wire.endTransmission();
  Wire.requestFrom(0b1101000,6); 
  while(Wire.available() < 6);
  accelX = (Wire.read()<<8|Wire.read()); 
  accelY = (Wire.read()<<8|Wire.read()); 
  accelZ = (Wire.read()<<8|Wire.read()); 
  processAccelData();

}

void processAccelData() {
  gForceX = (accelX/0.4096)-580; // 10,000 = 1G
  gForceY = (accelY/0.4096)+250; 
  gForceZ = (accelZ/0.4096)-350;
  

}

void readAndProcessGyroData() {
  gyroXPast = gyroXPresent;                                   // Assign Present gyro reaging to past gyro reading
  gyroYPast = gyroYPresent;                                   // Assign Present gyro reaging to past gyro reading
  gyroZPast = gyroZPresent;                                   // Assign Present gyro reaging to past gyro reading
  timePast = timePresent;                                     // Assign Present time to past time
  timePresent = millis();                                     // get the current time in milli seconds, it is the present time
  
  getGyroValues();                                            // get gyro readings
  calculateAngle();                                           // calculate the angle  
}

void getGyroValues() {
  Wire.beginTransmission(0b1101000);                          // Start the communication by using address of MPU 
  Wire.write(0x43);                                           // Access the starting register of gyro readings
  Wire.endTransmission();
  Wire.requestFrom(0b1101000,6);                              // Request for 6 bytes from gyro registers (43 - 48)
  while(Wire.available() < 6);                                // Wait untill all 6 bytes are available
  gyroXPresent = (Wire.read()<<8|Wire.read());                  // Store first two bytes into gyroXPresent
  gyroYPresent = (Wire.read()<<8|Wire.read());                  // Store next two bytes into gyroYPresent
  gyroZPresent = (Wire.read()<<8|Wire.read());                  //Store last two bytes into gyroZPresent
}

void calculateAngle() {  
  angelXold=angelX;
  angelYold=angelY;
  angelZold=angelZ;
  angelX = angelX + ((timePresent - timePast)*(gyroXPresent + gyroXPast - 2*gyroXCalli)) * 0.0007633588;
  angelY = angelY + ((timePresent - timePast)*(gyroYPresent + gyroYPast - 2*gyroYCalli)) * 0.0007633588;
  angelZ = angelZ + ((timePresent - timePast)*(gyroZPresent + gyroZPast - 2*gyroZCalli)) * 0.0007633588;
  
  timer2=timePresent*0.001;
  if(abs(angelX-angelXold)<50){ //9000 = 90*
  angelX=angelXold;
  }
  if(abs(angelY-angelYold)<50){
  angelY=angelYold;
  }
  if(abs(angelZ-angelZold)<30){
  angelZ=angelZold;
  }
  unsigned long xx=(gForceX/100)*(gForceX/100), yy=(gForceY/100)*(gForceY/100), zz=(gForceZ/100)*(gForceZ/100);
  float  eigenVector=sqrt((xx)+(yy)+(zz));
     if (eigenVector>98 && eigenVector<=102 && ((gForceZ)/(eigenVector))<100 && ((gForceZ)/(eigenVector))>-100 && ((gForceX)/(eigenVector))<100 && ((gForceX)/(eigenVector))>-100)
    {
    angelX=0.98*angelX+2*(90-(57.2958*acos((gForceZ)/(100*eigenVector))));
    angelZ=0.98*angelZ+2*(90-(57.2958*acos((gForceX)/(100*eigenVector))));
    }

}

void printData() {
    if(timer2>(15*n)){ 
     n=n+1;
      
      if(abs(angelZ-ZeroAngleZ)<20){
         angelZ=0;}
      else{
         ZeroAngleZ=angelZ;}
      if(abs(angelY-ZeroAngleY)<20){
         angelY=0;}
      else{
         ZeroAngleY=angelY;}
      if(abs(angelX-ZeroAngleX)<20){
         angelX=0;}
      else{
         ZeroAngleX=angelX;
      }
     }

    long int timer=timePresent*0.1;
    int sensorValue1 = analogRead(A0)*100;
    int sensorValue2 = analogRead(A1)*100;
    int Front=((sensorValue1/102.1)-0.009)*39.878; 
    int Rear=((sensorValue2/102.1)-0.009)*39.878; 
    char Output[128];
    int aX=angelX; long aY=angelY; int aZ=angelZ; int gX=gForceX; int gY=gForceY; int gZ=gForceZ; long int lt=lat*1000000; long int ln=lon*1000000;
    sprintf(Output, "%ld, %d, %ld, %d, %d, %d, %d, %d, %d, %ld, %ld", timer, aX, aY, aZ, gX, gY, gZ, Front, Rear, lt, ln); 
    Serial.println(Output);
    testfile = SD.open(fileName, FILE_WRITE);
    if (testfile) {
      testfile.println(Output);
      testfile.close();
  }

}

Gyro9.ino (6.94 KB)

First post and code tags! Karma++. Maybe Your circuitry pulls too little of current out of the USB. I have experienced such trouble sometimes. Could You try and use a Laptop instead of the phone charger, just for testing?

For initial testing i used my laptop and it recorded to the SD card correctly. I wanted to use a phone charger so i could leave it for a few hours and not have to carry my laptop around. Also i found that when my laptop goes to sleep/wakes it resets the program.

So far i have tried using an apple 5V - 1A charger and a 5V - 2.1A Ipad charger. They both had the same results. I have also tried 2-3 different cables with the same outcome. I also took voltage measurements of the Arduinos output voltage using the laptop and 2 phone chargers as a power source. The 5v out was ~4.51-4.53V and the 3.3V out was ~3.23-3.25V for all three.

I plan to either use a battery pack or wire it into a 12V motorcycle battery (With a 5v regulator).

When a Pc goes into power down it cuts off the USB power . I've experienced the same, that phone chargers cut off due to too little current being sent out. To cure that I asked Forum for help, installed a resistor on the UNO bord and a some small code made the UNO waist some current through the resistor and then it worked well.

I tried using 2 80Kohm resistors for the Analog in 0 and 1 to add load and trick it into thinking the potentiometers are hooked up(Currently not to worried about these values). I tried changing to a Motorola charging block and im still having issues with the SD card. I have also tried 2 different cards and the same results. Although now after changing the block and resistors it will spit out a few lines into the CSV that are recorded at different times.

Edit: I just ran this piece of code designed to just count up and save to an SD card. It resulted in the same effect of displaying a bunch of ?я for data in a cell then stopping. I will look more into the code. Does anyone have any suggestions?

#include <SD.h>
#include <Wire.h>

File testfile;
char* fileName = "Test.csv";
float a=0;
void setup() {
    Serial.begin(115200);
    Wire.begin();
  // put your setup code here, to run once:
  if (!SD.begin(10)) {
    //Serial.println("No SD Module Detected");
  }
  if (SD.exists(fileName)){
    //Serial.println("File exists, deleting and starting new");
    SD.remove(fileName);
  }
  testfile = SD.open(fileName, FILE_WRITE);
  if (testfile) {
    testfile.println("Time");
    testfile.close();
  } else {
    //Serial.println("error opening file");
  }
}

void loop() {
  // put your main code here, to run repeatedly:
  float a=millis();
testfile = SD.open(fileName, FILE_WRITE);
    if (testfile) {
      testfile.println(a);
      testfile.close();
      delay(100);
      Serial.println(a);
 }
}

I figured it out using the Arduino IDE example. I found out it is based off of a SPARKFUN Shield which uses PIN 8 not 10(I thought it was based off of an ADAFruit Shield).

Thank you Railroader for your help!