GPS logging of ADXL345

Adafruit Ethernet, Motor, Proto, Wave, Datalogger, GPS Shields - etc!

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
nickos
 
Posts: 2
Joined: Tue Nov 20, 2018 4:18 pm

GPS logging of ADXL345

Post by nickos »

Hi,

I want to chart the quality of the bicycle-lanes i use frequently, and planned to do that by using the Arduino UNO, the Adafruit Ultimate GPS shield and the ADXL345 accelerometer sensor. For the sensor I use the I2C pins on the UNO.
I carefully merged the codes from both libraries "shield-sdlog" and "sensor-test" , removing unused lines of code. see below

Code: Select all

 #include <SPI.h>
#include <Adafruit_GPS.h>
#include <SoftwareSerial.h>
#include <SD.h>
#include <avr/sleep.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_ADXL345_U.h>


Adafruit_ADXL345_Unified accel = Adafruit_ADXL345_Unified(12345);

// =============================== SD logging shield ==================================================================
  long sync_interval = 30000;                  // milliseconds between calls to flush() - to write data to the card = 30 seconds
  long lastMillis=0;
//  uint32_t syncTime = 0;                        // time of last sync()
  //#define yellowLEDpin 4                        // control LED pin
  //#define greenLEDpin 3                         // control LED pin


// Ladyada's logger modified by Bill Greiman to use the SdFat library
//
// This code shows how to listen to the GPS module in an interrupt
// which allows the program to have more 'freedom' - just parse
// when a new NMEA sentence is available! Then access data when
// desired.
//
// Tested and works great with the Adafruit Ultimate GPS Shield
// using MTK33x9 chipset
//    ------> http://www.adafruit.com/products/
// Pick one up today at the Adafruit electronics shop 
// and help support open source hardware & software! -ada
// Fllybob added 10 sec logging option
SoftwareSerial mySerial(8, 7);
Adafruit_GPS GPS(&mySerial);

// 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
/* set to true to only log to SD when GPS has a fix, for debugging, keep it false */
#define LOG_FIXONLY 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

// Set the pins used
#define chipSelect 10
#define ledPin 13

File logfile;


// blink out an error code
void error(uint8_t errno) {
  /*
  if (SD.errorCode()) {
   putstring("SD error: ");
   Serial.print(card.errorCode(), HEX);
   Serial.print(',');
   Serial.println(card.errorData(), HEX);
   }
   */
  while(1) {
    uint8_t i;
    for (i=0; i<errno; i++) {
      digitalWrite(ledPin, HIGH);
      delay(100);
      digitalWrite(ledPin, LOW);
      delay(100);
    }
    for (i=errno; i<10; i++) {
      delay(200);
    }
  }
}

void setup() {
  // for Leonardos, if you want to debug SD issues, uncomment this line
  // to see serial output
  //while (!Serial);

  // connect at 115200 so we can read the GPS fast enough and echo without dropping chars
  // also spit it out
  Serial.begin(9600);
  Serial.println("\r\nUltimate GPSlogger Shield");
  pinMode(ledPin, OUTPUT);

  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(10, OUTPUT);

  // see if the card is present and can be initialized:
//  if (!SD.begin(chipSelect, 11, 12, 13)) {
    if (!SD.begin(chipSelect)) {      // if you're using an UNO, you can use this line instead
    Serial.println("Card init. failed!");
    error(2);
  }
  char filename[15];
  strcpy(filename, "GPSLOG00.CSV");
  for (uint8_t i = 0; i < 100; i++) {
    filename[6] = '0' + i/10;
    filename[7] = '0' + i%10;
    // create if does not exist, do not open existing, write, sync after write
    if (! SD.exists(filename)) {
      break;
    }
  }

  logfile = SD.open(filename, FILE_WRITE);
  if( ! logfile ) {
    Serial.print("Couldnt create "); 
    Serial.println(filename);
    error(3);
  }
  Serial.print("Writing to "); 
  Serial.println(filename);
  
 /* Initialise the sensor */
  if(!accel.begin())
  {
    /* There was a problem detecting the ADXL345 ... check your connections */
    Serial.println("Ooops, no ADXL345 detected ... Check your wiring!");
    while(1);
  }

  /* Set the range to whatever is appropriate for your project */
  accel.setRange(ADXL345_RANGE_16_G);
  // accel.setRange(ADXL345_RANGE_8_G);
  // accel.setRange(ADXL345_RANGE_4_G);
  // accel.setRange(ADXL345_RANGE_2_G);
  // connect to the GPS at the desired rate
  GPS.begin(9600);

  // 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
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);
  // For logging data, we don't suggest using anything but either RMC only or RMC+GGA
  // to keep the log files at a reasonable size
  // Set the update rate
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);   // 100 millihertz (once every 10 seconds), 1Hz or 5Hz update rate

  // Turn off updates on antenna status, if the firmware permits it
  GPS.sendCommand(PGCMD_NOANTENNA);

  // the nice thing about this code is you can have a timer0 interrupt go off
  // every 1 millisecond, and read data from the GPS for you. that makes the
  // loop code a heck of a lot easier!
  useInterrupt(true);

  Serial.println("Ready!");
}


