Intro: Distance Measuring (and More) Device Using Arduino and GPS
In this Instructable, I'm going to show how:
- to calculate distance between two points using simple formula I developed.
- to use the LCD (Nokia 5110) to display info (speed, bearing, date, time, distance from a marked point).
- to use regulated power source from GPS for microcontroller (JeonLab mini, minimal Arduino) and LCD, which means you don't need separate battery pack.
- Calculate and display distance from a point, where you marked by pressing a button, to current position (can be used for playing golf).
- Alarm at certain speeds (can be used while you are driving).
Step 1: Parts List
- Arduino board: I used my minimal Arduino board, JeonLab mini, but there are other small or even smaller boards you can buy; Arduino mini, Arduino micro, or Arduino nano for instance. Small form factor for portability is the key, so choose one as small as possible and one you are familiar with.
- GPS: Holux M-1000 or any portable GPS unit with a serial data port
- LCD: Nokia 5110
- Push button switches: any momentary push button switches (normal open)
- Speaker: smaller the better. I found one in my junk drawer that I took out long time ago from either a PDA (Palm TX, m100, IIIe, T2 or....) or a digital camera, I don't remember...
- a piece of prototyping circuit board
- some double sided foam tape
- some wire: 28 to 30 wire gauge
- Time, creative mind and enthusiasmof yours
Step 2: Finding Proper Power Source for the Microcontroller and LCD
I opened up the GPS and found a test point, V28A, which must be regulated power from the Li-ion battery (3.7V). The microcontroller, ATmega328p, on Arduino can run at 1.8 - 5.5V and the LCD, Nokia 5110 need 2.7-3.3V. So 2.8V is perfect for both.
As shown in the picture, 30 gauge wires were soldered directly on the GPS pcb, on V28A (2.8V), TX, and GND.
The GPS, Holux M-1000 has TX and RX pins available on the USB mini-B port, but I needed only TX pin to send data to the microcontroller. Using a magnifying glass, I followed the trace of the USB pin and flipped the PCB over and found the spot to solder the wire for the TX pin.
The wire for the GND line is simply soldered to the battery contact pin.
The LCD and JeonLab mini board consume not much current, so with the built-in battery pack on the GPS, it lasts more than 10 hours with even the backlight of the LCD on.
Step 3: Assembling LCD and JeonLab Mini Board
The right angle header pin is used to connect the LCD and the JeonLab mini board.
In order to save power, no LEDs (power and digital pin 13) on the JeonLab mini board was attached. I wanted to make the board as thin as possible, so bent the legs of the ceramic resonator and found it didn't work. Probably it was damaged because I bent those legs too much. I didn't have any extra blue resonator at hand, had to replace it with a little bigger resonator (same frequency, 16MHz). Look at the pictures in
Step 4: Pin Connections
Here is the full list of pin connections.
Arduino 2 - LCD RST (reset)
Arduino 3 - LCD CS/CE (chip selection)
Arduino 4 - LCD DC (data/commands choice)
Arduino 5 - LCD MOSI/DIN (serial data line)
Arduino 6 - LCD SCLK (clock)
Arduino 10 - GPS TX
Arduino Vcc - LCD Vcc - GPS 2.8V
Arduino GND - LCD GND - GPS GND
Arduino 8 - LCD LED
Arduino 7 - Push button switch to toggle LCD backlight LED (other pin of the switch to GND)
Arduino 9 - Push button switch for future versions (other pin of the switch to GND)
Arduino 12 - Push button switch to mark current position (other pin of the switch to GND)
Arduino 11 - speaker (other pin of the switch to GND)
Step 5: Arduino Programming
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]
I have tested this method by measuring distance from home to my work and it worked fine. First of all, I got the coordinates of my home and my work and then calculated the distance by Haversine method and by my formula shown above. There is some difference in the results but negligeable.
Arduino sketch is attached. The LCD library can be downloaded from here.
Thank you for reading my Instructable. Hope someone find this useful.