preloader

Auf AEQ-WEB Suchen

AEQ-WEB | Blog

Lilygo TTGO ESP32 NEO6 GPS Board

ESP32 TTGO GPS Inbetriebnahme

Das TTGO GPS Board ist ein sehr umfangreiches Development Board und hat neben dem UBLOX NEO-6M GPS Modul auch ein LoRa-Modul verbaut. Auf der Rückseite befindet sich ein Batteriehalter für eine 18650-Zelle (Li-Ion Akku), der einen portablen Betrieb ermöglicht. Außerdem kann der Akku auch gleich direkt über USB geladen werden. Als Mikrocontroller kommt ein üblicher ESP32 zum Einsatz. Durch die Kombination von LoRa, GPS und dank des Batteriehalters kann aus diesem Board mit etwas Software ein genialer und vor allem auch sehr günstiger LoRaWAN GPS-Tracker gebaut werden. In diesem Artikel geht es um die Hardwareübersicht und Inbetriebnahme des GPS-Moduls sowie um die Umwandlung der Koordinaten von Grad und Minuten in Dezimalgrad (LAT, LON).

Das Lilygo Board

Im Gegensatz zu bekannten TTGO-Boards ist dieses Board deutlich größer. Grund dafür ist nicht nur der große Batteriesockel, sondern auch die vielen Komponenten, die auf diesem Board verbaut sind. Neben zahlreichen ICs für SRAM, EEPROM, UART befindet sich ein Li-Ion Power Controller (AXP192) auf diesem Board. Über diesen Controller wird die Batterie geladen und die Energieversorgung für Komponenten wie ESP32, GPS und LoRa gesteuert. Mit dem Powermanagement kann der Energieverbrauch für die LoRa Node so optimiert werden, dass ein Batteriebetrieb von Monaten bis hin zu Jahren möglich ist. Außerdem befinden sich noch ein User-Button und eine frei programmierbare LED am Board. Die Reichweite von LoRa ist zufriedenstellend und kann mit einer anderen Antenne verbessert werden.

Lilygo TTGO ESP32 LoRa GPS Board

Achtung: Von diesem Board existieren mehrere Versionen mit unterschiedlichen Pin-Belegungen. Das Pin-Mapping muss möglicherweise vor dem Upload angepasst werden.


Das GPS Modul

Als GPS-Empfänger ist das Ublox NEO-6M GPS Modul verbaut. Im Auslieferungszustand ist das Modul so konfiguriert, dass die aktuelle Position über eine serielle Schnittstelle im NMEA-0183 Format ausgegeben wird. Neben den Koordinaten bekommt man noch zahlreiche weitere Informationen wie z. B. die aktuelle Uhrzeit, Datum, Anzahl aktiver Satelliten bzw. Signalqualität oder auch die Höhe über den Meeresspiegel in Metern. Am GPS-Modul befindet sich zudem eine rote LED, welche bei GPS-Fix anfängt zu blinken. UBLOX stellt eine umfangreiche Software bereit, mit der über UART sämtliche Parameter und Einstellungen geändert werden können. In der Regel ist dies aber nicht notwendig, da die voreingestellte Konfiguration ausreichend ist. Im Auslieferungszustand liegt die eingestellte Baud-Rate bei 9600. Das Aktualisierungsintervall beträgt in etwa eine Sekunde.

GPS-Daten seriell lesen

Mehrmals pro Sekunde werden aktuelle Positionsdaten in verschiedenen NMEA 0183 Datensätzen über die serielle Schnittstelle gesendet. Am ESP32 wird daher eine serielle Schnittstelle (Hardware Serial) geöffnet, welche die Daten vom GPS-Modul entgegennimmt. Achtung: Die Pinbelegung vom GPS-Modul kann je nach TTGO Modell und Version variieren. Man findet diese Angabe direkt auf der Leiterplatte. Das folgende Codebeispiel leitet empfangene Datensätze an den Serial Monitor weiter.

