A GPS serial interrupt service routine that has an on the fly nmea parser. Works with a STM32F411RE and a Adafruit GPS logger.

Dependents:   Bicycl_Computer_NUCLEO-F411RE Bicycl_Computer_NUCLEO-L476RG

Fork of GPS by Simon Ford

main.cpp

#include "mbed.h"
#include "GPSISR.h"

#define PIN_RX_GPS      PA_12 //GPS Shield RX pin
#define PIN_TX_GPS      PA_11 //GPS Shield TX pin
Serial pc(USBTX, USBRX);

// Set up serial interrupe service handler for gps characters.
GPS MyGPS(PIN_TX_GPS,PIN_RX_GPS, 9600);
int main()
{
    while (1) {
	if (MyGPS.dataready()) {
					MyGPS.read();
					pc.printf("NMEA has valid data");
					pc.printf("Sats : %d \n", MyGPS.buffer.satellites);
					pc.printf("%d-%d-%d\n", MyGPS.buffer.month, MyGPS.buffer.day, MyGPS.buffer.year);
					pc.printf("%d:%d:%d\n", MyGPS.buffer.hours, MyGPS.buffer.minutes, MyGPS.buffer.seconds);
	}
	else {
                pc.printf("NMEA has no valid data");
	}   
   }  
} 

Files at this revision

API Documentation at this revision

Comitter:
trevieze
Date:
Wed Mar 01 03:38:03 2017 +0000
Parent:
4:7240a18102a6
Child:
6:f0c13bb7d266
Commit message:
Added NEWS indication to Lon and Lat display

Changed in this revision

