PARSING GPS DATA

Hey guys,

For my project I need to get GPS data from one arduino to another. Lets say that arduino that’s sending its GPS is called Tx while the one that’s receiving it is Rx.

So the GPS data on Tx comes as a string and it’s in this format.
e.g. 43⸮12’89.09"N

Now the Arduino Rx reads it via XBee S1 Pro and displays it as a string on the serial monitor.
Once this is done, i need to use the GPS data in maths to calculate the distance between them.

So what I’ve decided is that I, Arduino Tx, I get the string and parse it into two ints (degrees and minutes) and one float (seconds). This way the Arduino Rx will get GPS data split into degrees, minutes and seconds, parse its own GPS data and then compare the two.

The problem is that for some reason I can get the degrees and minutes but not the seconds, or I can get the degrees and seconds, but not the minutes. I don’t understand why this is but I’ve tried changing the delimiters and I still am not able to get all three variables.
This is the code that I’m using:

// Example 5 - Receive with start- and end-markers combined with parsing

const byte numChars = 35;
char receivedChars[numChars];
char tempChars[numChars];        // temporary array for use when parsing

      // variables to hold the parsed data
int integer1FromPC= 0;
int integer2FromPC = 0;
float floatFromPC = 0.0;

boolean newData = false;

//============

void setup() 
{
    Serial.begin(9600);
    Serial.println("This demo expects 3 pieces of data - text, an integer and a floating point value");
    //Serial.println("Enter data in this style <HelloWorld, 12, 24.7>  ");
    Serial.println();
}

//============

void loop() {
    recvWithStartEndMarkers();
    if (newData == true) {
        strcpy(tempChars, receivedChars);
            // this temporary copy is necessary to protect the original data
            //   because strtok() used in parseData() replaces the commas with \0
        parseData();
        showParsedData();
        newData = false;
    }
    
}

//============

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '\n';
    char endMarker = 'N';
    char rc;

    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();

        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

        else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
}

//============

void parseData() {      // split the data into its parts

    char * strtokIndx; // this is used by strtok() as an index

    strtokIndx = strtok(receivedChars,"⸮");      // get the first part - the string
    integer1FromPC = atoi(strtokIndx); // copy it to messageFromPC

    strtokIndx = strtok(NULL, "⸮"); // this continues where the previous call left off
    integer2FromPC = atoi(strtokIndx);     // convert this part to an integer

    strtokIndx = strtok(NULL, "N");
    floatFromPC = atof(strtokIndx);     // convert this part to a float

}

//============

void showParsedData() {
    Serial.print("Degree ");
    Serial.println(integer1FromPC);
    Serial.print("Minutes ");
    Serial.println(integer2FromPC);
    Serial.print("Seconds ");
    Serial.println(floatFromPC);
}

And this is the result on the serial monitor when 43⸮12’89.09"N was entered:

Degree 43
Minutes 12
Seconds 0.00

Can anyone tell me what I’m doing wrong and what I can do to fix this?

Let me know if you guys need more information, and apologies if I missed something…
I’m using an Arduino Mega
Digilent PMODGPS
Xbee S1 Pro 802.15.4

THANKS A LOT!

High Regards

Print the receivedChars array before you parse it. Does it contain what you expect, and only what you expect?

Print each token before calling atof() or atoi(). Is the token what you expect?

PaulS:
Print the receivedChars array before you parse it. Does it contain what you expect, and only what you expect?

No it does not.

I added

Serial.print(receivedChars[numChars]);

in the loop, and once the coordinates, i.e. 43⸮12’79.09"N, are entered in the serial monitor, the serial monitor just prints the first two digits i.e. 43

Print each token before calling atof() or atoi(). Is the token what you expect?

Yes and no. I added Serial.println(strtokIndx); before calling atof and atoi

    strtokIndx = strtok(receivedChars,"⸮");      // get the first part - the string
    Serial.println(strtokIndx);
    integer1FromPC = atoi(strtokIndx); // copy it to messageFromPC

    strtokIndx = strtok(NULL, "⸮"); // this continues where the previous call left off
    Serial.println(strtokIndx);
    integer2FromPC = atoi(strtokIndx);     // convert this part to an integer

    strtokIndx = strtok(NULL, "\"");
    Serial.println(strtokIndx);
    floatFromPC = atof(strtokIndx);

