Data logging and telemetry of GPS and other sensors

Hello,

I'm using an arduino Fio, an Altimu 10, an Adafruit ultimate GPS, a Adafruit micro Sd breakout and a Xbee S2B to locally log gps, atmospheric and inertial data, as well as sending it wirelessly.

Currently I have a problem with the GPS NMEA sentences, since while reading the GGA sentence it often cuts off the end (ie. $GPGGA,172841.600,3842.2050,N,00914.7984,W,2,08,1.20,97.7,M,50.).

the code i'm using is

#include <Wire.h>
#include <LSM303.h>
#include <LPS.h>
#include <L3G.h>
#include <SPI.h>
#include <SD.h>

const int chipSelect = 4;

L3G gyro;
LSM303 compass;
LPS ps;

#include <SoftwareSerial.h>
#include <Adafruit_GPS.h>

SoftwareSerial mySerial(3, 2);

Adafruit_GPS GPS(&mySerial);
// If using hardware serial (e.g. Arduino Mega), comment
// out the above six lines and enable this line instead:
//Adafruit_GPS GPS(&Serial1);


// Set GPSECHO to 'false' to turn off echoing the GPS data to the Serial console
// Set to 'true' if you want to debug and listen to the raw GPS sentences
#define GPSECHO  true

// this keeps track of whether we're using the interrupt
// off by default!
boolean usingInterrupt = false;
void useInterrupt(boolean); // Func prototype keeps Arduino 0023 happy


int byteGPS=-1;

String inputString = "";         // a string to hold incoming data
String dataString = "";

boolean stringComplete = false;

void setup()
{

  Serial.begin(57600);
  Wire.begin();
  compass.init();
  compass.enableDefault();
  Wire.beginTransmission(0x3C >> 1);
  Wire.write(0x01);
  // see table 62 in the datasheet for other gain_setting values
  Wire.write(0x60);
  Wire.endTransmission();

  // Calibration values. Use the Calibrate example program to get the values for
  // your compass.
  compass.m_min.x = -256; compass.m_min.y = -172; compass.m_min.z = -236;
  compass.m_max.x = +104; compass.m_max.y = +181; compass.m_max.z = +133;

  // connect at 115200 so we can read the GPS fast enuf and
  // also spit it out

  // 9600 NMEA is the default baud rate for MTK - some use 4800
  GPS.begin(9600);

  // You can adjust which sentences to have the module emit, below

  // uncomment this line to turn on RMC (recommended minimum) and GGA (fix data) including altitude
  //  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
  // uncomment this line to turn on only the "minimum recommended" data for high update rates!
  GPS.sendCommand("$PMTK314,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0*29");
  // uncomment this line to turn on all the available data - for 9600 baud you'll want 1 Hz rate
  //  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_ALLDATA);

  // Set the update rate
  // 1 Hz update rate
  //  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);
  // 5 Hz update rate- for 9600 baud you'll have to set the output to RMC or RMCGGA only (see above)
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_10HZ);
    GPS.sendCommand(PMTK_API_SET_FIX_CTL_5HZ);
  // 10 Hz update rate - for 9600 baud you'll have to set the output to RMC only (see above)
  //GPS.sendCommand(PMTK_SET_NMEA_UPDATE_10HZ);

    if (!gyro.init())
  {
    Serial.println("Fg");
    while (1);
  }

  gyro.enableDefault();

  Serial.print("I");

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

  inputString.reserve(250);
  dataString.reserve(300);
}


