SlashDevin / NeoGPS

NMEA and ublox GPS parser for Arduino, configurable to use as few as 10 bytes of RAM
GNU General Public License v3.0
718 stars 197 forks source link

NMEA senteces not valid? #155

Open RodEnry opened 2 years ago

RodEnry commented 2 years ago

Hello guys, I'm trying to figure out why my GPS sometimes throws strange values. An example on LAT: ...................... 345129181 345129183 444 345129184 345129182 ......................

First of all, I'm running an Ublox SAM-M8Q gps module with an ESP32 microcontroller. The GPS is set to 10Hz and a baudrate of 240400. To set everything I'm using this init function:

void initGPS() {
    uint8_t ubx10Hz[] = {0xB5, 0x62, 0x06, 0x08, 0x06, 0x00, 0x64, 0x00, 0x01, 0x00, 0x01, 0x00, 0x7A, 0x12};

    uint8_t ubx240400badurate[] = {0xB5, 0x62, 0x06, 0x00, 0x14, 0x00, 0x01, 0x00, 
    0x00, 0x00, 0xD0, 0x08, 0x00, 0x00, 0x00, 0x84, 0x03, 
    0x00, 0x23, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0xC8};

    GPS_Serial.begin(9600, SERIAL_8N1, RXD2, TXD2);

    //Set baudrate and refresh rate to 10Hz
    GPS_Serial.write(ubx10Hz, sizeof(ubx10Hz));
    GPS_Serial.flush(); 
    GPS_Serial.write(ubx240400badurate, sizeof(ubx240400badurate));
    GPS_Serial.flush(); 
    delay(10);
    GPS_Serial.end();

    //Restart UART with the new baudrate
    GPS_Serial.begin(240400, SERIAL_8N1, RXD2, TXD2);
    GPS_Serial.write(ubx240400badurate, sizeof(ubx240400badurate));
    GPS_Serial.flush(); 
    GPS_Serial.write(ubx10Hz, sizeof(ubx10Hz));
    GPS_Serial.flush(); 

}

I'm logging the data into an SD card (which is very fast). My original code was without the "if" statemets and I add them just for debugging purposes. The loop is:

while (gps.available( GPS_Serial )) {
            currentFix = gps.read();
        } 

        if (currentFix.valid.location) {
            myStruct.lat = currentFix.location.lat();
            myStruct.lng = currentFix.location.lon();
        } else {
            Serial.print(" -NOT VALID LOCATION -");
        }
        if(currentFix.valid.altitude) {
            myStruct.meters = currentFix.altitude();
        } else {
            Serial.print(" -NOT VALID ALTITUDE -");
        }
        if(currentFix.valid.speed) {
            myStruct.gpsSpeed = currentFix.speed_kph();
        } else {
            Serial.println(" -NOT VALID SPEED -");
        }   

        Serial.print("  SATELL "); Serial.print(currentFix.satellites);
        Serial.print("  LAT "); Serial.print(currentFix.location.lat());
        Serial.print("  LAT "); Serial.print(currentFix.location.lon());
        Serial.print("  ALT "); Serial.print(currentFix.altitude());
        Serial.print("  SPEED "); Serial.print(currentFix.speed_kph());
        Serial.print("  TIME "); Serial.print(currentFix.dateTime.seconds);
        Serial.println("");

The consolle output is pretty strange. I can clearly see that the FIX was not valid, but the printed values of LAT,LON,ALT,SPEED are constantly updated! image

danalvarez commented 2 years ago

A couple things:

  1. If the fix is not valid, you shouldn't trust the information provided by calls to lat(), lon() and the likes. I am not sure what happens under the hood in NeoGPS when a fix is not valid.
  2. Even though the fix is invalid, do the reported values make sense for your geographical location?

Also, you would typically access lat and lon values via currentFix.latitude() and currentFix.longitude(), not via currentFix.location.latitude() as you are doing in your code. More info here: https://github.com/SlashDevin/NeoGPS/blob/master/extras/doc/Data%20Model.md

RodEnry commented 2 years ago

Hello @danalvarez , thanks for your clear reply. The values definetly make sense! The GPS route is perfect, except for the strange values that sometimes happened.

Many thanks for your suggestion, I'll try to remove "location".

Another information: the while loop that read the GPS messages is inside a task that runs at 10Hz, exacly like the GPS. Is it possible that some timing issue is happening?

It's pretty strange the validation thing... but at the link you posted I can read: "You should also know that, even though you have enabled a particular member (see GPSfix_cfg.h), it may not have a value until the related NMEA sentence sets it. And if you have not enabled that sentence for parsing in NMEAGPS_cfg.h, it will never be valid."

I'll need to change to true the two #defines?

//------------------------------------------------------
//  Becase the NMEA checksum is not very good at error detection, you can 
//    choose to enable additional validity checks.  This trades a little more 
//    code and execution time for more reliability.
//
//  Validation at the character level is a syntactic check only.  For 
//    example, integer fields must contain characters in the range 0..9, 
//    latitude hemisphere letters can be 'N' or 'S'.  Characters that are not 
//    valid for a particular field will cause the entire sentence to be 
//    rejected as an error, *regardless* of whether the checksum would pass.
#define NMEAGPS_VALIDATE_CHARS false

//  Validation at the field level is a semantic check.  For 
//    example, latitude degrees must be in the range -90..+90.
//    Values that are not valid for a particular field will cause the 
//    entire sentence to be rejected as an error, *regardless* of whether the 
//    checksum would pass.
#define NMEAGPS_VALIDATE_FIELDS false