TinyGPS distance to

Hi there… I’m trying to pick apart the tinygps example so I can learn how to display certain things on an LCD display with a later use to create a reverse geocache.

I’m having a bit of trouble with distance to.

I can’t figure out how the line of code from the example works. I want to assign the value returned to an unsigned long to then display on the lcd

 print_int(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0UL : (unsigned long)TinyGPS::distance_between(flat, flon, LONDON_LAT, LONDON_LON) / 1000, 0xFFFFFFFF, 9);         //DISTANCE TO LONDON

That’s the line of code that displays the result in a serial output in serial monitor. I’d like to pull the same value into a variable to then display on my lcd.

Here’s the whole code so far…

#include <SoftwareSerial.h>

#include <TinyGPS.h>

/* This sample code demonstrates the normal use of a TinyGPS object.
   It requires the use of SoftwareSerial, and assumes that you have a
   4800-baud serial GPS device hooked up on pins 3(rx) and 4(tx).
*/

TinyGPS gps;

static void gpsdump(TinyGPS &gps);
static bool feedgps();
static void print_float(float val, float invalid, int len, int prec);
static void print_int(unsigned long val, unsigned long invalid, int len);
static void print_date(TinyGPS &gps);
static void print_str(const char *str, int len);






void setup()
{
  Serial.begin(115200);
  Serial1.begin(4800);
  Serial2.begin(19200);
  
  Serial.print("Testing TinyGPS library v. "); Serial.println(TinyGPS::library_version());
  Serial.println("by Mikal Hart");
  Serial.println();
  Serial.print("Sizeof(gpsobject) = "); Serial.println(sizeof(TinyGPS));
  Serial.println();
  Serial.println("Sats HDOP Latitude Longitude Fix  Date       Time       Date Alt     Course Speed Card  Distance Course Card  Chars Sentences Checksum");
  Serial.println("          (deg)    (deg)     Age                        Age  (m)     --- from GPS ----  ---- to London  ----  RX    RX        Fail");
  Serial.println("--------------------------------------------------------------------------------------------------------------------------------------");
}








void loop()
{
  bool newdata = false;
  unsigned long start = millis();
  
  // Every second we print an update
  while (millis() - start < 1000)
  {
    if (feedgps())
      newdata = true;
  }
  
  gpsdump(gps);
}









static void gpsdump(TinyGPS &gps)
{
 
  float flat, flon;
  unsigned long age, date, time, chars, distanc = 0;
  unsigned short sentences = 0, failed = 0;
  static const float LONDON_LAT = 51.508131, LONDON_LON = -0.128002;
  
  print_int(gps.satellites(), TinyGPS::GPS_INVALID_SATELLITES, 5);
  print_int(gps.hdop(), TinyGPS::GPS_INVALID_HDOP, 5);
  gps.f_get_position(&flat, &flon, &age);
  print_float(flat, TinyGPS::GPS_INVALID_F_ANGLE, 9, 5);
  print_float(flon, TinyGPS::GPS_INVALID_F_ANGLE, 10, 5);

  Serial2.write(254); Serial2.write(88); // Clear the LCD
Serial2.print(gps.hdop());

// Serial2.print(gps.satellites());        // Sats in view
// Serial2.print(" Sats in view     ");   

// Lat and lon on screen
// Serial2.print("Lat:");                  // Lat
// Serial2.println(flat, 9);
// Serial2.print("Lon:");                  // Lon
// Serial2.println(flon, 10);

//Serial2.print("Speed in Mph:");          //Speed in mph
//Serial2.println(gps.f_speed_mph(), 3);   //Speed in mph


//Serial2.print("Compass Direction: ");
//Serial2.print(TinyGPS::cardinal(gps.f_course()));       //Direction of travel in N/S/E/W




 print_int(age, TinyGPS::GPS_INVALID_AGE, 5);

  print_date(gps);

  print_float(gps.f_altitude(), TinyGPS::GPS_INVALID_F_ALTITUDE, 8, 2);
  print_float(gps.f_course(), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2);
  print_float(gps.f_speed_kmph(), TinyGPS::GPS_INVALID_F_SPEED, 6, 2);
  print_str(gps.f_course() == TinyGPS::GPS_INVALID_F_ANGLE ? "*** " : TinyGPS::cardinal(gps.f_course()), 6);
  
 print_int(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0UL : (unsigned long)TinyGPS::distance_between(flat, flon, LONDON_LAT, LONDON_LON) / 1000, 0xFFFFFFFF, 9);         //DISTANCE TO LONDON
  print_float(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : TinyGPS::course_to(flat, flon, 51.508131, -0.128002), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2);                 //BEARING TO LONDON
  print_str(flat == TinyGPS::GPS_INVALID_F_ANGLE ? "*** " : TinyGPS::cardinal(TinyGPS::course_to(flat, flon, LONDON_LAT, LONDON_LON)), 6);                            //DIRECTION TO LONDON
  

  

  gps.stats(&chars, &sentences, &failed);
  print_int(chars, 0xFFFFFFFF, 6);
  print_int(sentences, 0xFFFFFFFF, 10);
  print_int(failed, 0xFFFFFFFF, 9);
  Serial.println();
}