void loop()                     // run over and over again
{

mySerial.listen();

while (mySerial.available()) {
    // get the new byte:
    char    inChar = (char)mySerial.read();
    // add it to the inputString:
    inputString += inChar;
    // if the incoming character is a newline, set a flag
    // so the main loop can do something about it:
//    if (inChar == '\n') {
//      
//      File myFile = SD.open("datalog.txt", FILE_WRITE);
//      myFile.print(inputString);
//      myFile.close();
//      
//      Serial.print(inputString);
//      inputString = "";
//    
//    }
}

 
  File myFile = SD.open("datalog.txt", FILE_WRITE);
  myFile.println(inputString);
  myFile.close();

  Serial.println(inputString);
      
  inputString = "";
  
  
  //Serial.print((char)mySerial.read());    //copy data to console
  //myFile.print((char)mySerial.read());   
  
//  while (Serial.available()) {                    //while data available from console
//    mySerial.print((char)Serial.read());   //copy data to GPS
//  }

  dataString = "";


  float pressure = ps.readPressureMillibars();
  float altitude = ps.pressureToAltitudeMeters(pressure);
  float temperature = ps.readTemperatureC();   

  compass.read();

  gyro.read();
  
  
  
  Serial.print("p");
  Serial.print(pressure);
  Serial.print(",");
  Serial.print(altitude);
  Serial.print(",");
  Serial.println(temperature);

  myFile = SD.open("datalog.txt", FILE_WRITE);
  myFile.print("p");
  myFile.print(pressure);
  myFile.print(",");
  myFile.print(altitude);
  myFile.print(",");
  myFile.println(temperature);
  myFile.close();
//
// 
//          
//  Serial.print("A");
//  Serial.print(compass.a.x);
//  Serial.print(",");
//  Serial.print(compass.a.y);
//  Serial.print(",");
//  Serial.println(compass.a.x);
//   
//     Serial.print("M");
//  Serial.print(compass.m.x);
//  Serial.print(",");
//  Serial.print(compass.m.y);
//  Serial.print(",");
//  Serial.println(compass.m.z);
//
//
//  myFile.print("A");
//  myFile.print(compass.a.x);
//  myFile.print(",");
//  myFile.print(compass.a.y);
//  myFile.print(",");
//  myFile.println(compass.a.x);
//   
//  myFile.print("M");
//  myFile.print(compass.m.x);
//  myFile.print(",");
//  myFile.print(compass.m.y);
//  myFile.print(",");
//  myFile.println(compass.m.z);
//  
//  
//
//  Serial.print("G ");
//  Serial.print("X: ");
//  Serial.print((int)gyro.g.x);
//  Serial.print(" Y: ");
//  Serial.print((int)gyro.g.y);
//  Serial.print(" Z: ");
//  Serial.println((int)gyro.g.z);
//
//  Serial.println('\n');
  

}

Currently a lot a code is commented out since I've been trying several ways of reading the NMEA sentences and also trying to optimize the logging of the other sensors.

Any input would be much appreciated, thanks in advance!

You don't have enough sram to use Strings. You've already lost at least 512 bytes to the SD library.
You need to change your code so that you use null-terminated C strings (character arrays).

Pete

Thank you for your reply, I agree with you when it comes to saving memory, but I've just ran the same code without the logging (no SD writing) and so with 1002 bytes of dynamic memory available but I still have the same problem.

Here's the code

#include <Wire.h>
#include <LSM303.h>
#include <LPS.h>
#include <L3G.h>
//#include <SPI.h>
//#include <SD.h>
#include <SoftwareSerial.h>
#include <Adafruit_GPS.h>

L3G gyro;
LSM303 compass;
LPS ps;

SoftwareSerial mySerial(3, 2);

Adafruit_GPS GPS(&mySerial);

#define GPSECHO  true

boolean usingInterrupt = false;
void useInterrupt(boolean); // Func prototype keeps Arduino 0023 happy


int byteGPS=-1;

String inputString = "";         // a string to hold incoming data
String dataString = "";

void setup() {
  
  Serial.begin(57600);
  
  Wire.begin();
  
  compass.init();
  compass.enableDefault();
  
  Wire.beginTransmission(0x3C >> 1);
  Wire.write(0x01);
  Wire.write(0x60);
  Wire.endTransmission();

  // Calibration values. Use the Calibrate example program to get the values for
  // your compass.
  compass.m_min.x = -256; compass.m_min.y = -172; compass.m_min.z = -236;
  compass.m_max.x = +104; compass.m_max.y = +181; compass.m_max.z = +133;

  GPS.begin(9600);

  // uncomment this line to turn on only the "minimum recommended" data for high update rates!
  GPS.sendCommand("$PMTK314,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0*29");
  // 5 Hz update rate- for 9600 baud you'll have to set the output to RMC or RMCGGA only (see above)
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_10HZ);
    GPS.sendCommand(PMTK_API_SET_FIX_CTL_5HZ);

    if (!gyro.init())
  {
    Serial.println("Fg");
    while (1);
  }

  gyro.enableDefault();

  Serial.print("I");


}