The result on the serial monitor is this (when the above coordinates are entered into the serial monitor):
This demo expects 3 pieces of data - text, an integer and a floating point value
43
12
⸮⸮79.09"

Degree 43
Minutes 12
Seconds 0.00

I'm sure you can understand that I would want it to be
Degree 43
Minutes 12
Seconds 79.09

I don't understand why this is happening. What am I missing here? Any ideas?

High Regards

Looks like it's not stripping out those weird characters.

I would use a real serial monitor application (like hterm) that will tell you what the charcode of those weird characters is, so that you can more easily adapt your sketch to strip them out before trying to get a number out of that string.

Do you have to use ⸮as a delimiter? It looks like it's a two byte unicode character, which probably isn't helping your ability to parse it.

Yeah, I’m 90% sure that that’s not a backwards question mark but a multi-byte unicode charachter displaying wrong, and without knowing what it actually is, it’s hard to strip out. Hence my above recommendation. Unicode really doesn’t have any place in the world of 8-bit microcontrollers.

wildbill:
Do you have to use ⸮as a delimiter?

If I could, then I would. The GPS data from the GPS onto the serial monitor comes in this format:
43⸮12’79.09"N

Clearly it's supposed to be °, the degrees symbol. I hate the backwards question mark myself and what DrAzzy said is 100% correct.

DrAzzy:
I would use a real serial monitor application (like hterm) that will tell you what the charcode of those weird characters is, so that you can more easily adapt your sketch to strip them out before trying to get a number out of that string.

I did what you recommended, connected my Arduino to CoolTerm (Mac), and it throws out even weirder symbols.

This is the result on CoolTerm serial monitor:

43⸮12’79.09"N
43
12
Äô79.09"

Degree 43
Minutes 12
Seconds 0.00

Any other advice?

Thank you both for your help. I'm so close yet so far :frowning: :frowning: :frowning:

High Regards

Try changing the way you call strtok() and see if it works.

const byte numChars = 35;
char receivedChars[numChars];
char tempChars[numChars];        // temporary array for use when parsing

      // variables to hold the parsed data
int integer1FromPC= 0;
int integer2FromPC = 0;
float floatFromPC = 0.0;

void setup()
{
  Serial.begin(9600);
  Serial.println("start");

  strcpy(receivedChars,"43⸮12\'89.09\"N");
  parseData();
  showParsedData();
  
}

void loop()
{

  
}

void parseData() {      // split the data into its parts

    char * strtokIndx; // this is used by strtok() as an index

    strtokIndx = strtok(receivedChars,"⸮\'\"");      // get the first part - the string
    integer1FromPC = atoi(strtokIndx); // copy it to messageFromPC

    strtokIndx = strtok(NULL, "⸮\'\""); // this continues where the previous call left off
    integer2FromPC = atoi(strtokIndx);     // convert this part to an integer

    strtokIndx = strtok(NULL, "⸮\'\"");

    floatFromPC = atof(strtokIndx);     // convert this part to a float

}

void showParsedData() {
    Serial.print("Degree ");
    Serial.println(integer1FromPC);
    Serial.print("Minutes ");
    Serial.println(integer2FromPC);
    Serial.print("Seconds ");
    Serial.println(floatFromPC);
}

Serial output"

start
Degree 43
Minutes 12
Seconds 89.09

There is an established format for sending GPS data between devices. It is called NMEA. Use it.

I used your code and it parses the data correctly.

Serial.begin(9600);
Serial.println("start");

strcpy(receivedChars,"43⸮12\'89.09\"N");
parseData();
showParsedData();

But you've assumed that my GPS location won't change. It will as it is supposed to. I tried modifying your code so that it accepts new data coming in, and i get the same result on the serial monitor:

Start
Degree 43
Minutes 12
Seconds 89.09

43⸮12’79.09"N
Degree 43
Minutes 12
Seconds 0.00

MorganS:
There is an established format for sending GPS data between devices. It is called NMEA. Use it.