// Interrupt is called once a millisecond, looks for any new GPS data, and stores it
SIGNAL(TIMER0_COMPA_vect) {
  char c = GPS.read();
  // if you want to debug, this is a good time to do it!
  #ifdef UDR0
      if (GPSECHO)
        if (c) UDR0 = c;  
      // writing direct to UDR0 is much much faster than Serial.print 
      // but only one character can be written at a time. 
  #endif
}

void useInterrupt(boolean v) {
  if (v) {
    // Timer0 is already used for millis() - we'll just interrupt somewhere
    // in the middle and call the "Compare A" function above
    OCR0A = 0xAF;
    TIMSK0 |= _BV(OCIE0A);
    usingInterrupt = true;
  } 
  else {
    // do not call the interrupt function COMPA anymore
    TIMSK0 &= ~_BV(OCIE0A);
    usingInterrupt = false;
  }
}

void loop() {
  if (! usingInterrupt) {
    // read data from the GPS in the 'main loop'
    char c = GPS.read();
    // if you want to debug, this is a good time to do it!
    if (GPSECHO)
      if (c) Serial.print(c);
  }
   /* Get a new sensor event */ 
     sensors_event_t event; 
     accel.getEvent(&event);

  
  // if a sentence is received, we can check the checksum, parse it...
  if (GPS.newNMEAreceived()) {
    // a tricky thing here is if we print the NMEA sentence, or data
    // we end up not listening and catching other sentences! 
    // so be very wary if using OUTPUT_ALLDATA and trying to print out data
    
    // Don't call lastNMEA more than once between parse calls!  Calling lastNMEA 
    // will clear the received flag and can cause very subtle race conditions if
    // new data comes in before parse is called again.
    char *stringptr = GPS.lastNMEA();
    
    if (!GPS.parse(stringptr))   // this also sets the newNMEAreceived() flag to false
      return;  // we can fail to parse a sentence in which case we should just wait for another 
   
    // Sentence parsed! 
    Serial.println("OK");
    if (LOG_FIXONLY && !GPS.fix) {
      Serial.print("No Fix");
      return;
    }
   
    

    // Rad. lets log it!
    Serial.println("Log");
  /*  Serial.println(GPS.altitude,4);
    Serial.println(GPS.longitude,4);
    Serial.println(GPS.latitude,4);
    Serial.print(GPS.hour,DEC);Serial.print(":");
    Serial.print(GPS.minute,DEC);Serial.print(":");
    Serial.println(GPS.seconds,DEC);
    Serial.print(event.acceleration.x); Serial.print("  ");
    Serial.print("Y: "); Serial.print(event.acceleration.y); Serial.print("  ");
    Serial.print("Z: "); Serial.print(event.acceleration.z); Serial.print("  ");Serial.println("m/s^2 ");
    */
    logfile.print(GPS.longitude,4);logfile.print(",");
    logfile.print(GPS.latitude,4);logfile.print(",");
    logfile.print(GPS.altitude,4);logfile.print(",");
    logfile.print(GPS.hour,DEC);logfile.print(",");
    logfile.print(GPS.minute,DEC);logfile.print(",");
    logfile.print(GPS.seconds,DEC);logfile.print(",");
    logfile.print(event.acceleration.x); logfile.print(",");
    logfile.print(event.acceleration.y); logfile.print(",");
    logfile.println(event.acceleration.z);

    
//    
    
    
  }
     // =============================== refresh logfile ===================================================================

    if (millis() - lastMillis > sync_interval) 
               {            

               // Now we write data to disk! Don't sync too often - requires 2048 bytes of I/O to SD card
               // which uses a bunch of power and takes time
               // blink yellow LED to show we are syncing data to the card & updating FAT!
               
              // digitalWrite(yellowLEDpin, HIGH);
               logfile.flush();
             //  digitalWrite(yellowLEDpin, LOW);
               lastMillis = millis();
    }
	
	
	
	
  
}


