Quantcast
Viewing all articles
Browse latest Browse all 84

ESP32 (27) – GPS

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:

Image may be NSFW.
Clik here to view.
gps-010
Image may be NSFW.
Clik here to view.
gps-011

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:

Image may be NSFW.
Clik here to view.
gps-001
Image may be NSFW.
Clik here to view.
gps-002

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:

Image may be NSFW.
Clik here to view.
gps-003

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:

Image may be NSFW.
Clik here to view.
gps-001

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:

Image may be NSFW.
Clik here to view.
gps-010


Viewing all articles
Browse latest Browse all 84

Trending Articles