adafruit GPS logger giving some weird readings?

Hello,I'm using an Arduino Uno with the adafruit ultimate GPS logger shield. Right now I'm running the shield_sdlog example program, but am getting some weird outputs.

This is the output I'm getting:

Ultimate GPSlogger Shield
Writing to GPSLOG06.TXT
‚Ready!
Eµ	S&&›…$šQ-‚ŠI	iÒfC$PGACK,33,0*6E
$GPGGA,235958.800,,,,,0,0,,,M,,M,,*40
$GPRMC,O2K3
L5o9g5
8
.800,V,,,,,0.00,0.00,050180,,,N*49

OK
Log

$GPGGA,235959.800,,,,,0,0,,,M,,M,,*41
$GPRMC,O2K3
Log
95
9.800,V,,,,,0.00,0.00,050180,,,N*48

OK
Log

$GPGGA,000000.800,,,,,0,0,,,M,,M,,*40
$GPRMC,O0K0
L0o0g0
0
.800,V,,,,,0.00,0.00,060180,,,N*4A

OK
Log

$GPGGA,000001.800,,,,,0,0,,,M,,M,,*41
$GPRMC,O0K0
L0o0g0
1
.800,V,,,,,0.00,0.00,060180,,,N*4B

OK
Log

$GPGGA,000002.800,,,,,0,0,,,M,,M,,*42
$GPRMC,O0K0
Log
02.800,V,,,,,0.00,0.00,060180,,,N*48

OK
Log

$GPGGA,000003.800,,,,,0,0,,,M,,M,,*43
$GPRMC,O0K0
L0o0g0
3
.800,V,,,,,0.00,0.00,060180,,,N*49

OK
Log

$GPGGA,000004.800,,,,,0,0,,,M,,M,,*44
$GPRMC,O0K0
L0o0g0
4
.800,V,,,,,0.00,0.00,060180,,,N*4E

Now I am using this thing inside, so I assume this explains at least some of the weird GPS readings (because it can't get a fix), but I still think that some of these outputs might be indicative of another problem (for example, when it occasionally sticks zeros in the middle of the "log" statement, or the complete gibberish characters it gives me at the beginning: Eµ S&&›…$šQ-‚ŠI iÒfC$PGACK,33,0*6E).

Another possible reason for this weird behavior is that this program is apparently pretty long because the Arduino compiler is giving me a memory warning (66% of flash, 74% of RAM, warns me that "stability issues may occur").

So I was wondering, is it possible that this memory issue is causing the weird behavior? I'm not really sure what stability issues means--will I be able to tell if stability issues are occurring by whether or not the program crashes, or can stability issues be the cause of weird random characters? Or is there something else that could be causing this problem? Or am I blowing the problem out of proportion and these of the readings I'm supposed to be getting?

here's the code (I only modified the chipSelect line because it said to for the Uno):

#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);
    }
  }
}

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

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

    uint8_t stringsize = strlen(stringptr);
    if (stringsize != logfile.write((uint8_t *)stringptr, stringsize))    //write the string to the SD file
        error(4);
    if (strstr(stringptr, "RMC") || strstr(stringptr, "GGA"))   logfile.flush();
    Serial.println();
  }
}

mysteriousmonkey29:
Hello,I'm using an Arduino Uno with the adafruit ultimate GPS logger shield. Right now I'm running the shield_sdlog example program, but am getting some weird outputs.

/* set to true to only log to SD when GPS has a fix, for debugging, keep it false */

#define LOG_FIXONLY false

Why do you want to log when the GPS does NOT have a fix? (unknown location)

I recommend changing this to true. You will not see the garbage when the GPS does not have lock.

chuck.

Combining Serial.print, SoftwareSerial GPS, and SD card operations is going to be difficult. Adafruit also adds a Timer interrupt to try and read the SoftwareSerial. These operations interfere with each other, and can cause dropped characters like you're seeing.

It is possible to make it work, but it usually requires coordinating with the GPS "quiet time". You should also identify exactly which information you want to save and/or print. The more data you try to save/print, the harder it's going to be.

