Aventuras y Desventuras de un hobbyist

Aventuras y Desventuras de un hobbyist....

Parsing NMEA sentences in C


I am starting a new project involving a GPS with Bluetooth capabilities, so far I have been able to get the information from the GPS module but it comes as NMEA sentences containing the precious data.

So before doing something fancy on the computer it is needed to decode the information

There are 19 interpreted sentences:
   $GPBOD - Bearing, origin to destination
   $GPBWC - Bearing and distance to waypoint, great circle
   $GPGGA - Global Positioning System Fix Data
   $GPGLL - Geographic position, latitude / longitude
   $GPGSA - GPS DOP and active satellites 
   $GPGSV - GPS Satellites in view
   $GPHDT - Heading, True
   $GPR00 - List of waypoints in currently active route
   $GPRMA - Recommended minimum specific Loran-C data
   $GPRMB - Recommended minimum navigation info
   $GPRMC - Recommended minimum specific GPS/Transit data
   $GPRTE - Routes
   $GPTRF - Transit Fix Data
   $GPSTN - Multiple Data ID
   $GPVBW - Dual Ground / Water Speed
   $GPVTG - Track made good and ground speed
   $GPWPL - Waypoint location
   $GPXTE - Cross-track error, Measured
   $GPZDA - Date & Time

The data I am getting comes only in 5 sentences:
   
   $GPGGA - Global Positioning System Fix Data
   $GPGSA - GPS DOP and active satellites 
   $GPGSV - GPS Satellites in view
   $GPRMC - Recommended minimum specific GPS/Transit data
   $GPVTG - Track made good and ground speed
  
From these 5 I am only interested in $GPRMC The lines of data are
something similar to these two:

eg1. $GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62
eg2. $GPRMC,225446,A,4916.45,N,12311.12,W,000.5,054.7,191194,020.3,E*68


           225446       Time of fix 22:54:46 UTC
           A            Navigation receiver warning A = OK, V = warning
           4916.45,N    Latitude 49 deg. 16.45 min North
           12311.12,W   Longitude 123 deg. 11.12 min West
           000.5        Speed over ground, Knots
           054.7        Course Made Good, True
           191194       Date of fix  19 November 1994
           020.3,E      Magnetic variation 20.3 deg East
           *68          mandatory checksum
So to decode  we need to understand that where a numeric latitude or longitude is given, the two digits immediately to the left of the decimal point are whole minutes, to the right are decimals of minutes, and the remaining digits to the left of the whole minutes are whole degrees.
      eg. 4533.35 is 45 degrees and 33.35 minutes. ".35" of a minute is exactly 21 seconds.
      eg. 16708.033 is 167 degrees and 8.033 minutes. ".033" of a minute is about 2 seconds

So I wrote a small program that outputs a json file, although I have it divided into 3 files I am posting it as a whole unit:


Once we have this file we can use it in many webapps to display the location and some information about the points, the file will look like:
There are many smart formats and visualizers to display this info such as geoJson, tileJson,
 GPX (a standard format used with many devices and programs, including Garmin's eTrex, GPSMAP, Oregon, Dakota, Colorado, & Nüvi series), Google Earth (.kml/.kmz), Google Maps routes (URLs), Geocaching.com (.loc), FAI/IGC glider logs, Microsoft Excel, Google Spreadsheets,XML feeds, Garmin Forerunner (.xml/.hst/.tcx), Timex Trainer, OziExplorer, Cetus GPS, PathAway, cotoGPS, CompeGPS, TomTom (.pgl), IGN Rando (.rdn), Emtac Trine, Suunto X9/X9i (.sdf), Fugawi, NetStumbler, and of course tab-delimited or comma-separated text.


Finally  you end up with a nice map similar the one below:


7 comentarios:

  1. the outpout file is not a valid json

    ResponderEliminar
  2. parse into object:

    ```c
    #include
    #include
    #include

    #define MAX_LONGITUDE 180
    #define MAX_LATITUDE 90
    #define KNOTS_TO_KM 1.852
    #define DELIMITER__ "," /* Change this value to the delimiter of your
    SourceFile*/
    struct GPS_Data {
    float latitude;
    char latitude_hemisphere;
    float longitude;
    char longitude_hemisphere;
    float speed;
    };

    /* Function prototypes*/
    void parse_nmea_string( char *oneline, struct GPS_Data *gps);
    float convertFromNmeaSentenceToDecimalCoord(float coordinates, const char *val);
    float convertFromKnotsToKmHour(float knots);

    int main(){
    char line[80] = "$GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62";
    struct GPS_Data gps;
    // if GPRMC found filter it
    if(strstr(line, "$GPRMC")){
    // Get tokens from strings
    parse_nmea_string(line, &gps);
    }

    printf(
    "Latitude: %f %c\nLongitude: %f %c\nSpeed: %f",
    gps.latitude, gps.latitude_hemisphere,
    gps.longitude, gps.longitude_hemisphere,
    gps.speed
    );

    return 0;
    }

    /*tokenize() reads each line and takes tokens when divider found (comma)*/
    void parse_nmea_string( char *oneline, struct GPS_Data *gps){

    const char delimiter[2] = DELIMITER__;
    char *token;
    int counter = 0;
    /* get the first token */
    token = strtok(oneline, delimiter);
    float ltemp;
    /* walk through other tokens */
    while( token != NULL ) {
    /*convert the 4th token latitude*/
    if(counter == 3){
    ltemp = atof(token);
    printf("%f", ltemp);
    ltemp = convertFromNmeaSentenceToDecimalCoord(ltemp,"m"); //"m" for meridian
    }
    /*If 5th token == South multiply by -1*/
    if (counter == 4){
    if (*token == 'S'){
    gps->latitude_hemisphere = 'S';
    //ltemp *= ( -1 );
    } else {
    gps->latitude_hemisphere = 'N';
    }
    gps->latitude = ltemp;
    }
    /*convert the 6th token longitude*/
    if(counter == 5){
    ltemp = atof(token);
    ltemp = convertFromNmeaSentenceToDecimalCoord(ltemp, "p"); //"p" for parallel
    }
    /*If 6th token == East multiply by -1*/
    if (counter == 6){/*convert the 4th token latitude*/
    if (*token == 'W'){
    //ltemp *= ( -1 );
    gps->longitude_hemisphere = 'W';
    } else {
    gps->longitude_hemisphere = 'E';
    }
    gps->longitude = ltemp;
    }
    if (counter == 7 ){
    ltemp = atof(token);
    ltemp = convertFromKnotsToKmHour(ltemp);
    gps->speed = ltemp;
    }

    token = strtok(NULL, delimiter);
    ++counter;
    }
    }

    /*selfexplantory*/
    float convertFromNmeaSentenceToDecimalCoord(float coordinates, const char *val){
    /* Sample from gps 5153.6605*/
    /* Check limits*/
    if ((*val == 'm') && (coordinates < 0.0 && coordinates > MAX_LATITUDE)){
    return 0;
    }
    if (*val == 'p' && (coordinates < 0.0 && coordinates > MAX_LONGITUDE)){
    return 0;
    }
    int b;//to store the degrees
    float c; //to store de decimal

    /*Calculate the value in format nn.nnnnnn*/
    /*Explanations at:
    http://www.mapwindow.org/phorum/read.php?3,16271,16310*/

    b = coordinates/100; // 51 degrees
    c= (coordinates/100 - b)*100 ; //(51.536605 - 51)* 100 = 53.6605
    c /= 60; // 53.6605 / 60 = 0.8943417
    c += b; // 0.8943417 + 51 = 51.8943417
    return c;
    }
    /* Selfexplanatory*/
    float convertFromKnotsToKmHour(float knots){
    knots = knots * KNOTS_TO_KM;
    return knots;
    }

    ```

    ResponderEliminar
  3. Free Hollywood Bollywood Hindi Movie Download

    ResponderEliminar