NMEA Parsing for GPS

12 Feb 2010 . Edited: 12 Feb 2010

I have a Skytraq Venus 6 GPS that outputs the full NMEA serial string connected to my mbed.  Does anyone have a NMEA parser code already ported to the mbed?  I need to pull data from several string formats as you can not get position, altitude, speed, and heading from one single format.

The Search comes up empty.

Thanks,

12 Feb 2010

There is http://mbed.org/projects/cookbook/wiki/GPS from the cookbook... 

I'm looking for the same thing and have decided to try and port tinyGPS to the mbed...  http://arduiniana.org/libraries/TinyGPS/

 

I learned of it from here, http://www.maartenlamers.com/nmea/   which is pretty good it seems as well.

13 Feb 2010

Keep me posted on your progress.  I will ty doing the same.

 

05 Mar 2010

I am trying to port over TinyGPS to the mbed.  The full code comes from the link above.  There are a few lines of code that are not recognized.  I do not have enough experience to tell what these lines are doing.  Can someone help?

The first is that the millis() is undefined.  I assume this means millisecond.

_new_time_fix = millis();

 

The second is an undefined "byte".  I assume this is a data definition such as int or char.   Here is one example.

 

if (_is_checksum_term)
{
byte checksum = 16 * from_hex(_term[0]) + from_hex(_term[1]);
if (checksum == _parity)

 

a second example.

inline void crack_datetime(int *year, byte *month, byte *day,
byte *hour, byte *minute, byte *second, byte *hundredths = 0, unsigned long *fix_age = 0)

06 Mar 2010

millis() is an arduino method. It returns the number of milliseconds elapsed since the arduino powered up. I'm not sure quite sure how to do this in C++ yet.

08 Mar 2010

From reading through the code and trying to track all of the sub routines and definitions it appears that millis() and timer() are related.  I am going to setup my own count timer and reference each of the functions with a simple delay.  Basically, if the function time is less than wait (X) then move on to next.  Now I have to figure out where to put this in the code.  HMM I think I recall seeing code for a timer in the cookbook somewhere.

Any help is greatly appreciated.

 

08 Mar 2010

After some quick reading I found the ticker/timer/timeout functions.

 

I will try to define the timeout function set to a delay for the GPS lock and other code lines that flag.

08 Mar 2010

Let me know how it works for you. I'm working on a GPS project at the moment too. I was planning on just storing the NMEA sentences for later on an SD card, but if you figure out how to parse them, it'll cut down on my post project work :).

09 Mar 2010

Thank you so much for the example code.  This is much more simple than what I was trying to use.  I will see what I can do to integrate this.

 

09 Mar 2010

Yes, thank you, this is very compact compared to what I had in mind. Thank you for the example!

10 Mar 2010

James for that matter, this might be worth a look at as well... Something I wrote a while back...

It's not perfect....or finished really, and there's a hundred better ways....it does work though...and hopefully easy to understand..

int parseGSV() {
                    gsv2 = strtok(gsv1, ",");
                    while (gsv2 != NULL) {
                        sep++;
                        switch (sep) {
                            case 1:
                                // # of sentences
                                lcd.printf("#:%s\n",gsv2);
                            break;
                            case 2 :
                                // Sentence # of #
                                lcd.printf("S#:%s",gsv2);
                            break;
                            case 3 :
                                // Number of Satellites in view (Should give a hint as to how many cases to expect here...
                                lcd.printf("#:%s\n",gsv2);
                            break;
                            case 4 :
                                // Satellite PRN Number
                                lcd.printf("PRN#:%s\n",gsv2);
                            break;
                            case 5 :
                                // Elevation in Degrees
                            break;
                            case 6:
                                // Azimuth in Degrees 
                            break;
                            case 7:
                                // SNR - up to 4 satellites per sentence
                            break;
                        }
                        gsv2 = strtok(NULL, ",");
                    }
                    sep = 0;
    return *gsv2;
}

