Go Down

Topic: IMU Sensor stops updating values after SD Card activated (Read 438 times) previous topic - next topic

Muulka

Hi guys,

First of all I should say that I'm very new to this whole area; this is the first project I'm doing on my own, and I don't have any kind of electronics background, so please forgive my ignorance, and if I've posted this in the wrong place please let me know...

I'm currently working on on a project to build a datalogger for a go-kart to aid in driver performance analysis, saving all the info to an onboard SD card to analyse later. The aim is that eventually it'll be something fairly extensive, but for the first stage I'm just looking at implementing accelerometer and gyro data.

To that end, I've purchased an ethernet shield and the 9 axes motion shield. I've done some playing around, and I've figured out how to get the data off the motion shield (despite the difficulty finding much documentation for it...) and, separately, how to stream data straight to the SD card.

I'm having problems occur when I try to combine the two, however. Namely, when the sketch uses the SD card, the motion sensor no longer updates, so I end up with an output file which is hundreds of identical lines no matter how I move the sensor while it's logging.

Could the problem be that the two shields use one of the pins for different tasks and they're conflicting? I haven't made any modifications or done any soldering to the boards; might there have been something I've missed in the documentation?

The code I'm using is below:
Code: [Select]

#include <SPI.h>
#include <SD.h>
#include "NAxisMotion.h"
#include <Wire.h>

const int chipSelect = 4;
const int interval = 100; // Possible to get this from something in the SD card?
// Might have to do it inside setup()?

NAxisMotion mySensor;                 //Object that for the sensor
unsigned long lastStreamTime = 0;     //To store the last streamed time stamp
bool updateSensorData = true;         //Flag to update the sensor data. Default is true to perform the first read before the first stream



void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(115200);
  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.");

  I2C.begin();                    //Initialize I2C communication to the let the library communicate with the 9DoF sensor.
  //Sensor Initialization
  mySensor.initSensor();          //The I2C Address can be changed here inside this function in the library
  mySensor.setOperationMode(OPERATION_MODE_NDOF);   //Can be configured to other operation modes as desired
  mySensor.setUpdateMode(MANUAL);  //The default is AUTO. Changing to manual requires calling the relevant update functions prior to calling the read functions
  mySensor.writeAccelConfig(ACCEL_RANGE_8G,ACCEL_BW_7_81HZ,ACCEL_NORMAL);
  //Setting to MANUAL requires lesser reads to the sensor
  mySensor.updateAccelConfig();
  updateSensorData = true;
  Serial.println();
  Serial.println("Default accelerometer configuration settings...");
  Serial.print("Range: ");
  Serial.println(mySensor.readAccelRange());
  Serial.print("Bandwidth: ");
  Serial.println(mySensor.readAccelBandwidth());
  Serial.print("Power Mode: ");
  Serial.println(mySensor.readAccelPowerMode());
  Serial.println("Streaming in ..."); //Countdown
  Serial.print("3...");
  delay(200);  //Wait for a bit
  Serial.print("2...");
  delay(200);  //Wait for a bit
  Serial.println("1...");
  delay(200);  //Wait for a bit
}

void loop() {

  if (updateSensorData)  //Keep the updating of data as a separate task
  {
    mySensor.updateAccel();        //Update the Accelerometer data
    mySensor.updateLinearAccel();  //Update the Linear Acceleration data
    mySensor.updateGravAccel();    //Update the Gravity Acceleration data
    mySensor.updateCalibStatus();  //Update the Calibration Status
    updateSensorData = false;
  }

  if ((millis() - lastStreamTime) >= interval) {
    // make a string for assembling the data to log:
    String dataString = "";

    dataString += mySensor.readAccelX(); //Accelerometer X-Axis data
    dataString += ",";

    dataString += mySensor.readAccelY();  //Accelerometer Y-Axis data
    dataString += ",";

    dataString += mySensor.readAccelZ();  //Accelerometer Z-Axis data
    dataString += ",";

    dataString += mySensor.readGravAccelX(); //Accelerometer X-Axis data
    dataString += ",";

    dataString += mySensor.readGravAccelY();  //Accelerometer Y-Axis data
    dataString += ",";

    dataString += mySensor.readGravAccelZ();  //Accelerometer Z-Axis data
    dataString += ",";

    // open the file. note that only one file can be open at a time,
    // so you have to close this one before opening another.
    File dataFile = SD.open("datalog.txt", FILE_WRITE);

    // if the file is available, write to it:
    if (dataFile) {
      dataFile.println(dataString);
      dataFile.close();
      // print to the serial port too:
      Serial.println(dataString);
    }
    // if the file isn't open, pop up an error:
    else {
      Serial.println("error opening datalog.txt");
    }

    updateSensorData = true;
  }
}


Any guidance you can give me would be greatly appreciated!!!

MK1888

Your program could be written better.  If the second IF block in the main loop() never executes then your sensor never updates after the first time.  Likewise, if the execution stays in the second IF block your sensor will also not update after the first time.

But your problem is likely that your variable lastStreamTime is never updated at all.  You set it to zero at the beginning and that's it.  Your program probably stays in the second IF block forever.

A simple print statement between your two IF blocks would have clued you in to this.

Muulka

Your program could be written better.  If the second IF block in the main loop() never executes then your sensor never updates after the first time.  Likewise, if the execution stays in the second IF block your sensor will also not update after the first time.

But your problem is likely that your variable lastStreamTime is never updated at all.  You set it to zero at the beginning and that's it.  Your program probably stays in the second IF block forever.

A simple print statement between your two IF blocks would have clued you in to this.
Not updating lastStreamTime (which, I grant you, is a significant oversight) won't stop it executing the second block because the left side of the inequality being tested will always be increasing. The impact is that it'll be executing on each run through the loop, which means that it's then updating the sensor data every time as well. I tried putting the sensor update lines inside the second IF statement to make sure that that wasn't the problem, and what do you know - exactly the same problem.

And when I remove the line initialising the SD card, it magically starts streaming correct data to the serial monitor. So the problem isn't a coding issue (though of course I accept that this bodged-together code isn't great). Any insight into what might be causing the SD initialisation to break the data update?

MK1888

Sorry, I wasn't thinking clearly last night.  I interpreted the IF blocks as WHILE loops.

Which line are you removing to make it work?

Also, showing your circuit might be useful.

Muulka

Sorry, I wasn't thinking clearly last night.  I interpreted the IF blocks as WHILE loops.

Which line are you removing to make it work?

Also, showing your circuit might be useful.
Removing this section makes it work:
Code: [Select]
if (!SD.begin(chipSelect)) {
   Serial.println("Card failed, or not present");
   // don't do anything more:
   return;
 }


Obviously I changed the printing to the file to printing to the serial monitor as well, making the sketch ignore the SD card entirely.

The circuit is pretty trivial; It's an Arduino UNO with the Ethernet and Motion shields stacked on top (in that order). As I said in the OP, I have very little practical electronics experience, so please forgive me if that's a stupid thing to do!

MK1888

It's not a stupid thing to do (because we would assume the shields would play well with each other), but it could be the source of your problem if the shields are sharing certain pins (other than power).

Post the exact shields you are using.  And you might have a look at the pinouts of each (in their datasheets) to see if anything jumps out.  They both might be trying to use the same pin for data.

Go Up