/* End code */

 
Compiling/Uploading the resulted in the well known " low memory available, stability problem ahead " warning.
Running it , resulted in the creation of approx 25 csv-files in one minute, sometimes blank ,sometimes containing a few gps /time and accelerometer data.
As the manufacturer of both the shield and the sensor I was hoping you could come up with a solution for this problem.

Greetings

Nicko

User avatar
nickos
 
Posts: 2
Joined: Tue Nov 20, 2018 4:18 pm

Re: GPS logging of ADXL345

Post by nickos »

Hi,

After searching the Arduino forum I've found the solution for my question provided by "/dev" . The problem of memory consumption by the Adafruit GPS library is apparently well known. "/dev" provides a leaner one called NeoGPS. Also see https://forum.arduino.cc/index.php?topic=515350.0
I've based my new sketch on this library and a few other tips from "/dev" and it works as desired.

Code: Select all

#include <avr/sleep.h>

#include <SPI.h>
#include <SdFat.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_ADXL345_U.h>

#define CHIP_SELECT 10
#define LED_PIN 13 
#define LOG_FIXONLY true

SdFat SD;
Adafruit_ADXL345_Unified accel = Adafruit_ADXL345_Unified(12345);
File logfile;

#include <NeoSWSerial.h>
NeoSWSerial gpsPort(8, 7); // AltSoftSerial on 8/9 would be better!

#include <NMEAGPS.h>
NMEAGPS gps;

// =============================== SD logging shield ==================================================================
  long sync_interval = 30000;                  // milliseconds between calls to flush() - to write data to the card = 30 seconds
  long lastMillis=0;
//  uint32_t syncTime = 0;                      // time of last sync()
//#define yellowLEDpin 4                        // control LED pin
//#define greenLEDpin 3                         // control LED pin




// read a Hex value and return the decimal equivalent
uint8_t parseHex(char c) {
  if (c < '0')
    return 0;
  if (c <= '9')
    return c - '0';
  if (c < 'A')
    return 0;
  if (c <= 'F')
    return (c - 'A')+10;
}

// blink out an error code
void error(uint8_t errno) {
  /*
  if (SD.errorCode()) {
   putstring("SD error: ");
   Serial.print(card.errorCode(), HEX);
   Serial.print(',');
   Serial.println(card.errorData(), HEX);
   }
   */
  while(1) {
    uint8_t i;
    for (i=0; i<errno; i++) {
      digitalWrite(LED_PIN, HIGH);
      delay(100);
      digitalWrite(LED_PIN, LOW);
      delay(100);
    }
    for (i=errno; i<10; i++) {
      delay(200);
    }
  }
}