I know what its called, and the code that the GPS came with already is using that. I've gone through the datasheet of the GPS and it doesn't mention anywhere that it's using anything other than NMEA. Have a look at it yourself. If you can find that there is something I need to change in the code in order to get the right format, do let me know. I would be much obliged.

/**************************************************/
/* PmodGPS Demo                                   */
/**************************************************/
/*    Author: Thomas Kappenman                    */
/*    Copyright 2014, Digilent Inc.               */
/*                                                */
/*   Made for use with chipKIT Pro MX7            */
/*   PmodGPS on connector JF 1-6                  */
/**************************************************/
/*  Module Description:                           */
/*                                                */
/*    This module implements a demo application   */
/*    of the PmodGPS.                             */
/*                                                */
/*  Functionality:                                */
/*                                                */  
/*    The module works automatically, first       */
/*    resetting the GPS and then detecting a      */
/*    GPS signal from several satellites before   */
/*    outputting data to the serial monitor.      */
/*    LD1 on the PmodGPS should blink while       */
/*    searching of satellites.                    */
/*                                                */
/**************************************************/
/*  Revision History:                             */
/*                                                */
/*      6/23/2014(TommyK): Created                */
/*                                                */
/**************************************************/
/*                                                */
/*  The data received from the PmodGPS is stored  */
/*  in several structs within the GPS class. This */
/*  data can be accessed by either calling the    */
/*  GPS.getXXX() function to access the struct,   */
/*  or by calling several other get functions.    */
/*                                                */
/*  Example: If I want to see how many satellites */
/*  the GPS is connected to I would access either */
/*  GPSdata.getGGA().NUMSAT to get the char*      */
/*  string, or myGPS.getNumSats() to get an       */
/*  integer value.                                */
/*                                                */
/**************************************************/

#include "PmodGPS.h"

//chipKIT Pro MX7
#define _3DFpin   40 //pin 40, JF-01
#define _1PPSpin  43 //pin43, JF-04
#define RSTpin    37 //pin 37, JE-08

typedef enum{
  RESTART,
  NOTFIXED,
  FIXED
}STATE;


GPS myGPS;
char* LAT;
char* LONG;
NMEA mode;

STATE state=RESTART;

void setup() { 
  Serial.begin(9600);
  myGPS.GPSinit(Serial1, 9600, _3DFpin, _1PPSpin);
}

void loop() {
  //State machine for GPS
  switch (state)
  {
    case(RESTART):
        state=NOTFIXED;
        break;
    case(NOTFIXED)://Look for satellites, display how many the GPS is connected to
      mode = myGPS.getData(Serial1);//Receive data from GPS
      if (mode == GGA){//If GGAdata was received
        Serial.print("Number of Satellites: ");Serial.println(myGPS.getNumSats());
        if (myGPS.isFixed()){//When it is fixed, continue
          state=FIXED;
        }
      }
        break;
    case(FIXED):
        if(myGPS.isFixed()){//Update data while there is a position fix
          mode = myGPS.getData(Serial1);
          if (mode == GGA)//If GGAdata was received
          {
              Serial.print("Latitude: ");Serial.println(myGPS.getLatitude());
              Serial.print("Longitude: ");Serial.println(myGPS.getLongitude());
              Serial.print("Altitude: ");Serial.println(myGPS.getAltitudeString());
              Serial.print("Number of Satellites: ");Serial.println(myGPS.getNumSats());
              Serial.print("\n");
          }
        }
        else {
          state=RESTART;//If PFI = 0, re-enter connecting state
        }
      break;
  }
}

Thanks all for your help again.

High Regards

My only assumption is it will always be in the format you mentioned. This works for me:

const byte numChars = 35;
char receivedChars[numChars];
char tempChars[numChars];        // temporary array for use when parsing

// variables to hold the parsed data
int integer1FromPC = 0;
int integer2FromPC = 0;
float floatFromPC = 0.0;

void setup()
{
  Serial.begin(9600);
  Serial.println("start");

  Serial.println("");
  Serial.println("Reading #1:");
  strcpy(receivedChars, "43⸮12\'89.09\"N");
  parseData();
  showParsedData();

  Serial.println("");
  Serial.println("Reading #2:");
  strcpy(receivedChars, "43⸮12\'79.09\"N");
  parseData();
  showParsedData();
  
}