//More information at: https://www.aeq-web.com/

#define SERIAL1_RX 34 // GPS_TX -> 34
#define SERIAL1_TX 12 // 12 -> GPS_RX

void setup(){
  Serial.begin(115200);
  Serial.println("TTGO GPS TEST");
  delay(2000);
  Serial1.begin(9600, SERIAL_8N1, SERIAL1_RX, SERIAL1_TX);
}

void loop() {
  if (Serial1.available()) {
    Serial.write(Serial1.read());
    Serial1.println();
  }
}

Der folgende Screenshot zeigt die Ausgabe der NMEA-Datensätze im Serial Monitor bei GPS-Empfang. Der rot markierte Datensatz beginnend mit "$GPGAA,..." enthält neben Datum, Uhrzeit und Höhe auch die Positionsdaten in Gard und Minuten sowie die Ausrichtung (Nord, Süd & West, Ost). Aus diesem Datensatz werden in weiterer Folge die einzelnen Parameter generiert.

ESP32 TTGO GPS LoRa Serial Monitor NMEA Position

NMEA-0183 Datensatz zerlegen

Mehrmals pro Sekunde werden verschiedene NMEA-Datensätze vom Modul an den ESP32 gesendet. In den einzelnen Datensätzen befinden sich verschiedene Parameter. Es ist ausreichend, wenn die Zeile beginnend mit "$GPGGA,.." für die Positionsbestimmung herangezogenen wird. Jeder Parameter in dieser Zeile wird mit einem Beistrich (",") beendet. Es ist daher notwendig, eine Software zu entwickeln, welche die einzelnen Parameter aus dem Datensatz herausfiltert. Die folgende Grafik zeigt die Aufteilung wichtiger Werte eines einzelnen NMEA-Datensatzes:

NMEA 0183 GGA Sentence UBLOX NEO 6 GPS

Der folgende Beispielcode holt sich die einzelnen Parameter aus dem GPGGA-Datensatz:

//More information at: https://www.aeq-web.com/

#define SERIAL1_RX 34 // GPS_TX -> 34
#define SERIAL1_TX 12 // 12 -> GPS_RX
String read_sentence;

void setup() {
  Serial.begin(115200);
  Serial.println("TTGO GPS TEST");
  delay(2000);
  Serial1.begin(9600, SERIAL_8N1, SERIAL1_RX, SERIAL1_TX);
}

void loop() {
  read_sentence = Serial1.readStringUntil(13); //13 = return (ASCII)
  read_sentence.trim();

  if (read_sentence.startsWith("$GPGGA")) {
    String gps_lat = sentence_sep(read_sentence, 2); //Latitude in degrees & minutes
    String gps_lon = sentence_sep(read_sentence, 4); //Longitude in degrees & minutes
    String gps_sat = sentence_sep(read_sentence, 7);
    String gps_hgt = sentence_sep(read_sentence, 9);
    String gps_lat_o = sentence_sep(read_sentence, 3); //Orientation (N or S)
    String gps_lon_o = sentence_sep(read_sentence, 5); //Orientation (E or W)

    Serial.print("LAT: ");
    Serial.print(gps_lat);
    Serial.print(" LON: ");
    Serial.print(gps_lon);
    Serial.print(" HEIGHT: ");
    Serial.print(gps_hgt);
    Serial.print(" SAT: ");
    Serial.println(gps_sat);
  }
}

String sentence_sep(String input, int index) {
  int finder = 0;
  int strIndex[] = { 0, -1 };
  int maxIndex = input.length() - 1;

  for (int i = 0; i <= maxIndex && finder <= index; i++) {
    if (input.charAt(i) == ',' || i == maxIndex) {  //',' = separator
      finder++;
      strIndex[0] = strIndex[1] + 1;
      strIndex[1] = (i == maxIndex) ? i + 1 : i;
    }
  }
  
  return finder > index ? input.substring(strIndex[0], strIndex[1]) : "";
}