void loop() {
  // put your main code here, to run repeatedly:
mySerial.listen();

while (mySerial.available()) {
    // get the new byte:
    char    inChar = (char)mySerial.read();
    // add it to the inputString:
    inputString += inChar;

}

 
    Serial.println(inputString);
      
  inputString = "";


  float pressure = ps.readPressureMillibars();
  float altitude = ps.pressureToAltitudeMeters(pressure);
  float temperature = ps.readTemperatureC();   

  compass.read();

  gyro.read();
  
  
  
  Serial.print("p");
  Serial.print(pressure);
  Serial.print(",");
  Serial.print(altitude);
  Serial.print(",");
  Serial.println(temperature);




}

and a sample of the output

p756.50,2397.43,42.50
$GPGGA,184455.000,3842.2037,N,00914.7995,W,1,05,1.50,72.8,M,50.
p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50
$GPGGA,184455.200,3842.2037,N,00
p756.50,2397.43,42.50
914.7995,W,1,06,1.42,72.8,M,50.7,M,,*4E

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50
$GPGGA,184455.400,3842.2037,N,00914.7995,W,1,06,1.43,72.8,M,50.7,M,,*49

p756.50,2397.43,42.50


p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50
$GPGGA,184455.600,3842.2037,N,00914.7995,W,1,06,1.42,72.8,M,50.7,M,,*4A

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50
$GPGGA,184455.800,3842.2037,N,00914.7995,W,1,06,1.42,72.8,M,50.44

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50
$GPGGA,184456.000,3842.2037,N,00914.7995,W,1,06,1.42,72.8,M,50.
p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50
$GPGGA,184456.200,3842.2037,N,00914.7995,W,1,06,1.42,72.8,M,50.
p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50
$GPGGA,184456.400,3842.2037,N,00914.7995,W,1,06,1.43,72.8,M,50.
p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50
$GPGGA,184456.600,3842.2037,N,00914.7995,W,1,06,1.43,72.8,M,50.
p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50

p756.50,2397.43,42.50
$GPGGA,184456.800,3842.2037,N,00914.7995
p756.50,2397.43,42.50
,W,1,06,1.43,72.8,M,50.7,M,,*46

p756.50,2397.43,42.50

Thanks again!

with 1002 bytes of dynamic memory available but I still have the same problem

The problem is with the way that the String library manages memory. It doesn't do a good job of it - with a small amount of memory it wouldn't be easy anyway.
You need to remove all the String stuff.

Pete

You also have a problem with the way your code is written right now with those comments.
You have removed the code which handles the end of line so when there are no more characters available from mySerial you just write what you have, which might only be part of a line.

Pete

Hello,

I've changed a few strings to char and added the '\n' detector, what happens ist that the program often leaves the while (mySerial.available()) loop before the '\n' appears, resulting in several parts of concatenated NMEA sentences printed when it actually finds the next '\n'.

e.g.($GPGGA,223752.000,3842.2038,N,00914.7967,W,2,07,1.24,81.9,M,50.$GPGGA,223752.200,3842.2038,N,00914.7967,W,2,07,1.24,81.9,M,50.$GPGGA,223752.400,3842.2038,N,00914.7967,W,2,07,1.24,81.9,M,50.7,M,0000,0000*4F)

I will substitute the string with char arrays, but will this solve the issue with leaving the loop before the '\n' appears?

Thank you, and sorry for the bother.

#include <Wire.h>
#include <LSM303.h>
#include <LPS.h>
#include <L3G.h>
//#include <SPI.h>
//#include <SD.h>
#include <SoftwareSerial.h>
#include <Adafruit_GPS.h>

L3G gyro;
LSM303 compass;
LPS ps;

SoftwareSerial mySerial(3, 2);

Adafruit_GPS GPS(&mySerial);

#define GPSECHO  true

boolean usingInterrupt = false;
void useInterrupt(boolean); // Func prototype keeps Arduino 0023 happy


int byteGPS=-1;

String inputString = "";         // a string to hold incoming data
String dataString = "";