void loop()
{


}

void parseData() {      // split the data into its parts

  char * strtokIndx; // this is used by strtok() as an index

  strtokIndx = strtok(receivedChars, "⸮\'\"");     // get the first part - the string
  integer1FromPC = atoi(strtokIndx); // copy it to messageFromPC

  strtokIndx = strtok(NULL, "⸮\'\""); // this continues where the previous call left off
  integer2FromPC = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, "⸮\'\"");

  floatFromPC = atof(strtokIndx);     // convert this part to a float

}

void showParsedData() {
  Serial.print("Degree ");
  Serial.println(integer1FromPC);
  Serial.print("Minutes ");
  Serial.println(integer2FromPC);
  Serial.print("Seconds ");
  Serial.println(floatFromPC);
}
start

Reading #1:
Degree 43
Minutes 12
Seconds 89.09

Reading #2:
Degree 43
Minutes 12
Seconds 79.09

Is there a specific reason why you are parsing the output from the GPS yourself ?

There are a number of libraries that will read standard NMEA from the GPS and convert the lat and long into floats.

Sending the co-odinates of the transmitting Arduino and having it received by another Arduino with its own GPS is fairly trivial.

Once the receiver knows its own co-ordinates and those of the transmitter, just use a standard library calculation to work out the distance and direction.

That’s the right assumption.
Now I used your code, and from what i understand is that you’ve stored the coordinates in setup(). What your result was is the same for me. However, again. I open up the serial monitor, enter new coordinates, hit enter, and it doesn’t read anything.
So I changed it up a bit.

strcpy(receivedChars, Serial.read());
  parseData();
  showParsedData();

This way it reads the input from the serial monitor. So it should work. It doesn’t. Same result:

start

Reading #1:
Degree 0
Minutes 0
Seconds 0.00

Reading #2:
Degree 0
Minutes 0
Seconds 0.00
43⸮12’79.09"NDegree 3
Minutes 12
Seconds 0.00

Now if you go back to the code that I posted in the first post, I used that and yours and put them together to get this:

#include <string.h>

const byte numChars = 35;
char receivedChars[numChars];
char tempChars[numChars];        // temporary array for use when parsing

// variables to hold the parsed data
int integer1FromPC = 0;
int integer2FromPC = 0;
float floatFromPC = 0.0;

boolean newData = false;

void setup()
{
  Serial.begin(9600);
  Serial.println("start");

  Serial.println("");
  Serial.println("Reading #1:");
  strcpy(receivedChars, Serial.read());
  parseData();
  showParsedData();

  Serial.println("");
  Serial.println("Reading #2:");
  strcpy(receivedChars, Serial.read());
  parseData();
  showParsedData();
  
}

void loop()
{
    recvWithStartEndMarkers();
    if (newData == true) {
        strcpy(tempChars, receivedChars);
        // this temporary copy is necessary to protect the original data
        //   because strtok() used in parseData() replaces the commas with \0
        parseData();
        showParsedData();
        newData = false;
        //Serial.print(receivedChars[numChars]);

        
    }
    

}
void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '\n';
    char endMarker = 'N';
    char rc;

    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();
        Serial.print(rc);
        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                    
                }
            }
            else {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

        else 
         //if (rc == startMarker)
        {
            recvInProgress = true;
        }
    }
}

//============

void parseData() {      // split the data into its parts

  char * strtokIndx; // this is used by strtok() as an index

  strtokIndx = strtok(receivedChars, "⸮\'\"");     // get the first part - the string
  integer1FromPC = atoi(strtokIndx); // copy it to messageFromPC

  strtokIndx = strtok(NULL, "⸮\'\""); // this continues where the previous call left off
  integer2FromPC = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, "⸮\'\"");

  floatFromPC = atof(strtokIndx);     // convert this part to a float

}

void showParsedData() {
  Serial.print("Degree ");
  Serial.println(integer1FromPC);
  Serial.print("Minutes ");
  Serial.println(integer2FromPC);
  Serial.print("Seconds ");
  Serial.println(floatFromPC);
}