GPSISR.h Show annotated file Show diff for this revision Revisions of this file
nav.cpp Show annotated file Show diff for this revision Revisions of this file
nav.h Show annotated file Show diff for this revision Revisions of this file
nmea.cpp Show annotated file Show diff for this revision Revisions of this file
nmea.h Show annotated file Show diff for this revision Revisions of this file
--- a/GPSISR.h	Sat Feb 18 01:37:25 2017 +0000
+++ b/GPSISR.h	Wed Mar 01 03:38:03 2017 +0000
@@ -47,6 +47,8 @@
 struct reading {
     float latitude;     //Signed positive if N, negative if S
     float longitude;    //Signed positive if E, negative if W
+    char  latc;
+    char  lonc;
     uint8_t day;
     uint8_t month;
     uint8_t year;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nav.cpp	Wed Mar 01 03:38:03 2017 +0000
@@ -0,0 +1,239 @@
+    /*
+    File:       nav.cpp
+    Version:    0.1.0
+    Date:       Feb. 28, 2017
+    License:    GPL v2
+    
+    Navigation class
+    
+    ****************************************************************************
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+    ****************************************************************************
+ */
+       #include <math.h>
+       #include "nav.h" 
+       // Calculate the heading
+        double NAV::CalculateDistance (double from_lat, double from_lon, double to_lat, double to_lon)
+        {
+            double R = 6371e3;
+            double lat1 = DegreeToRadian(from_lat);
+            double lat2 = DegreeToRadian(to_lat);
+            double deltaLat = DegreeToRadian(to_lat - from_lat);
+            double deltaLong = DegreeToRadian(to_lon - from_lon);
+
+            double a = sin(deltaLat / 2) * sin(deltaLat / 2) + cos(lat1) * cos(lat2) * sin(deltaLong / 2) * sin(deltaLong / 2);
+            double c = 2 * atan2(sqrt(a), sqrt(1 - a));
+            double d = R * c;
+
+            return d;
+        }
+        
+        // Calculate bearing
+        double NAV::CalculateBearing(double from_lat, double from_lon, double to_lat, double to_lon)
+        {
+            double lat1 = DegreeToRadian(from_lat);
+            double lat2 = DegreeToRadian(to_lat);
+            double long1 = DegreeToRadian(from_lon);
+            double long2 = DegreeToRadian(to_lon);
+
+            double y = sin(long2 - long1) * cos(lat2);
+            double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(long2 - long1);
+
+            double bearing = RadianToDegree(atan2(y, x));
+
+            // Correct "wrap around" if necessary
+            if (bearing < 0) bearing = 360.0 + bearing;
+            if (bearing > 360.0) bearing = bearing - 360.0;
+
+            return bearing;
+        }
+        
+        /*
+        This function takes as input the next gps coordinate that the boat is suppossed to achieve and calculates the compass
+        heading to the waypoint
+        Jeff Witten - 05/26/14 from Github VT-SailBOT/Navigation sailbot.c
+        */
+        int NAV::direction_to_next_point (double from_lat, double from_lon, double to_lat, double to_lon)
+        {
+            double dist_lat = 111132.954 - 559.822*cos(2*from_lat) + 1.1175*cos(4*from_lat);
+            double dist_lon = PI/180*6367449*cos(from_lat);
+            double lat_meter = fabs(fabs(to_lat) - fabs(from_lat))*dist_lat;
+            double lon_meter = fabs(fabs(to_lon) - fabs(from_lon))*dist_lon;
+            double difference = (lat_meter/lon_meter);
+            double  degree = atan(difference);  
+            degree = fabs(degree*180/PI);
+            int angle = 0;
+    
+            if(to_lat >= from_lat && to_lon >= from_lon)           //Quadrant I
+                angle = 90 - degree;
+            else if(to_lat <= from_lat && to_lon >= from_lon)          //Quadrant II
+                angle = 90 + degree;
+            else if(to_lat <= from_lat && to_lon <= from_lon)          //Quadrant III
+                angle = 270 - degree;
+            else if(to_lat >= from_lat && to_lon <= from_lon)          //Quadrant IV
+                angle = 270 + degree;
+
+        return angle;
+        }
+        
+        /*
+        This function takes as input the gps coordinates of the boat and the gps coordinates of a waypoint that the boat desires to approach
+        The function then sets a flag based on whether or not the boat is within a predetermined perimeter of the waypoint
+        Approach:
+        1.) Latitude and Longitude of San Francisco = 37.7844 N, 122.4167 W
+        2.) At 40 degrees North: 1 degree latitude = 111.03 km, 1 degree longitude = 85.39 km
+        3.) 111.03 = 85.39 * (1.30027) - used to correct approximately rectangular lat/lon grid to approximately square
+        4.) Through unit analysis, 1 meter = 0.0000111509 degrees longitude 
+        Jeff Witten - 03/27/14 from Github VT-SailBOT/Navigation sailbot.c
+        */
+        int NAV::point_proximity(double from_lat, double from_lon, double to_lat, double to_lon)
+        {
+        int number = 0;
+        double dist_lat = 111132.954 - 559.822*cos(2*from_lat) + 1.1175*cos(4*from_lat);
+        double dist_lon = PI/180*6367449*cos(from_lat);
+        double lat_meter = fabs(fabs(to_lat) - fabs(from_lat))*dist_lat;
+        double lon_meter = fabs(fabs(to_lon) - fabs(from_lon))*dist_lon;
+        distance = sqrt(pow(lat_meter, 2) + pow(lon_meter,2));
+
+        if (distance <= point_proximity_radius){
+            number = 1;
+        } else {
+            number = 0;
+        }    
+            return number;
+        }
+        
+        /**
+ * \brief Calculate distance between two points
+ * This function uses an algorithm for an oblate spheroid earth model.
+ * The algorithm is described here: 
+ * http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
+ * \return Distance in meters
+ */
+double NAV::distance_ellipsoid(double from_lat,  double from_lon, double from_azimuth, double to_lat, double to_lon, double to_azimuth)
+{
+    /* All variables */
+    double f, a, b, sqr_a, sqr_b;
+    double L, phi1, phi2, U1, U2, sin_U1, sin_U2, cos_U1, cos_U2;
+    double sigma, sin_sigma, cos_sigma, cos_2_sigmam, sqr_cos_2_sigmam, sqr_cos_alpha, lambda, sin_lambda, cos_lambda, delta_lambda;
+    int remaining_steps; 
+    double sqr_u, A, B, delta_sigma;
+ 
+    if ((from_lat == to_lat) && (from_lon == to_lon))
+    { /* Identical points */
+        if ( from_azimuth != 0 )
+            from_azimuth = 0;
+        if ( to_azimuth != 0 )
+            to_azimuth = 0;
+        return 0;    
+    } /* Identical points */
+
+    /* Earth geometry */
+    f = NMEA_EARTH_FLATTENING;
+    a = NMEA_EARTH_SEMIMAJORAXIS_M;
+    b = (1 - f) * a;
+    sqr_a = a * a;
+    sqr_b = b * b;
+
+    /* Calculation */
+    L = to_lon - from_lon;
+    phi1 = from_lat;
+    phi2 = to_lat;
+    U1 = atan((1 - f) * tan(phi1));
+    U2 = atan((1 - f) * tan(phi2));
+    sin_U1 = sin(U1);
+    sin_U2 = sin(U2);
+    cos_U1 = cos(U1);
+    cos_U2 = cos(U2);
+
+    /* Initialize iteration */
+    sigma = 0;
+    sin_sigma = sin(sigma);
+    cos_sigma = cos(sigma);
+    cos_2_sigmam = 0;
+    sqr_cos_2_sigmam = cos_2_sigmam * cos_2_sigmam;
+    sqr_cos_alpha = 0;
+    lambda = L;
+    sin_lambda = sin(lambda);                            
+    cos_lambda = cos(lambda);                       
+    delta_lambda = lambda;
+    remaining_steps = 20; 
+
+    while ((delta_lambda > 1e-12) && (remaining_steps > 0)) 
+    { /* Iterate */
+        /* Variables */
+        double tmp1, tmp2, tan_sigma, sin_alpha, cos_alpha, C, lambda_prev; 
+
+        /* Calculation */
+        tmp1 = cos_U2 * sin_lambda;
+        tmp2 = cos_U1 * sin_U2 - sin_U1 * cos_U2 * cos_lambda;  
+        sin_sigma = sqrt(tmp1 * tmp1 + tmp2 * tmp2);                
+        cos_sigma = sin_U1 * sin_U2 + cos_U1 * cos_U2 * cos_lambda;   
+        tan_sigma = sin_sigma / cos_sigma;                  
+        sin_alpha = cos_U1 * cos_U2 * sin_lambda / sin_sigma;  
+        cos_alpha = cos(asin(sin_alpha));                 
+        sqr_cos_alpha = cos_alpha * cos_alpha;                     
+        cos_2_sigmam = cos_sigma - 2 * sin_U1 * sin_U2 / sqr_cos_alpha;
+        sqr_cos_2_sigmam = cos_2_sigmam * cos_2_sigmam; 
+        C = f / 16 * sqr_cos_alpha * (4 + f * (4 - 3 * sqr_cos_alpha));
+        lambda_prev = lambda; 
+        sigma = asin(sin_sigma); 
+        lambda = L + 
+            (1 - C) * f * sin_alpha
+            * (sigma + C * sin_sigma * (cos_2_sigmam + C * cos_sigma * (-1 + 2 * sqr_cos_2_sigmam)));                                                
+        delta_lambda = lambda_prev - lambda; 
+        if ( delta_lambda < 0 ) delta_lambda = -delta_lambda; 
+        sin_lambda = sin(lambda);
+        cos_lambda = cos(lambda);
+        remaining_steps--; 
+    }  /* Iterate */
+
+    /* More calculation  */
+    sqr_u = sqr_cos_alpha * (sqr_a - sqr_b) / sqr_b; 
+    A = 1 + sqr_u / 16384 * (4096 + sqr_u * (-768 + sqr_u * (320 - 175 * sqr_u)));
+    B = sqr_u / 1024 * (256 + sqr_u * (-128 + sqr_u * (74 - 47 * sqr_u)));
+    delta_sigma = B * sin_sigma * ( 
+        cos_2_sigmam + B / 4 * ( 
+        cos_sigma * (-1 + 2 * sqr_cos_2_sigmam) -
+        B / 6 * cos_2_sigmam * (-3 + 4 * sin_sigma * sin_sigma) * (-3 + 4 * sqr_cos_2_sigmam)
+        ));
+
+    /* Calculate result */
+    if ( from_azimuth != 0 )
+    {
+        double tan_alpha_1 = cos_U2 * sin_lambda / (cos_U1 * sin_U2 - sin_U1 * cos_U2 * cos_lambda);
+        from_azimuth = atan(tan_alpha_1);
+    }
+    if ( to_azimuth != 0 )
+    {
+        double tan_alpha_2 = cos_U1 * sin_lambda / (-sin_U1 * cos_U2 + cos_U1 * sin_U2 * cos_lambda);
+        to_azimuth = atan(tan_alpha_2);
+    }
+
+    return b * A * (sigma - delta_sigma);
+}
+        
+        
+        // Convert Degrees to Radians
+        double NAV::DegreeToRadian(double angle)
+        {
+            return PI * angle / 180.0;
+        }
+        
+       // Convert Radians to Degrees
+        double NAV::RadianToDegree(double angle)
+        {
+            return angle * (180.0 / PI);
+        } 
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nav.h	Wed Mar 01 03:38:03 2017 +0000
@@ -0,0 +1,66 @@
+/*
+    File:       nav.h
+    Version:    0.1.0
+    Date:       Feb. 28, 2017
+    License:    GPL v2
+    
+    Navigation class
+    
+    ****************************************************************************
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+    ****************************************************************************
+ */
+class NAV {
+    #define PI  3.14159265358979f
+    #define point_proximity_radius 10
+    #define NMEA_EARTH_FLATTENING       (1 / 298.257223563)             /**< Earth's flattening according WGS 84 */
+    #define NMEA_EARTH_SEMIMAJORAXIS_M  (6378137.0)                     /**< Earth's semi-major axis in m according WGS84 */
+    #define NMEA_EARTH_SEMIMAJORAXIS_KM (NMEA_EARTH_SEMIMAJORAXIS_M / 1000) /**< Earth's semi-major axis in km according WGS 84 */
+
+
+    private:
+    // Convert Degrees to Radians
+    double DegreeToRadian(double angle);
+    // Convert Radians to Degrees
+    double RadianToDegree(double angle);
+    
+    public:
+    // Calculate the heading
+    double CalculateDistance (double latitude1, double longitude1, double latitude2, double longitude2);
+    // Calculate bearing
+    double CalculateBearing(double latitude1, double longitude1, double latitude2, double longitude2);
+    /*
+        This function takes as input the next gps coordinate that the boat is suppossed to achieve and calculates the compass
+        heading to the waypoint
+        Jeff Witten - 05/26/14 from Github VT-SailBOT/Navigation sailbot.c
+    */
+    int direction_to_next_point (double latitude, double longitude, double next_latitude, double next_longitude);
+    /*
+        This function takes as input the gps coordinates of the boat and the gps coordinates of a waypoint that the boat desires to approach
+        The function then sets a flag based on whether or not the boat is within a predetermined perimeter of the waypoint
+        Approach:
+        1.) Latitude and Longitude of San Francisco = 37.7844 N, 122.4167 W
+        2.) At 40 degrees North: 1 degree latitude = 111.03 km, 1 degree longitude = 85.39 km
+        3.) 111.03 = 85.39 * (1.30027) - used to correct approximately rectangular lat/lon grid to approximately square
+        4.) Through unit analysis, 1 meter = 0.0000111509 degrees longitude 
+        Jeff Witten - 03/27/14 from Github VT-SailBOT/Navigation sailbot.c
+        */
+    int point_proximity(double boat_latitude, double boat_longitude, double next_latitude, double next_longitude);
+    
+    double distance_ellipsoid(double from_lat,  double from_lon, double from_azimuth, double to_lat, double to_lon, double to_azimuth);
+    
+    int distance;
+    
+   };
\ No newline at end of file
--- a/nmea.cpp	Sat Feb 18 01:37:25 2017 +0000
+++ b/nmea.cpp	Wed Mar 01 03:38:03 2017 +0000
@@ -207,7 +207,9 @@
 		res_fLongitude = string2float(tmp_words[5]);
 		// get decimal format
 		if (tmp_words[4][0] == 'S') res_fLatitude  *= -1.0;
+		res_clat = tmp_words[4][0];
 		if (tmp_words[6][0] == 'W') res_fLongitude *= -1.0;
+		res_clon = tmp_words[6][0];
 		float degrees = trunc(res_fLatitude / 100.0f);
 		float minutes = res_fLatitude - (degrees * 100.0f);
 		res_fLatitude = degrees + minutes / 60.0f;
@@ -328,6 +330,14 @@
 	return res_fBearing;
 }
 
+char NMEA::getlatc() {
+	return res_clat;
+}	
+
+char NMEA::getlonc() {
+	return res_clon;
+}	
+
 float NMEA::trunc(float v) {
     if(v < 0.0) {
         v*= -1.0;
--- a/nmea.h	Sat Feb 18 01:37:25 2017 +0000
+++ b/nmea.h	Wed Mar 01 03:38:03 2017 +0000
@@ -51,7 +51,9 @@
 		
 		// globals to store parser results
 		float			res_fLongitude;					// GPRMC and GPGGA
+		char			res_clon;						// E or W
 		float			res_fLatitude;					// GPRMC and GPGGA
+		char			res_clat;						// N or S
 		unsigned char	res_nUTCHour, res_nUTCMin, res_nUTCSec,		// GPRMC and GPGGA 
 						res_nUTCDay, res_nUTCMonth, res_nUTCYear;	// GPRMC
 		int				res_nSatellitesUsed;			// GPGGA
@@ -95,7 +97,9 @@
 		int				getMonth();
 		int				getYear();
 		float			getLatitude();
+		char			getlatc();
 		float			getLongitude();
+		char			getlonc();
 		int				getSatellites();
 		float			getAltitude();
 		float			getSpeed();