GPS Navigation für Geo-Cacher - [Teil 2]

Hallo und Willkommen einer weiteren Folge unserer neuen GPS-Projektreihe.

Im heutigen Teil machen wir aus unserem GPS Monitor ein waschechtes GPS-Navigationsgerät! Unser „Navi“ kennt zu jeder Zeit, wie auch alle modernen Navigationsgeräte, zwei unterschiedliche Geo-Koordinaten. Dies ist einmal die aktuelle Position [P], ermittelt aus den Moduldaten, und unsere Zielkoordinaten [T]. Aus diesen beiden Werten berechnet unser Navi die Entfernung in km und Meter, sowie die Himmelsrichtung zum Ziel. Diesen beiden Werten reichen aus um damit bis zum Zielpunkt zu navigieren!

Die Zielkoordinaten werden in den Zeilen:

float TargetGpsLAT = 48.85826;  // Coordinates EIFFEL_TOWER in France
float TargetGpsLON = 2.294516;

im Code deklariert. Im Code entsprechen sie den Koordinaten des Eiffelturms in Frankreich. Diese können aber vor dem Hochlanden ganz einfach gegen eigene Koordinaten (zum Beispiel den eigenen Wohnort) ausgetauscht werden. Außerdem können die Ziel Koordinaten jederzeit durch Druck auf den Taster durch die aktuelle Position ersetzt werden. Nützlich ist dies Funktion z. B, wenn der Weg an einen bestimmten Ort zurückgefunden werden muss.

Benötigte Hardware

Wir brauchen für unser Navigationsgerät nur wenige Bauteile:

Anzahl Bauteil Anmerkungen
1 HD44780 2004 LCD Display Bundle 4x20 Zeichen mit I2C Schnittstelle für Arduino
1 NEO-6M GPS Modul
1 Nano V3.0 CH340 Chip fertig verlötet
1 Taster Modul


Der Aufbau 

Alle notwendigen Informationen wie Orts- und Geschwindigkeitsinformationen werden auf einem 4x20 Zeichen Display angezeigt.

Kürzel Bezeichnung Ergänzende Hinweise
A Altitude Höhe über Wasser
Gs Ground Speed Akt. Geschwindigkeit
P Position Aktuelle Position
T Target Position Zielposition
W Geographische Breite Dezimale Schreibweise
L Geographische Länge Dezimale Schreibweise
Dst Distance Abstand zum Zielpunkt
Dir Direction (Himmelsrichtung) Richtung zum Zielpunkt