Notice in void recvWithStartEndMarkers(), theres char variable char endMarker = 'N';
As you must know that there will be the longitude and latitude, i.e. N/S or W/E.
I changed that char endMarker

char endMarker = 'W';

Entered my longitude location (001⸮28’77.05"W) and voila. It works:

001⸮28'77.05"W
Degree 1
Minutes 28
Seconds 77.05

I’ve realized what the mistake was from this. There are two kinds of apostrophes. ’ and ’. This code can not read the latter. I had copy pasted my coordinates on to a text, but I had changed my coordinates. I only changed the number, but when I hit command+z, it showed that the apostrophe had also changed from ’ to ’. I don’t know why this happened. I just tried my initial code as well. It all works perfectly fine now. This is so stupid. Can anyone tell me why this is.

Thank you all so much for bearing with this crap. My apologies.

But Blue Eyes, I thank you the most, you blue eyed beauty.

srnet:
Is there a specific reason why you are parsing the output from the GPS yourself ?

There are a number of libraries that will read standard NMEA from the GPS and convert the lat and long into floats.

Could you please give me an example? I've tried tinyGPS, TinyGPS+++, NeoGPS. They don't work for the GPS that I have. The only library that does work is the PMODGPS library and it has only two codes. This is why i'm parsing it, so I can get degrees, minutes and seconds as ints and floats. Send that to the receiver, and then compare it with its own coordinates. I wouldn't want to go through this if i knew of any other way, and if you know, please let me know. This has been a b*tch to get it working, and now i've finally got it. Next step is calculating the distance.

srnet:
Sending the co-odinates of the transmitting Arduino and having it received by another Arduino with its own GPS is fairly trivial.

Once the receiver knows its own co-ordinates and those of the transmitter, just use a standard library calculation to work out the distance and direction.

I don't want you to spoonfeed me, (I do) and I know that most forums hate doing that, but could you point me in the right direction?

I feel that moving on it should be fairly simple, now that I've parsed it. It should be pythogras and basic trig right?
If you know of a better and simpler way, do let me know.

THANKS TO ALL. YOU'VE ALL BEEN VERY HELPFUL.

High Regards

I've tried tinyGPS, TinyGPS+++, NeoGPS. They don't work for the GPS that I have. The only library that does work is the PMODGPS library and it has only two codes.

Then your GPS is not putting out NMEA, what does the actual output from the GPS look like ?

I use TinyGPS+ for my tracker programs, works with every GPS I have tried so far.

There is lots of sample code here;

Tracker transmitter code in the HAB2 and Locator2 repositories, simple receviers that will display distance and direction to the remote transmitter in the Receiver1 repository.

The designs use LoRa radio modules, good for 400km+ when tracking high altitude balloons etc.

One last thing before this thread is closed. Obviously, the GPS coordinates could be north, south, east or west. I've tried doing the following but it only reads the last letter i.e. S. Can someone tell me how I can do this or will I have to do this separately for each N, W, E and S. That just seems a bit ineffective.

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '\n';
    char endMarker = 'N, W, E, S';
    char rc;

    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();
        Serial.print(rc);
        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                    
                }
            }
            else {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

        else 
         //if (rc == startMarker)
        {
            recvInProgress = true;
        }
    }
}

High Regards

There are a number of libraries that will read standard NMEA from the GPS and convert the lat and long into floats.

+1

Here’s a NeoGPS version of your sketch:

#include <NMEAGPS.h>
NMEAGPS gps;
gps_fix fix;

#define gpsPort Serial1

void setup()
{
  Serial.begin(9600);
  gpsPort.begin( 9600 );

//  NOT USED:
//
//  chipKIT Pro MX7
//  #define _3DFpin   40 // JF-01
//  #define _1PPSpin  43 // JF-04
//  pinMode( _3DFpin, INPUT ); 
//  pinMode( _1PPSpin, INPUT );

//  Might be needed:
//
//  pinMode(RST, OUTPUT);
//  digitalWrite(RST, LOW);
}