int parseGGA() {
                    gga2 = strtok(gga1, ",");
                    while (gga2 != NULL) {
                        sep++;
                        switch (sep) {
                            case 1:
                                if (mode == 1) {
                                    lcd.cls();
                                    lcd.printf("Time:%s\n",gga2);
                                }
                            break;
                            case 2 :
                                if (mode == 2) {
                                    lcd.cls();
                                    lcd.printf("Lat:%s",gga2);
                                }
                            break;
                            case 3 :
                                if (mode == 2) {
                                    lcd.printf("%s\n",gga2);
                                    wait(0.25);
                                }
                            break;
                            case 4 :
                                if (mode == 2) {
                                    lcd.cls();
                                    lcd.printf("Lon:%s",gga2);
                                }
                            break;
                            case 5 :
                                if (mode == 2) {
                                    lcd.printf("%s\n",gga2);
                                    wait(0.25);
                                }
                            break;
                            case 6:
                                if (mode == 1) {
                                    if (gga2 == "0") {
                                        fix = "Invalid";
                                    }
                                    if (gga2 == "1") {
                                        fix = "GPS Fix (SPS)";
                                    }
                                    if (gga2 == "2") {
                                        fix = "DGPS Fix";
                                    }
                                    if (gga2 == "3") {
                                        fix = "PPS Fix";
                                    }
                                    if (gga2 == "4") {
                                        fix = "Real Time Kinematic";
                                    }
                                    if (gga2 == "5") {
                                        fix = "Float RTK";
                                    }
                                    if (gga2 == "6") {
                                        fix = "Estimated (Dead Reckoning)";
                                    }
                                    if (gga2 == "7") {
                                        fix = "Manual Input Mode";
                                    }
                                    if (gga2 == "8") {
                                        fix = "Simulation Mode";
                                    }
                                    lcd.printf("FIX: %s_%s",gga2,fix);
                                }
                            break;
                        }
                        gga2 = strtok(NULL, ",");
                    }
                    sep = 0;
    return *gga2;
}


int getGPSstring(int str) {
    if (gps.scanf("%s", &gpsString) ==1) {
        if (str == 1) {
            if (sscanf(gpsString, "$GPGSV,%s",gsv1) >= 1) {
                sep = 0;
                parseGSV();
            }
        return *gsv2;
        }
        if (str == 2) {
            if (sscanf(gpsString, "$GPRMC,%s",rmc1) >= 1) {
                sep = 0;
                parseRMC();
            }
        return *rmc2;
        }
        if (str == 3) {
            if (sscanf(gpsString, "$GPGGA,%s",gga1) >=1) {
                sep = 0;
                parseGGA();
            }
        return *gga2;
        }
    }
    return 0;
}
10 Mar 2010

Mark,  could you identify the following gsv1, gsv2, sep, fix, gga1, gga2.

I understand they are related to the NMEA string output but am unclear your definitions and declarations in the code.  Is there a header or other library with these definitions?

10 Mar 2010

Sorry james...  I had an include for data.h in there I guess I missed it...

This could be refined...alot probably.. but I hope it helps..

 

main.cpp

#include "mbed.h"
#include "gps.h"
#include "data.h"

int main() {
    while(1) {
        getGPSstring(1);    // The one denotes the mode
    }
}

 

data.h

#ifndef _DATA_H_
#define _DATA_H_
    char gpsString[1024];
    char gsv1[1024];
    char * gsv2;
    char rmc1[1024];
    char * rmc2;
    char gga1[1024];
    char * gga2;
    char * fix;
    int sep;
    int mode = 1;
        
#endif

 

 

gps.h

#include "mbed.h"
#include "TextLCD.h"
#include "data.h"
// Green wire to pin13
// White wire to pin14

DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);
Serial pc(USBTX, USBRX);
Serial gps(p13, p14);
TextLCD lcd(p21, p22, p23, p24, p25, p27, p28);


int parseGSV() {
                    gsv2 = strtok(gsv1, ",");
                    while (gsv2 != NULL) {
                        sep++;
                        switch (sep) {
                            case 1:
                                // # of sentences
                                lcd.printf("#:%s\n",gsv2);
                            break;
                            case 2 :
                                // Sentence # of #
                                lcd.printf("S#:%s",gsv2);
                            break;
                            case 3 :
                                // Number of Satellites in view (Should give a hint as to how many cases to expect here...
                                lcd.printf("#:%s\n",gsv2);
                            break;
                            case 4 :
                                // Satellite PRN Number
                                lcd.printf("PRN#:%s\n",gsv2);
                            break;
                            case 5 :
                                // Elevation in Degrees
                            break;
                            case 6:
                                // Azimuth in Degrees 
                            break;
                            case 7:
                                // SNR - up to 4 satellites per sentence
                            break;
                        }
                        gsv2 = strtok(NULL, ",");
                    }
                    sep = 0;
    return *gsv2;
}

int parseRMC() {

    return 0;
}

