Using GPS speed to calculate distance

Hello everyone,

I am working on a project building an instrument cluster on a display. One of the features I want to have is a GPS speedometer, which I got working this morning wonderfully. I also want to have a trip meter and odometer that is saved to EEPROM.

I am not really sure about the logic of how to use the speed to use the speed to keep track of distance driven. I know I probably need a time component of some sort to calculate distance. I then have to add each mile driven to the odometer in EEPROM.

Any advice on how to accomplish this would be much appreciated! I also want to make sure that I am doing this in the most efficient way possible reading and writing to/from EEPROM to make sure I don’t kill it or anything over time. I think I would need to maybe shift the address of the bytes in the EEPROM after x amount of cycles to extend the lift expectancy.

Thoughts? Anything would be greatly appreciated, thank you! :slight_smile:

Note: I am updating the GPS info every 100ms.

#include <TinyGPS++.h> // Include the TinyGPS++ library
TinyGPSPlus tinyGPS; // Create a TinyGPSPlus object

#define GPS_BAUD 9600 // GPS module baud rate. GP3906 defaults to 9600.


#define SerialMonitor Serial


void setup()
{
  SerialMonitor.begin(9600);
  Serial1.begin(GPS_BAUD);
}

void loop()
{
  // print position, altitude, speed, time/date, and satellites:
  printGPSInfo();

  // "Smart delay" looks for GPS data while the Arduino's not doing anything else
  smartDelay(100); 
}

void printGPSInfo()
{
  // Print latitude, longitude, altitude in feet, course, speed, date, time,
  // and the number of visible satellites.
  SerialMonitor.print("Lat: "); SerialMonitor.println(tinyGPS.location.lat(), 6);
  SerialMonitor.print("Long: "); SerialMonitor.println(tinyGPS.location.lng(), 6);
  SerialMonitor.print("Alt: "); SerialMonitor.println(tinyGPS.altitude.feet());
  SerialMonitor.print("Course: "); SerialMonitor.println(tinyGPS.course.deg());
  SerialMonitor.print("Speed: "); SerialMonitor.println(tinyGPS.speed.mph()); //need to add 1 
  SerialMonitor.print("Date: "); printDate();
  SerialMonitor.print("Time: "); printTime();
  SerialMonitor.print("Sats: "); SerialMonitor.println(tinyGPS.satellites.value());
  SerialMonitor.println();
}

// This custom version of delay() ensures that the tinyGPS object
// is being "fed". From the TinyGPS++ examples.
static void smartDelay(unsigned long ms)
{
  unsigned long start = millis();
  do
  {
    // If data has come in from the GPS module
    while (Serial1.available())
      tinyGPS.encode(Serial1.read()); // Send it to the encode function
    // tinyGPS.encode(char) continues to "load" the tinGPS object with new
    // data coming in from the GPS module. As full NMEA strings begin to come in
    // the tinyGPS library will be able to start parsing them for pertinent info
  } while (millis() - start < ms);
}

// printDate() formats the date into dd/mm/yy.
void printDate()
{
  SerialMonitor.print(tinyGPS.date.day());
  SerialMonitor.print("/");
  SerialMonitor.print(tinyGPS.date.month());
  SerialMonitor.print("/");
  SerialMonitor.println(tinyGPS.date.year());
}

// printTime() formats the time into "hh:mm:ss", and prints leading 0's
// where they're called for.
void printTime()
{
  SerialMonitor.print(tinyGPS.time.hour());
  SerialMonitor.print(":");
  if (tinyGPS.time.minute() < 10) SerialMonitor.print('0');
  SerialMonitor.print(tinyGPS.time.minute());
  SerialMonitor.print(":");
  if (tinyGPS.time.second() < 10) SerialMonitor.print('0');
  SerialMonitor.println(tinyGPS.time.second());
}

The formula you need is S = UT + 0.5AT2 where S = distance, U = initial speed, T = time and A = acceleration.

If you assume that the speed is constant between one GPS reading and the next that can reduce to S = UT for that interval. The just add up all the S values for all the intervals.

…R

You could also calculate distance from the gps position data, calculating the distance traveled between each reading.

Robin2:
The formula you need is S = UT + 0.5AT2 where S = distance, U = initial speed, T = time and A = acceleration.

If you assume that the speed is constant between one GPS reading and the next that can reduce to S = UT for that interval. The just add up all the S values for all the intervals.

…R

Thanks for the reply! So let’s see if I get it…

I’ll just assume constant speed between one reading and the next which only a 0.1 second interval, so that’ll be fine (like you mentioned). I’ll check millis() before and after the reading so I can make sure i get the time just right, although it should be just about 100ms or so. Then I’ll add that reading to the trip meter and odometer values.
I think that’s right?

In regard to EERPROM, what is the best way to go about saving the odometer value? I’ll be reading and writing to it a lot, and I don’t want to reach the limits where it starts failing quickly. How could I code something so it only updates odometer in eeprom after each complete mile added? Just not sure about the logic of that and how to accomplish that.

