Nell’articolo di oggi vedremo come interfacciare il chip esp32 ad un ricevitore GPS per conoscere posizione attuale, velocità e molti altri dati…
Ricevitore GPS
Sul mercato esistono moltissimi ricevitori GPS… grazie alla diffusione di navigatori, cellulari e multicotteri è ora possibile acquistarne uno per pochi euro. Per questo tutorial ho utilizzato un ricevitore GPS venduto da Banggood e basato sul chip u-blox NEO-M8:
Praticamente tutti i ricevitori GPS offrono almeno una interfaccia seriale, possiamo quindi collegarli al chip esp32 sfruttando una delle sue periferiche UART come spiegato in un precedente articolo. A volte non è semplice identificare i vari pin e può essere necessario – come nel mio caso – aprire il case plastico che racchiude il chip per leggere la serigrafia del PCB:
Dalle fotografie sopra si comprende che il mio ricevitore ha la seguente piedinatura:
- GND (massa) -> cavo nero
- VCC (alimentazione) -> cavo rosso
- TXD (trasmissione) -> cavo verde
- RXD (ricezione) -> cavo giallo
Ho scelto di utilizzare la periferica UART1 del chip esp32 con i pin 4 (TX) e 16 (RX). Ho quindi effettuato i collegamenti, ricordando che il pin TX del ricevitore GPS va collegato al pin RX del chip esp32 e viceversa:
NMEA
I ricevitori GPS inviano dati secondo lo standard NMEA 0183 (normalmente chiamato semplicemente NMEA).
Lo standard prevede l’invio di stringhe (sentences = frasi) formate da un massimo di 80 caratteri e terminate da CRLF. Ogni stringa ha il seguente formato:
$PREFIX,data1,data2 ... dataN-1,datoN*CHECKSUM
Il prefisso (5 caratteri) indica il tipo di dispositivo (per i ricevitori GPS è GP) e il tipo di frase (i successivi 3 caratteri). Ogni frase termina con un checksum (XOR) che consente di verificare la correttezza della frase ricevuta.
Lo standard NMEA definisce molte frasi diverse e i singoli produttori possono aggiungere tipi di frasi proprietarie per comunicare ulteriori dati. Un elenco esaustivo di frasi NMEA è disponibile a questo indirizzo. Vediamo un esempio di frase GGA (Global Positioning System Fix Data):
$GPGGA,183619,3877.038,N,07702.110,W,1,08,0.9,545.4,M,46.9,M,,*47
Il ricevitore sta comunicando la posizione attuale (latitudine 38°77.038′ NORD e longitudine 77°02.110′ OVEST), ottenuta alle 18:36:19 grazie a 8 satelliti. La qualità della posizione è GPS Fix (1).
Per poter ottenere i dati dal ricevitore GPS dobbiamo quindi essere in grado di “comprendere” le frasi NMEA. Ho trovato una comoda libreria, minmea, sviluppata in C e in grado di effettuare il parsing delle frasi NMEA più importanti.
Per integrare la libreria in un progetto esp-idf è sufficiente copiare i due files sorgenti (minmea.c e minmea.h) in una cartella all’interno della cartella components e creare un file component.mk come segue:
Il flag evidenziato è necessario perché il framework non contiene la funzione timegm() e quindi, come indicato anche nel README della libreria, va indicato al compilatore di sostituire la funzione con mktime().
Programma
Nel mio repository Github trovate il programma di esempio che ho sviluppato per questo tutorial. Vediamo gli elementi principali:
Per poter utilizzare la libreria minmea, includiamo il relativo file header:
#include "minmea.h" |
Leggiamo una riga dalla periferica UART1 e passiamola alla libreria per eseguire il parsing:
char *line = read_line(UART_NUM_1); switch (minmea_sentence_id(line, false)) { case MINMEA_SENTENCE_RMC: [...] case MINMEA_SENTENCE_GGA: [...] } |
Infine verifichiamo se i parametri ricevuti sono diversi da quelli già memorizzati e, in tal caso, visualizziamoli sullo schermo:
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); } |
Ho aggiunto un valore di soglia (0.001) per evitare di stampare piccoli spostamenti, dovuti a disturbi o oscillazioni sui dati ricevuti.
Ecco il programma in esecuzione:
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.