Jede NMEA-Zeile wird mit einem Return-Zeichen beendet. Daher wird in der ersten Zeile vom Loop jeder Datensatz eingelesen bis zum Return, was im ASCII-Code der Zahl 13 entspricht. Gleichzeitig wird diese Zeile in einen String konvertiert und zwischengespeichert. Anschließend wird die zuvor zwischengespeicherte Zeile eingelesen und überprüft, ob diese mit "$GPGAA" beginnt. Ist dies der Fall, so handelt es sich um die richtige Zeile mit den gewünschten Parametern. Anschließend werden die einzelnen Parameter aus der Zeile herauskopiert. Dies geschieht über die String-Funktion "sentence_sep()". Dieser Funktion wird beim Aufruf jedes Mal der komplette Datensatz übergeben sowie die gewünschte Stelle, von welcher der Parameter heraussortiert werden soll. Wie in der oberen Grafik zu sehen, liegt der Breitengrad beispielsweise an der zweiten Stelle (von Null ausgehend). Die Separator-Funktion liest den Text zwischen dem zweiten und dritten Komma und gibt alle Werte in diesem Bereich über ein Return zurück. Anschließend wird ein String mit dem jeweiligen Wert erstellt und über den seriellen Monitor ausgegeben.

Hinweis: Grundsätzlich sollten Zahlenwerte nicht als String gespeichert werden. Damit Nachkommastellen und eventuell vorhandene Nullen vor einer Zahl nicht verschwinden, wird vorerst auf eine Datentyp-Optimierung verzichtet.

ESP32 TTGO NEO6M GPS Decoded LAT LON Coordinates

Umrechnung der Koordinaten

Das GPS Modul gibt die Koordinaten in Grad und Minuten(GM) aus, sowie die Ausrichtung. Bei den meisten Systemen und Anwendungen wie etwa Google Maps werden Koordinaten im Dezimalgrad (LAT, LON) angegeben. Die folgende Grafik zeigt, wie Koordinaten vom GM in Dezimalgrad umgerechnet werden. Als Rechenbeispiel wurden die Koordinaten vom Berliner Fernsehturm genommen:

NEMA 0183 Convert Degree Minute to Decimal Degree

Die Gradzahl bleibt unverändert und wird nach Umrechnung der Minuten zum Dezimalgrad addiert. Die darauffolgenden Minuten inklusive Kommastelle werden durch 60 dividiert. Daraus ergibt sich ein sehr kleiner Wert, der anschließend mit dem Grad addiert wird. Als Ergebnis erhält man den jeweiligen Dezimalgrad. Ist die Ausrichtung vom Breitengrad südlich bzw. vom Längengrad westlich, so ist das Ergebnis eine negative Zahl. Die folgende Methode zeigt die Umrechnung von Grad-Minuten in den Dezimalgrad:

float convert_gps_coord(float deg_min, String orientation) {
  double gps_min = fmod((double)deg_min, 100.0);
  int gps_deg = deg_min / 100;
  double dec_deg = gps_deg + ( gps_min / 60 );
  if (orientation == "W" || orientation == "S") {
    dec_deg = 0 - dec_deg;
  }
  return dec_deg;
}

Die Float-Methode konvertiert Grad-Minuten vom NMEA-Format in den Dezimalgrad. Die Methode benötigt dazu die Koordinate und deren Ausrichtung. Über die Modulo-Funktion (fmod) werden die Minuten von Grad-Minuten getrennt. Die Variable "gps_deg" ist als Integer deklariert. Werden damit die Grad-Minuten durch 100 dividiert, erhält man den Grad ohne Kommastellen. Anschließend werden die Minuten (gps_min) durch 60 dividiert und zum Grad (gps_deg) addiert. Im letzten Schritt wird die Ausrichtung der Koordinate überprüft. Ist diese westlich oder südlich, so wird das Ergebnis negiert. Die Methode gibt als Return die umgerechnete Koordinate zurück.