I would also suggest getting familiar with the individual pieces of this problem. Try some examples that just do SD operations. Then try just GPS. If you search the forum, you will see that many people struggle with this combination.

Good luck,
/dev

That's the stock example that comes with the Adafruit library. I'm sure I ran that when I first got my GPS logging board. It's a pretty dicey bit of code but I'm almost positive it worked as is, unmodified.

I'll have to try it again and see....

....it worked fine. All I had to do was edit that one line, specific for the Uno. It logged before the GPS got a fix and logged after it got a fix. No errors. Echoed the NMEA strings on the serial monitor.

One possible source of trouble is the header pins that you have to solder yourself. Check there, specifically at pin 8, and make sure it's a good solder job. Touch it up if it looks at all questionable.

Okay, first, I changed the line Chuck mentioned, so now it only logs when I have a fix.

And as Jboy mentioned, I think the logging in this program is working (it's hard to tell, but it definitely looks like GPS NMEA sentences). Should I be concerned by the weird characters that I'm getting in the serial monitor though? Could the interference that /dev mentioned interfere with the actual GPS readings, or is it just screwing up some of the serial monitor output?

Just not really sure if there is an problem that I actually need to fix somehow.

Thanks!

It's your choice.
If the output from my Ult. GPS logger looked like that I'd want it fixed.

So you didn't get that kind of output when you ran the program? And another question. If some kind of interference between the two functions really is the problem, but this problem can be avoided by properly formatting your program, why am I having this problem with the example program? I would assume that they are written correctly

Yes, no garbled strings or garbage characters. Clean output to the monitor and to the file, both before and after GPS fix. The example sketch is weak and a poor starting point for a project, in my opinion. But it works. I'll say it again:

The example sketch works fine.

You probably have a hardware problem.

Okay, two questions. First, I was just wondering why you think this is a poor starting place for a project? What is wrong with the code? Second, I have already checked the welds on my adafruit header pins; are there any other common hardware problems that could cause something like this?

mysteriousmonkey29:
...I was just wondering why you think this is a poor starting place for a project? What is wrong with the code?

It's just not very robust. It works, barely, but is easy to break if you modify it the wrong way. A big part of the problem is SoftwareSerial. One of the sketches in the GPS examples folder doesn't even work properly because of SoftwareSerial.

mysteriousmonkey29:
Second, I have already checked the welds on my adafruit header pins; are there any other common hardware problems that could cause something like this?

That was my first guess, that you either had a bad solder joint or a short there. I'd say double check it with a DMM. Make sure it's really connected to the other places on the GPS board that say TX and RX. Make sure the adjacent pins are not shorted. Even if it checks out, touch it with the soldering iron again anyway.

If that's not it then it's something else in the chain. Maybe you have a bad wire.

Did you try the board with the slide switch set to "Direct" as described in their tutorial?

All right, I'll keep that in mind with regards to the software, thanks. As for the hardware, I checked the connections as you suggested, but found no problems. I also tried another adafruit GPS logger shield that I have lying around and it exhibited the same behavior. Maybe it could be the Arduino itself?

And yes, I tried the direct connection at first and it worked.

mysteriousmonkey29:
And yes, I tried the direct connection at first and it worked.

Good. That means the GPS itself works. And it means you have connectivity to pin 1.

Here's a test you can do:

First, load a blank sketch onto your Uno. Set the switch to "Direct". Open the Serial monitor at 9600 baud and you should see good GPS strings, just like before.

Next, disconnect the USB cable, separate the Uno and the GPS shield and put the shield next to the Uno. Use jumper wires to connect the Uno to the GPS shield like this:

Uno <---> GPS
-------------
GND <---> GND
5V  <---> 5V
D1  <---> D8

Set the switch to "Soft Serial".
Connect the USB cable and open the serial monitor.

Do you still see good strings?

Okay, repeating the direct connection test, I think I'm getting normal GPS strings, although I realize now that I'm not actually sure because the strings look weird and I'm not sure if that's just because I'm inside and don't have a fix or something else. This is a sample of the output with the direct connection and blank sketch:

$GPGGA,000055.799,,,,,0,0,,,M,,M,,*4F
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPRMC,000055.799,V,,,,,0.00,0.00,060180,,,N*45
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32
$GPGGA,000056.799,,,,,0,0,,,M,,M,,*4C
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPRMC,000056.799,V,,,,,0.00,0.00,060180,,,N*46
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32
$GPGGA,000057.799,,,,,0,0,,,M,,M,,*4D
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPRMC,000057.799,V,,,,,0.00,0.00,060180,,,N*47
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32
$GPGGA,000058.799,,,,,0,0,,,M,,M,,*42
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPGSV,1,1,00*79

Then, after connecting D1 to D8, ground to ground, and 5V to 5V, and switching the switch to soft serial, I get similar looking strings in the serial monitor (again though, they look weird possibly because I don't have a fix):

$GPGGA,000106.799,,,,,0,0,,,M,,M,,*48
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPRMC,000106.799,V,,,,,0.00,0.00,060180,,,N*42
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32
$GPGGA,000107.799,,,,,0,0,,,M,,M,,*49
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPRMC,000107.799,V,,,,,0.00,0.00,060180,,,N*43
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32
$GPGGA,000108.799,,,,,0,0,,,M,,M,,*46
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPGSV,1,1,00*79
$GPRMC,000108.799,V,,,,,0.00,0.00,060180,,,N*4C
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32
$GPGGA,000109.799,,,,,0,0,,,M,,M,,*47
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPRMC,000109.799,V,,,,,0.00,0.00,060180,,,N*4D

Okay, assuming that those strings that I posted in the last post our normal GPS strings given no fix, then I've solved the problem. I added a ton of delay statements: a one second delay before and after each print statement, and now I'm not getting any weird characters, so I guess the problem was that the program was trying to communicate to quickly over the serial port.

Thanks for all your help!

PS: definitely let me know if those strings aren't normal because then I have another problem.

Those strings look normal. They aren't garbled like in your first post.

You say you fixed the stock Adafruit example sketch by adding 1 second delays? That doesn't make sense. The example sketch works without modification.

Does the problem come back if you take those delays out?

Yes, the delays are definitely solving the problem. I see the weird messages without them and no weird messages with them. They don't have to be one second by the way; I played around with them and concluded that they just needs to be some kind of manual delay (I'm using 100 ms now) around the print statements that were giving the garbled characters. Maybe the Arduino was trying to communicate too fast for the serial communication or computer or whatever to parse correctly?

Can you post the sketch that works?

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

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

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;

// 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) 
{
  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() 
{
  // 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))
  {
    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);

  delay(100);

  // uncomment this line to turn on RMC (recommended minimum) and GGA (fix data) including altitude
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
  delay(100);
  // 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

  delay(100);
  // 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);

  delay(100);
  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);
  }
  
  // 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

    delay(100);

    // Sentence parsed!
    Serial.println("OK");
    if (LOG_FIXONLY && !GPS.fix) 
    {
      Serial.println("No Fix");
      return;
    }

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

    uint8_t stringsize = strlen(stringptr);
    if (stringsize != logfile.write((uint8_t *)stringptr, stringsize))    //write the string to the SD file
        error(4);
    if (strstr(stringptr, "RMC") || strstr(stringptr, "GGA"))   logfile.flush();
      Serial.println();
  }
}

Your sketch works for me, with or without those delays.

The only delay that's likely to be having any effect is the one in loop(). By pausing for 100ms after receiving a sentence you allow the next sentence to arrive without anything else going on: no serial output to your computer and no writes to the SD card. I think that still points to something funny with your hardware.

You could try to isolate it by: (1) removing the delays and the Serial.print statements in loop() and see if the data on the SD card looks okay; and then (2) remove the delays and the logfile.write() and logfile.flush() calls and see if what is printed on the screen looks okay.

Well I may have hardware problems, but these displays are definitely at least compensating for them. You mentioned that the one in the loop is the one that's likely to be having an effect, but if I remove any of the other ones I get garbled characters at the beginning.

I tried what you suggested, and removing all the serial.print statements removed the weird characters while removing the write and flush commands did not. Not sure what that tells us though