void setup() {
  
  Serial.begin(57600);
  
  Wire.begin();
  
  compass.init();
  compass.enableDefault();
  
  Wire.beginTransmission(0x3C >> 1);
  Wire.write(0x01);
  Wire.write(0x60);
  Wire.endTransmission();

  // Calibration values. Use the Calibrate example program to get the values for
  // your compass.
  compass.m_min.x = -256; compass.m_min.y = -172; compass.m_min.z = -236;
  compass.m_max.x = +104; compass.m_max.y = +181; compass.m_max.z = +133;

  GPS.begin(9600);

  // uncomment this line to turn on only the "minimum recommended" data for high update rates!
  GPS.sendCommand("$PMTK314,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0*29");
  // 5 Hz update rate- for 9600 baud you'll have to set the output to RMC or RMCGGA only (see above)
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_10HZ);
    GPS.sendCommand(PMTK_API_SET_FIX_CTL_5HZ);

    if (!gyro.init())
  {
    Serial.println(F("Fg"));
    while (1);
  }

  gyro.enableDefault();


}

void loop() {
  // put your main code here, to run repeatedly:
mySerial.listen();

while (mySerial.available()) {
    // get the new byte:
    char    inChar = (char)mySerial.read();
    // add it to the inputString:
    inputString += inChar;
    if (inChar == '\n') {

      Serial.print(inputString);
      inputString = "";
    
    }
}

 
//    Serial.println(inputString);
//      
//  inputString = "";


  float pressure = ps.readPressureMillibars();
  float altitude = ps.pressureToAltitudeMeters(pressure);
  float temperature = ps.readTemperatureC();   

  compass.read();

  gyro.read();
  
  
  
  Serial.print('p');
  Serial.print(pressure);
  Serial.print(',');
  Serial.print(altitude);
  Serial.print(',');
  Serial.println(temperature);

  Serial.print('A');
  Serial.print(compass.a.x);
  Serial.print(',');
  Serial.print(compass.a.y);
  Serial.print(',');
  Serial.println(compass.a.x);

  Serial.print('M');
  Serial.print(compass.m.x);
  Serial.print(',');
  Serial.print(compass.m.y);
  Serial.print(',');
  Serial.println(compass.m.z);

  Serial.print('G');
  Serial.print((int)gyro.g.x);
  Serial.print(',');
  Serial.print((int)gyro.g.y);
  Serial.print(',');
  Serial.println((int)gyro.g.z);
}

Your programming logic is fundamentally flawed. It only works if you almost received the entire sentence before you enter the while loop. Otherwise, you get a portion of the sentence that made it to arduino and quit the loop while the rest is still coming in. Also, your use of string class is wrong. Look into string.reserve if you want to use it right. To correct your logic, you should keep calling serial.available() and getting every char if available, until the new line char shows up.

No it won't. There is no guarantee that the entire line will be in the serial input buffer when you start in that while loop. The characters from one line might come in several separate chunks until you see the linefeed.
You need to change the code so that it accumulates the characters in the string but does not process the line until it sees the \n. The use of SoftwareSerial, which I don't think you can avoid with the FIO, is also a problem. It is probably dropping characters because you aren't calling mySerial.listen() frequently enough. I think I would change the code a bit like this:

    mySerial.listen();

    if(mySerial.available() < 1)return;

    // now read ONE character and store it.
    // if the character is not a linefeed, return
    
    // Now process the line and the other sensors.

This way, you only stop looking at mySerial when you reach the end of line, which is a safer place to pause than in the middle of an NMEA sentence.

The String vs. string is a separate issue but which is (or will) also causing problems.

Pete

Thank you very much for all your help, this is the code currently.

#include <Wire.h>
#include <LSM303.h>
#include <LPS.h>
#include <L3G.h>
#include <SPI.h>
#include <SD.h>
#include <SoftwareSerial.h>
#include <Adafruit_GPS.h>

//ALTIMU
L3G gyro;
LSM303 compass;
LPS ps;

//GPS
SoftwareSerial mySerial(3, 2);

Adafruit_GPS GPS(&mySerial);

#define GPSECHO  true

boolean usingInterrupt = false;
void useInterrupt(boolean); // Func prototype keeps Arduino 0023 happy

char NMEA[73];
int a = 0;

//SD
const int chipSelect = 4;
File dataFile;

