I knew the dimension of the LCD (Nokia 5110) as 43mm x 43mm but it looked smaller than I thought. That’s good because I want to put it on top of the GPS (Holux M-1000).

In my previous post, I explained how to get coordinates, date & time, speed, and bearing data from GPS, Holux M-1000. Now that I have the LCD, it’s time to add two parts to the Arduino sketch: 1) LCD driver/display, 2) distance calculation between two locations.

1. LCD Driver

First of all, I searched for a simple and small library for the LCD, Nokia 5110. There were a few different libraries for this LCD: Adafruit’s, Sparkfun’s, and Henning Karlsen’s. Among these libraries, I chose Henning Karlsen’s because I needed only simple text display with a couple of different font sizes. Henning Karlsen has separate library for graphics as well. I would like to thank Henning for his sharing his nice work on the library. Henning’s library supports 3 different font sizes: SmallFont (text and number, 6×8), MediumNumber (number only, 12×16), and BigNumber (number only, 14x 24). Only downside of this library is that the Medium and Big fonts do not support texts but only numbers. However I would need only numbers to display with bigger fonts, this limitation was no problem with me.

2. Distance calculation between two locations

There are number of websites showing how to calculate distance between two locations from latitudes and longitudes. Movable Type Scripts shows various calculations of distance, bearing and other useful conversions using Haversine formula and BlueMM posted the Excel formula to calculate distance which is basically the same way as Haversine.

The calculation is quite straightforward but I found there was a problem: Arduino (Atmega328p) cannot handle over 6-7th decimal digits which is very important in trigonometric calculation for short distance.

Arduino reference page says “*Floats have only 6-7 decimal digits of precision. That means the total number of digits, not the number to the right of the decimal point. Unlike other platforms, where you can get more precision by using a double (e.g. up to 15 digits), on the Arduino, double is the same size as float*.”

Let me give you an example. Suppose we started from a position A (lat: 40.00, long: 80) to a position B (lat: 40.01, long: 80.00). That is, we moved 0.01 degrees in latitude only. If you calculate the distance using Haversine formula on your PC, you will get about 1,111.9m. However, Arduino calculates it as 3,110.8m. Big error! More interesting thing is that even if you reduce the latitude difference to 0.001 or 0.0001 degrees, you get the same results, 3,110.8m. So I investigate further what exactly cause this error. Of course I know the culprit is the float precision limitation as said above. But I wanted to know which part of the calculation by Arduino cause this big error. In the Haversine formula, there are COS, SIN and ACOS functions used. I tested a few different calculations using these functions and found the calculation of COS and SIN functions affect minimal but the problem was the ACOS. If you calculate the formula on your PC only inside of ACOS bracket, you will get 0.9999999848. See my point? The decimal places below 6th in ACOS function is actually important to calculate the angular difference for small distance, but unfortunately Arduino cannot handle this. Not only for small distance but for even relatively long distance (say over 1 degree for instance) there is error between the results on the PC and Arduino.

Well, so I started thinking about how to avoid trigonometric function calculation when over 6th decimal places are important. And I found a solution! Instead of calculating angular difference between two positions and THEN calculating the distance by multiplying the mean earth radius, calculating a ratio of angle between two positions (latitude and longitude separately) over 360 degrees and divide the circumference of the earth by this ratio. In other words, keep the numbers big while calculation. Arduino’s float type has a limitation on the small decimal places, but can handle relatively big numbers!

Here is my formula:

The mean circumference of the earth is 2 x 6,371,000m x π = 40,030,170m

Δd (lat) = 40,030,170 x ΔΘ (lat) / 360 (assuming ΔΘ is small)

Δd(long) = 40,030,170 x ΔΘ(long) x cosΘm / 360 (Θm: mean latitude between two positions)

Now, the distance is √[Δd (lat)^2 + Δd (long)^2]

Below is the test Arduino sketch to test my formula. The result is 11.029m while Haversine formula for the same coordinates gives 11.119m. This is close enough considering the accuracy of the most GPS is bigger than one meter.

float gpsLat0 = 40.0; float gpsLat = 40.0001; float gpsLong0 = 80.0; float gpsLong = 80.0; void setup() { Serial.begin(38400); float delLat = abs(gpsLat0-gpsLat)*111194.9; float delLong = 111194.9*abs(gpsLong0-gpsLong)*cos(radians((gpsLat0+gpsLat)/2)); float distance = sqrt(pow(delLat,2)+pow(delLong,2)); Serial.println(distance,3); } void loop() { }

To be continued….

hi, I am about to embark on a similar project using Arduino. Have you tried the code above using live GPS data? if so was it accurate enough? your post would make a fantastic starting point.

Yes, I did and it works fine. Take a look at my Instructable (http://www.instructables.com/id/Distance-measuring-and-more-device-using-Arduino-a/). I tested it when I played golf and the distance marked at the golf course and my device showed very small difference. I also measured the distance between my home and work (about 50km) with my device and checked it on Google maps to get the coordinate and calculated the distance on-line and that was also quite acceptable. Good luck and enjoy your project.

You’re to modest. Youre approach is 100 % right. The difference with other right calculations are caused by the use of slightly different constants.

Common methods need about 10 goniometric calculations. Because I needed something faster in my Arduino project, I also started thinking. The result, after several hours of struggling I must admit, is:

distance = 60*mile*sqrt(sq(cos(pi*(pplat+wplat)/360)*(pplon-wplon))+(sq(pplat-wplat))

Then I started searching the internet for something similar because I could not believe to be the first. Doing so I landed on this Site with your post.

The result is a faster, simpler formula with one goniometric calculation. Compliments.

Thank you Rolf.

(Oops)^2. Thought the beast was killed but it’s still alive. The larger the distance, the worse the result of the formula. Continue fight.

Do you have any figures for the size of the error as distance increases? For example: at 100m = 40cm error, at 2km = 10m error, at 50km and so on? Oh and good work on the formula of course, it looks like a neat solution.

I haven’t tested to get the error range, but I remember that I measured the distance from home to work (about 52km) and compared to the on-line distance calculator and the difference was less than 1km. And for your reference, the smallest radius the GPS can measure is 3-6m.

Thanks.

Hey, did you also try to calculate the bearing(angle) between the two points?

Thanks!

Jack

I haven’t calculated the bearing angle, but I think there must be a simple ways to calculate the angle from coordinates of two positions.

Sorry, I’m using a translator.

Is it possible to slightly change your program to support a compass, and show the arrow to the target on lcd?

You can modify and use my code for your own projects under two conditions: 1) not for commercial purposes, 2) you need to show your code is based on my code and link to my blog and let me know when you post your code on your own blog.

Thanks.

Ooooooooooo – super: D !!

Unfortunately, I do not know when this will happen, because the change was made by a colleague – I unfortunately can give him only an idea .. Commercial are not entering the game, and of course I will announce the results 🙂