Parsing NMEA strings received via UDP - Howto

I'm receiving NMEA strings on a ESP32 board via a WIFI connection. I want to parse those comma separated strings. What is the best way to parse these strings and get the data values out of these strings.

I've searched the internet and there are many NMEA libs available, but all of what I've seen and found are build to receive the information over a serial interface. I cannot use those libraries as I'm receiving the data over UDP.
The NMEA libraries are processing the chars one by one when received over the serial interface. Over UDP you get the entire NMEA sting in one go.

Any suggestions? Which library to use? Or build my own library, but that will cost a lot of time of course.

Looking forward to some suggestions.

Examples of the NMEA sentences being received over UDP.

$SARMC,114910,A,5119.846,N,00256.107,E,18.6,44,270517,0>.0,W*45
!AIVDM,1,1,,A,133tF2002UP=7ALMMV9DuT0N0<4O,0*24
!AIVDM,1,1,,A,D33wEjQlTNfp00N000,4*71
!AIVDM,1,1,,B,13aL>1hP000=HTnMD3H=VwvL05K4,0*6C
$SAVWR,24.0,L,6.7,N,,,,*74
!AIVDM,1,1,,A,69WJRB40OEGr06P140,4*78
!AIVDM,1,1,,B,401uEOAv5Mci>0=GMjMDRKw0088h,0*76
!AIVDM,1,1,,B,D33wEjR;LNfp00N000,4*3E
$SAVWR,24.0,L,6.5,N,,,,*76
!AIVDM,1,1,,A,3344Eh0031P<hhBMGw7UDDDL0P00,0*50
$SADPT,13.3,0*7D
$SADBT,,f,13.3,M,,F*32
$SAVHW,,T,42.0,M,6.6,N,,,*16
$SAHDG,42.0,,,,*6D
$SAMTW,16.0,C*06
$SAVWR,28.5,L,6.5,N,,,,*7F
$SAVWR,28.5,L,6.5,N,,,,*7F
$GPVTG,043.0,T,043.0,M,7.3,N,13.5,K,D*15
!AIVDM,1,1,,B,133qNL00000>i<lMG=95H0lP0@9N,0*28
$SADPT,13.0,0*7E
$SADBT,,f,13.0,M,,F*31
$SAVHW,,T,42.0,M,6.6,N,,,*16
$SAHDG,42.0,,,,*6D
$GPZDA,114902.40,27,05,2017,,*69

Over UDP you get the entire NMEA sting in one go.

No you don't... they also arrive byte by byte... Your API might present them to you in one sentence.

if you look at the TinyGPS++ library you feed characters received from your GPS device, usually done from getting the input from a Serial line

while (Serial1.available() > 0)  gps.encode(Serial1.read());

In your case it's just a matter of reading the UDP communication and feeding the beast by calling gps.encode() with the data. if the only thing you get is a full sentence, then just go through the bytes of that sentence and call gps.encode()

Then the rest of the library would work

if you post the code you used to print what's above, it should not be rocket science to add the communication with the library since you have all the bytes.

Excellent, thanks for the feedback. Will take a look at that lib, looks promising.

Below the code I'm using right now to receive the NMEA message over UDP.

#define MAXLEN_NMEA_0183_MESSAGE 90
char packetBuffer[MAXLEN_NMEA_0183_MESSAGE];  // buffer to hold incoming packet,

    int packetSize = udp.parsePacket();
    if (packetSize) 
    {
      // read the packet into packetBufffer
      udp.read(packetBuffer, MAXLEN_NMEA_0183_MESSAGE);

      // Terminate the received characters with 0.
      packetBuffer[packetSize] = '\0';
}

How could I call the gps.encode function using the packetBuffer char array?

so not too difficult - something like

#define MAXLEN_NMEA_0183_MESSAGE 90
char packetBuffer[MAXLEN_NMEA_0183_MESSAGE];  // buffer to hold incoming packet,

int packetSize = udp.parsePacket();
bool gpsDataReady = false;

if (packetSize) {
  // read the packet into packetBufffer
  udp.read(packetBuffer, MAXLEN_NMEA_0183_MESSAGE);

  // Terminate the received characters with 0.
  packetBuffer[packetSize] = '\0';

  // send the data to our NMEA parser
  for (size_t i = 0; i < packetSize; i++)
    gps.encode(packetBuffer[i]);

  // check if we have updated information
  gpsDataReady = gps.location.isUpdated());
}

if (gpsDataReady) {
  // handle GPS data
  ....
  gpsDataReady = false;
}

Great feedback, that seems to be working :slight_smile: Thanks for the support.

:slight_smile:

have fun!

PS: you should declare your buffer as

char packetBuffer[MAXLEN_NMEA_0183_MESSAGE+1];  // buffer to hold incoming packet,

just to make sure you have space for a trailing null char.

The first GPGGA messages are being processed :slight_smile: Having said this, I see the following message

$GPGGA,114932.13,5119.890,N,00256.177,E,2,08,1.0,6553.40,M,4.70,M,0.10,0*48.

Being converted into
51.331500, 2.936283

This doesn't seem correct to me, still need to do some investigations but OpenCPN application give me the following GPS coordinates, which is (more or less) in line with the NMEA string. Any suggestions why there is a deviation?

Screenshot 2021-01-21 at 15.32.39.png

Screenshot 2021-01-21 at 15.32.39.png

51.331500 is (floating point approximation aside) the same as 51 19.859 :slight_smile:
the first one is in decimal degrees and your display in degrees, and decimal minutes

The format for NMEA coordinates is (d)ddmm.mmmm with d=degrees and m=minutes

To get to decimal degrees from degrees and minutes, you use the following formula:
(d)dd + (mm.mmmm/60) (* -1 for W and S)

so here you got 5119.890 so this is 51 degrees and 19.890 minutes
the decimal representation is thus 51 + 19.890/60 = 51+ 0.3315 = 51.3315 which is what the library shows.

the fact that you see small difference if you do the math is due to floating point approximations and maybe some corrections

if you want to go to seconds, you were at 51°19'53.40''N, 2°56'10.62''E and 6553.4m above ground - the 53.40 is obtained by 0.890*60

Thanks, that explains a lot. Great!!

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.