void setup() {

  Serial.begin(57600);

  //ALTIMU
  Wire.begin();

  compass.init();
  compass.enableDefault();

  Wire.beginTransmission(0x3C >> 1);
  Wire.write(0x01);
  Wire.write(0x60);
  Wire.endTransmission();

  // Calibration values. Use the Calibrate example program to get the values for
  // your compass.
  compass.m_min.x = -256; compass.m_min.y = -172; compass.m_min.z = -236;
  compass.m_max.x = +104; compass.m_max.y = +181; compass.m_max.z = +133;

  if (!gyro.init())
  {
    Serial.println(F("Fg"));
    while (1);
  }

  gyro.enableDefault();

  ps.enableDefault();

  //GPS

  GPS.begin(9600);

  // uncomment this line to turn on only the "minimum recommended" data for high update rates!
  GPS.sendCommand("$PMTK314,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0*29");
  // 5 Hz update rate- for 9600 baud you'll have to set the output to RMC or RMCGGA only (see above)
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_10HZ);
  GPS.sendCommand(PMTK_API_SET_FIX_CTL_5HZ);


  //SD

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

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

}

void loop() {
  // put your main code here, to run repeatedly:

  mySerial.listen();



  if (mySerial.available() < 1)return;
  {
    mySerial.listen();
    char    inChar = (char)mySerial.read();

    if (inChar != '\n') {
      NMEA[a] = inChar;
      a++;
      return;

    } else {
      NMEA[a] = '\0';
      dataFile = SD.open("data.txt", FILE_WRITE);
      if (dataFile) {
        dataFile.println(NMEA);
        dataFile.close();
        // print to the serial port too:
      }
      // if the file isn't open, pop up an error:
      else {
        Serial.println(F("error opening datalog.txt"));
      }

      Serial.println(NMEA);
      a = 0;
    }
  }

  int i;

  for (i = 1; i < 3; i++) {
    float pressure = ps.readPressureMillibars();
    float altitude = ps.pressureToAltitudeMeters(pressure);
    float temperature = ps.readTemperatureC();
    compass.read();
    gyro.read();

//    File dataFile = SD.open("datalog.txt", FILE_WRITE);
//    dataFile.print('p');
//    dataFile.print(pressure);
//    dataFile.print(',');
//    dataFile.print(altitude);
//    dataFile.print(',');
//    dataFile.println(temperature);
//
//    dataFile.print('A');
//    dataFile.print(compass.a.x);
//    dataFile.print(',');
//    dataFile.print(compass.a.y);
//    dataFile.print(',');
//    dataFile.println(compass.a.x);
//
//    dataFile.print('M');
//    dataFile.print(compass.m.x);
//    dataFile.print(',');
//    dataFile.print(compass.m.y);
//    dataFile.print(',');
//    dataFile.println(compass.m.z);
//
//    dataFile.print('G');
//    dataFile.print((int)gyro.g.x);
//    dataFile.print(',');
//    dataFile.print((int)gyro.g.y);
//    dataFile.print(',');
//    dataFile.println((int)gyro.g.z);
//    dataFile.println(NMEA);
//    dataFile.close();


    Serial.print('p');
    Serial.print(pressure);
    Serial.print(',');
    Serial.print(altitude);
    Serial.print(',');
    Serial.println(temperature);
//
//    Serial.print('A');
//    Serial.print(compass.a.x);
//    Serial.print(',');
//    Serial.print(compass.a.y);
//    Serial.print(',');
//    Serial.println(compass.a.x);
//
//    Serial.print('M');
//    Serial.print(compass.m.x);
//    Serial.print(',');
//    Serial.print(compass.m.y);
//    Serial.print(',');
//    Serial.println(compass.m.z);
//
//    Serial.print('G');
//    Serial.print((int)gyro.g.x);
//    Serial.print(',');
//    Serial.print((int)gyro.g.y);
//    Serial.print(',');
//    Serial.println((int)gyro.g.z);
  }
}

I currently have a problem opening the sd card file, do any of you know why, and if you have any tips regarding optimization I would love to hear them!

Thank you very much for all your help!

Sorry for re-replying, I currently have 281 bytes for local variables, how can I know if the sd open problem derives from this lack of memory, and how can I solve it.

A sample of the first outputs follows, notice the first line is "weird" for lack of a better word.