(Ansicht LCD-Display in Betrieb (fiktive Daten(Daten geändert) )


Auch unser heutiges Projekt benötigt, wie das vorherige auch, zwei zusätzliche Bibliotheken. Die erste Bibliothek, TinyGPS ++ ist eine Arduino-Bibliothek zum Parsen von NMEA-Datenströmen, die von GPS-Modulen bereitgestellt werden. Diese Bibliothek bietet alle Methoden, die wir für unser Projekt benötigen.

So nimmt sie uns beispielsweise die Berechnungsarbeiten zur  Entfernungsbestimmung zwischen aktuellem Ort und Zielort ab und stellt und diese in der Einheit Metern zur weiteren Bearbeitung zur Verfügung. Die Bibliothek TinyGPS++ kann auf GIT Hub heruntergeladen werden: https://github.com/mikalhart/TinyGPSPlus/releases

Die zweite, von unserem Projekt benötigte Bibliothek wird zur Ansteuerung des IC2 LCD-Displays benötigt. Die Bibliothek hört auf den Namen „LiquidCrystal I2C“ und ist von Frank de Brabander. Sie kann direkt über den Bibliotheksverwalter unter dem gefunden und installiert werden:

Wie erweitern die Hardware um einen Taster, der die Zielkoordinaten aus den aktuellen Koordinaten übernimmt. Es kann somit jederzeit der aktuelle Standort aus Zielort übernommen werden.

 

Die Software

Nach Umbau bzw. Ausbau der Hardware kann der aktualisierte bzw. erweiterte Code hochgeladen werden:

// GPS Empänger mit Navigation 2020 Tobias Kuch GPL 3.0
#define SwitchPIN 7
#include <LiquidCrystal_I2C.h>
#include <SoftwareSerial.h>
#include <TinyGPS++.h>
LiquidCrystal_I2C lcd(0x27,20,4);  // set the LCD address to 0x27 for a 20 chars and 4 line display

TinyGPSPlus gps;
SoftwareSerial ss(4, 3);


float TargetGpsLAT = 48.85826;  // Coordinates EIFFEL_TOWER in France
float TargetGpsLON = 2.294516;
bool DistanceInKM = false;
bool Button1Pressed = false;
double Distance = 0;
double courseToT = 0;

void setup()
{
  Serial.begin(9600);
  pinMode(SwitchPIN, INPUT_PULLUP); // Setzt den Digitalpin 13 als Outputpin
  lcd.init();                      // initialize theI2C lcd 
  lcd.backlight();
  lcd.setCursor(0,0);
  lcd.clear(); 
  ss.begin(9600);
  smartdelay(1);
}

void loop()
{
if (gps.altitude.isValid())
    {
    if (gps.altitude.isUpdated()||gps.satellites.isUpdated()||gps.speed.isValid() )
      {  
      lcd.setCursor(0,0);
      lcd.print("A:");
      lcd.print(gps.altitude.meters(),0); // Altitude in meters (double)
      lcd.print("m ");
      lcd.print("Gs:");
      lcd.print(gps.speed.kmph(),1);
      lcd.print("km/h");
      }
    } else
    {
    lcd.setCursor(0,0);
    lcd.print("No valid Data       ");
    }
if (gps.location.isValid())
    {
    if (gps.location.isUpdated())
      {  
      lcd.setCursor(0,1);
      lcd.print("P W:");
      lcd.print(gps.location.lat(), 4); // Raw longitude in whole degrees
      lcd.print(" L:");
      lcd.print(gps.location.lng(), 4); // Raw longitude in whole degrees
      }
    } else
    {
    lcd.setCursor(0,1);
    lcd.print("No valid location   ");
    }

if (TargetGpsLAT < 90 & TargetGpsLON < 180  )
    {
    lcd.setCursor(0,2);
    lcd.print("T W:");
    lcd.print(TargetGpsLAT, 4); // Raw longitude in whole degrees
    lcd.print(" L:");
    lcd.print(TargetGpsLON, 4); // Raw longitude in whole degrees
    } else
    {
    lcd.setCursor(0,2);
    lcd.print("No valid Target     ");
    }

if (gps.location.isValid() & TargetGpsLAT < 90 & TargetGpsLON < 180 )
    { 
      DistanceInKM = false;
      Distance = gps.distanceBetween(gps.location.lat(),gps.location.lng(),TargetGpsLAT,TargetGpsLON);
      courseToT = gps.courseTo(gps.location.lat(),gps.location.lng(),TargetGpsLAT,TargetGpsLON);
      if (Distance > 1000)
        {
        Distance = Distance / 1000;
        DistanceInKM = true;
        }
      lcd.setCursor(0,3);
      lcd.print("Dst:");
      lcd.print(Distance);
      if(DistanceInKM)  {lcd.print("km ");} else { lcd.print("m "); }
      lcd.print("Dir:"); 
      lcd.print(gps.cardinal(courseToT));
    } else
    {
    lcd.setCursor(0,3);
    lcd.print("No valid Way calc.  ");
    }
 
smartdelay(5000);
}

static void smartdelay(unsigned long ms)
{
  unsigned long start = millis();
  do 
  {
    if (!(digitalRead(SwitchPIN)))   // read the input pin
      {
      delay(100);   //debouncing  
      if (!Button1Pressed)
        {
        Button1Pressed = true;
        TargetGpsLAT = gps.location.lat();
        TargetGpsLON = gps.location.lng();
        lcd.setCursor(0,2);
        lcd.print("T W:");
        lcd.print(TargetGpsLAT, 4); // Raw longitude in whole degrees
        lcd.print(" L:");
        lcd.print(TargetGpsLON, 4); // Raw longitude in whole degrees
        } 
      }  else
      {
      Button1Pressed = false;  
      }
      
    while (ss.available())
      gps.encode(ss.read());
  } while (millis() - start < ms);
}

Das Endergebnis

Nach dem Einschalten wird ein angepasster Initialisierungsbildschirm angezeigt:


Nach Empfang eines validen GPS-Signals (blaue LED des GPS Moduls blinkt) werden Geografie und Navigationsinformationen angezeigt. Im nachfolgenden Beispiel (und auch im Code) sind als Zielkoordinaten (Target) die Geodaten des Eiffelturms eingegeben worden (Zeile T). Aus der aktuellen Position (Zeile P) errechnet sich der Abstand (Distance) bis zum Ziel von 492,58 km in Richtung Süden (S).


(fiktive Daten / Daten geändert)

Ich wünsche viel Spaß beim Nachbau. Wie immer findet Ihr alle Projekte unter der GitHub Seite https://github.com/kuchto 

10 Kommentare

Ulrich Engel

Ulrich Engel

Hallo,
sehr schönes Projekt. Lief auf Anhieb. Danke.
Gibt es noch einen Teil3? Wenn ich mir etwas wünschen kann, dann fehlt mir noch ein Kompass (HMC5883L 3-axis-compass modul) im Projekt, der mir anzeigt, wo es hin geht. Dann wüsste ich gleich, in welche Richtung ich starten muss. Vielleicht mit einem LED-Ring als Anzeige der Laufrichtung.
Viele Grüße Ulli

Ulrich Engel

Ulrich Engel

AAHHHH!
Jetzt hat es geklappt.
Man muss auf Prozessor: “ATmega328P(Ols Bootloader”)
umstellen.

Ulrich Engel

Ulrich Engel

Hallo,
ich habe ein Problem beim “Hochladen” des Sketch. Ich arbeite sonst nur mit UNO, MEGA oder ESP. Mit Nano habe ich noch nie gearbeitet.
Das Programm kompiliert fehlerfrei, nur Hochladen endet mit Fehlermeldung:
……………………………..
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 1 of 10: not in sync: resp=0xc6
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 2 of 10: not in sync: resp=0xc6
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 3 of 10: not in sync: resp=0xc6
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 4 of 10: not in sync: resp=0xc6
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 5 of 10: not in sync: resp=0xc6
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 6 of 10: not in sync: resp=0xc6
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 7 of 10: not in sync: resp=0xc6
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 8 of 10: not in sync: resp=0xc6
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 9 of 10: not in sync: resp=0xc6
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 10 of 10: not in sync: resp=0xc6
…………………………………………

Was mache ich falsch? Das Nano-Board habe ich ausgewählt und der angegebene Port ist auch ausgewählt.

Danke für die Hilfe. Bin schon ganz gespannt auf das tolle Projekt.
Viele Grüße

Bernd Albrecht

Bernd Albrecht

@ GeoCacher: Betr. Umrechnung in Bogenminuten: Nachkommastellen mit 60 multiplizieren
@ André Münz: Danke für den Hinweis. Bild des Schaltplans geändert.
@ Jörg Raber: Betr. Genauigkeit des Moduls? Das hängt von verschiedenen Faktoren ab, z.B. Anzahl der Satelliten. Eigene Erfahrungswerte: Lat/Long <10 m, Höhe schlechter
Siehe auch u.a. Link

@ Ralf Kastmann: Betr. 1. Orientierung der Antenne? Ja, mit dem Keramikteil nach oben wie auf den Bildern. 2. Muss die Antenne “freie Sicht” zum Himmel haben? Grundsätzlich ja, da GPS-Frequenzen sehr kurzwellig sind (1.575,42 MHz/1.227,6 MHz). Und je mehr Satelliten aufgefasst werden, umso besser.
Weitere Details finden Sie z.B. auf https://de.wikipedia.org/wiki/Global_Positioning_System

Ralf Kastmann

Ralf Kastmann

Wie man die Koordinaten Geocachertauglich umwandeln kann, hatte ich in einem Kommentar zum 1. Teil veröffentlicht. Schade, dass das im 2. Teil nicht verarbeitet wurde.
Zur Antenne des GPS-Moduls habe ich aber noch eine Frage: Gibt es eine Orientierung dazu? Mit dem Keramikteil nach oben zeigend? Darf die Antenne abgedeckt verbaut werden, oder muss sie “freie Sicht” zum Himmel haben?

Jörg Raber

Jörg Raber

Mit was einer Genauigkeit funktioniert das Modul?

Jean-François TEILHAC

Jean-François TEILHAC

Hello,
There is one line missing, for GPS module NEO 6M, in Geo-Cacher sketch, which is “ss.begin(9600);”.
Regards
JFT

Chris

Chris

Für Geocacher? Nicht wirklich.

Als Geocacher benutzen wir üblicherweise ein anderes Format der Koordinaten. Wie wäre es denn mal, wenn ihr dafür mal noch die korrekte Umrechnung in den Code einbauen würdet.

Grad° Bogenminuten’ mit Dezimalstellen (dies ist das übliche Format beim Geocachen)
Beispiel:
N50° 25.123’
E006° 45.000’

Die Infos findet ihr hier: https://www.cachewiki.de/wiki/Koordinaten

Damit passt dann der Titel auch zu uns Geocachern.

Falls ihr das noch umsetzten solltet, vielen Dank.

Volker Holst

Volker Holst

Schön, um im Wald sein geparktes Fahrzeug wiederzufinden.
Für Geocacher (noch) nicht wirklich nutzbar, da das Koordinatenanzeigeformat für Fahrzeuge, aber nicht für Geocaching üblich ist. Eventuell paßt ja dann auch noch eine Koordinaten-Eingabe per Taster mit in den Speicher, dann wäre es als Geocaching-Tool wirklich nützlich.
Bleibt gesund!

André Münz

André Münz

Kann es sein, dass in der Fritzing Darstellung der I2C Adapter falsch herum verdrahtet ist?
Auf diesem Bild ist der Adapter um 180 Grad gedreht eingezeichnet (PIN 15, 16 verbunden mit PIN 15 und 16 (A, K) des Displays).
https://cdn.shopify.com/s/files/1/1509/1638/files/I2C_Arduino.png?8072112794423721238

Einen Kommentar hinterlassen

Alle Kommentare werden vor der Veröffentlichung moderiert