Merge pull request #156 from sparkfun/release_candidate
Create Example31_Great_Circle_Distance.ino
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
Calculating the Great Circle Distance and Course to a target position
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: September 21st, 2022
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to query a u-blox module for its latitude/longitude and then
|
||||
calculate the Great Circle Distance and Course to a target location.
|
||||
|
||||
Thanks! distanceBetween and courseTo were taken from Mikal Hart's TinyGPSPlus:
|
||||
https://github.com/mikalhart/TinyGPSPlus/blob/ca29434514a5c5172bd807af0608df7f296582a2/src/TinyGPS%2B%2B.cpp#L285-L328
|
||||
|
||||
Note: Lat/Long are large numbers because they are degrees * 10^-7. To convert lat/long
|
||||
to something google maps understands simply divide the numbers by 10,000,000. We
|
||||
do this so that we don't have to use floating point numbers.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
|
||||
|
||||
//#include <math.h> //Uncomment if required. May be needed for sqrt, atan2, etc..
|
||||
|
||||
double distanceBetween(long lat1_l, long long1_l, long lat2_l, long long2_l)
|
||||
{
|
||||
// returns distance in meters between two positions, both specified
|
||||
// as signed decimal-degrees latitude and longitude. Uses great-circle
|
||||
// distance computation for hypothetical sphere of radius 6372795 meters.
|
||||
// Because Earth is no exact sphere, rounding errors may be up to 0.5%.
|
||||
// Courtesy of Maarten Lamers
|
||||
double lat1 = (double)lat1_l / 10000000.0; // Convert lat and long to degrees
|
||||
double long1 = (double)long1_l / 10000000.0;
|
||||
double lat2 = (double)lat2_l / 10000000.0;
|
||||
double long2 = (double)long2_l / 10000000.0;
|
||||
double delta = radians(long1-long2);
|
||||
double sdlong = sin(delta);
|
||||
double cdlong = cos(delta);
|
||||
lat1 = radians(lat1);
|
||||
lat2 = radians(lat2);
|
||||
double slat1 = sin(lat1);
|
||||
double clat1 = cos(lat1);
|
||||
double slat2 = sin(lat2);
|
||||
double clat2 = cos(lat2);
|
||||
delta = (clat1 * slat2) - (slat1 * clat2 * cdlong);
|
||||
delta = sq(delta);
|
||||
delta += sq(clat2 * sdlong);
|
||||
delta = sqrt(delta);
|
||||
double denom = (slat1 * slat2) + (clat1 * clat2 * cdlong);
|
||||
delta = atan2(delta, denom);
|
||||
return delta * 6372795;
|
||||
}
|
||||
|
||||
double courseTo(long lat1_l, long long1_l, long lat2_l, long long2_l)
|
||||
{
|
||||
// returns course in degrees (North=0, West=270) from position 1 to position 2,
|
||||
// both specified as signed decimal-degrees latitude and longitude.
|
||||
// Because Earth is no exact sphere, calculated course may be off by a tiny fraction.
|
||||
// Courtesy of Maarten Lamers
|
||||
double lat1 = (double)lat1_l / 10000000.0; // Convert lat and long to degrees
|
||||
double long1 = (double)long1_l / 10000000.0;
|
||||
double lat2 = (double)lat2_l / 10000000.0;
|
||||
double long2 = (double)long2_l / 10000000.0;
|
||||
double dlon = radians(long2-long1);
|
||||
lat1 = radians(lat1);
|
||||
lat2 = radians(lat2);
|
||||
double a1 = sin(dlon) * cos(lat2);
|
||||
double a2 = sin(lat1) * cos(lat2) * cos(dlon);
|
||||
a2 = cos(lat1) * sin(lat2) - a2;
|
||||
a2 = atan2(a1, a2);
|
||||
if (a2 < 0.0)
|
||||
{
|
||||
a2 += TWO_PI;
|
||||
}
|
||||
return degrees(a2);
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
//Query module only every second. Doing it more often will just cause I2C traffic.
|
||||
//The module only responds when a new position is available
|
||||
if (millis() - lastTime > 1000)
|
||||
{
|
||||
lastTime = millis(); //Update the timer
|
||||
|
||||
long latitude = myGNSS.getLatitude();
|
||||
Serial.print(F("Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = myGNSS.getLongitude();
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
Serial.println(F(" (degrees * 10^-7)"));
|
||||
|
||||
static const long TARGET_LAT = 400909142, TARGET_LON = -1051849833; // SparkFun's location: degrees * 10^-7 (40.091 N, 105.185 W)
|
||||
|
||||
double distanceToTarget = distanceBetween(
|
||||
latitude,
|
||||
longitude,
|
||||
TARGET_LAT,
|
||||
TARGET_LON);
|
||||
|
||||
Serial.print(F("Distance to target: "));
|
||||
Serial.print(distanceToTarget, 2);
|
||||
Serial.print(F(" (m) "));
|
||||
|
||||
double courseToTarget = courseTo(
|
||||
latitude,
|
||||
longitude,
|
||||
TARGET_LAT,
|
||||
TARGET_LON);
|
||||
|
||||
Serial.print(F("Course to target: "));
|
||||
Serial.print(courseToTarget, 1);
|
||||
Serial.println(F(" (degrees)"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user