Der vollständige Sketch

Der folgende Sketch liest die seriell empfangenen NMEA Datensätze aus und generiert daraus die einzelnen Parameter. Anschließend werden die Koordinaten von Grad-Minuten in den Dezimalgrad umgerechnet, sodass diese einheitlich von einem anderen System gelesen werden können:

//More information at: https://www.aeq-web.com/

#define SERIAL1_RX 34 // GPS_TX -> 34
#define SERIAL1_TX 12 // 12 -> GPS_RX
String read_sentence;

void setup() {
  Serial.begin(115200);
  Serial.println("TTGO GPS TEST");
  delay(2000);
  Serial1.begin(9600, SERIAL_8N1, SERIAL1_RX, SERIAL1_TX);
}

void loop() {
  read_sentence = Serial1.readStringUntil(13); //13 = return (ASCII)
  read_sentence.trim();

  if (read_sentence.startsWith("$GPGGA")) {
    String gps_lat = sentence_sep(read_sentence, 2); //Latitude in degrees & minutes
    String gps_lon = sentence_sep(read_sentence, 4); //Longitude in degrees & minutes
    String gps_sat = sentence_sep(read_sentence, 7);
    String gps_hgt = sentence_sep(read_sentence, 9);
    String gps_lat_o = sentence_sep(read_sentence, 3);  //Orientation (N or S)
    String gps_lon_o = sentence_sep(read_sentence, 5); //Orientation (E or W)

    Serial.print("LAT: ");
    Serial.print(gps_lat);
    Serial.print(" LON: ");
    Serial.print(gps_lon);
    Serial.print(" HEIGHT: ");
    Serial.print(gps_hgt);
    Serial.print(" SAT: ");
    Serial.println(gps_sat);

    float latitude = convert_gps_coord(gps_lat.toFloat(), gps_lat_o);
    float longitude = convert_gps_coord(gps_lon.toFloat(), gps_lon_o);

    Serial.print(latitude, 6);
    Serial.print(",");
    Serial.println(longitude, 6);
  }
}

String sentence_sep(String input, int index) {
  int finder = 0;
  int strIndex[] = { 0, -1 };
  int maxIndex = input.length() - 1;

  for (int i = 0; i <= maxIndex && finder <= index; i++) {
    if (input.charAt(i) == ',' || i == maxIndex) {  //',' = separator
      finder++;
      strIndex[0] = strIndex[1] + 1;
      strIndex[1] = (i == maxIndex) ? i + 1 : i;
    }
  }
  return finder > index ? input.substring(strIndex[0], strIndex[1]) : "";
}

float convert_gps_coord(float deg_min, String orientation) {
  double gps_min = fmod((double)deg_min, 100.0);
  int gps_deg = deg_min / 100;
  double dec_deg = gps_deg + ( gps_min / 60 );
  if (orientation == "W" || orientation == "S") {
    dec_deg = 0 - dec_deg;
  }
  return dec_deg;
}

Der LoRaWAN GPS-Tracker

Im nächsten Artikel geht es weiter mit der Inbetriebnahme von LoRa. Basierend auf diesen Beispielcode wird die aktuelle GPS-Position über LoRaWAN ausgesendet. Im Things Network wie TTN, TTS oder ähnlichen stehen die Positionsdaten für die weitere Verarbeitung in der gewünschten Applikation bereit.


Share:
thumbnail
08.06.2018
ESP32 WiFi Webserver

In diesem Artikel zeigen wir, wie mit dem ESP32 ein Webserver im lokalen Netzwerk erstellt wird und wie weitere WLAN-Netzwerke gescannt werden

Alex @ AEQ-WEB
thumbnail
25.03.2019
NodeMCU & ESP HTTPS Request

In diesem Artikel zeigen wir, wie ein einfacher HTTPS Post/GET Request über eine SSL-Verbindung mit einem NodeMCU Board oder einem ESP8266 gemacht wird.

Alex @ AEQ-WEB