static void print_int(unsigned long val, unsigned long invalid, int len)
{
  char sz[32];
  if (val == invalid)
    strcpy(sz, "*******");
  else
    sprintf(sz, "%ld", val);
  sz[len] = 0;
  for (int i=strlen(sz); i<len; ++i)
    sz[i] = ' ';
  if (len > 0) 
    sz[len-1] = ' ';
  Serial.print(sz);
  feedgps();
}

static void print_float(float val, float invalid, int len, int prec)
{
  char sz[32];
  if (val == invalid)
  {
    strcpy(sz, "*******");
    sz[len] = 0;
        if (len > 0) 
          sz[len-1] = ' ';
    for (int i=7; i<len; ++i)
        sz[i] = ' ';
    Serial.print(sz);
  }
  else
  {
    Serial.print(val, prec);
    int vi = abs((int)val);
    int flen = prec + (val < 0.0 ? 2 : 1);
    flen += vi >= 1000 ? 4 : vi >= 100 ? 3 : vi >= 10 ? 2 : 1;
    for (int i=flen; i<len; ++i)
      Serial.print(" ");
  }
  feedgps();
}









static void print_date(TinyGPS &gps)
{
  int year;
  byte month, day, hour, minute, second, hundredths;
  unsigned long age;
  gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths, &age);
  if (age == TinyGPS::GPS_INVALID_AGE)
    Serial.print("*******    *******    ");
  else
  {
    char sz[32];
    sprintf(sz, "%02d/%02d/%02d %02d:%02d:%02d   ",
        month, day, year, hour, minute, second);
    Serial.print(sz);
  }
  print_int(age, TinyGPS::GPS_INVALID_AGE, 5);
  feedgps();
}










static void print_str(const char *str, int len)
{
  int slen = strlen(str);
  for (int i=0; i<len; ++i)
    Serial.print(i<slen ? str[i] : ' ');
  feedgps();
}









static bool feedgps()
{
  while (Serial1.available())
  {
    if (gps.encode(Serial1.read()))
      return true;
  }
  return false;
}

Thanks so much!

What part(s) of that code are you having problems with?

print_int(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0UL : (unsigned long)TinyGPS::distance_between(flat, flon, LONDON_LAT, LONDON_LON) / 1000, 0xFFFFFFFF, 9);

The ?: part is a ternary operator. It is equivalent to this:

if(flat == TinyGPS::GPS_INVALID_F_ANGLE)
  print_int(0UL);
else
  print_int((unsigned long)TinyGPS::distance_between(flat, flon, LONDON_LAT, LONDON_LON) / 1000, 0xFFFFFFFF, 9));

