Editorial Solution

  • In the given task, we have to create a device that can calculate the distance and direction between the camp location and the soldier's location.
  • Instead of an Army GPS device, we are going to send a GPS string via Serial Monitor to avoid hardware complexity. 
  • Communication between the serial monitor and the Arduino occurs via UART (Universal Asynchronous Receiver-Transmitter). 
  • Since the GPS module operates at a baud rate of 9600, it is essential to set the baud rate of both the Arduino UNO and the serial monitor to 9600 to ensure proper communication.

Hardware Connection

We have to connect the Arduino UNO board to the PC using a USB cable.

Firmware 

  • In the given task we have created our own custom GPS string.  
    • String = ”X=18.532525,Y=73.850457”. 
    • X = Latitude(degree)
    • Y = Longitude(degree)

Distance Calculation

  • We used the Haversine formula for distance calculation using latitude and longitude.
  • It’s used to calculate the shortest distance between two points on the Earth’s surface. It provides good accuracy for small distances.

Note: In the given string and Y coordinates are in degrees so we have to convert it into radians

Direction calculation

  • The bearing angle is used for the calculation of direction between two points.
  • The bearing angle (also called the azimuth) is the angle between the north direction and the direction of the line connecting two GPS coordinates, measured clockwise from north.
  • It is a crucial concept in navigation, as it provides the direction from one point to another.
  • To calculate the direction, we first need to determine the bearing angle using the following formula.
  • θ is in radians, so we have to convert it to degrees. And normalize it to [0 to 360].
  • Normalize the Bearing Angle
    • The bearing angle should be in the range [0°, 360°]. If the result is negative, add 360° to normalize it.
  • Depending on the bearing angle we will decide which direction soldiers should travel.

 

Sr.NoRange of angleDirections
  1.       

              337.5° to 360°                   

 and

to 22.5°

North  

2.22.5° to 67.5°

Northeast

3.67.5° to 112.5°

East

4. 112.5° to 157.5°

Southeast

5.157.5° to 202.5°

South

6.202.5° to 247.5°

Southwest

7.247.5° to 292.5°

West

8.292.5° to 337.5°

Northwest


 

Code

#include <math.h>

#define CAMP_LAT 18.556283  // Camp Latitude (destination)
#define CAMP_LON 73.955067  // Camp Longitude (destination)

#define R 6371  // Earth's radius in kilometers

void setup() {
  Serial.begin(9600);  //Initialize serial communication
}

void loop() {
  if (Serial.available()) {  // Check for data on Serial monitor
    String gpsString = Serial.readString();
    gpsString.trim();  // Remove any leading/trailing whitespace
    double soldierLat, soldierLon;
    if (parseCoordinates(gpsString, soldierLat, soldierLon)) {  // Extract latitude and longitude from the string

      double distance = calculateDistance(soldierLat, soldierLon, CAMP_LAT, CAMP_LON);    // Calculate distance to camp
      String direction = calculateDirection(soldierLat, soldierLon, CAMP_LAT, CAMP_LON);  // Determine compass direction

      Serial.print("Distance to camp: ");
      Serial.print(distance, 2);  // Display distance with 2 decimal places on Serial monitor
      Serial.println(" km ");
      Serial.print("Direction to camp: ");
      Serial.println(direction);  // Display compass direction (e.g., N, NE, E) on serial monitor
    }
  }
}


/* Parses GPS coordinates from a custom-formatted string */

bool parseCoordinates(String gpsString, double &lat, double &lon) {

  if (gpsString.startsWith("X=")) {
    int xIndex = gpsString.indexOf("X=");   // Find the position of "X="
    int yIndex = gpsString.indexOf(",Y=");  // Find the position of ",Y="

    // Extract latitude and longitude substrings and convert to double
    lat = gpsString.substring(xIndex + 2, yIndex).toDouble();
    lon = gpsString.substring(yIndex + 3).toDouble();  // Extract longitude correctly

    return true;
  } else {
    Serial.println("Error: Invalid GPS format");
    return false;
  }
}


/* Calculates the great-circle distance between two GPS coordinates using the Haversine formula.*/

double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
  double dLat = radians(lat2 - lat1);  // Convert latitude difference to radians
  double dLon = radians(lon2 - lon1);  // Convert longitude difference to radians
  lat1 = radians(lat1);                // Convert initial latitude to radians
  lat2 = radians(lat2);                // Convert final latitude to radians

  // Apply Haversine formula
  double a = sin(dLat / 2) * sin(dLat / 2) + cos(lat1) * cos(lat2) * sin(dLon / 2) * sin(dLon / 2);
  double c = 2 * atan2(sqrt(a), sqrt(1 - a));

  return R * c;  // Return distance in kilometers
}


/* Calculates the compass direction (bearing) from the current position to the camp.*/

String calculateDirection(double lat1, double lon1, double lat2, double lon2) {
  double dLon = radians(lon2 - lon1);  // Convert longitude difference to radians
  lat1 = radians(lat1);                // Convert current latitude to radians
  lat2 = radians(lat2);                // Convert destination latitude to radians

  // Calculate bearing using trigonometric functions
  double y = sin(dLon) * cos(lat2);
  double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);
  double bearing = atan2(y, x);  // Compute initial bearing in radians
  bearing = degrees(bearing);    // Convert bearing to degrees

  // Normalize bearing to 0-360 degrees
  if (bearing < 0) {
    bearing += 360;
  }

  // Convert bearing to compass direction
  if (bearing >= 337.5 || bearing < 22.5) return "N";
  else if (bearing >= 22.5 && bearing < 67.5) return "NE";
  else if (bearing >= 67.5 && bearing < 112.5) return "E";
  else if (bearing >= 112.5 && bearing < 157.5) return "SE";
  else if (bearing >= 157.5 && bearing < 202.5) return "S";
  else if (bearing >= 202.5 && bearing < 247.5) return "SW";
  else if (bearing >= 247.5 && bearing < 292.5) return "W";
  else return "NW";
}

Code Explanation

  • Constants and Setup:
    • CAMP_LAT and CAMP_LON  → Latitude and longitude of the camp (destination). 
    • → This is the Earth's radius in kilometers.
    • Serial.begin(9600); →  Initializes serial communication at 9600 baud rate to receive GPS coordinates.

 

  • Main Loop:
    • Continuously reads the GPS coordinates from the Serial Monitor.
    • Extracts latitude and longitude using parseCoordinates(). 

 

  • Distance Calculation:
    • Uses the Haversine formula in calculateDistance() to compute the distance (in kilometers) between the soldier and the camp.
    • calculateDistance();
      • Steps
        • Convert latitude/longitude differences and values to radians.
        • Apply Haversine formula.
          • a = sin²(Δlat/2) + cos(lat1) * cos(lat2) * sin²(Δlon/2)
          • c = 2 * atan2(√a, √(1−a))
        • Multiply by Earth's radius (R) for distance in kilometers.

 

  • Direction Calculation:
    • Computes the bearing using trigonometric functions in calculateDirection(); and converts it to compass directions (e.g., N, NE, E).
    • calculateDirection();
      • Steps
        • Converts longitude difference and latitudes to radians.
        • Calculates the bearing using trigonometric functions
          • y = sin(Δlon) * cos(lat2)
          • x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(Δlon)
          • bearing = atan2(y, x)
        • Converts the bearing from radians to degrees.
        • Normalizes the bearing to a range of 0-360 degrees.
        • Maps the bearing to a compass direction (e.g., N, NE, E).

 

  • Output:
    • Displays the distance and direction to the camp in the Serial Monitor.

 

Output

Screen-Shot of Output 

 

 

Video



 

Submit Your Solution