I am using an Arduino Mega 2560 along with the Adafruit Ultimate GPS Logger Shield (with external antenna) and several other sensors used to measure water quality properties. I an trying to record data from the GPS (time and location) and all the other sensors about once every second. I want to have the data both saved on a microSD card and printed to the serial.
I wrote a code to do this (attached) and it seems to work fine except that every once in a while there is a weird issue where the GPS data doesn't seem to be parsing correctly. I have attached a screenshot I took of the data printed to the serial to show what I mean. The columns in the image correspond to year, month, day, hour, minute, second, millisecond, latitude, longitude, altitude, number of satellites, millis(), and then the data from the other sensors included in the system. Some lines show the correct date, month, and year, but others show values that are impossible. Also, some of the latitudes and altitudes are showing correctly, but occasionally I get unrealistic values. Even stranger, these two issues don't seem to always happen at the same time.
Any advice on what could be causing the GPS to parse incorrectly and how to fix it would be greatly appreciated. Thanks in advance!
If you rely on a third-party library to provide you with valid data, and the data is not valid, go back to the people who developed the library and ask them to tell you what's wrong. This is not an Adafruit forum.
If you can use the shield without their library, read the serial data and use one of many parsing functions available. Bear in mind that GPS data is just another serial stream and is subject to errors as with any other communications link. The last two digits of every GPS message are a checksum and can easily be calculated as the data arrives. If the checksum isn't right, simply ignore the message.
When I first got the GPS I used it on its own to make sure it was working correctly and I didn't notice an issue with the parsing. However, I will try again to make sure it still works on its own.
I will also create a post on the Adafruit forum to see if they can tell me if there is a problem with the library.
Why would you waste the bandwidth needed to post a picture of TEXT? Far simpler to post the damned text.
String f = ""; // String for reading from files
Wrong. You should be avoiding Strings like a venereal disease.
// Begin a New File and Print Header to the File
Serial.println("GPS looking for signal...");
while (!GPS.newNMEAreceived()) { // Wait for GPS data before continuing
GPS.read();
}
That isn't even remotely close to what that code does.
// Get Data from EC
void serialEvent1() { // Triggered if there is an incoming string from EC
sEC = ""; // Clear the EC sensor string variable
sEC = Serial1.readStringUntil(13); // Store the incoming string in the EC sensor string variable, to be sent to the serial and/or logged
sEC_complete = true; // Indicate that there is a string to be sent to the serial and/or data to be logged
if (sEC.length() > 5) { // If there is an error and the data is too long (two data points mashed together)
sEC_complete = false; // Indicate that there is no data to be logged instead
}
}
With an intelligent name for the function, the comment before the function would be unnecessary.
if ((ll + lr) <= millis() && millis() >= 5000) { // Check if it's time for next data point
I can't even guess what those variables are for, and not logging in the first 5 seconds, when it is extremely likely that it will take more than 5 seconds to get to this point in the code, hardly makes sense.
I use MsTimer2.h for the UltimateGPS. I found my extensive use of timer0 caused GPS read errors.
//***************************************************************************************
//// Interrupt is called once a millisecond, does a data read so main loop can parse GPS data
//***************************************************************************************
void GPSSIGNAL()
{
//cause a GPS data read so that the
//if (GPS.newNMEAreceived())
//can do its thing
GPS.read();
//this 1-ish ms count is used for timing of other routines
iLEDBlinkTicCount = iLEDBlinkTicCount + 1;
}
Needed for the UGPS(Ultimate GPS
void setup() {
GPS.begin(9600);
GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA); // has speed n altitude
// Note you must send both commands below to change both the output rate (how often the position
// is written to the serial line), and the position fix rate.
// 1 Hz update rate
GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);
GPS.sendCommand(PMTK_API_SET_FIX_CTL_1HZ);
//turn off antenna data being sent
GPS.sendCommand("$PGCMD,33,0*6D/r/n");
//speed threshold level
//0/0.2/0.4/0.5/0.8/1.0/1.5/2.0 m/s
//GPS.sendCommand("$PMTK397,0.2*3F/r/n");
// //set time on ms for overflow, each overflow causes xFunc, void w no parameters, to be called
MsTimer2::set(1, GPSSIGNAL);
//enable interrupt
MsTimer2::start();
//disable interrupt
//MsTimer2::stop()
Set up of the UGPS n the interrupt timer
void loop() {
//put code here that is to be run if no gps data or fix
if (byteVoltsTicCount >= byteVoltsInterval)
// when byteVoltsTicCount = 5 do voltage check
// equals about once every 5 seconds
{
//Analog-Digital converter factor, 10 bits, is 5 volts / 1023
//r1 = 100K
//r2 = 1020k
floatVbatt = (5.0 * analogRead(A1) / 1023) / 10020 * ((100000 + 10020));
//floatVbatt = floatVbatt + floatV_InOffSet;
fBatteryPercentRemaingCharge();
byteVoltsTicCount = 0;
if (digitalRead(byteStartStopDistanceCounterPin) == 0)
//increment on start signal
{
byteUpdateDistanceInterval = byteUpdateDistanceInterval + 1; //increments 1X every 5ish seconds
if (byteUpdateDistanceInterval >= 6)
{
byteUpdateDistanceInterval = 0;
}
}
}
//leave this code alone!!!!!!!!!!!!!!!!!!!!!
//query GPS: has a new complete chunk of data been received?
if (GPS.newNMEAreceived())
{
//if received cause parse data
if (!GPS.parse(GPS.lastNMEA()))
//else exit routine
return;
}
//note the return if bad or no data or incomplete data --- code below this line will NOT run if GPS-produces
//bad or no or incomplete data -
if (GPS.fix)
{
if (byteUpdateDistanceInterval >= 5)
{
fCalDistance();
byteUpdateDistanceInterval = 0;
}
}
//display data
if (byteSH1106_TicCount >= byteRefreshSH1106_Interval)
{
u8g.firstPage();
do
{
(*pages[bytePage])();
} while ( u8g.nextPage() );
byteSH1106_TicCount = 0;
bytePage = bytePage + 1;
if (bytePage == 2)
bytePage = 0;
}
}//end void loop