LoRaWAN UDP Packet Forwarder 1
17.12.2024
Elektronik | Funk | Software
Der Technik-Blog
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).
Teil 2: LoRaWAN Registrierung und Payload Encoder/Decoder
ESP32 im Arduino IDE installieren
LILYGO ESP32 LoRa GPS Board (V1.1)
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.
Achtung: Von diesem Board existieren mehrere Versionen mit unterschiedlichen Pin-Belegungen. Das Pin-Mapping muss möglicherweise vor dem Upload angepasst werden.
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.
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.
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:
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]) : ""; }
Hinweis: Einige Module liefern keinen GPGGA-Datensatz, sondern einen GNGGA-Datensatz. In einigen fällen muss der Beispielcode daher entsprechend angepasst werden.
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.
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:
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 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; }
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.
Mit dem Flash Download Tool können fertig exportierte Programme (.BIN Datei) auf den ESP32/ESP8266 ohne Arduino IDE geladen werden
WeiterlesenDas SIM800 ist ein geniales GSM/GPRS Modul. In diesem Artikel geht es um die Inbetriebnahme und Verdrahtung vom SIM800 mit dem Arduino und dem ESP32 (TTGO)
WeiterlesenAEQ-WEB © 2015-2024 All Right Reserved