Iterate through multiple GPS coordinates

I am planning to provide multiple GPS coordinates for the code below, and iterate through these points. As I get to each location, I want the LED to come on for 60 seconds (delay).

The code for this single location works.

I have searched on google, and it is possible to do this using for/loop command.

I don't know how to implement it on this code. Can somebody help me?

#include <TinyGPS++.h>
#include <SoftwareSerial.h>
static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 9600;
// The TinyGPS++ object
TinyGPSPlus gps;
// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);
// For stats that happen every 5 seconds
unsigned long last = 0UL;
int ledPin = 13;
void setup()
{
 Serial.begin(9600);
 ss.begin(GPSBaud);
pinMode(ledPin, OUTPUT);
}
void loop()
{
 // Dispatch incoming characters
 while (ss.available() > 0)
   gps.encode(ss.read());
 if (gps.location.isUpdated())
 {
   Serial.print(F("  Lat="));
   Serial.print(gps.location.lat(), 6);
   Serial.print(F(" Long="));
   Serial.println(gps.location.lng(), 6);
   Serial.print(F(" course="));
   Serial.println(gps.course.deg());
 }
 else if (millis() - last > 5000)
 {
   Serial.println();
   if (gps.location.isValid())
   {
     // replace 'Dest_LAT' and 'Dest_LON' values basedon your location  
     // you can find Latitude and Longitude from Read_Lat_Lng.ino  
     static const double Dest_LAT = 38.210169, Dest_LON = -75.689734;
     double distanceToDest =
       TinyGPSPlus::distanceBetween(
         gps.location.lat(),
         gps.location.lng(),
         Dest_LAT, 
         Dest_LON);
     double courseTo =
       TinyGPSPlus::courseTo(
         gps.location.lat(),
         gps.location.lng(),
         Dest_LAT, 
         Dest_LON);
     Serial.print(F("Distance to Destination ="));
     Serial.print(distanceToDest/1000, 6);       // *Prints distance to destination 
     Serial.print("Course to Destination: ");
     Serial.println(courseTo);
     
     if(distanceToDest/1000 < 6.050000)   //Here when distanceToDest/1000 is less than  0.050000  LED turns on . So change *distance to destination as per your requirement. 
     {
       digitalWrite(ledPin, HIGH);
     }
     else
     {
       digitalWrite(ledPin, LOW);
     }
   }
   if (gps.charsProcessed() < 10)
     Serial.println(F("WARNING: No GPS data.  Check wiring."));
   last = millis();
   Serial.println();
 }
}

Most people would make arrays out of Dest_LAT and Dest_LON and use the loop index to address them sequentially.

float Dest_LAT[5]={ some latitudes }, Dest_LON[5] = {some longitudes};

