Zuverlässiger GPS-Tracker fürs Auto mit Thinger.io Echtzeit-Karte
Benötigte Bauteile
| Arduino Leonardo | Wichtig: dedizierter Hardware-Serial (Serial1) für GPS | 1 |
| SIM900 Development Board | GSM/GPRS (auch SIM800 kompatibel, ungetestet) | 1 |
| u-blox NEO-6M GPS-Modul | Mit Antenne | 1 |
| GPS-Antenne | Qualität beachten – billige Antennen oft schlechter Empfang | 1 |
| Widerstand 220 Ω | Für Status-LEDs | 2 |
| LED (beliebig) | Power & GPS-Lock Anzeige | 2 |
| Lochrasterplatine 7×5 cm | Für LED-Schaltung (passt in 3D-Gehäuse) | 1 |
| 12 V → 5 V Step-Down Modul | Für Auto-Bordnetz / Zigarettenanzünder | 1 |
| MicroSD-Kartenleser (Adafruit, 5 V tolerant) | SPI-Interface | 1 |
| MicroSD-Karte | FAT32 formatiert | 1 |
Benötigte Werkzeuge
- Lötkolben
Software & Dienste
- Thinger.io (kostenlose IoT-Plattform mit Dashboards & Maps-Widget)
- Arduino IDE + Bibliotheken:
- NeoGPS (Library Manager) – leichtgewichtig, RAM-sparend
- Time (Paul Stoffregen) – Zeitzonen
- PetitFS (greiman/PetitFS) – ultraleichtes FAT-Dateisystem für SD-Karte
Projektfunktionen
- GPS-Koordinaten alle 2 Min per HTTP POST an Thinger.io → Karten-Dashboard.
- SMS-Befehle:
POS(aktuelle/letzte Position + Google Maps Link),GETKM(gefahrene km),RESETKM(Kilometerzähler zurücksetzen). - Software-Odometer: SMS-Erinnerung alle X km (z. B. 4000 km → Ölnachfüllung).
- Datenlogging auf SD-Karte (PetitFS) – persistenter Kilometerstand.
Warum Arduino Leonardo?
Zwei serielle Schnittstellen nötig: Hardware-Serial (Serial1) für GPS (9600 Baud), Software-Serial für SIM900 (Pins 8/9). Uno hätte nur einen Hardware-Serial – GPS müsste zum Flashen abgeklemmt werden, kein Debug-Monitor.
Bibliotheks-Konfiguration
NeoGPS einrichten
Datei GPSport.h im NeoGPS-Installationsordner komplett ersetzen:
#ifndef GPSport_h
#define GPSport_h
#define gpsPort Serial1
#define GPS_PORT_NAME "Serial1"
#define DEBUG_PORT Serial
#endif
Bei anderen Boards (Mega: Serial2/Serial3) hier anpassen.
PetitFS einrichten
Datei pffArduino.h: SD_CS_PIN auf 10 setzen (SPI SS).
Datei pffconf.h: Folgende Optionen deaktivieren (0 setzen) für kleinere Binary:
- _USE_DIR
- _USE_LSEEK
- _FS_FAT12
- _FS_FAT16
Erster Kompilierfehler (fehlender Return-Typ in pff.cpp) ignorieren oder FRESULT als Return-Typ ergänzen.
SD-Karte vorbereiten
- Als FAT32 formatieren (offizielles „SD Card Formatter“ Tool).
- Dateien
dist.txt(Startwert Kilometer, z. B. „0“) undsettings.txt(Trigger-Distanz in Metern, z. B. „4000000“) auf Karte kopieren. Exakt die mitgelieferten Referenzdateien nutzen – PetitFS ist pingelig bei Format/Länge. - Test: Sketch starten, Serial Monitor prüfen – Kilometerstand & Trigger werden gelesen.
SIM900 vorbereiten
- Externe Stromversorgung: ≥2 A bei 5–9 V (DC-Buchse 5,5 mm). Arduino reicht nicht (Spitzen bis 2 A).
- Power Selector: Jumper auf „External“.
- Serial Selector: Jumpers auf „Software Serial“ (Pins 7/8 am SIM900 Board → Arduino 8/9).
- Software Power-On: Jumper R13 verlöten → SIM900 Pin 9 an Arduino Pin 7. Funktion
SIM900power()im Code. - SIM-Karte: PIN-Sperre deaktivieren (im Handy).
- Firmware ≥ B10 zwingend! Ältere Versionen unterstützen
AT+HTTPPARA="CONTENT","application/json"nicht → HTTP 400. Prüfen mitAT+CGMR. Update-Anleitung: „SIM900 firmware update ACOPTEX“.
Code-Anpassungen (vor Upload)
- APN: In
connectGPRS()„TeleXXX“ durch Provider-APN ersetzen. - Thinger.io URL & Auth-Key: In
postDataThinger()eigene Device-URL & Authorization-Header eintragen. Wichtig: „https://“ → „https://“ ändern (SIM900 kein SSL). - Zeitzone:
#define UTC_OFFSET 1(z. B. UTC+1 für MEZ). - SMS-Benachrichtigung: Text & Trigger-Distanz in
settings.txt/ Code anpassen (oder deaktivieren). - Standard-Telefonnummer:
#define DEFAULT_NUMBER "+49..."für Odometer-SMS. - Serial-Wait:
while(!Serial);imsetup()nur für Debug am PC aktivieren – bei Standalone-Betrieb auskommentieren!
Thinger.io Integration
- Account erstellen → „Bucket“ anlegen (Datenbank).
- „HTTP Device“ anlegen (Doku: thinger.io HTTP Devices).
- Device Callback → Settings: „Write Bucket“ auf eigenen Bucket zeigen.
- Callback Overview: Method URL & Authorization Header (ohne „Bearer“) notieren.
- Im Code: URL & Key in
postDataThinger()einsetzen. Kurzgerätenamen wählen (langer Name → langer Key → Pufferüberlauf >256 Byte). - Erfolg: Serial Monitor zeigt
+HTTPACTION: 1,200,0. - Dashboard: Maps-Widget mit Bucket als Datenquelle.
Zusätzliche Daten an Thinger senden
Im sprintf(httpContent, ...) weitere Felder im JSON ergänzen: {"longitude":%s,"latitude":%s,"date":"%s %s","speed":%s,...}. Exakte Bytezahl in AT+HTTPDATA=len,10000 anpassen.
3D-Gehäuse
- STL-Dateien: Front (hoch/flach), Rückseite, SIM900-Halterungen.
- M3-Schrauben für Montage.
- Obere Schale: GPS-Modul + LED-Platine (7×5 cm Lochraster). Kleine Distanzhalter nutzen.
- Untere Schale: SIM900 + Arduino Leonardo (Aussparungen für USB, Antenne, SIM).
- Montagelöcher in Oberteil geschlossen → nach Druck 3 mm aufbohren (supportlos druckbar).
- Druck: 0,2 mm Layer, Brim, keine Supports (außer Front: „Touch Buildplate Only“).
Stromversorgung im Auto
Anschluss an „Zigarettenanzünder“-Stromkreis (schaltet mit Zündung) – Gerät läuft nur bei laufendem Auto. Für Diebstahlschutz (Tracker auch bei ausgeschaltetem Auto) Direktanschluss an Batterie + Puffer-Akku. Step-Down (12 V → 5 V, 2× USB) versorgt Arduino & SIM900. Verbrauch ca. 110 mA (GSM aktiv), mehr bei schlechtem Empfang.
Bekannte Probleme
- SMS-Kommando während HTTP-POST an Thinger → wird nicht verarbeitet (keine Antwort). Einfach wenige Sekunden später wiederholen.
- Kein Auto-Reconnect bei Netzausfall beim Start – Gerät verbindet nur im
setup(). Workaround: Watchdog-Reset oder periodischer Reconnect inloop()nachrüsten.
Code (Haupt-Sketch: GPS_tracker_Leonardo_v2.ino)
#include <SoftwareSerial.h>
#include <NMEAGPS.h>
#include <GPSport.h>
#include <TimeLib.h>
#include "PF.h"
#include "PetitSerial.h"
#define UTC_OFFSET 1
#define TXPin 8
#define RXPin 9
#define PWRPin 7
#define DEFAULT_NUMBER "+49123456789"
FATFS fs;
String textMessage, number = DEFAULT_NUMBER;
char sms_msg[160];
float Lat = 0, Long = 0;
boolean valid_location = false;
uint8_t num_sat;
NeoGPS::Location_t prevFix;
NMEAGPS gps;
gps_fix fix;
const char *googlePrefix = "https://maps.google.com/maps?q=";
const char *filename = "DIST.TXT";
const char *settings = "SETTINGS.TXT";
NeoGPS::time_t timeFix;
char datePrint[13], timePrint[10];
float totalDistance = 0;
float triggerDistance = 4000000;
SoftwareSerial SIM900(TXPin, RXPin);
void setup() {
pinMode(3, OUTPUT); pinMode(4, OUTPUT);
digitalWrite(3, HIGH); // Power LED
Serial.begin(9600);
// while (!Serial); // Nur für Debug!
SIM900.begin(9600);
gpsPort.begin(9600);
initializeSD();
SIM900power();
SIM900.println(F("AT")); delay(500); updateSIM900();
SIM900.println(F("AT+CMGF=1")); delay(500); updateSIM900();
SIM900.println(F("AT+CNMI=1,2,0,0,0")); delay(500); updateSIM900();
connectGPRS();
}
void loop() {
while (gps.available(gpsPort)) {
fix = gps.read();
num_sat = fix.satellites;
if (fix.valid.location) {
digitalWrite(4, HIGH); // GPS Lock LED
Lat = fix.latitude(); Long = fix.longitude();
if (Lat != 0 && Long != 0 && !valid_location) {
valid_location = true; prevFix = fix.location;
}
}
if (fix.valid.date && fix.valid.time) {
timeFix = fix.dateTime; updateTime();
}
if (valid_location) {
// Distanz-Update alle 15 s
static const unsigned long REFRESH_INTERVAL_UPD = 15000;
static unsigned long lastRefreshTime = millis();
if (millis() - lastRefreshTime >= REFRESH_INTERVAL_UPD) {
lastRefreshTime += REFRESH_INTERVAL_UPD;
float distanceDelta = prevFix.DistanceKm(fix.location) * 1000;
if (distanceDelta > 10 && distanceDelta < 10000) totalDistance += distanceDelta;
prevFix = fix.location;
}
// SD-Schreiben & Thinger-Upload alle 2 Min
static const unsigned long REFRESH_INTERVAL_WRITE_SD = 120000UL;
static unsigned long lastRefreshTimeWriteSD = millis();
if (millis() - lastRefreshTimeWriteSD >= REFRESH_INTERVAL_WRITE_SD) {
lastRefreshTimeWriteSD += REFRESH_INTERVAL_WRITE_SD;
char buf[9]; dtostrf(totalDistance, 8, 0, buf);
if (PF.open(filename)) Serial.println(F("error open file"));
while (1) {
UINT nr;
if (PF.writeFile(buf, sizeof(buf), &nr)) Serial.println(F("error write file"));
if (nr == sizeof(buf)) { PF.writeFile(0, 0, &nr); break; }
}
// HTTP POST an Thinger
char httpContent[60], tempstrLong[10], tempstrLat[10];
dtostrf(Lat, 2, 6, tempstrLat); dtostrf(Long, 2, 6, tempstrLong);
sprintf(httpContent, "{\"longitude\":%s,\"latitude\":%s,\"date\":\"%s %s\"}", tempstrLong, tempstrLat, datePrint, timePrint);
char httpdataLen[20]; sprintf(httpdataLen, "AT+HTTPDATA=%i,10000", strlen(httpContent));
postDataThinger(httpdataLen, httpContent);
}
}
}
// Odometer-Trigger SMS
if (totalDistance > triggerDistance) {
char distanceTotalMsg[10];
itoa((totalDistance / 1000), distanceTotalMsg, 10);
sprintf(sms_msg, "Empty catchtank! Current distance: %skm", distanceTotalMsg);
textMessage = ""; number = DEFAULT_NUMBER; totalDistance = 0;
sendSMS(sms_msg);
}
updateSerial();
}
// ... Hilfsfunktionen: updateSerial(), SIM900power(), updateSIM900(), extractSenderNumber(),
// sendSMS(), connectGPRS(), postDataThinger(), initializeSD(), updateTime() ...
// (Vollständiger Code im Original-Projekt)
Dateien im Projekt
GPS_tracker_Leonardo_v2.ino– Hauptsketchdist.txt/settings.txt– Referenzdateien für SD-Karte- STL-Dateien für Gehäuse (4 Teile)
- Schaltplan (PNG)
Herstellungsprozess
- Bügelbrett-Fertigung: Design, Materialien und Produktionsprozess
- Surfboard-Konstruktion und Design: Von polynesischen Wurzeln zur modernen Innovation
- Outdoor GPS Asset Tracking: Trends, Challenges, Emerging Technologies
- Raspberry Pi stellt RP2040 MCU und 4-Dollar Pico Board vor
- Sensordaten in Raspberry Pi integrieren: GPS & MPU-9150 Hands-On Guide
- PSoC 6 Pioneer Board mit IoT Add-On Shield meistern: Entwickler-Leitfaden
- COVID-19-Medikamenten-Repurposing mit BIOVIA Living Map beschleunigen
- Pythons map()-Funktion meistern: Syntax, Beispiele und Best Practices
- Interne Integrationssysteme nutzen für Präzisionsfertigung
- Risiken des Fahrens mit zu niedrigem Kühlmittelstand