error opening datalog.txt
¢Âbr±00914pű±bŠbé驊I“á$GPGGA,150856.200,3842.2048,N,00914.8011,W,1,10,1.11,76.7,M,50.7,M,,*40

p756.50,2397.43,42.50
p756.50,2397.43,42.50
error opening datalog.txt
$PMTK001,314,3*36

p756.50,2397.43,42.50
p756.50,2397.43,42.50
error opening datalog.txt
$PMTK001,220,3*30

p756.50,2397.43,42.50
p756.50,2397.43,42.50
error opening datalog.txt
$PMTK001,300,3*33

p756.50,2397.43,42.50
p756.50,2397.43,42.50
error opening datalog.txt
$GPGGA,150856.400,3842.2048,N,00914.8011,W,1,10,1.11,76.7,M,50.$GPGGA,150856.600,3842.2048,N,00914.8011,W,1,10,1.11,76.7,M,50.7,M,,*44

p756.50,2397.43,42.50
p756.50,2397.43,42.50
error opening datalog.txt
$GPGGA,150856.800,3842.2048,N,00914.8011,W,1,10,1.11,76.7,M,50.7,M,,*4A

p756.50,2397.43,42.50
p756.50,2397.43,42.50
error opening datalog.txt
$GPGGA,150857.000,3842.2048,N,00914.8011,W,1,10,1.11,76.7,M,50.7,M,,*43

p756.50,2397.43,42.50
p756.50,2397.43,42.50
error opening datalog.txt
$GPGGA,150857.200,3842.2048,N,00914.8011,W,1,10,1.11,76.7,M,50.7,M,,*41

p756.50,2397.43,42.50
p756.50,2397.43,42.50
error opening datalog.txt

Thank you all for your help.

The weirdness at the beginning of the first line is probably due to the software serial starting up in the middle of a GPS transmission.
The SD open problem is not likely to be due to lack of memory. The SD library allocates what it needs. The most common problem I have found when an SD card won't open is a wiring problem. Usually it was due to a loose ground wire. Make sure that all the SD wires are in their correct places and that they are all making good contact at both ends.

You could improve the way that the NMEA sentence is read by only starting to read the sentence when you see $ which always starts an NMEA sentence.
You could do this by first initializing 'a' to -1. Then in the loop, if 'a' is -1 you don't start storing anything until you see a '$'. Then you store the '$' in NMEA[0] and set 'a' to 1. After that you store the string normally until you see the '\n'. At that point you should have a good NMEA string and you reset a to -1. If you now start reading in the middle of an NMEA sentence you aren't as likely to store junk.
One further thing you must do is that while you are reading the string, you must make sure that 'a' never indexes past the end of the NMEA array. If 'a' does reach the length of the NMEA array, the best thing to do is just throw away the existing string by setting 'a' to -1 again.

Pete

Thank you for your help!
Regarding the SD card, I don't think it was the ground connection as I did not have any problems with the sd logger example even when I added the libraries, yet they started when I added a string. I've since changed the sd library to the SdFat lib and encountered no more problems (though that might also be because I started opening the file only once).

I've added the '$' detection el_supremo suggested.

There are some PMTK sentences in the beginning, since I can't turn them off, I might add a sentence detector.

The code as is:

/*
 * Simple data logger.
 */
#include <SPI.h>
#include <SdFat.h>
#include <Wire.h>
#include <LSM303.h>
#include <LPS.h>
#include <L3G.h>
#include <SoftwareSerial.h>
#include <Adafruit_GPS.h>

//ALTIMU
L3G gyro;
LSM303 compass;
LPS ps;

//GPS
SoftwareSerial mySerial(3, 2);

Adafruit_GPS GPS(&mySerial);

char NMEA[73];
int a = -1;


// SD chip select pin.  Be sure to disable any other SPI devices such as Enet.
const uint8_t chipSelect = 4;

// Interval between data records in milliseconds.
// The interval must be greater than the maximum SD write latency plus the
// time to acquire and write data to the SD to avoid overrun errors.
// Run the bench example to check the quality of your SD card.
const uint32_t SAMPLE_INTERVAL_MS = 200;

// Log file base name.  Must be six characters or less.
#define FILE_BASE_NAME "Data"
//------------------------------------------------------------------------------
// File system object.
SdFat sd;

// Log file.
SdFile file;

// Time in micros for next data record.
uint32_t logTime;

//==============================================================================
// User functions.  Edit writeHeader() and logData() for your requirements.


//------------------------------------------------------------------------------
// Write data header.

//------------------------------------------------------------------------------
// Log a data record.

//==============================================================================
// Error messages stored in flash.
#define error(msg) sd.errorHalt(F(msg))
//------------------------------------------------------------------------------
void setup() {
  const uint8_t BASE_NAME_SIZE = sizeof(FILE_BASE_NAME) - 1;
  char fileName[13] = FILE_BASE_NAME "00.csv";

  Serial.begin(57600);

  Serial.println(F("Type any character to start"));
  while (!Serial.available()) {}

  // Initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
  // breadboards.  use SPI_FULL_SPEED for better performance.
  if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
    sd.initErrorHalt();
  }

  // Find an unused file name.
  if (BASE_NAME_SIZE > 6) {
    error("FILE_BASE_NAME too long");
  }
  while (sd.exists(fileName)) {
    if (fileName[BASE_NAME_SIZE + 1] != '9') {
      fileName[BASE_NAME_SIZE + 1]++;
    } else if (fileName[BASE_NAME_SIZE] != '9') {
      fileName[BASE_NAME_SIZE + 1] = '0';
      fileName[BASE_NAME_SIZE]++;
    } else {
      error("Can't create file name");
    }
  }
  if (!file.open(fileName, O_CREAT | O_WRITE | O_EXCL)) {
    error("file.open");
  }
  do {
    delay(10);
  } while (Serial.read() >= 0);

  Serial.print(F("Logging to: "));
  Serial.println(fileName);



  //ALTIMU
  Wire.begin();

  compass.init();
  compass.enableDefault();

  gyro.init();
  gyro.enableDefault();

  ps.enableDefault();

  //GPS

  GPS.begin(9600);

  // uncomment this line to turn on only the "minimum recommended" data for high update rates!
  GPS.sendCommand("$PMTK314,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0*29");
  // 5 Hz update rate- for 9600 baud you'll have to set the output to RMC or RMCGGA only (see above)
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_10HZ);
  GPS.sendCommand(PMTK_API_SET_FIX_CTL_5HZ);

}
//------------------------------------------------------------------------------
void loop() {




  if (mySerial.available() < 1)return;
  {
    mySerial.listen();
    char    inChar = (char)mySerial.read();
    if (a == -1) {
      if (inChar == '

As always I welcome any comments and suggestions on how to improve it, thanks for all the help!

) {
        a = 0;
      } else {
        return;
      }
    }
    if (inChar != '\n') {
      NMEA[a] = inChar;
      a++;
      if (a > 73) {
        a = -1;
      }
      return;

} else {
      NMEA[a] = '\0';

file.println(NMEA);
      if (!file.sync() || file.getWriteError()) {
        error("write error");
      }
      Serial.println(NMEA);
      a = -1;
    }
  }

int i;

for (i = 1; i < 3; i++) {
    float pressure = ps.readPressureMillibars();
    float altitude = ps.pressureToAltitudeMeters(pressure);
    float temperature = ps.readTemperatureC();
    compass.read();
    gyro.read();

file.print('p');
    file.print(pressure);
    file.print(',');
    file.print(altitude);
    file.print(',');
    file.println(temperature);

file.print('A');
    file.print(compass.a.x);
    file.print(',');
    file.print(compass.a.y);
    file.print(',');
    file.println(compass.a.x);

file.print('M');
    file.print(compass.m.x);
    file.print(',');
    file.print(compass.m.y);
    file.print(',');
    file.println(compass.m.z);

file.print('G');
    file.print((int)gyro.g.x);
    file.print(',');
    file.print((int)gyro.g.y);
    file.print(',');
    file.println((int)gyro.g.z);

Serial.print('p');
    Serial.print(pressure);
    Serial.print(',');
    Serial.print(altitude);
    Serial.print(',');
    Serial.println(temperature);
    Serial.print('A');
    Serial.print(compass.a.x);
    Serial.print(',');
    Serial.print(compass.a.y);
    Serial.print(',');
    Serial.println(compass.a.x);

Serial.print('M');
    Serial.print(compass.m.x);
    Serial.print(',');
    Serial.print(compass.m.y);
    Serial.print(',');
    Serial.println(compass.m.z);

Serial.print('G');
    Serial.print((int)gyro.g.x);
    Serial.print(',');
    Serial.print((int)gyro.g.y);
    Serial.print(',');
    Serial.println((int)gyro.g.z);

}

// Force data to SD and update the directory entry to avoid data loss.
  if (!file.sync() || file.getWriteError()) {
    error("write error");
  }

if (millis() > 300000 || Serial.available()) {
    // Close file and stop.
    file.close();
    Serial.println(F("Done"));
    while (1) {}
  }
}