void loop()
{
  if (gps.available( gpsPort )) {
    fix = gps.read();

    Serial.print( "Number of Satellites: " );
    if (fix.valid.satellites) {
      Serial.print( fix.satellites );
    }
    Serial.println();

    if (fix.valid.location && fix.valid.altitude) {
      Serial.print( "Latitude: " );
      Serial.println( fix.latitude(), 6 );

      Serial.print( "Longitude: " );
      Serial.println( fix.longitude(), 6 );

      Serial.print("Altitude: ");
      Serial.println( fix.altitude() );
    }

    Serial.println();
  }
}

Once per second, NeoGPS provides a fix structure that contains all the parsed GPS fields, like fix.latitude(), a float. Sending a float to the receiving Arduino is much easier than that goofy degrees/minutes/seconds with UNICODE characters. :stuck_out_tongue:

NeoGPS is smaller, faster, more accurate and more reliable than all other GPS libraries. It’s available from the Arduino Library Manager, under the menu Sketch-> Include Library-> Manage Libraries. Even if you don’t use it, there are lots of tips on the Installation and Troubleshooting pages.

From your latest response:

I’ve tried tinyGPS, TinyGPS+++, NeoGPS. They don’t work for the GPS that I have. The only library that does work is the PMODGPS

There’s something else wrong here… Your code appears to expect the GPS device to be connected to Serial1 at 9600. The GPS TX pin should be connected to pin 19, and the GPS RX pin should be connected to pin 18. The above NeoGPS sketch should work.

Did you also connect the RST pin? If so, you need to write it LOW to enable the GPS device (uncomment code in setup above).

There’s nothing else in the PMODGPS library that should make it work better than the other libraries. It is parsing NMEA sentences. It does have lots of code that will make it work worse. :stuck_out_tongue:

FWIW, NeoGPS also has a diagnostic example you could try. All the examples will try to use Serial1 on a Mega. There are very accurate distance and bearing functions that you could use on the receiver, too.

-dev:
Here's a NeoGPS version of your sketch:

Oh wow thank you so very much. I've tried using NeoGPS before. Trust me, it was probably one of the very first ones that I tried. That and tinyGPS+. I will try this again tonight once I'm home and can get a satellite link.

-dev:
all the parsed GPS fields, like fix.latitude(), a float. Sending a float to the receiving Arduino is much easier than that goofy degrees/minutes/seconds

Can you tell me what the format of this will be? Like if its a float, will it be anything like this 4807.038,N. If so, then if the receiver arduino is getting its coordinates in the same format, then it should be extremely easy to do distance calculations. However, what about N, S, W and E? Will I still have to parse it or something? Or will it just be positive/negative. I guess I'll just have to try it.

-dev:
Did you also connect the RST pin?

No, I did not. In the GPS code that I used, I had commented it out. So I guess I'll carry on not using it.

But anyway. Thank you so much. I'm unsure if it will work or not, but if it does, all of my love to you.

srnet:
Then your GPS is not putting out NMEA, what does the actual output from the GPS look like ?

I don't understand what you mean by actual output? Do you mean whats on the serial monitor, because that does come in this format: 43⸮12'79.09"N

srnet:
Tracker transmitter code in the HAB2 and Locator2 repositories, simple receviers that will display distance and direction to the remote transmitter in the Receiver1 repository.

The designs use LoRa radio modules, good for 400km+ when tracking high altitude balloons etc.

Ah I wish i had found this out a year ago, it would have made my life a lot easier. I will look into it more and see if I can utilize your code into mine.

High Regards

fayzanhr:
I don't understand what you mean by actual output? Do you mean whats on the serial monitor, because that does come in this format: 43⸮12'79.09"N

The GPS are serial devices, they put out text in serial format that looks like this;

$GPGGA,084950.00,5233.64215,N,00218.87336,W,1,04,14.14,65.2,M,49.3,M,,*44

Thats what a standard NMEA sentence for a GPS looks like.

Libraries such as TinyGPS+ receive each of these characters and convert the latitude and longitude into floats.

The distance and direction calculations from with TinyGPS+ are easy to use;