I would suggest that you investigate FRAM memory. It is non-volatile like EEPROM but has virtually no limit on writes.

YoungestEVer:
I'll just assume constant speed between one reading and the next which only a 0.1 second interval, so that'll be fine (like you mentioned). I'll check millis() before and after the reading so I can make sure i get the time just right, although it should be just about 100ms or so. Then I'll add that reading to the trip meter and odometer values.
I think that's right?

If you travel at (say) 12mph for 0.1 seconds then you will travel 12 * 1760 / 60 /60 * 0.1 = 0.5867 yards (hope my maths is right)

In regard to EERPROM, what is the best way to go about saving the odometer value? I'll be reading and writing to it a lot, and I don't want to reach the limits where it starts failing quickly. How could I code something so it only updates odometer in eeprom after each complete mile added? Just not sure about the logic of that and how to accomplish that.

I would only write the odometer value to the EEPROM every tenth of a mile. If you use wear-levelling (look it up) you should get a lot of readings before the EEPROM wears out.

Or use a FRAM as suggested in Reply #4

...R

Robin2:
If you travel at (say) 12mph for 0.1 seconds then you will travel 12 * 1760 / 60 /60 * 0.1 = 0.5867 yards (hope my maths is right)
I would only write the odometer value to the EEPROM every tenth of a mile. If you use wear-levelling (look it up) you should get a lot of readings before the EEPROM wears out.

Or use a FRAM as suggested in Reply #4

...R

Makes sense, thanks. Thank you both for the replies, I'll definitely look into FRAM memory. It looks like adafruit has a little breakout for it, so I'll check that out. Thanks again for the help!:slight_smile:

Robin2:
If you travel at (say) 12mph for 0.1 seconds then you will travel 12 * 1760 / 60 /60 * 0.1 = 0.5867 yards (hope my maths is right)
I would only write the odometer value to the EEPROM every tenth of a mile. If you use wear-levelling (look it up) you should get a lot of readings before the EEPROM wears out.

Or use a FRAM as suggested in Reply #4

...R

Another thought, it's actually cheaper to use a TF card module and microSD card than the FRAM module. I'm sure microSC cards also have very high read/write life, right? Would this also be a fine option to use as well?

Hi.

You might need to watch out for spurious speed readings. I find that, while mostly reliable, the GPS can show wildly erratic readings for short time durations. Like 120 kph while stopped at a red light.

Also, reception can drop out. The TinyGPS examples show how to check that reception is occurring. When reception is lost while driving you would lose your distance travelled computation. Perhaps you could compensate by computing the distance travelled during loss of reception by using last known position and position when reception is restored. Getting complicated.

A Hall Effect sensor would do the job with 100% accuracy and reliability. Simple too.

John.

HillmanImp:
Hi.

You might need to watch out for spurious speed readings. I find that, while mostly reliable, the GPS can show wildly erratic readings for short time durations. Like 120 kph while stopped at a red light.

Also, reception can drop out. The TinyGPS examples show how to check that reception is occurring. When reception is lost while driving you would lose your distance travelled computation. Perhaps you could compensate by computing the distance travelled during loss of reception by using last known position and position when reception is restored. Getting complicated.

A Hall Effect sensor would do the job with 100% accuracy and reliability. Simple too.

John.

John,
Thanks for the reply. I just saw that yesterday in testing and couldn't understand why the readings spiked like that. I was just sitting in the backyard too. But while driving around for 20 min it didn't do it once. Very strange, and hard to understand why

Given that you will have the the current and past positions (Lat and long) why not just use the distance_between function of the library tto calculate te distance travelled?

YoungestEVer:
John,
Thanks for the reply. I just saw that yesterday in testing and couldn’t understand why the readings spiked like that. I was just sitting in the backyard too. But while driving around for 20 min it didn’t do it once. Very strange, and hard to understand why

I definitely get spurious readings more when stopped or at low speeds than at driving speeds. You could filter out any reading varying by more than 10% from the previous. But then you lose the distance calculation for that time duration.

Calculating distance travelled from successive locations as Paul suggests would work in theory but there are unavoidable inaccuracies in the position. Using u-center you can see how much your receiver “moves around” when it’s actually fixed in place.

I think we have to accept that GPS is something of a mystery black box. When it works it’s great; when it doesn’t it’s frustrating. There’s stuff going on inside the GPS receiver that is proprietary. There’s the theory that we can read up on and then there’s the algorithms that the manufacturers use which are secret. How speed is determined is not public as far as I could find out. I was told it’s a combination of using successive locations and Doppler shift and that it’s proprietary.

I thinks what’s “strange” is that with a tiny device worth a few dollars I can get the precise time from an atomic clock on a two ton satellite 20,000 km away.

John.

Hi,
I agree with @david_2018 and @countrypaul, use the distance between readings that the GPS can give you.
Simpler and more accurate than calculating from velocity.

I have used it and it works fine,I just did not use any distances that are under 2m, as this will be jitter when stationary.
TinyGPS library has the function.

https://forum.arduino.cc/index.php?topic=393886.0

Tom... :slight_smile: