Gps Tracker arduino – lo sketch

Dopo una settimana di sperimentazioni e test ho finalmente ultimato ed ottimizzato lo sketch che ti propongo.

gps tracker arduino lato

In questa settimana ho anche provveduto ad acquistare una antenna estarna ed un adattatore per migliorare il segnale ricevuto dai satelliti perché durante i miei esperimenti in laboratorio mi sono reso conto che l’antenna installata sulla Gps shield in taluni condizioni si rilevava insufficiente:

gps antenna

l’adattatore necessario per collegare questo tipo di antenna alla Gps Shield è questo:

interface cable gps

Gps Tracker arduino kit

Al termine dei miei esperimenti ho deciso di trasformare questo progetto in un kit che puoi acquistare direttamente dal sito robotics-3d.com.

  • Il kit puoi acquistarlo solo come componenti elettronici:
  • arduino uno
  • gps shield
  • adattatore SMA per antenna Gps
  • antenna Gps
  • display 20×4 I2C
  • 4 wire femmina/maschio per collegare il display alla centralina

ed in aggiunta richiedere il case tagliato a laser a cui aggiungere la viteria per il montaggio.

gps tracker arduino fronte

Lo sketch

Come ti ho promesso nel titolo ecco lo sketch del Gps Tracker arduino che ho ottimizzato per il progetto partendo da uno degli esempi inclusi nella libraria rilasciata dal produttore della shield gps: adafruit.

#include <Adafruit_GPS.h>
#include <SoftwareSerial.h>
#include <SPI.h>
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include <SdFat.h>

/***************************************************************************/

#define GPSECHO true
#define SD_CS    10 

/***************************************************************************/

SoftwareSerial mySerial( 8,7 );
Adafruit_GPS GPS(&mySerial);

/***************************************************************************/

boolean usingInterrupt = false;

/***************************************************************************/

SdFat SD;
File logfile;

/***************************************************************************/

LiquidCrystal_I2C lcd(0x20,20,4);

/***************************************************************************/

void setup() {
  if ( GPSECHO ) { Serial.begin(115200); }
  
  /***************************************************************************/
  
  lcd.init();
  lcd.print(F("GPS Tracker"));
  lcd.backlight();
  lcd.setCursor(0,1);
  
  /***************************************************************************/
  pinMode(SD_CS, OUTPUT);
  if (!SD.begin(SD_CS)) {
    if ( GPSECHO ) { Serial.println(F("SD card failed!")); }
    lcd.print(F("SD .. failed!"));
    return;
  }
  if ( GPSECHO ) { Serial.println(F("SD card ... success")); }
  lcd.print(F("SD card ... success"));
  
  /***************************************************************************/
  
  GPS.begin(9600);                                
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);
  GPS.sendCommand(PMTK_API_SET_FIX_CTL_1HZ);
  GPS.sendCommand(PGCMD_ANTENNA);            
  useInterrupt(true);                            

  /***************************************************************************/

  lcd.setCursor(0,3);
  lcd.print(F("www.mauroalfieri.it"));
  
  /***************************************************************************/

  delay(3000);
  lcd.clear();

  /***************************************************************************/
}

/***************************************************************************/

// Interrupt is called once a millisecond, looks for any new GPS data, 
// and stores it
SIGNAL(TIMER0_COMPA_vect) {
  char c = GPS.read();
  // if you want to debug, this is a good time to do it!
  if (GPSECHO ) { if (c) UDR0 = c; }
}

void useInterrupt(boolean v) {
  if (v) {
    // Timer0 is already used for millis() - we'll just interrupt somewhere
    // in the middle and call the "Compare A" function above
    OCR0A = 0xAF;
    TIMSK0 |= _BV(OCIE0A);
    usingInterrupt = true;
  } else {
    // do not call the interrupt function COMPA anymore
    TIMSK0 &= ~_BV(OCIE0A);
    usingInterrupt = false;
  }
}

/***************************************************************************/

void loop() {
  if (GPS.newNMEAreceived()) {
    char *stringptr = GPS.lastNMEA();
    char *str;

    char *data;
    char *ora;
    char *longitude;
    char *longitudeC;
    char *latitude;
    char *latitudeC;
    
    byte counter = 0;
    boolean ctrl = false;
      
    if (!GPS.parse(stringptr))  return;

    if (strstr(stringptr, "RMC") || strstr(stringptr, "GGA")) {  
      /***************************************************************************/
      
      logfile = SD.open("dati.log", FILE_WRITE);
      if (logfile) { logfile.println( stringptr ); logfile.close(); }
      
      /***************************************************************************/
      
      if ( GPSECHO ) { Serial.print( stringptr ); }

      counter = 0;
      while ((str = strtok_r(stringptr, ",", &stringptr)) != NULL) {
        if ( counter == 2 && strstr(str, "A") ) ctrl = true;
        
        if ( counter == 1 ) { ora = str; }
        if ( counter == 3 ) { latitude = str;   }
        if ( counter == 4 ) { latitudeC = str;  }
        if ( counter == 5 ) { longitude = str;  }
        if ( counter == 6 ) { longitudeC = str; }
        if ( counter == 9 ) { data = str; }
        counter++;
      }

      if ( ctrl && data != "" && ora != "" && longitude != "" && 
           latitude != "" && longitudeC != "" && latitudeC != "") {
        if ( GPSECHO ) { 
          Serial.print( F("\nScrivo:\n") );
          Serial.print( F("data:") );    Serial.println( data );
          Serial.print( F("ora: ") );    Serial.println( ora );
          Serial.print( F("long:") );    Serial.println( longitude );
          Serial.print( F("lat: ") );    Serial.println( latitude );
          Serial.print( F("lonC:") );    Serial.println( longitudeC );
          Serial.print( F("latC:") );    Serial.println( latitudeC );
          Serial.println( F(" --- --- --- ") );  
        }
        
        lcd.clear();
        lcd.setCursor(0,0);   lcd.print( data[0] );
        lcd.setCursor(1,0);   lcd.print( data[1] );
        lcd.setCursor(2,0);   lcd.print( F("/") );
        
        lcd.setCursor(3,0);   lcd.print( data[2] );
        lcd.setCursor(4,0);   lcd.print( data[3] );
        lcd.setCursor(5,0);   lcd.print( F("/") );
        
        lcd.setCursor(6,0);   lcd.print( F("20") );
        lcd.setCursor(8,0);   lcd.print( data[4] );
        lcd.setCursor(9,0);   lcd.print( data[5] );
        
        lcd.setCursor(12,0);  lcd.print( ora[0] );
        lcd.setCursor(13,0);  lcd.print( ora[1] );
        lcd.setCursor(14,0);  lcd.print( F(":") );

        lcd.setCursor(15,0);  lcd.print( ora[2] );
        lcd.setCursor(16,0);  lcd.print( ora[3] );
        lcd.setCursor(17,0);  lcd.print( F(":") );

        lcd.setCursor(18,0);  lcd.print( ora[4] );
        lcd.setCursor(19,0);  lcd.print( ora[5] );

        lcd.setCursor(0,1);   lcd.print( F("lat: ") );
        lcd.setCursor(6,1);   lcd.print( latitude );
        lcd.setCursor(19,1);  lcd.print( latitudeC );

        lcd.setCursor(0,2);   lcd.print( F("lng: ") ); 
        lcd.setCursor(6,2);   lcd.print( longitude );
        lcd.setCursor(19,2);  lcd.print( longitudeC );
        
        lcd.setCursor(0,3);   lcd.print( F("www.mauroalfieri.it") );
        
      } else {
        lcd.clear();
        lcd.setCursor(0,1);   lcd.print( F("lat: ") );
        lcd.setCursor(6,1);   lcd.print( F("0000.000000  ") );
        lcd.setCursor(0,2);   lcd.print( F("lng: ") );
        lcd.setCursor(6,2);   lcd.print( F("0000.000000  ") );
      }
    }
  }
}

Il primo passo, come al solito in questo tipo di progetti è procurarti le librerie necessarie che sono elencate nella prima parte dello sketch dalla linea 001 alla 006: in particolare oltre alla libreria Adafruit_Gps ti occorre anche la SoftwareSerial per comunicare con la gps shield attraverso i pin 7 ed 8 in simulazione seriale. Le altre librerie servono a comunicare con la SD card e con il display i2c;

linee 010-011: definisci una prima costante GPSECHO destinata ad attivare o disattivare il debug seriale verso il Pc, ed una seconda SD_CS che indica il pin di CS usato dalla SD Card per scrivere i dati;

linee 015-016: inizializza un oggetto myserial che apre la comunicazione, simulata, sui pin 7 ed 8 e lo passi come argomento all’oggetto gps inizializato alla linea 016;

linea 020: definisci una variabile di tipo boolean il cui valore servirà a definire se utilizzare o non utilizzare l’interrupt;

linee 024-025: definisci un oggetto SD per la comunicazione con la SD Card ed un oggetto logfile di tipo File che utilizzerai per scrivere le righe di log in un file sulla SD Card;

linea 029: inizializza l’oggetto lcd con cui comunicherai con il display LCD sull’indirizzo 0x20 ( leggi gli articoli sull’I2C scanner per trovare l’indirizzo del tuo display ) da 20 colonne e 4 righe;

linea 034: nella funzione setup se è definita la costante GPSECHO, vedi linea 010, attivi la comunicazione seriale verso il Pc a 115200 baud;

linee 038-041: attiva la comunicazione verso il display LCD e scrivi sulla prima linea “Gps Tracker”, attiva la retroilluminazione del display e posizionati alla riga 1 ossia la riga successiva del display;

linee 044-051: sone le consuete linee necessarie alla libreria SDFat per verificare la presenza di una SD card inserita e prepararsi alla scrittura di un file su di essa;

linee 055-060: definisci la comunicazione con la gps shield a 9600 baud, valore indicato dal costruttore della shield, e invia alcuni comandi per la corretta sincronizzazione dei dati, in particolare:

PMTK_SET_NMEA_OUTPUT_RMCGGA: imposta il tipo di output da parte del GPS in formato NMEA con codifica RMC e GGA ( sul sito Adafruit trovi tutte le definizioni e psecifiche di questo formato )

PMTK_SET_NMEA_UPDATE_1HZ: imposta l’aggiornamento dei dati a 1Hz ossia 1 al secondo;

PMTK_API_SET_FIX_CTL_1HZ: imposta il controllo sulla qualità del dato ricevuto, ossia il fix, ad in 1Hz come per l’update;

PGCMD_ANTENNA: indica al Gps che è presente una antenna esterna e che vuoi utilizzarla per migliorare la ricezione;

infine richiama la funzione useInterrupt passandole il valore true;

linee 064-065: scrivi sulla 4° linea del display “www.mauroalfieri.it”;

linee 069-070: attendi 3 secondi e pulisci il display prima di terminare la funzione setup();

linee 077-097: sono riportate identiche a come impostate dal produttore della shield e contengono la funzione useInterrupt che agisce sui registri del microcontrollore arduino;

linea 102: verifichi che siano arrivati dei dati in formato NMEA nell’oggetto Gps, questo perché l’interrupt si occupa di richiamare i dati dall’antenna Gps con la regolarità che hai impostato nelle linee 055-060 e solo quando i dati sono consistenti diventano disponibili per l’elaborazione;

linea 103: recupera l’ultima ricezione dati dal Gps Tacker arduino e assegnala alla variabile stringptr per le successive elaborazioni;

linee 104-111: definisci altre variabili di tipo char in cui memorizzerai i valori letti dal Gps prima di memorizzarli nella SD e mostrarli a video;

linee 113-114: definisci una variabile di controllo ctrl di tipo boolean ed un contatore che userai tra poco;

linea 116: passa il contenuto ricevuto dal Gps al metodo parse della libreria GPS di Adafruit per verificare ch i dati siano anche sintatticamente corretti, se non lo sono retituisce un false e questo causa il return, ossia l’uscita da questo ciclo loop() per passare ad un successivo;

linea 118: siccome i dati ricevuti nel formato NMEA sono molti ma a te interessano solo quelli di tipo RMC e GGA verifica che in ciascuna stringa ricevuta dal gps ci sia il termine RMC oppure GGA e scarta gli altri valori;

linee 121-122: apri il file “dati.log” e scrivi la linea gps corrente, in particolare nel file troverai sia i dati RMC sia i dati GGA per poterli elaborare successivamente;

linea 126: se definita la costante GPSECHO scrivi sul monitor seriale la stringa ricevuta dal Gps Tracker arduino;

linee 128-139: in questo blocco di linee fai un lavoro molte semplice scomponi la linea ricevuta in singole stringhe ciascuna separata dalla “,” e seguendo lo schema rilasciato da Adafruit ( vedi link in alto ) sul tipo di codifica impari a leggere questa linea tipo:

$GPRMC,194509.000,A,4042.6142,N,07400.4168,W,2.03,221.11,160412,,,A*77

in cui ogni posizione ha un significato preciso: partendo dalla posizione 0 = $GPRMC indica il tipo di messaggio, fino all’ultima posizione. Io ho estratto solo i valori che mi interssa visualizzare sul display ossia le posizioni:

  • 1 – ora
  • 2 – carattere di controllo
  • 3 – latitudine
  • 4 – segno della latitudine ( N o S )
  • 5 – longitudine
  • 6 – segno della longitudine ( E o W )
  • 9 – data corrente da satellite

devo avvisarti subito che l’ora è riferita a Greenwich ossia il meridiamo 0° per cui rispetto a noi che siamo GMT + 1 ( Greenwich + 1 ) l’ora che visualizzi è un ora indietro;

linee 141-142: ho diviso la condizione di if su due linee per comodità, questo if determina se tutte le variabili “data,ora,longitudine,latitudine,ctrl,… ” sono correttamente valorizzate ed è quindi possibile procedere alla visualizzazione dell’informazione sul display;

linee 143-152: se la GPSECHO è definita scrivi sul monitor seriale i valori letti dal Gps ed elaborati alle linee precedenti;

linea 154-186: scrivi sul display i valori letti ed elaborati come visibile in foto:

gps tracker arduino on

linee 189-193: se il gps dovesse perdere il segnale o i dati non dovessero arrivare più in modo consistente il display visualizzerà solo:

lat:  0000.000000
lng: 0000.000000

fino al recupero dei dati Gps corretti; sulla SD Card troverai i valori letti dal Gps anche se non visualizzati dal display.

Prima di inserire un commento, per favore, leggi il regolamento

Permanent link to this article: https://www.mauroalfieri.it/elettronica/gps-tracker-arduino-lo-sketch.html

27 pings

Skip to comment form

  1. […] « Gps Tracker arduino – lo sketch […]

Lascia un commento

Your email address will not be published.

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.