I'm trying to write out the distance to result to a serial display but am struggling to understand how to do it.

I'd like to do (in my head!)

Serial2.println(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0UL : (unsigned long)TinyGPS::distance_between(flat, flon, LONDON_LAT, LONDON_LON) / 1000, 0xFFFFFFFF, 9);

print_int is declared as static void. Can you explain what this means in newbie terms..? The example code for the tinygps library is a bit beyond me and theres quite a bit of code in it without comments which is adding to the confusion.

Many thanks for your help Andy

static void print_int(unsigned long val, unsigned long invalid, int len);
|----| |--| |-------||--------------------------------------------------|
^      ^    ^        ^
|      |    |        |.Function Parameters
|      |    |..........Function Name
|      |...............Return Type (ex: void, int, bool)  void means you're not returning any data back to the calling function.
|.......................Function modifiers (ex: static, __inline)

in c/c++, the static keyword is used mainly for compiler optimization. It does restrict scope however (you won't be able to call the function from another .ino or .cpp file). It also allows the compiler to run the function inline when it deems necessary.

Don't get too hung up on when or when not to use static. You could remove it and nothing noticeable will change for your program. Mainly, you want to use the static keyword on as many functions as you can if your goal is to get very small, compact, and fast code.

One piece of advice, is when you're starting out and learning... Don't try to write dense code. You'll spend more time trying to figure out what you were trying to do and decipher the cryptic syntax than anything else. There's not a huge performance penalty by just writing the code expanded.

This would be the preferred method:

if (flat == TinyGPS::GPS_INVALID_F_ANGLE)
     Serial.println(0UL);
else
     Serial.println((unsigned long)TinyGPS::distance_between(flat, flon, LONDON_LAT, LONDON_LON) / 1000, 0xFFFFFFFF, 9);

When you start having to add debug prints everywhere to track down errors, you'll appreciate code that's not super compact.

I couldn't agree more.

It's a case of me being a beginner trying to reverse engineer some example code which has confused me no end! Thanks for your help, I'll have another try. I think the problem the original author had was that the code in its un-dense form wouldn't fit in the flash space so as a result he compacted it down.

Not much more luck there. I have an error when compiling.

no matching function for call to 'HardwareSerial::println(long unsigned int, long unsigned int, int)'

I pasted it here:

  print_int(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0UL : (unsigned long)TinyGPS::distance_between(flat, flon, LONDON_LAT, LONDON_LON) / 1000, 0xFFFFFFFF, 9);         //DISTANCE TO LONDON
  print_float(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : TinyGPS::course_to(flat, flon, 51.508131, -0.128002), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2);                 //BEARING TO LONDON
  print_str(flat == TinyGPS::GPS_INVALID_F_ANGLE ? "*** " : TinyGPS::cardinal(TinyGPS::course_to(flat, flon, LONDON_LAT, LONDON_LON)), 6);                            //DIRECTION TO LONDON


 if (flat == TinyGPS::GPS_INVALID_F_ANGLE)
     Serial.println(0UL);
else
     Serial2.println((unsigned long)TinyGPS::distance_between(flat, flon, LONDON_LAT, LONDON_LON) / 1000, 0xFFFFFFFF, 9);    // Print distance to london on LCD

Apologies, I didn’t look at the actual print_int function when i re-posted the code for you.

print_int takes 3 parameters, the first is the actual value.

Try this:

if (flat == TinyGPS::GPS_INVALID_F_ANGLE)
{
  Serial.println(0UL);
}
else
{
  unsigned long distance = TinyGPS::distance_between(flat, flon, LONDON_LAT, LONDON_LON) / 1000;
  if (distance!= 0xFFFFFFFF)
  {
    Serial.println(distance);
  }
  else
  {
    Serial.println(F("Invalid distance"));
  }
}

to at least get it compiled and something printing.