In today’s post I’ll show you how to interface the esp32 chip to a GPS receiver to receive the actual position, speed and more…
GPS receiver
On the Internet and in electronic stores you can find different GPS receivers… thanks to the spread of navigators, smartphones and multicopters you can now buy one for few euros. For this tutorial, I used a GPS receiver sold by Banggood and based on the u-blox NEO-M8 chip:
Almost all the GPS receivers offer a serial interface, you can therefore connect them to an esp32 chip using one of its UART controllers, as I explained in a previous article. Sometimes it’s not easy to identify the various pins and it may be necessary – as in my case – to open the plastic case that contains the chip to read the PCB silk screen:
From the photos above you can understand the pinout of my receiver:
- GND (ground) -> black cable
- VCC (power supply) -> red cable
- TXD (transmit) -> green cable
- RXD (receive) -> yellow cable
I decided to use the UART1 controller of my esp32 chip, with pins 4 (TX) and 16 (RX). I therefore connected all the cables, paying attention to connect the TX pin of the receiver to the RX pin of the chip and viceversa:
NMEA
GPS receivers send data following the NMEA 0183 standard (often called just NMEA).
NMEA is based on strings (sentences) composed by a maximum of 80 characters with an ending CRLF. Each string has the following format:
$PREFIX,data1,data2 ... dataN-1,datoN*CHECKSUM
The prefix (5 chars) defines the type of device (for GPS receiver is GP) and the type of sentence (the following 3 chars). Each sentence includes a checksum (XOR) that allows the receiver to validate the data received.
The NMEA standard defines many types of sentences and each manufacturer can add proprietary types to communicate specific data. A complete list of NMEA sentences is available at this website. Let’s analyze one GGA (Global Positioning System Fix Data) sentence:
$GPGGA,183619,3877.038,N,07702.110,W,1,08,0.9,545.4,M,46.9,M,,*47
The receiver is sending the actual position (latitude 38°77.038′ NORTH and longitude 77°02.110′ WEST), obtained at 18:36:19 thanks to 8 satellites. The fix (position) quality is GPS Fix (1).
To be able to get data from the GPS receiver your program must therefore “understand” the NMEA sentences it receives. I found a very good library, minmea, developed in C and able to parse the most important NMEA sentences.
You only need to copy the two source files (minmea.c e minmea.h) in a subfolder of the components folder of your project and to create a component.mk file as it follows:
I had to add the highlighted flag because of the esp framework does not include the timegm() function and therefore, as explained also in the README of the library, you need to tell the compiler to use the more common mktime() instead.
Program
In my Github repository you can find the program I developed for this tutorial. Let’s analyse the most important pieces of code:
To use the minmea library, include its header file:
#include "minmea.h" |
Read a line from the UART1 controller and pass it to the library to be parsed:
char *line = read_line(UART_NUM_1); switch (minmea_sentence_id(line, false)) { case MINMEA_SENTENCE_RMC: [...] case MINMEA_SENTENCE_GGA: [...] } |
Finally verify if the new parameters are different from the ones already saved and, if so, print them on the screen:
float new_latitude = minmea_tocoord(&frame.latitude); if((new_latitude != NAN) && (abs(new_latitude - latitude) > 0.001)) { latitude = new_latitude; printf("New latitude: %f\n", latitude); } |
I added a threshold value (0.001) to avoid printing a lot of small updates, due to disturbances or oscillations on received data.
Here’s the program running on my laptop:
Hello, good and interesting article.
I have a question: How many readings gives the GPS per second?
I ask this because in a smartphone I can’t get more than 1 reading per second, and could be interested in investigating with these uart GPS devices.
In the Banggood site they say:
” Nav. update rate1 Single GNSS: up to 18 HZ
Concurrent GNSS: up to 10 Hz”
Is that the true readings per second?
Thanks
Hi, you can configure the “update rate” (sometimes called “refresh rate”) of the receiver using (for UBlox devices) the u-center config tool. Here’s a video that explains how to do it.
Nice, so you just have to send it a hex string. Interesting.
I’ve seen a module (VK2828U7G5LF) very cheap and I’ve bought one.
The datasheet tells all the commands (strings) to change the serial baud rate, update rate and so on.
Thanks!
You’re welcome, let me know if you have success!
Hi, I’ve tested the module and works fine.
I get precision around 10 cm while walking, with a 14 cm noise. So the mean position is smooth but individual readings have noise.
In addition there is a slow and smooth drift of around 1.5 meters with twenty seconds of period or so.
I’ve tested with 1 Hz, 5 Hz and 10 Hz refresh rates.
I had fun tinkering with it but now I don’t know what to use it for 🙂
“the esp framework does not include the timegm() function and therefore, as explained also in the README of the library, you need to tell the compiler to use the more common mktime() instead.”
Q1: which README exactly do you refer to?
Q2: mktime() and timegm() are equivalent! timegm() assumes the values passed to it are in UTC. What am I missing?
Hi Marcel, everything is well explained in the minmea’s README
Argg…make that “mktime() and timegm() are NOT equivalent” in my Q2, sorry. You really need to set your system to UTC for this fix to work but I just saw that the README already mentions this.