{"id":768,"date":"2015-01-01T12:21:15","date_gmt":"2015-01-01T12:21:15","guid":{"rendered":"http:\/\/ava.upuaut.net\/?p=768"},"modified":"2015-01-01T14:36:04","modified_gmt":"2015-01-01T14:36:04","slug":"getting-started-with-ublox-part-4-basic-nmea-parser","status":"publish","type":"post","link":"https:\/\/ava.upuaut.net\/?p=768","title":{"rendered":"Getting Started with Ublox Part 4 \u2013 Basic NMEA Parser"},"content":{"rendered":"<p>Credits : Thanks to <a href=\"www.daveakerman.com\">Dave Akerman<\/a> who&#8217;s NMEA Parser code these examples are based on.<\/p>\n<p>Ok so now we have the GPS talking to the Arduino and you have some method of debugging its time to read that NMEA from the GPS and turn it into something we can use within our code.<\/p>\n<p>The basic principle of an NMEA parser is to locate the NMEA sentences we are interested in , usually GPGGA and\u00a0GPRMC. These two sentences contain most of the information you need for navigation, GPGGA is the main one used. This example will show how to parse the information from GPGGA.<\/p>\n<p>Side note on the Ublox 8 series GPGGA is replaced by GNGGA by default to indicate the navigation information is from multiple GNSS sources (I.e American GPS and Russian GLONASS normally). So for this example we will look for $$GNGGA sentences. GGA sentences contain essential fix data which provide a 3D location.<\/p>\n<p>An example of this is :<\/p>\n<p>$GNGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47<\/p>\n<p>Where :<br \/>\n<pre class=\"preserve-code-formatting\">&nbsp;&nbsp;&nbsp;&nbsp; GGA&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Global Positioning System Fix Data\n&nbsp;&nbsp;&nbsp;&nbsp; 123519&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Fix taken at 12:35:19 UTC\n&nbsp;&nbsp;&nbsp;&nbsp; 4807.038,N&nbsp;&nbsp; Latitude 48 deg 07.038&#039; N\n&nbsp;&nbsp;&nbsp;&nbsp; 01131.000,E&nbsp;&nbsp;Longitude 11 deg 31.000&#039; E\n&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Fix quality: 0 = invalid\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 = GPS fix (SPS)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2 = DGPS fix\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3 = PPS fix\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4 = Real Time Kinematic\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5 = Float RTK\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6 = estimated (dead reckoning) (2.3 feature)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7 = Manual input mode\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8 = Simulation mode\n&nbsp;&nbsp;&nbsp;&nbsp; 08&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Number of satellites being tracked\n&nbsp;&nbsp;&nbsp;&nbsp; 0.9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Horizontal dilution of position\n&nbsp;&nbsp;&nbsp;&nbsp; 545.4,M&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Altitude, Meters, above mean sea level\n&nbsp;&nbsp;&nbsp;&nbsp; 46.9,M&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Height of geoid (mean sea level) above WGS84\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ellipsoid\n&nbsp;&nbsp;&nbsp;&nbsp; (empty field) time in seconds since last DGPS update\n&nbsp;&nbsp;&nbsp;&nbsp; (empty field) DGPS station ID number\n&nbsp;&nbsp;&nbsp;&nbsp; *47&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;the checksum data, always begins with *<\/pre><br \/>\nSo we need to read the incoming data from the GPS module, look for a $ to indicate the start of a sentence, when the full sentence is read in go see if it is a GNGGA line. Building on the previous code we\u00a0add a new procedure to read data in and transmit to the debug when a sentence is detected (or not).<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n\r\n#include &lt;SoftwareSerial.h&gt;\r\n\r\n#define GPSENABLE 2\r\nSoftwareSerial mySerial(4, 3); \/\/ RX, TX\r\nbyte GPSBuffer&#x5B;82];\r\nbyte GPSIndex=0;\r\nvoid setup()\r\n{\r\n  pinMode(GPSENABLE, OUTPUT);\r\n  digitalWrite(GPSENABLE, HIGH);\r\n  Serial.begin(9600);\r\n  mySerial.begin(9600);\r\n  mySerial.println(&quot;Test Program&quot;);\r\n}\r\n\r\nvoid loop()\r\n{\r\n  CheckGPS();\r\n}\r\n\r\nvoid CheckGPS()\r\n{\r\n  int inByte;\r\n  while (Serial.available() &gt; 0)\r\n  {\r\n    inByte = Serial.read();\r\n\r\n    if ((inByte =='$') || (GPSIndex &gt;= 80))\r\n    {\r\n      GPSIndex = 0;\r\n    }\r\n\r\n    if (inByte != '\\r')\r\n    {\r\n      GPSBuffer&#x5B;GPSIndex++] = inByte;\r\n    }\r\n\r\n    if (inByte == '\\n')\r\n    {\r\n      ProcessGPSLine();\r\n      GPSIndex = 0;\r\n    }\r\n  }\r\n}\r\nvoid ProcessGPSLine()\r\n{\r\n  if ((GPSBuffer&#x5B;1] == 'G') &amp;&amp; (GPSBuffer&#x5B;2] == 'N') &amp;&amp; (GPSBuffer&#x5B;3] == 'G') &amp;&amp; (GPSBuffer&#x5B;4] == 'G') &amp;&amp; (GPSBuffer&#x5B;5] == 'A'))\r\n  {\r\n    mySerial.println(&quot;GNGGA Detected!&quot;);\r\n  }\r\n  else\r\n  {\r\n    mySerial.println(&quot;It was something else!&quot;);\r\n  }\r\n}\r\n\r\n\r\n<\/pre>\n<p>Now from your software serial monitor you should see :<br \/>\n<pre class=\"preserve-code-formatting\">GNGGA Detected!\nIt was something else!\nIt was something else!\nIt was something else!\nIt was something else!\nIt was something else!\nIt was something else!\nIt was something else!\nGNGGA Detected!<\/pre><br \/>\nAs you can see we are now detecting when we have a $GNGGA sentence and ignoring the others. So lets start extracting some data from that $GNGGA string.<\/p>\n<p>We know the structure of the sentence, it starts with a $ all the fields are delimited by a comma. Firstly lets up the debug speed to 19200 as we are likely to be outputting data fairly quickly. Amend the connection speed in PuTTY to 19200 and note the change in the code below.Comment out line 31 to stop the NMEA from the GPS appearing.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n#include &lt;SoftwareSerial.h&gt;\r\n\r\n#define GPSENABLE 2\r\nSoftwareSerial mySerial(4, 3); \/\/ RX, TX\r\nbyte GPSBuffer&#x5B;82];\r\nbyte GPSIndex=0;\r\nunsigned int GPS_Satellites=0;\r\nunsigned int GPS_Altitude=0;\r\n\r\nvoid setup()\r\n{\r\n  pinMode(GPSENABLE, OUTPUT);\r\n  digitalWrite(GPSENABLE, HIGH);\r\n  Serial.begin(9600);\r\n  mySerial.begin(19200);\r\n  mySerial.println(&quot;Test Program&quot;);\r\n}\r\n\r\nvoid loop()\r\n{\r\n  CheckGPS();\r\n}\r\n\r\nvoid CheckGPS()\r\n{\r\n  int inByte;\r\n  while (Serial.available() &gt; 0)\r\n  {\r\n    inByte = Serial.read();\r\n\r\n    mySerial.write(inByte); \/\/ Output exactly what we read from the GPS to debug\r\n\r\n    if ((inByte =='$') || (GPSIndex &gt;= 80))\r\n    {\r\n      GPSIndex = 0;\r\n    }\r\n\r\n    if (inByte != '\\r')\r\n    {\r\n      GPSBuffer&#x5B;GPSIndex++] = inByte;\r\n    }\r\n\r\n    if (inByte == '\\n')\r\n    {\r\n      ProcessGPSLine();\r\n      GPSIndex = 0;\r\n    }\r\n  }\r\n}\r\nvoid ProcessGPSLine()\r\n{\r\n  if ((GPSBuffer&#x5B;1] == 'G') &amp;&amp; (GPSBuffer&#x5B;2] == 'N') &amp;&amp; (GPSBuffer&#x5B;3] == 'G') &amp;&amp; (GPSBuffer&#x5B;4] == 'G') &amp;&amp; (GPSBuffer&#x5B;5] == 'A'))\r\n  {\r\n    mySerial.println(&quot;GNGGA Detected!&quot;);\r\n    ProcessGNGGACommand();\r\n    mySerial.print(&quot;Altitude :&quot;);\r\n    mySerial.println(GPS_Altitude);\r\n    mySerial.print(&quot;Satellites :&quot;);\r\n    mySerial.println(GPS_Satellites);\r\n  }\r\n}\r\nvoid ProcessGNGGACommand()\r\n{\r\n  int i, j, k, IntegerPart;\r\n  unsigned int Altitude;\r\n\r\n  \/\/ $GNGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47\r\n  \/\/                                               =====  &lt;-- altitude in field 8\r\n\r\n  IntegerPart = 1;\r\n  GPS_Satellites = 0;\r\n  Altitude = 0;\r\n\r\n  for (i=7, j=0, k=0; (i&lt;GPSIndex) &amp;&amp; (j&lt;9); i++) \/\/ We start at 7 so we ignore the '$GNGGA,'\r\n  {\r\n    if (GPSBuffer&#x5B;i] == ',')\r\n    {\r\n      j++;    \/\/ Segment index\r\n      k=0;    \/\/ Index into target variable\r\n      IntegerPart = 1;\r\n    }\r\n    else\r\n    {\r\n      if (j == 6)\r\n      {\r\n        \/\/ Satellite Count\r\n        if ((GPSBuffer&#x5B;i] &gt;= '0') &amp;&amp; (GPSBuffer&#x5B;i] &lt;= '9'))\r\n        {\r\n          GPS_Satellites = GPS_Satellites * 10;\r\n          GPS_Satellites += (unsigned int)(GPSBuffer&#x5B;i] - '0');\r\n        }\r\n      }\r\n      else if (j == 8)\r\n      {\r\n        \/\/ Altitude\r\n        if ((GPSBuffer&#x5B;i] &gt;= '0') &amp;&amp; (GPSBuffer&#x5B;i] &lt;= '9') &amp;&amp; IntegerPart)\r\n        {\r\n          Altitude = Altitude * 10;\r\n          Altitude += (unsigned int)(GPSBuffer&#x5B;i] - '0');\r\n        }\r\n        else\r\n        {\r\n          IntegerPart = 0;\r\n        }\r\n      }\r\n    }\r\n    GPS_Altitude = Altitude;\r\n  }\r\n}\r\n<\/pre>\n<p>Why not the rest ? Exercise left for reader \ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Credits : Thanks to Dave Akerman who&#8217;s NMEA Parser code these examples are based on. Ok so now we have the GPS talking to the Arduino and you have some method of debugging its time to read that NMEA from &hellip;<\/p>\n<p class=\"read-more\"><a href=\"https:\/\/ava.upuaut.net\/?p=768\">Read more &raquo;<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-768","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/ava.upuaut.net\/index.php?rest_route=\/wp\/v2\/posts\/768","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ava.upuaut.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ava.upuaut.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ava.upuaut.net\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/ava.upuaut.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=768"}],"version-history":[{"count":8,"href":"https:\/\/ava.upuaut.net\/index.php?rest_route=\/wp\/v2\/posts\/768\/revisions"}],"predecessor-version":[{"id":776,"href":"https:\/\/ava.upuaut.net\/index.php?rest_route=\/wp\/v2\/posts\/768\/revisions\/776"}],"wp:attachment":[{"href":"https:\/\/ava.upuaut.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=768"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ava.upuaut.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=768"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ava.upuaut.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=768"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}