mikalhart / TinyGPSPlus

A new, customizable Arduino NMEA parsing library
http://arduiniana.org
1.05k stars 486 forks source link

Issues with extracting the fix data using custom NMEA sentence extraction #114

Open classbproject opened 1 year ago

classbproject commented 1 year ago

I'm trying to extract the GPS Fix data using the custom NMEA sentence extraction but it does not seem to work.

The GPS fix data is present in the GNGGA sentence as the 6th element. In the code, I have,

TinyGPSPlus gps;
TinyGPSCustom fixStatus(gps, "GNGGA", 6);

and in the loop() function, I have,

Serial.print("Fix status: "); Serial.println(fixStatus.value());

However, I do not see 1 though the GPGGA sentence does show it,

$GNGGA,125322.00,xxxx.xxxxx,X,xxxx.xxxxx,X,1,11,0.78,560.0,M,-68.1,M,,*68

The full code is here.

cyberman54 commented 1 year ago

Using GNGGA means you want GLONASS navigation. Are you using a current version of TinyGPS? GLONASS support was added later: https://github.com/mikalhart/TinyGPSPlus/commit/ba91ede894eb6491b1f2444cbf0b3f8309747bfb

classbproject commented 1 year ago

I never realised that I was using an older version - 1.0.2. I added the library from the Arduino IDE and assumed it would be the latest version. I've now updated to the latest release. I still do not see the fix value. Also, I accidentally set the 5th value to be extracted (instead of 6th) and it showed me -68.1. In the GNGGA sentence that is the 11th value. Something is not quite right!

adamgarbo commented 11 months ago

@classbproject I use the following code with good success to determine the fix and validity of my received data:

TinyGPSPlus gnss;

// Custom TinyGPS objects to store fix and validity information
TinyGPSCustom gnssFix(gnss, "GNGGA", 6); // Fix quality
TinyGPSCustom gnssValidity(gnss, "GNRMC", 2); // Validity

And then to check if the sentences are valid, I check the custom fix and validity values, as well as the number of satellites:

// Check if NMEA sentences have a valid fix and are not stale
if ((gnssFix.value() > 0 && gnssFix.age() < 1000) &&
    (String(gnssValidity.value()) == "A" && gnssValidity.age() < 1000) &&
    gnss.satellites.value() > 0)
{

Cheers, Adam

cyberman54 commented 11 months ago

@adamgarbo

// Check if NMEA sentences have a valid fix and are not stale if ((gnssFix.value() > 0 && gnssFix.age() < 1000) && (String(gnssValidity.value()) == "A" && gnssValidity.age() < 1000) && gnss.satellites.value() > 0) {

This doesn't make sense to me, since it adds overhead to calculate a status which is already processed by TinyGPS. Simply check if location.isValid() and/or altitude.isValid(). TinyGPS commits these values, if a fix was present when these values arrived.

To detect a fix TinyGPS does exactly the same as your code suggests:

case COMBINE(GPS_SENTENCE_GPRMC, 2): // GPRMC validity
      sentenceHasFix = term[0] == 'A';

case COMBINE(GPS_SENTENCE_GPGGA, 6): // Fix data (GPGGA)
      sentenceHasFix = term[0] > '0';

I am using this approach: https://github.com/hottimuc/Lora-TTNMapper-T-Beam/blob/master/fromV08/gps.cpp#L67

adamgarbo commented 11 months ago

Thanks for your input.

To give you some background, I previously had an issue with the validity check I was using where I would lose contact with my instruments for a month.

if ((gps.location.isValid() && gps.date.isValid() && gps.time.isValid()) &&
    (gps.location.isUpdated() && gps.date.isUpdated() && gps.time.isUpdated())) {}

Somehow, data with incorrect dates were making it past the check and causing havoc with my real-time clock alarms. I spoke to Mikal directly about this and it turns out date.isValid() and time.isValid() are not very rigorous and can easily report an incorrect date and/or time as valid.

After that, I started doing things explicitly myself to ensure the validity check worked. I don't mind the redundancy.

Cheers, Adam

cyberman54 commented 11 months ago

isValid() means the data was seen by TinyGPS in a sentence with fix. It does not mean the sentence is not stale. Thus, you should combine this with checking the age of the sentence. That's all. See my example.

adamgarbo commented 11 months ago

Thanks for your feedback. Glad to have confirmation my code above is the correct (albeit redundant) approach.

classbproject commented 6 months ago

@classbproject I use the following code with good success to determine the fix and validity of my received data:

TinyGPSPlus gnss;

// Custom TinyGPS objects to store fix and validity information
TinyGPSCustom gnssFix(gnss, "GNGGA", 6); // Fix quality
TinyGPSCustom gnssValidity(gnss, "GNRMC", 2); // Validity

And then to check if the sentences are valid, I check the custom fix and validity values, as well as the number of satellites:

// Check if NMEA sentences have a valid fix and are not stale
if ((gnssFix.value() > 0 && gnssFix.age() < 1000) &&
    (String(gnssValidity.value()) == "A" && gnssValidity.age() < 1000) &&
    gnss.satellites.value() > 0)
{

Cheers, Adam

@adamgarbo My apologies for the delayed response. I got a chance to work on this again now. I saw your comment on another thread for the fix check. For some reason the custom TinyGPS function won't work. I need to do more experiments to see why that won't work. This was a hardware issue that I've now fixed. Both the versions work. Thanks.

bool checkGPSFix()
{
  while ((gpsSerial.available() > 0))
  {
    if (gps.encode(gpsSerial.read()))
    {
      if ((gps.location.isValid() && gps.date.isValid() && gps.time.isValid()) &&
          (gps.location.isUpdated() && gps.date.isUpdated() && gps.time.isUpdated()) &&
          (gps.satellites.value() > 0))
      {
        fixStatus = true;
        Serial.print("Fix status: ");
        Serial.println(fixStatus);
        return fixStatus;
      }
    }
  }
  return 0;
}

void setup()
{
  Serial.begin(serialBaud);
  gpsSerial.begin(gpsBaud);

  // Check if NMEA sentences have a valid fix and are not stale
  Serial.println("\nWaiting for valid GPS signal...");
  while (!checkGPSFix())
  {
    ;
  }
  Serial.println("Valid GPS signal established.");
}