direction = (int) TinyGPSPlus::courseTo(LocalLat, LocalLon, TRackerLat, TRackerLon);
distance = TinyGPSPlus::distanceBetween(LocalLat, LocalLon, TRackerLat, TRackerLon);

Can you tell me what the format of this will be? Like if its a float, will it be anything like this 4807.038,N.

You can control this, since the PMODGPS library won’t format it for you. You could send it like this:

     Serial.print( fix.latitude(), 6 );

For your example NMEA latitude “4807.038,N”, it will print “48.117300”. It would be negative for a southern latitude. Likewise, sending the longitude would be positive for E and negative for W.

Note that the NMEA format is 2 digits of degrees (48), followed by a floating-point minutes (07.038). The floating-point degrees value for that latitude is 48 + (7.038/60) = 48.1173. You need this kind of number to perform distance and bearing calculations between two locations.

For your example longitude, 1° 28’ 77.05" W (invalid seconds value), the result would be “-1.482514”. I see France!

I have attached example transmitter and receiver sketches. The transmitter reads the GPS port (Serial1) and writes a CSV line to the Serial port, like this:

    7,48.117300,-1.482514,54.1

The receiver sketch parses these lines and prints the result:

Sats 7
Lat 48.117298
Lon -1.482514
Alt 54.10

Cheers,
/dev


SKETCHES:

#include <NMEAGPS.h>
NMEAGPS gps;
gps_fix fix;

#define gpsPort Serial1

void setup()
{
  Serial.begin(9600);
  gpsPort.begin( 9600 );

//  NOT USED:
//
//  chipKIT Pro MX7
//  #define _3DFpin   40 // JF-01
//  #define _1PPSpin  43 // JF-04
//  pinMode( _3DFpin, INPUT ); 
//  pinMode( _1PPSpin, INPUT );

//  Might be needed:
//
//  #define RSTpin    37 //pin 37, JE-08
//  pinMode(RST, OUTPUT);
//  digitalWrite(RST, LOW);
}

void loop()
{
  if (gps.available( gpsPort )) {
    fix = gps.read();

    if (fix.valid.satellites) {
      Serial.print( fix.satellites );
    }
    Serial.print(',');

    if (fix.valid.location)
      Serial.print( fix.latitude(), 6 );
    Serial.print(',');

    if (fix.valid.location)
      Serial.print( fix.longitude(), 6 );
    Serial.print(',');

    if (fix.valid.altitude)
      Serial.print( fix.altitude() );

    Serial.println();
  }
}
#include <Location.h>

const byte numChars = 35;
char receivedChars[numChars];

// variables to hold the parsed data
int                receivedSat;
NeoGPS::Location_t receivedLoc;
float              receivedAlt;

boolean newData = false;

void setup()
{
  Serial.begin(9600);
  Serial.println("start");
}

void loop()
{
  recvWithEndMarkers();
  if (newData) {
    parseData();
    showParsedData();
    newData = false;
  }
}

void recvWithEndMarkers()
{
  static size_t index = 0;
  const char endMarker = '\n';

  while (Serial.available() && !newData) {

    char rc = Serial.read();
    //Serial.print(rc);

    if (rc != endMarker) {
      if (index < numChars-1) {
        receivedChars[ index++ ] = rc;
      }
    } else {
      receivedChars[index] = '\0'; // terminate the string
      index                = 0; // reset for next time
      newData              = true;
    }
  }
}

//============

void parseData() {      // split the data into its parts

  char *field;

  field  = strtok( receivedChars, "," );
  receivedSat = atoi( field );

  field = strtok( nullptr, "," );
  receivedLoc.latF( atof( field ) );

  field = strtok( nullptr, "," );
  receivedLoc.lonF( atof( field ) );

  field = strtok( nullptr, "," );
  receivedAlt = atof( field );
}

void showParsedData()
{
  Serial.print("Sats ");
  Serial.println( receivedSat );
  Serial.print("Lat ");
  Serial.println( receivedLoc.latF(), 6 );
  Serial.print("Lon ");
  Serial.println( receivedLoc.lonF(), 6 );
  Serial.print("Alt ");
  Serial.println( receivedAlt );
  Serial.println();
}