void setup() {



  // connect at 115200 so we can read the GPS fast enough and echo without dropping chars
  // also spit it out
  Serial.begin(115200);
  Serial.println( F("\r\nUltimate GPSlogger Shield with NeoGPS") ); // F macro saves RAM!
  pinMode(LED_PIN, OUTPUT);

  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(10, OUTPUT);


  // see if the card is present and can be initialized:
  if (!SD.begin(CHIP_SELECT)) {      // if you're using an UNO, you can use this line instead
    Serial.println( F("Card init. failed!") );
    error(2);
  }

  char filename[15] = "GPSLOG00.CSV";
  for (uint8_t i = 0; i < 100; i++) {
    filename[6] = '0' + i/10;
    filename[7] = '0' + i%10;
    // create if does not exist, do not open existing, write, sync after write
    if (! SD.exists(filename)) {
      break;
    }
  }

  logfile = SD.open(filename, FILE_WRITE);
  if( ! logfile.isOpen() ) {
    Serial.print( F("Couldnt create ") ); 
    Serial.println(filename);
    error(3);
  }

  Serial.print( F("Writing to ") ); 
  Serial.println(filename);
  
   /* Initialise the sensor */
  if(!accel.begin())
  {
    /* There was a problem detecting the ADXL345 ... check your connections */
    Serial.println("Ooops, no ADXL345 detected ... Check your wiring!");
    while(1);
  }
  /* Set the range to whatever is appropriate for your project */
  accel.setRange(ADXL345_RANGE_16_G);
  // accel.setRange(ADXL345_RANGE_8_G);
  // accel.setRange(ADXL345_RANGE_4_G);
  // accel.setRange(ADXL345_RANGE_2_G);
  
  // connect to the GPS at the desired rate
  gpsPort.begin( 9600 );

  gps.send_P( &gpsPort, F("PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0") ); // RMC_GGA
  gps.send_P( &gpsPort, F("PMTK220,500") );  // 2Hz
  gps.send_P( &gpsPort, F("PGCMD,33,0") );   // No antenna status messages needed

  Serial.println("Ready!");
}


void loop() {

/* Get a new sensor event */ 
     sensors_event_t event; 
     accel.getEvent(&event);



  // Parse GPS characters until a complete fix has been assembled.
  if (gps.available( gpsPort )) {

    // A complete fix structure is finally ready, get it.
    gps_fix fix = gps.read();

   

    if (LOG_FIXONLY && !fix.valid.location) {
      Serial.println( F("No Fix") );
      return;
    } 

    // Rad. lets log it!
    Serial.println( F("Log") );

    logfile.print(fix.dateTime.hours); 
    logfile.print(':');
    logfile.print(fix.dateTime.minutes); 
    logfile.print(':');
    logfile.print(fix.dateTime.seconds); 
    logfile.print('.');
    if (fix.dateTime_cs < 10)
      logfile.print( '0' );
    logfile.print(fix.dateTime_cs);
    logfile.print(',');

    logfile.print(fix.dateTime.date); 
    logfile.print('/');
    logfile.print(fix.dateTime.month); 
    logfile.print(','); 
    logfile.print(fix.latitude(), 4); 
    logfile.print(", ");
    logfile.print(fix.longitude(), 4); 
    logfile.print(", ");
    logfile.print(fix.altitude() ); 
    logfile.print(',');
    logfile.print(event.acceleration.x);
    logfile.print(',');
    logfile.print(event.acceleration.y);
    logfile.print(',');
    logfile.println(event.acceleration.z);
	
 // =============================== refresh logfile ===================================================================

    if (millis() - lastMillis > sync_interval) 
               {            

               // Now we write data to disk! Don't sync too often - requires 2048 bytes of I/O to SD card
               // which uses a bunch of power and takes time
               // blink yellow LED to show we are syncing data to the card & updating FAT!
               
              // digitalWrite(yellowLEDpin, HIGH);
               Serial.println(F("flush"));
               logfile.flush();
             //  digitalWrite(yellowLEDpin, LOW);
               lastMillis = millis();
    }
    
  }
}
 

Cheers,

Nicko

Locked
Please be positive and constructive with your questions and comments.

Return to “Arduino Shields from Adafruit”