...
for (int dest=0; dest<5; dest++) {
distanceToDest =
       TinyGPSPlus::distanceBetween(
         gps.location.lat(),
         gps.location.lng(),
         Dest_LAT[dest], 
         Dest_LON[dest]);
...

Thank you!

Or a two-dimensional array:

static const double LatLonList[5][2] = 
{
  {38.210169, -75.689734},
  {38.210169, -75.689734},
  {38.210169, -75.689734},
  {38.210169, -75.689734},
  {38.210169, -75.689734}
};

     double distanceToDest =
       TinyGPSPlus::distanceBetween(
         gps.location.lat(),
         gps.location.lng(),
         LatLonList[index][0],
         LatLonList[index][1]);

Hi @jremington

I followed your approach, and it somewhat works.
As seen on Serial Monitor, it loops through all the given point at once.

What I am trying to achieve is this - get to the first GPS coordinates, before the program proceeds and do the computation for the next coordinates.Arduino Help

I appreciate your help so far.

@johnwasser This is neat. How would you loop through the points, to overcome this challenge?

Change the variable named 'index'. I would have thought that was obvious.

An even neater solution is to use a 'struct' (structure) to associate the two values into one type:

struct LatLon
{
  double Lat;
  double Lon;
};

static const LatLon LatLonList[5] =
{
  {38.210169, -75.689734},
  {38.210169, -75.689734},
  {38.210169, -75.689734},
  {38.210169, -75.689734},
  {38.210169, -75.689734}
};

  double distanceToDest =
    TinyGPSPlus::distanceBetween(
      gps.location.lat(),
      gps.location.lng(),
      LatLonList[index].Lat,
      LatLonList[index].Lon);

This is my real challenge.

I want to use this system for point to point navigation. It is after I have gotten to Destination A, before the system should do the computation for Destination B,... and so on. That is, as I am moving, I only care about the next point.

Using @jremington method, I have the code looping through all the points without stopping.

I added a delay, but that didn't help.

While I was at Destination B, it was computing distances for Destinations C, D, E, back to A, B; and accordingly turning the LED on or off.

Arduino Help

Finally, when I get to destination E, I want to break the loop.

Keep a global variable that points to the current destination. When you reach that destination, increment the global variable.

Note: Unless you plan to keep the Arduino powered on for the entire set of journeys, you should probably store the 'index' in EEPROM so you can continue with the same destination after a power cycle.

#include <EEPROM.h>

struct LatLon
{
  double Lat;
  double Lon;
};

static const LatLon LatLonList[] =
{
  {38.210169, -75.689734},
  {23.424076,  53.847818}, // United Arab Emirates
  {33.93911,   67.709953}, // Afghanistan
  {41.153332,  20.168331}, // Albania
  {40.069099,  45.038189}, // Armenia
};

const int LatLonCount = sizeof LatLonList /  sizeof LatLonList[0];

byte Index = 0;

#include <TinyGPS++.h>
#include <SoftwareSerial.h>
static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 9600;
// The TinyGPS++ object
TinyGPSPlus gps;
// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);
// For stats that happen every 5 seconds
unsigned long last = 0UL;
int ledPin = 13;

void setup()
{
  Serial.begin(9600);
  ss.begin(GPSBaud);
  pinMode(ledPin, OUTPUT);

  EEPROM.get(0, Index);
  if (Index >= LatLonCount)
    Index = 0;
}

void loop()
{
  // Dispatch incoming characters
  while (ss.available() > 0)
    gps.encode(ss.read());
  if (gps.location.isUpdated())
  {
    Serial.print(F("  Lat="));
    Serial.print(gps.location.lat(), 6);
    Serial.print(F(" Long="));
    Serial.println(gps.location.lng(), 6);
    Serial.print(F(" course="));
    Serial.println(gps.course.deg());
  }
  else if (millis() - last > 5000)
  {
    Serial.println();
    if (gps.location.isValid())
    {
      double distanceToDest =
        TinyGPSPlus::distanceBetween(
          gps.location.lat(),
          gps.location.lng(),
          LatLonList[Index].Lat,
          LatLonList[Index].Lon);

      double courseTo =
        TinyGPSPlus::courseTo(
          gps.location.lat(),
          gps.location.lng(),
          LatLonList[Index].Lat,
          LatLonList[Index].Lon);

      Serial.print(F("Distance to Destination ="));
      Serial.print(distanceToDest / 1000, 6);     // *Prints distance to destination
      Serial.print("  Course to Destination: ");
      Serial.println(courseTo);

      if (distanceToDest / 1000 < 6.050000) //Here when distanceToDest/1000 is less than  0.050000  LED turns on . So change *distance to destination as per your requirement.
      {
        // We have arrived.
        digitalWrite(ledPin, HIGH);
        Index++;
        delay(10000);
        if (Index >= LatLonCount)
          Index = 0; // Start over when we run out of destinations
        EEPROM.put(0, Index);
      }
      else
      {
        digitalWrite(ledPin, LOW);
      }
    }
    if (gps.charsProcessed() < 10)
      Serial.println(F("WARNING: No GPS data.  Check wiring."));
    last = millis();
    Serial.println();
  }
}

@johnwasser Thank you!

I will implement this during the week, and let you know the outcome.

Hello @johnwasser,

I tried it, but I am getting same results.

I think what I need, is to add a conditional statement using the "while command".

Something like - while distance is greater than some number, don't proceed to the next point.

I suppose this will be placed before the "Index++" line.

Can you help me write this in Arduino sketch?

Run this version which has more debug output. Then show me all the output. Copy and paste it from the Serial Monitor window.

#include <EEPROM.h>

struct LatLon
{
  double Lat;
  double Lon;
};

static const LatLon LatLonList[] =
{
  {38.210169, -75.689734},
  {23.424076,  53.847818}, // United Arab Emirates
  {33.93911,   67.709953}, // Afghanistan
  {41.153332,  20.168331}, // Albania
  {40.069099,  45.038189}, // Armenia
};

const int LatLonCount = sizeof LatLonList /  sizeof LatLonList[0];

byte Index = 0;

#include <TinyGPS++.h>
#include <SoftwareSerial.h>
static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 9600;
// The TinyGPS++ object
TinyGPSPlus gps;
// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);
// For stats that happen every 5 seconds
unsigned long last = 0UL;
int ledPin = 13;

void setup()
{
  Serial.begin(9600);
  ss.begin(GPSBaud);
  pinMode(ledPin, OUTPUT);

  EEPROM.get(0, Index);
  if (Index >= LatLonCount)
    Index = 0;
}

void loop()
{
  float currentLat, currentLon;

  // Dispatch incoming characters
  while (ss.available() > 0)
    gps.encode(ss.read());

  if (gps.location.isUpdated() && millis() - last > 5000)
  {
    last = millis();

    currentLat = gps.location.lat();
    currentLon = gps.location.lng();
    Serial.print(F("  Lat="));
    Serial.print(currentLat, 6);
    Serial.print(F(" Long="));
    Serial.println(currentLon, 6);
    Serial.print(F(" course="));
    Serial.println(gps.course.deg());

    if (gps.location.isValid())
    {
      Serial.println("Fix is valid.");
    }
    else
    {
      Serial.println("Fix is not yet valid.");
      return;
    }

    Serial.print("Destination: ");
    Serial.print(LatLonList[Index].Lat, 6);
    Serial.print(", ");
    Serial.println(LatLonList[Index].Lon, 6);

    double distanceToDest =
      TinyGPSPlus::distanceBetween(
        currentLat,
        currentLon,
        LatLonList[Index].Lat,
        LatLonList[Index].Lon);

    double courseTo =
      TinyGPSPlus::courseTo(
        currentLat,
        currentLon,
        LatLonList[Index].Lat,
        LatLonList[Index].Lon);

    Serial.print(F("Distance to Destination: "));
    Serial.print(distanceToDest / 1000, 6);     // *Prints distance to destination
    Serial.print("  Course to Destination: ");
    Serial.println(courseTo);

    if (distanceToDest / 1000 < 6.050000) //Here when distanceToDest/1000 is less than  0.050000  LED turns on . So change *distance to destination as per your requirement.
    {
      Serial.println("We have arrived.");
      digitalWrite(ledPin, HIGH);
      Index++;
      delay(10000);
      if (Index >= LatLonCount)
        Index = 0; // Start over when we run out of destinations
      EEPROM.put(0, Index);
    }
    else
    {
      digitalWrite(ledPin, LOW);
    }
  }

  if (gps.charsProcessed() < 10)
    Serial.println(F("WARNING: No GPS data.  Check wiring."));
}

Hello @johnwasser

Please accept my apologies. Both codes you wrote, worked as expected. I had been doing a poor job fitting it into my project which included codes for a compass, and Wireless Nrf24l01.

These are the outputs for both of your codes.

Conversation #8

And conversation #11

I have been able to correctly implement it into my project.

Thank you for your help!

Over the next couple of weeks, I will begin proper field testing.

Call us when you get to Abu Dhabi. :slight_smile:

I think the "one new fix every 10 seconds" might be a setting in the GPS module. You will need to find documentation for your particular GPS module and learn how to set the update rate.