As always I welcome any comments and suggestions on how to improve it, thanks for all the help!
      if (a > 73) {

No, that is wrong. There are 73 characters in the array, so the last one is at NMEA[72] and that one must be the NULL at the end of the string. So the value of 'a' should not exceed 71.
It's best to define the length of the array as a manifest constant (or you can use const int)

#define NMEA_LENGTH 73

and then declare the array

char NMEA[NMEA_LENGTH];

and test the value of 'a' with it

      if (a > NMEA_LENGTH-2) {

This also has the advantage that if you find that 73 characters isn't long enough, you only have to change the code in one place.

Pete

Pete,

Read reference before answering a question with false information

I understand you are trying to help. That aside, be sure you are telling the right thing.

I will substitute the string with char arrays, but will this solve the issue with leaving the loop before the '\n' appears?

Probably not. The "String issue" is put out by certain persons when they don't have a clue as to what the problem is. My question would be is the data packet have end of packet markers. If the device directly prints out to the serial monitor, then it probably uses a carriage return/line feed as the end of data marker. You might be able to just use the arduino hardware serial to do your trouble shooting. Note that the SD card can interfer with other attached devices if the same pins are used by both. There are ways to temporarily disable the SD card while other devices are loaded.

$GPGGA,172841.600,3842.2050,N,00914.7984,W,2,08,1.20,97.7,M,50.
$GPGGA,172841.600,3842.2050,N,00914.7984,W,2,08,1.20,97.7,M,50.
$GPGGA,172841.600,3842.2050,N,00914.7984,W,2,08,1.20,97.7,M,50.

liudr:
Read reference before answering a question with false information

Which false information?

The "end of packet markers" issue is put out by certain persons when they haven't got a clue what they're talking about.
The "device" is an Adafruit Ultimate GPS. I have two of them. The end of their NMEA sentences is a CR and LF. In my code I use LF as the end of line marker and ignore CR.

Note that the SD card can interfer with other attached devices if the same pins are used by both. There are ways to temporarily disable the SD card while other devices are loaded.

More nonsensical babble. The SD card is an SPI device. It can share MOSI/MISO/etc pins with multiple SPI devices but it wouldn't make sense to have non-SPI devices on those same pins and, so far, there's no evidence that the OP has done so.

Pete

I have two of them.

Then quit peeing in your pants and post some code that works.

@zoomkat.
(a) I am not peeing in my pants. You're the a..hole who's having a hissy fit.
(b) Just because I offer help to people on here doesn't mean i have to write their code for them.
You do it.

Pete

Hello and thank you all for your help!

No need to start arguing, and no need to post the code.

I've changed the a>73 thing, a complete oversight.

Regarding the end of packet markers i believe these are CR and LF.

The only pins currently being shared are the power pins. GPS is on D2-D3 with a soft serial, ALTIMU is on A4-A5 in I2C, SD on 13-11 and 4, and an Xbee on the Xbee slot which should use RX TX (though not when I'm testing since I use a FTDI).

I don't know what was wrong but since I changed the SD to SDfat I've had no more problems, I might change back just for curiosity.

Is there any way to speed up writing? currently I can get 4 writes in between GPS sentences, which comes to 20Hz update rate, but higher is always better.

Thanks again!

currently I can get 4 writes in between GPS sentences

How much data are you writing in each of those 4 writes and is that per second?

User fat16lib wrote the sdfat library and he has lots of info/advice about optimizing writes to an SD card. Unfortunately, some of it is spread around as responses in other threads. Dig through the Storage section here but start with this "sticky".
http://forum.arduino.cc/index.php?topic=228201.0

Pete