Ultimate GPS+Logger Shield

Post here about your Arduino projects, get help - for Adafruit customers!

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
srellis
 
Posts: 8
Joined: Mon Aug 18, 2014 12:52 pm

Ultimate GPS+Logger Shield

Post by srellis »

Hello,

I am currently using GPS.altitude to log altitude values from the GPS, but the reported values do not appear to be in cm. I am crosschecking these values with a handheld Garmin that using barometric pressure to determine altitude (I know this is more accurate so I am expecting some discrepancy, but not several hundred meters. From what I can tell, the altitude is either reporting in meters or yards. Do you know which? I am using the adafruit example code to parse the data, so I don't think that's where the problem is.

I am currently reading 137.7 when the correct altitude is roughly 397 ft.


Code: Select all

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

// 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 false  

// 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;

// 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(ledPin, HIGH);
      delay(100);
      digitalWrite(ledPin, LOW);
      delay(100);
    }
    for (i=errno; i<10; i++) {
      delay(200);
    }
  }
}
const int temperaturePin = 0;
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(115200);
  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.TXT");
  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);

  // 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;
  }

  logfile.print("Time");
  logfile.print(" ");
  logfile.print("Lattitude");
  logfile.print(" ");
  logfile.print("Longitude");
  logfile.print(" ");
  logfile.print("Speed");
  logfile.print(" ");
  logfile.print("Altitude");
  logfile.print(" ");
  logfile.print("Satellites");
  logfile.print(" ");
  logfile.print("Box Temp");
  logfile.println();
  
}

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);
  }
  
  //float voltage, degreesC;
  //degreesC = (voltage - 0.5) * 100.0;
  //Serial.print("  deg C: ");
  //Serial.println(degreesC);
  
  
  // 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();
    float voltage, degreesC;
    voltage = analogRead(temperaturePin) * 0.004882814;
    degreesC = (voltage - 0.5) * 100.0;
    
    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");

    //uint8_t stringsize = strlen(stringptr);
    
    logfile.print(GPS.hour, DEC);  //write the string to the SD file
    logfile.print(":");
    logfile.print(GPS.minute, DEC);  //write the string to the SD file
    logfile.print(":");
    logfile.print(GPS.seconds, DEC);  //write the string to the SD file
    //logfile.print(".");
    //logfile.print(GPS.milliseconds);
    logfile.print(" ");
    logfile.print(GPS.latitude, 4); 
    logfile.print(GPS.lat);
    logfile.print(" ");
    logfile.print(GPS.longitude,4); 
    logfile.print(GPS.lon);
    logfile.print(" ");
    logfile.print(GPS.speed);
    logfile.print(" ");
    logfile.print(GPS.altitude);
    logfile.print(" ");
    logfile.print((int)GPS.satellites);
    logfile.print(" ");
    logfile.print(degreesC);
 
    
    
    logfile.println();
    if (strstr(stringptr, "RMC") || strstr(stringptr, "GGA"))   logfile.flush();
    Serial.println();
  }
}


/* End code */

User avatar
Franklin97355
 
Posts: 23910
Joined: Mon Apr 21, 2008 2:33 pm

Re: Ultimate GPS+Logger Shield

Post by Franklin97355 »

137.7 meters is 451.8 feet and remember pressure needs to be adjusted to pressure at sea level.

User avatar
srellis
 
Posts: 8
Joined: Mon Aug 18, 2014 12:52 pm

Re: Ultimate GPS+Logger Shield

Post by srellis »

Thank you for your reply.

The documentation for that library says that altitude is reported in centimeters when you call GPS.altitude. Are you saying this is incorrect and I can assume that value is in meters? Yards would also give a value around 400 ft, so I just want to confirm the units.

"Once data is parsed, we can just ask for data from the library like GPS.day, GPS.month and GPS.year for the current date. GPS.fix will be 1 if there is a fix, 0 if there is none. If we have a fix then we can ask for GPS.latitude, GPS.longitude, GPS.speed (in knots, not mph or k/hr!), GPS.angle, GPS.altitude (in centimeters) and GPS.satellites (number of satellites)."

https://learn.adafruit.com/adafruit-ult ... rsing-data

User avatar
Franklin97355
 
Posts: 23910
Joined: Mon Apr 21, 2008 2:33 pm

Re: Ultimate GPS+Logger Shield

Post by Franklin97355 »

$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47

Where:
GGA Global Positioning System Fix Data
123519 Fix taken at 12:35:19 UTC
4807.038,N Latitude 48 deg 07.038' N
01131.000,E Longitude 11 deg 31.000' E
1 Fix quality: 0 = invalid
1 = GPS fix (SPS)
2 = DGPS fix
3 = PPS fix
4 = Real Time Kinematic
5 = Float RTK
6 = estimated (dead reckoning) (2.3 feature)
7 = Manual input mode
8 = Simulation mode
08 Number of satellites being tracked
0.9 Horizontal dilution of position
545.4,M Altitude, Meters, above mean sea level
46.9,M Height of geoid (mean sea level) above WGS84
ellipsoid
(empty field) time in seconds since last DGPS update
(empty field) DGPS station ID number
*47 the checksum data, always begins with *
In the parsing code the raw altitude is multiplied by 3.28 which looks to be a conversion to feet from meters. I'll check on the tutorial.

User avatar
tdicola
 
Posts: 1074
Joined: Thu Oct 17, 2013 9:11 pm

Re: Ultimate GPS+Logger Shield

Post by tdicola »

I took a closer look at the library and it's actually just parsing out the altitude value given by the $GPGGA string. From what franklin mentions this should be a value in meters, so it looks like the tutorial page is a little out of date. I'll update the page to clarify this is in meters and not centimeters. Thanks for catching the issue!

User avatar
srellis
 
Posts: 8
Joined: Mon Aug 18, 2014 12:52 pm

Re: Ultimate GPS+Logger Shield

Post by srellis »

Thank you guys for the help!

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

Return to “Arduino”