int parseGGA() {
                    gga2 = strtok(gga1, ",");
                    while (gga2 != NULL) {
                        sep++;
                        switch (sep) {
                            case 1:
                                if (mode == 1) {
                                    lcd.cls();
                                    lcd.printf("Time:%s\n",gga2);
                                }
                            break;
                            case 2 :
                                if (mode == 2) {
                                    lcd.cls();
                                    lcd.printf("Lat:%s",gga2);
                                }
                            break;
                            case 3 :
                                if (mode == 2) {
                                    lcd.printf("%s\n",gga2);
                                    wait(0.25);
                                }
                            break;
                            case 4 :
                                if (mode == 2) {
                                    lcd.cls();
                                    lcd.printf("Lon:%s",gga2);
                                }
                            break;
                            case 5 :
                                if (mode == 2) {
                                    lcd.printf("%s\n",gga2);
                                    wait(0.25);
                                }
                            break;
                            case 6:
                                if (mode == 1) {
                                    if (gga2 == "0") {
                                        fix = "Invalid";
                                    }
                                    if (gga2 == "1") {
                                        fix = "GPS Fix (SPS)";
                                    }
                                    if (gga2 == "2") {
                                        fix = "DGPS Fix";
                                    }
                                    if (gga2 == "3") {
                                        fix = "PPS Fix";
                                    }
                                    if (gga2 == "4") {
                                        fix = "Real Time Kinematic";
                                    }
                                    if (gga2 == "5") {
                                        fix = "Float RTK";
                                    }
                                    if (gga2 == "6") {
                                        fix = "Estimated (Dead Reckoning)";
                                    }
                                    if (gga2 == "7") {
                                        fix = "Manual Input Mode";
                                    }
                                    if (gga2 == "8") {
                                        fix = "Simulation Mode";
                                    }
                                    lcd.printf("FIX: %s_%s",gga2,fix);
                                }
                            break;
                        }
                        gga2 = strtok(NULL, ",");
                    }
                    sep = 0;
    return *gga2;
}

int getGPSstring(int str) {
    if (gps.scanf("%s", &gpsString) ==1) {
        if (str == 1) {
            if (sscanf(gpsString, "$GPGSV,%s",gsv1) >= 1) {
                sep = 0;
                parseGSV();
            }
        return *gsv2;
        }
        if (str == 2) {
            if (sscanf(gpsString, "$GPRMC,%s",rmc1) >= 1) {
                sep = 0;
                parseRMC();
            }
        return *rmc2;
        }
        if (str == 3) {
            if (sscanf(gpsString, "$GPGGA,%s",gga1) >=1) {
                sep = 0;
                parseGGA();
            }
        return *gga2;
        }
    }
    return 0;
}

10 Mar 2010

I also just tried publishing it, hope that helps too...

GPS_Test

10 Mar 2010

AHHH very helpful.  Thank you so much.

 

I will try to load it and see what I can do.

I just need to add the following definition and I should be good.

gps.getc = getGPSstring(1);
10 Mar 2010

Mark,   I loaded your code and set the string as my data.  Then I switched to print in hyperterminal instead of the LCD.  I am working indoors so there is no GPS signal everying appears to be working at first glance.  Excellent job.

10 Mar 2010

Great!  Glad to hear it James..!  I haven't had a chance to get to the tinyGPS stuff yet, I plan on using it when I get around to that part..  When I get that going, I will post my results..

In the meantime, I'm glad you're up to an extent now!

27 Mar 2010

Mark,

I have the code working well.  I wrote additional parse functions so that now there is GGA, GSA, GSV, RMC and VTG strings.  I do have one issue.

The getGPSstring function will only run the first call in the list.  I have created different GPS string commands based upon the particular format.  This way you can call the functions independently based upon the data that is needed.

As soon as I figure out how to publish the code I will put it up.

Jamie

30 Mar 2010

Sounds great James...  I just got back from vacation and while I was out, I couldn't keep from checking even if it was on my droid...;)  So, I found this...  http://mbed.org/users/todotani/notebook/gps-nmea-parser/  And it looks like someone has put considerable effort into this and is doing very well.  I haven't really had much of a chance to look further, even though the compiler loads on my droid...I had some difficulty both with time and my attention span while out..

I'm anxious to see what you've done...

mark

31 Mar 2010

Mark, Thank you for the link.  I just loaded it into the compiler and will try to see how it works.

 

Glad you enjoyed your vacation.

Jamie

21 Mar 2012

In case anyone runs across this later, I did a port of TinyGPS