Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Manufacturing Technology >> Herstellungsprozess

Auto-GPS-Tracker mit Kartenintegration von thinger.io

Komponenten und Verbrauchsmaterialien

Arduino Leonardo
Verwenden von Leonardo, um eine dedizierte Hardware-Seriennummer zu erhalten.
× 1
SIM900-Entwicklungsboard
× 1
u-blox NEO-6M GPS-Modul
× 1
Antenne, GPS
× 1
Widerstand 220 Ohm
× 2
LED (generisch)
× 2
Lötplatte 7 x 5cm
Ich habe eine Lötplatine verwendet, die in das 3D-gedruckte Gehäuse für die Status-LEDs "Schaltung" passt. Sie können jedoch ein beliebiges allgemeines Steckbrett verwenden oder es ganz überspringen, wenn Sie keine Status-LEDs möchten
× 1
12V bis 5V Abwärtsmodul
Zum Anschluss des Netzteils an die Autobatterie (oder Zigarettenbuchse)
× 1
Adafruit SD-Kartenleser
× 1
Flash-Speicherkarte, MicroSD-Karte
× 1

Notwendige Werkzeuge und Maschinen

Lötkolben (generisch)

Apps und Onlinedienste

Thinger.io-Plattform
Ein kostenloser IoT-Dienst mit Dashboards!

Über dieses Projekt

Dieses Projekt begann als einfache „GPS-Tracker-Idee“ und es stellte sich heraus, dass es sich um einen „Mehrzweck-GPS-Tracker“ handelte. Als mein erstes Projekt war die Lernkurve steil und daher bin ich immer offen für Input, Feedback und Verbesserungen am Design! :)

Der Tracker soll in meinem Auto platziert werden und hat die folgenden Funktionen:

  • Verfolgen Sie die GPS-Koordinaten und posten Sie alle 2 Minuten den letzten bekannten Standort auf dem thinger.io IoT-Cloud-Dashboard (auf einer Karte angezeigt). Posten auf thinger.io mit HTTP POST-Anfragen.
  • Antwortet auf SMS-Befehle und gibt einen Google Map-Link zum aktuellen oder letzten bekannten Standort zurück (letzter bekannter Standort, wenn kein aktueller Standort verfügbar ist).
  • Sende alle XX Kilometer eine SMS-Benachrichtigung (die Idee ist, dass mich der Tracker alle 4000km daran erinnert, meinen Ölauffangtank zu leeren). Dies funktioniert als anpassbarer Software-"Kilometerzähler".

Während dieses Projekts wurde mir schnell klar, wie "begrenzt" das Arduino in Bezug auf den verfügbaren Speicher ist, und ich musste Techniken lernen, um den Overhead zu reduzieren und effizienten Code zu erstellen (zumindest habe ich es versucht). Ich habe auch leichte Bibliotheken verwendet, um alles auf dem Chip und verfügbaren RAM unterzubringen.

Die verwendeten Komponenten sind wie folgt (wie in der Komponentenliste):

  • NEO-6M GPS-Gerät. Dies scheint ein sehr beliebtes GPS-Gerät zu sein, das bei Ebay und ähnlich günstig erhältlich ist. Die Kommunikation mit GPS erfolgt hardware-seriell.
  • GPS-Antenne. Irgendein kompatibles geht, aber ich fand, dass die billigsten von Ebay nicht so gut funktionierten, d.h. schlechter Empfang / niedrige Satellitenanzahl. Vielleicht hatte ich mit der ersten Antenne nur Pech, aber für einen stabilen Empfang musste ich mir eine andere mit besserer Qualität zulegen.
  • SIM900-Entwicklungsboard für GSM- und GPRS-Konnektivität. Dieses Projekt sollte auch mit SIM800- und kompatiblen Modulen funktionieren, jedoch ohne Gewähr. Die Kommunikation mit SIM900 erfolgt softwareseriell.
  • ArduinoLeonardo Gremium. Ich habe das Leonardo-Board verwendet, um eine dedizierte serielle Hardwareleitung zu haben da wir zwei serielle Leitungen brauchen. Es ist zwar möglich, auch ein normales UNO-Board zu verwenden, aber Sie müssen das GPS trennen, um die Software herunterzuladen, und Sie haben auch keinen seriellen Monitor zum Debuggen. Wir benötigen zwei serielle Leitungen (eine für GPS und eine für das SIM900-Board); eine Software-Serie und eine Hardware-Serie.
  • SD-Kartenleser (Ich habe den Adafruit-Kartenleser verwendet, der 5V-kompatibel ist (die Verbindung zum 5V-SPI-Header war einfach). Andere billigere Module könnten genauso gut funktionieren. Micro-SD-Karte wird verwendet, um die zurückgelegte Distanz zu speichern. Warnung: Stellen Sie sicher, dass Ihr SD-Kartenleser eine 5-V-Versorgung unterstützt, wenn Sie meinen Schaltplänen folgen. Viele SD-Kartenleser verwenden nur 3,3 V. Die Verwendung falscher Spannungspegel wird höchstwahrscheinlich die Elektronik beschädigen. Die Kommunikation mit dem SD-Kartenleser erfolgt über die SPI-Schnittstelle.
  • LEDs und Widerstände zur Herstellung von Statusanzeigeschaltungen (Strom- und GPS-Sperr-LED).
  • SIM-Karte mit Daten.
  • Ich habe auch ein 3D-druckbares Gehäuse mit angehängten STL-Dateien entworfen, das direkt auf einem 3D-Drucker gedruckt werden kann.

Zuerst müssen wir die notwendigen Bibliotheken installieren. Ich habe die folgenden Bibliotheken für dieses Projekt verwendet:

  • NeoGPS für GPS-Tracking und -Dekodierung. Kann direkt aus dem Bibliotheksmanager in der Arduino IDE installiert werden. Weitere Informationen:https://github.com/SlashDevin/NeoGPS
  • Zeit Bibliothek (wird für die UTC-Zeitzonenkonvertierung verwendet):https://github.com/PaulStoffregen/Time
  • PetitFS zum Lesen/Schreiben auf SD-Karte:https://github.com/greiman/PetitFS Leichte SD-FAT-Bibliothek.

Warum nicht die verfügbare Bibliothek für Arduino von . verwenden? thinger.io?

Obwohl die von thinger.io bereitgestellte Bibliothek sehr einfach zu bedienen ist und die Dinge erheblich vereinfachen würde, um nicht zu sagen, dass sie bereits in die IDE integriert ist, verbraucht sie fast 80% des Speichers auf dem Arduino Leo und lässt wenig bis keinen Platz für den restlichen Code. Es ist also einfach zu groß für dieses Projekt und wir müssen es auf die harte Tour machen. Für die Kommunikation mit der thinger.io Cloud verwenden wir HTTP POST-Anfragen.

SMS Befehle

Die verfügbaren Befehle für SMS sind wie folgt (alle Großbuchstaben). Dies sind die unterstützten Befehle im bereitgestellten Code; Sie können Befehle für Ihr eigenes Projekt / Ihre Anforderungen hinzufügen / entfernen:

  • "POS" gibt die Koordinaten mit dem Google Maps-Link zurück, wenn Koordinaten verfügbar sind. Andernfalls wird der letzte bekannte Standort zurückgegeben.
  • "GETKM" gibt die aktuelle Distanz seit dem letzten "Zurücksetzen" zurück.
  • "RESETKM" setzt den Distanzzähler auf 0 (Kilometerzähler zurücksetzen).
>>

NeoGPS einrichten

Wir verwenden die NeoGPS-Bibliothek für Leistung und Ressourcennutzung gegenüber Alternativen wie TinyGPS++. Es verbraucht sehr wenig RAM, und das wird benötigt; andernfalls erhalten wir Warnungen wegen Speichermangel und Stabilität.

Ändern Sie nach der Installation der Bibliothek die Datei GPSPort.h im Installationspfad der Bibliothek (Beispiel für OS X - für Windows finden Sie die Bibliothek an einem anderen Ort)

Ersetzen Sie alle Inhalte in GPSPort.h durch Folgendes:

#ifndef GPSport_h#define GPSport_h#define gpsPort Serial1#define GPS_PORT_NAME "Serial1"#define DEBUG_PORT Serial#endif 

Diese Datei enthält Definitionen, die von der NeoGPS-Bibliothek verwendet werden. Wenn Sie ein anderes Arduino-Board verwenden, definieren Sie hier die serielle Leitung zum GPS-Empfänger, z. "Serial2", "Serial3" für Arduino MEGA.

Hinweise zur Genauigkeit

Beachten Sie, dass GPS nicht die genaueste Methode zur Messung und Akkumulierung von Entfernungen ist, da die Position auch im Stillstand leicht driftet. Sie können dies testen, indem Sie an derselben Stelle stillstehen und beobachten, dass die GPS-Koordinaten bei jeder Messung anders sind. Bei dieser Anwendung ist die Genauigkeit weniger wichtig und daher sind kleinere Abweichungen in Ordnung.

Ich habe jedoch versucht, kleine Koordinatenabweichungen zu berücksichtigen, und die Software fügt die Distanz nur für Bewegungen über 10 m (alle Bewegungen unter 10 m werden stationär angenommen) über 15 Sekunden hinzu.

Denken Sie auch daran, dass die Entfernung in einer geraden Linie berechnet wird, während die tatsächliche Entfernung, die das Auto zurücklegt, von der Straße, Kurven usw. abhängt. Ich habe die Abtastrate auf 15 Sekunden eingestellt, Sie können diese jedoch verringern, wenn Sie höher möchten Genauigkeit.

PetitFS einrichten

Diese Bibliothek ist eine superleichte Bibliothek zum Lesen/Schreiben auf SD-Karten im FAT-Format. Ich habe einige Zeit gebraucht, um herauszufinden, wie das funktioniert, da die Dokumentation so gut wie nicht existiert und an manchen Stellen sogar falsch / veraltet ist. Der bereitgestellte Beispielcode für die Bibliothek wird nicht einmal kompiliert. Es kommt mit einer Menge von Einschränkungen (im Gegensatz zu einer "normalen" Bibliothek wie Arduinos SD-Bibliothek oder SDFat):

  • Datei kann nicht erstellt werden. Es kann nur in eine vorhandene Datei geschrieben werden.
  • Dateigröße kann nicht erweitert werden.
  • Der Zeitstempel der Datei kann nicht aktualisiert werden.
  • Kann keine Daten an die Datei anhängen (schreibt die Datei jedes Mal neu).
  • Es ist immer nur eine Datei geöffnet.

Warum eine kleine und begrenzte Bibliothek mit vielen Macken verwenden?

Größe, im Grunde. Ich habe einige Bibliotheken ausprobiert, darunter die Arduino SD Library, SDFat und auch fat16lib. Sie sind alle zu groß, um den gesamten Code auf den Chip zu passen. Um die Funktionalität nicht zu entfernen, habe ich diese Bibliothek verwendet (die Standard-Arduino-SD-Bibliothek benötigt ungefähr 12% mehr Speicherplatz). Trotz aller Macken und Einschränkungen bietet es immer noch das, was wir für diese Anwendung brauchen:einfaches Lesen und Schreiben eines einzigen Wertes zum Speichern.

Wenn Sie nicht den gesamten Code verwenden und genügend Platz vorhanden ist, um etwas mehr einzufügen, ist es viel einfacher, mit Bibliotheken wie der Standard-SD-Bibliothek zu arbeiten.

Öffne die Datei pffArduino.h aus dem PetitFS-Bibliotheksordner. Ändern Sie die SD_CS_PIN bis 10. Dies ist der SS-Pin, der für die Kommunikation mit der SD-Karte mit SPI verwendet wird.

Öffne die Datei pffconf.h aus dem Bibliotheksordner. Deaktivieren folgende Optionen durch Umschalten des eingestellten Wertes von 1 auf 0:

  • _USE_DIR
  • _USE_LSEEK
  • _FS_FAT12
  • _FS_FAT16

Durch das Deaktivieren dieser Optionen benötigt das kompilierte Programm weniger Speicherplatz - der benötigt wird; Die endgültige Skizze dauert ca. 96 % des Speicherplatzes.

Beim ersten Import der Bibliothek erhalten Sie einen Kompilierungsfehler, der * ignoriert* werden kann (bei der zweiten Kompilierung wird der Fehler nicht angezeigt - verstehe immer noch nicht warum). Wenn Sie dies jedoch beheben möchten (es wird jedes Mal wieder angezeigt, wenn Sie Arduino IDE starten -> Kompilieren), fügen Sie den fehlenden Funktionsrückgabeparameter "FRESULT" wie im obigen Screenshot gezeigt hinzu. Dies ist in der Datei pff.cpp im Bibliotheksordner.

Ich habe mein Bestes gegeben, um herauszufinden, wie diese Bibliothek funktioniert, und obwohl ich alles zum Laufen habe, bin ich mir ziemlich sicher, dass die Dinge auch verbessert werden können. Wenn Sie Fehler oder Verbesserungen in den von mir geschriebenen Routinen finden, können Sie diese gerne mitteilen! Ich würde sehr gerne lernen und mehr Erfahrung sammeln.

Bereiten Sie die SD-Karte vor

Ich habe für dieses Projekt eine Micro-SD-Karte verwendet. Da die Bibliothek die Datei(en) nicht selbst erstellen kann, ist es wichtig, vor der Verwendung die Dateien "dist.txt" und "settings.txt" auf der Karte zu erstellen. Ich empfehle die beigefügten "dist.txt" und "settings.txt" zu kopieren Datei von dieser Projektseite, da diese Dateien bereits das richtige Format haben und funktionieren (die Bibliothek ist sehr wählerisch bei Textformat und Inhalt).

Bevor Sie die Datei auf die Micro-SD-Karte legen, formatieren Sie die Karte richtig (als FAT32). ). Ich empfehle die Verwendung des offiziellen "SD Card Formatter" der SD Association:https://www.sdcard.org/downloads/formatter/.

Sicherstellen, dass die SD-Karte funktioniert (korrektes Lesen/Schreiben der Datei)

Die PetitFS-Bibliothek ist sehr wählerisch bei den Eingabedateien. Wenn Sie das Gerät booten und keine Ausgabe im seriellen Monitor angezeigt wird (nur leer), bleibt es höchstwahrscheinlich in der "Schleife" hängen, in der es versucht, die Datei von der Karte zu lesen, aber aus irgendeinem Grund nicht (Funktion initializeSD()). Ich hatte unzählige Textdateien, die aus irgendeinem Grund nicht gelesen werden konnten, daher habe ich die referenzierten Textdateien eingefügt, die ich verwendet habe und die funktionieren. Platzieren Sie diese Referenz Dateien auf der SD-Karte und sie sollte in der Lage sein, sie richtig zu lesen und richtig darauf zu schreiben.

Eine andere Möglichkeit besteht darin, die Textdatei mit einer größeren Zahl zu füllen als die, die es geschrieben hat. Ich habe dies nicht getestet, aber da die Bibliothek die Dateigröße selbst nicht erweitern kann, gehe ich davon aus, dass dies ein Problem sein könnte.

PetitFS schreibt die gesamte Länge des Zeichenarrays in die Datei, daher werden vor der tatsächlichen Zahl Leerzeichen angezeigt (es sei denn, die Zahl ist groß genug, um das Array zu füllen - die Länge des "Arrays" ist im Code definiert). Diese Leerzeichen müssen bei Änderungen an der Datei eingehalten werden - da PetitFS keine Änderungen der Dateigröße vornehmen kann, kann es zu Problemen kommen, wenn die Anzahl der Zeichen geändert wird.

Setzen Sie die Datei „dist.txt“ auf „0“, wenn der Kilometerzähler bei „0“ beginnen soll, oder auf eine andere Zahl, um die Funktionsfähigkeit zu überprüfen, z. Senden des Befehls "GETKM" zur Überprüfung der SMS-Antwort.

In "settings.txt" stellen Sie die Benachrichtigungsauslösedistanz ein, die Distanz, bei der der Kilometerzähler die Benachrichtigungs-SMS auslöst (in Metern).

Bereiten Sie die SIM900-Karte vor

Ein paar Dinge müssen auf dem SIM900 Board eingerichtet werden, bevor wir es verwenden können. Für Details gibt es eine großartige Ressource unter https://lastminuteengineers.com/sim900-gsm-shield-arduino-tutorial/ für die Einrichtung dieses Boards.

Stromquelle

Das Arduino-Board kann nicht genügend Strom liefern, daher müssen wir ein externes Netzteil verwenden. Da Spikes bis zu 2A ziehen können, stellen Sie sicher, dass Sie ein Netzteil verwenden, das mindestens 2A bei 5V-9V DC liefern kann; Es verwendet den 5,5-mm-Stecker.

Stromquellenauswahl

Neben der DC-Buchse befindet sich ein Stromquellenwähler . Um eine externe Stromquelle zu verwenden, bewegen Sie den Schieberegler wie im Bild oben gezeigt.

Serienauswahl

Stellen Sie das Board so ein, dass es Software Serial verwendet indem Sie die Jumper wie oben gezeigt ausrichten.

Software-Trigger

Anstatt jedes Mal die Power-Taste manuell zu drücken, können Sie die SIM900 in der Software ein- und ausschalten. Dazu muss der Jumper mit der Bezeichnung R13 angelötet werden. Das Board wird dann eingeschaltet, indem der SIM900-Pin # 9 mit dem Arduino-Pin # 7 verbunden wird (wie in den Schaltplänen gezeigt).

Wenn die Funktionalität "manuelles Einschalten" beibehalten wird, kann die Funktion "SIM900power()" im Code entfernt werden.

PIN-Sperre der SIM-Karte entfernen

Achten Sie darauf, die PIN-Sperre zu entfernen auf der SIM-Karte vor der Verwendung. Dies können Sie tun, indem Sie es in ein normales Telefon einlegen und die PIN-Sperre aus dem entsprechenden Einstellungsmenü entfernen.

Beachten Sie auch, dass das SIM900-Modul in den Schaltplänen möglicherweise anders aussieht als die tatsächliche Platine, aber das Pin-Layout ist korrekt, was der wichtigste Teil ist.

SIM900-Firmwareversion (Wichtig!)

Es ist sehr wichtig, dass die richtige Version der Firmware auf dem Chip geladen ist. Dies liegt daran, dass einer der Befehle zum korrekten Einrichten des HTTP-POST-Headers erst ab Version B10 der Firmware unterstützt wird. Das bedeutet, dass Sie mindestens die Version B10 oder höher benötigen, damit die http-Kommunikation funktioniert. Insbesondere mit einer niedrigeren Firmware-Version wird es nicht möglich sein, "Inhaltstyp" im http-Header einzustellen. Wenn der Inhaltstyp in der Post-Anfrage nicht auf "application/json" gesetzt ist, wird er vom Server abgelehnt.

Um Ihre Firmware-Version zu überprüfen, verwenden Sie den folgenden AT-Befehl:

AT+CGMR 

Der SIM900-Chip gibt Ihnen dann die aktuelle Firmware-Version in der Ausgabekonsole aus. Fügen Sie Folgendes am Ende des Abschnitts setup() ein, um die Firmware-Version beim Start zu drucken:

SIM900.println(F("AT+CGMR"));  

In meinem Fall würde es dies zeigen (bevor ich aktualisiert habe):

Revision:1137B01SIM900M64_ST_AM 

Dies war die älteste mögliche Firmware-Version für diesen Chip ("B01"), daher habe ich auf Version B10 aktualisiert:1137B10SIM900M64_ST . Neuere Firmwares sollten auch funktionieren.

Ich werde in dieser Anleitung nicht darauf eingehen, wie man die Firmware aktualisiert, es gibt bereits eine ausgezeichnete Anleitung dazu:SIM900 Firmware-Update - ACOPTEX (wenn auch ein etwas mühsamer Prozess).

Ich weiß nicht, ob dies bei anderen Chips wie dem SIM800 der Fall sein wird, aber da es sich um einen neueren Chip handelt, würde ich sagen, dass es wahrscheinlicher ist, dass dieser dort bereits vorhanden ist.

Code-Anpassungen

Um den Code für Ihr eigenes Projekt anzupassen, sind einige Anpassungen erforderlich:

  • Ändern Sie die APN-Informationen (Netzwerkanbieter).
  • Ändern Sie die URL von thinger.io so, dass sie mit Ihrer eigenen übereinstimmt (die URL verknüpft die Update-Anfrage mit Ihrem eigenen "Bucket" mit Zugriffstoken). Dies wird im Kapitel "Thinger.io-Integration" behandelt.
  • Stellen Sie die richtige Zeitzone ein.
  • Auslösedistanz für SMS-Benachrichtigung festlegen
  • Setzen (oder deaktivieren) Sie den SMS-Benachrichtigungstext.
  • Standardtelefonnummer für Benachrichtigungen festlegen.

APN-Anbieter

void connectGPRS(){... SIM900.println( F("AT+SAPBR=3,1,\"APN\",\"TeleXXX\"") ); Verzögerung (1000); updateSIM900();... 

Unter connectGPRS() Funktion finden Sie den APN-Namen Ihres Netzanbieters, oben als "TeleXXX". . angezeigt Ersetzen Sie dies durch Ihren eigenen APN-Namen.

ATOKAT+CMGF=1OKAT+CNMI=1,2,0,0,0OKAT+SAPBR=3,1,"CONTYPE","GPRS"OKAT+SAPBR=3,1,"APN"," TeleXXX"OKAT+SAPBR=1,1OKAT+SAPBR=2,1+SAPBR:1,1,"36.57.240.233"OK  

Oben:Ausgabe der Funktion connectGPRS(), wenn die Verbindung funktioniert. Alle Befehle sollten den Status "OK" zurückgeben.

Zeitzone

#define UTC_OFFSET 1 // Zeitzonen-Offset setzen, d.h. 1 =UTC+1 

Stellen Sie im Abschnitt "Definieren" die Zeitzone nach Ihren Wünschen ein. Der Code ist auf UTC+1 eingestellt .

SMS-Benachrichtigung

Ich habe alle 4000km eine Benachrichtigung eingerichtet, um meinen Ölauffangtank zu leeren. Da mir klar ist, dass die meisten Leute keinen Ölauffangtank haben, sollte diese Benachrichtigung dann nach Belieben geändert (oder ganz deaktiviert) werden.

void loop() {... // sendet eine Benachrichtigung per SMS, wenn die Gesamtstrecke 4000km überschreitet if (totalDistance> triggerDistance) { char sms_msg[160]; ZeichenabstandTotalMsg[10]; itoa( (totalDistance / 1000) , distanceTotalMsg, 10); sprintf(sms_msg, "Catchtank leeren! Aktuelle Entfernung:%skm", distanceTotalMsg); textMessage =""; Gesamtdistanz =0; // legt die Standardtelefonnummer zum Auslösen der Benachrichtigungsnummer fest =DEFAULT_NUMBER; sendSMS(sms_msg); } ...} 

Oben:Codeabschnitt, der eine Benachrichtigung auslöst (innerhalb der Hauptschleife()).

Kommentieren Sie diesen Abschnitt aus / entfernen Sie ihn, wenn Sie keine ausgelösten Benachrichtigungen wünschen. Ändern Sie alternativ den Text in etwas Nützliches.

Die Benachrichtigung wird ausgelöst, sobald der "Kilometerzähler" (kumulierte Distanz) die konfigurierte Distanz erreicht, die in der Datei "settings.txt" eingestellt ist.

Standardtelefonnummer

Dies ist die Telefonnummer, an die die ausgelöste Benachrichtigung gesendet wird (da die Benachrichtigung keine "Absender"-Nummer zum Antworten hat)

// Telefonnummer für ausgelöste Benachrichtigung#define DEFAULT_NUMBER "+4712345678"  

Auf serielle Verbindung warten

Es ist auch eine gute Idee, die folgende Zeile im Code zu entkommentieren. Dadurch wartet das Arduino-Board darauf, dass die serielle Verbindung aktiv wird, d. h. der serielle Monitor zum Debuggen. Auf diese Weise verpassen Sie keine Debug-Meldungen am Anfang des Codes, bevor die serielle Leitung aktiv wird.

Denken Sie daran, die Leitung zu entfernen / zu kommentieren, bevor Sie das Arduino von externen Stromquellen mit Strom versorgen, da es sonst in einer Endlosschleife anhält, bis es mit einem PC verbunden ist.

 // while (!Serial); // warten, bis der serielle Port eine Verbindung herstellt - für ATmega32u4 (Leonardo) 

Thinger.io-Integration

Ich werde nicht ins Detail gehen, wie man thinger.io einrichtet, da es ziemlich einfach ist; Sie müssen ein Konto und einen "Bucket" erstellen, um die Daten über ihre Website zu erhalten, sowie ein "Gerät", mit dem wir eine Verbindung herstellen. Ein "Bucket" ist die Datenbank zum Empfangen von Daten. Das "Gerät" ist der Verbindungspunkt für unseren Code, an dem wir entscheiden, was mit den Daten zu tun ist (in unserem Fall die "Bucket"-Datenbank auffüllen).

Erstellen Sie wie oben gezeigt einen "Eimer" mit Ihrem eigenen Namen und Ihrer Beschreibung.

Erstellen Sie nun ein "HTTP-Gerät", wie in der offiziellen Dokumentation beschrieben:https://docs.thinger.io/quick-sart/devices/http-devices.

Verwenden Sie eine kurze Gerät Name . Da der Gerätename Teil des Algorithmus ist, der den Autorisierungsschlüssel generiert, habe ich festgestellt, dass ein längerer Gerätename auch einen längeren Autorisierungsschlüssel generiert. Das Problem? Der Autorisierungsschlüssel wurde schnell länger als der 256-Zeichen-Puffer, der zum Senden der Zeichenfolge von Arduino verwendet wurde. Es gibt wahrscheinlich einige bessere Möglichkeiten, dies zu beheben, aber ich fand den einfachsten Ansatz, den Gerätenamen kurz zu halten und das Problem zu vermeiden.

Im Rückruf des Geräts > Einstellungen Stellen Sie sicher, dass die Einstellung "Bucket schreiben" auf den zuvor erstellten Bucket zeigt. Dies weist das "Gerät" an, eingehende Daten in unsere Datenbank zu schreiben.

Im Rückruf des Geräts > Übersicht Merken Sie sich die Methode URL und Autorisierungsheader (langer String ohne das Schlüsselwort "Bearer").

Um Daten an ein thinger.io zu senden, verwenden wir eine "Autorisierungs-URL" in der HTTP POST-Anfrage. Sie müssen dann die URL und den Autorisierungsschlüssel im Code durch Ihre eigenen ersetzen.

Im postDataThinger() Funktion finden Sie den Anruf (eigentlich verschlüsselter Berechtigungsschlüssel):

SIM900.println( F("AT+HTTPPARA=\"URL\",\"http://backend.thinger.io/v3/users/tom/devices/CT/callback/data?authorization =eyJhbGciOiJIUzI1NiIsInR5cdfkjowiuerdf.sdfsdf.wekrjciI6InRvcm1vZCJ9.AR1gWvIZB9KmtI-5Z12YXKuchPTGn58AkwBJSZQIoxQ\" .") ); 

Sie müssen dann die URL ersetzen und Autorisierung Schlüssel im Code mit Ihrem eigenen, der durch Befolgen der Anweisungen im obigen Link generiert wird.

http://backend.thinger.io/... 

Die generierte Autorisierungs-URL lautet standardmäßig https . Die SIM900 nicht Unterstützung SSL (zumindest habe ich es nicht zum Laufen gebracht), also ändere "https ://" bis "http://". Die Ding-API unterstützt auch Nicht-SSL-Verbindungen. Dies ist sehr wichtig. Wenn Sie "https" beibehalten, wird es nicht funktionieren. Wenn alles funktioniert, sollte der serielle Monitor ein "200 - OK" antworten Sie beim Senden der HTTP-Post-Anfrage.

Nach dem AT-Befehl "AT+HTTPACTION=1" (HTTP-POST-Anfrage senden) Sie sollten eine Antwort wie diese im seriellen Monitor erhalten:

+HTTPACTION:1.200,0 

Wenn Sie eine "400 - ungültige Anfrage"-Antwort oder ähnliches erhalten..

+HTTPACTION:0,400,51  

..mit der URL stimmt höchstwahrscheinlich etwas nicht, z.B. "https" statt "http", falsche Syntax des "Autorisierungsschlüssels" usw. Wenn Sie eine "200 - OK"-Nachricht erhalten, sollten die Daten wie unten gezeigt im Ding-Bucket angezeigt werden. Sie können auch eine 400 - "schlechte Anfrage" erhalten, wenn Sie nicht die richtige Firmware haben, wie zuvor erwähnt.

Oben ist eine Ansicht des Buckets, sobald die Daten eintreffen (aus Datenschutzgründen verschlüsselt). Der Inhalt (Datenspalten) wird durch die HTTP-POST-Anforderungssyntax im Code festgelegt, es ist keine Einrichtung bei thinger.io erforderlich.

Unten sehen Sie eine serielle Ausgabe der HTTP POST-Anforderung, wie sie aussehen sollte, wenn alles funktioniert. +HTTPACTION:1, 200, 0 zeigt an, dass das Update erfolgreich war.

AT+HTTPINITOKAT+HTTPPARA="CID",1OKAT+HTTPPARA="URL","OKAT+HTTPPARA="CONTENT","application/json"OKAT+HTTPDATA=84,10000DOWNLOADOKAT+HTTPACTION=1OK+ HTTPACTION:1,200,0AT+HTTPTERMOK  

Das Dashboard kann dann einfach bei thinger mit dem Karten-Widget eingerichtet werden, indem der Bucket als Datenquelle verwendet wird.

Mehr Daten?

Möchten Sie mehr Daten als Längengrad, Breitengrad und Datum/Uhrzeit übertragen? Fügen Sie einfach wie unten gezeigt weitere Datenfelder zur http-Anfrage hinzu.

Das Format ist { "field1 name" :field1, "field2 name" :field2, "field3 name" :field3 }

sprintf(httpContent, "{ \"longitude\" :%s , \"latitude\" :%s , \"date\" :\"%s %s\" }", tempstrLong, tempstrLat , Datum1, Uhrzeit1); 

Der obige sprintf-Befehl kompiliert den an thinger gesendeten Datenstring. Die Syntax ist *sehr* streng und Sie müssen auf genau dieselbe Weise neue Datenfelder hinzufügen. Beispiel ist im Code (Kommentarabschnitt) angegeben. Eine gute Idee ist es, sich den seriellen Monitordruck des Befehls zu notieren, der die Zeichenfolge anzeigt. Dann fügst du "field4" hinzu und so weiter..

Gehäuse

Ich habe ein komplettes 3D-druckbares Gehäuse beigefügt. Es ist so konzipiert, dass es genau auf die PCBs passt, die für dieses Projekt verwendet werden. Zur Montage werden M3-Schrauben verwendet.

Es ist für eine 7x5cm Lötplatine für die LED-"Schaltung" ausgelegt und nicht für ein Steckbrett. Wenn Sie ein Steckbrett verwenden, verwenden Sie stattdessen einfach etwas Kleber. Im oberen Gehäuse ist die GPS- und Lötplatine ("Breadboard") montiert. Verwenden Sie kleine Abstandshalter für eine optimale Montage der Leiterplatten im oberen Gehäuse.

Ich habe auch die Befestigungspunkte im oberen Gehäuse fest gehalten (keine Löcher), um das Drucken ohne Stützen zu erleichtern. Öffnen Sie diese mit einem 3mm Bohrer.

Es druckt gut auf 0,2 mm ohne Stützen.

Anschluss an Autobatterie / Stromquelle

Es gibt wahrscheinlich Hunderte von Möglichkeiten, dies zu tun, daher habe ich nicht die einzige oder beste Antwort in dieser Hinsicht; how to wire it up to the car battery. It all depends on your application, but I'll quickly describe my solution.

I wanted the device to start with the car, hence not connected directly to the battery (and drawing power while the car is turned off). So I've connected it to the "cigarette socket" circuit that is already turning on/off with the car. If you want it to be online even when the car is off, you'll have to find a way to wire it to the battery. For most cars the cigarette socket turns off with the car, but you'll have to check this for your own. I will not show the exact wiring for mine as this will also be different for every car. You can also place a battery pack in between to keep the device going for hours after the car has been switched off (or stolen..).

You can of course also just use an adapter, like one of those USB phone chargers, but that defeats my purpose of hiding it (in case the car gets stolen). We also have two power sources, the Arduino board and the SIM900 module. I used a "China cheap-o matic" step-down module, that converts from 12V-5V (the actual input range was said to be 9V-20V). It's probably not good quality, but has been working ok so far :)

The step-down module transforms the 12V input to 5V output to two USB female connectors. I then connected the Arduino- and SIM900 module to each of these USB outputs to power them. There are probably other and more "professional" solutions, but this was cheap and worked well enough.

I have measured the power draw during GSM activity to around 110maH, so very little power consumption. It will probably draw more power in areas with poor GSM coverage.

Known issues

If an SMS command is received at the same time as the thinger.io http request is processed (while data is being pushed to thinger) the command will not be picked up by the software. In this case, you will not receive a SMS reply. Send a new command some seconds later and it will work again. I've not made a workaround for this, as its not a big problem. If someone should make a fix for this, please feel free to share.

Also, if the Arduino is started in an area without network coverage, it won't reconnect when the network is available again, as it only connects during startup. I might modify the code at some point to fix this, but at the moment it

Code

  • GPS_tracker_Leonardo_v2.ino
GPS_tracker_Leonardo_v2.inoArduino
#include #include #include #include #include "PF.h"#include "PetitSerial.h"#define UTC_OFFSET 1 // set time zone offset, i.e. 1 =UTC+1#define TXPin 8 // SIM900 Tx pin#define RXPin 9 // SIM900 Rx pin#define PWRPin 7 // SIM900 software power pin// phone number for triggered notification#define DEFAULT_NUMBER "+4712345678"FATFS fs; // file system object - for reading SD card// GSM variablesString textMessage; // holds the last received text messageString number =DEFAULT_NUMBER; // phone number from last text messagechar sms_msg[160]; // holds the SMS reply text// location variablesfloat Lat =0, Long =0;boolean valid_location =false; // initial valid location flaguint8_t num_sat;NeoGPS::Location_t prevFix; // holds previous location for distance calculationNMEAGPS gps; // parses the GPS charactersgps_fix fix; // holds on to the latest valuesconst char *googlePrefix ="http://maps.google.com/maps?q=";const char *filename ="DIST.TXT";const char *settings ="SETTINGS.TXT";// time variablesNeoGPS::time_t timeFix; // time object for current gps fixchar datePrint[13];char timePrint[10];// distance tracking variablesfloat totalDistance =0; // in meters// triggerdistance (odometer notification) is read from SD card on initfloat triggerDistance =4000000;SoftwareSerial SIM900( TXPin, RXPin ); // SIM900 Tx &Rx is connected to Arduino #8 	void setup() { pinMode(3, OUTPUT); pinMode(4, OUTPUT); digitalWrite(3, HIGH); // turn on power LED Serial.begin(9600); // serial monitor /* the "while (!serial)" construct below must only be enabled for debugging purposes when connected to a PC. If this is kept in the code the program will stop in a loop when connected to external power sources, as no serial connection will be established */ // while (!Serial); // wait for serial port to connect - for ATmega32u4 (Leonardo) SIM900.begin(9600); // SIM900 module on pins #8 and #9 gpsPort.begin(9600); // GPS receiver on Serial1 pins #0 and #1 - defined in GPSport.h // initialize the SD card and reads standard setting and accumulated distance initializeSD(); // power up SIM900 with software trigger SIM900power(); SIM900.println( F("AT") ); // Handshaking with SIM900 delay(500); SIM900.println( F("AT+CMGF=1") ); // Configuring TEXT mode delay(500); SIM900.println( F("AT+CNMI=1,2,0,0,0") ); // Decides how newly arrived SMS messages should be handled delay(500); connectGPRS();}void loop() { while (gps.available( gpsPort )) { fix =gps.read(); num_sat =fix.satellites; if (fix.valid.location) { digitalWrite(4, HIGH); // sets GPS lock LED Lat =fix.latitude(); Long =fix.longitude(); // saves the first "GPS lock" flag - we now have useful data if (Lat !=0 &&Long !=0 &&!valid_location) { valid_location =true; prevFix =fix.location; } } if (fix.valid.date &&fix.valid.time) { timeFix =fix.dateTime; updateTime(); } // update thinger.io and write values to SD card only for valid gps fix // typically at startup before gps has locked in coordinates first time if (valid_location) { // updates the distance travelled every 15 seconds static const unsigned long REFRESH_INTERVAL_UPD =15000; // 15 seconds static unsigned long lastRefreshTime =millis(); if (millis() - lastRefreshTime>=REFRESH_INTERVAL_UPD) { lastRefreshTime +=REFRESH_INTERVAL_UPD; // calculates distance between current and previous fix in meters float distanceDelta =prevFix.DistanceKm(fix.location) * 1000; // only update if distance is greater than 10 meters and less than 10km // 10km check is implemented to avoid erroneous data reading from GPS if (distanceDelta> 10 &&distanceDelta <10000) { totalDistance +=distanceDelta; } // reset the calculation point for next loop (set "previous" location) prevFix =fix.location; } // writes distance travelled to SD card every 2 minutes // uploads coordinates to thinger.io every 2 minutes static const unsigned long REFRESH_INTERVAL_WRITE_SD =120000UL; // 2 minutes static unsigned long lastRefreshTimeWriteSD =millis(); if (millis() - lastRefreshTimeWriteSD>=REFRESH_INTERVAL_WRITE_SD) { lastRefreshTimeWriteSD +=REFRESH_INTERVAL_WRITE_SD; // file write to SD card begin 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); // finalize write operation by writing a null pointer break; } } // Petit FS has no "close" operation on file // next section transfers data to thinger.io IoT cloud with HTTP POST request. // only update thinger.io after first successful GPS lock char httpContent[60]; char tempstrLong[10]; char tempstrLat[10]; dtostrf(Lat, 2, 6, tempstrLat); dtostrf(Long, 2, 6, tempstrLong); // data fields to thinger.io bucket. Access to bucket is given through URL authorization in the post function. // format is { "field1 name" :field1 , "field2 name" :field2 , "field3 name" :field3 } with exact byte count. sprintf(httpContent, "{ \"longitude\":%s , \"latitude\":%s , \"date\":\"%s %s\" }", tempstrLong, tempstrLat, datePrint, timePrint); char httpdataLen[20]; // exact byte count for the content must be added to HTTPDATA // otherwise HTTP POST request is invalid, i.e. status 400 is retured. sprintf(httpdataLen, "AT+HTTPDATA=%i,10000", strlen(httpContent)); postDataThinger(httpdataLen, httpContent); } } } // send SMS notification if the total distance exceeds configured limit 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();}void updateSerial(){ // read incoming buffer. reads content of any text message if (SIM900.available()> 0) { textMessage =SIM900.readString(); } if (textMessage.indexOf("POS")>=0) { extractSenderNumber(); textMessage =""; char latPrint[10]; dtostrf(Lat, 5, 6, latPrint); char LonPrint[10]; dtostrf(Long, 5, 6, LonPrint); if (num_sat>=3 &&valid_location) { sprintf(sms_msg, "Current location:Lat:%s, Long:%s. %s%s,+%s\n", latPrint, LonPrint, googlePrefix, latPrint, LonPrint); } else if (num_sat <3 &&valid_location) { sprintf(sms_msg, "No gps fix. Last seen %s%sat:Lat:%s, Long:%s. %s%s,+%s\n", datePrint, timePrint, latPrint, LonPrint, googlePrefix, latPrint, LonPrint); } else if (!valid_location) { sprintf(sms_msg, "Tom not found. Maybe he is in North-Korea?"); } sendSMS(sms_msg); } // returns the current total accumulated distance if (textMessage.indexOf("GETKM")>=0 ) { char sms_msg[32]; char distanceTotalMsg[10]; itoa( (totalDistance / 1000) , distanceTotalMsg, 10); sprintf(sms_msg, "Current distance:%skm", distanceTotalMsg); textMessage =""; sendSMS(sms_msg); } // resets the distance counter to 0 if (textMessage.indexOf("RESETKM")>=0) { totalDistance =0; char sms_msg[] ="Acknowledge:distance reset"; textMessage =""; sendSMS(sms_msg); }}void SIM900power(){ // power up SIM900 board from pin #7 (default) -> 2sec. signal pinMode(PWRPin, OUTPUT); digitalWrite(PWRPin, LOW); Verzögerung (1000); digitalWrite(PWRPin, HIGH); Verzögerung (2000); digitalWrite(PWRPin, LOW); delay(15000); // give module time to boot}void updateSIM900(){ // empty incoming buffer from SIM900 with read() delay(500); while (SIM900.available()) { // outputs buffer to serial monitor if connected Serial.write(SIM900.read()); }}void extractSenderNumber(){ uint8_t startPos =textMessage.indexOf("+", 6); uint8_t endPos =textMessage.indexOf(","); number =textMessage.substring(startPos, endPos - 1);}void sendSMS(char *content){ // really crappy string conversion since I was too lazy to do proper // char handling in the first place. // SMS is returned to the sender number. char numberChar[number.length() + 1]; number.toCharArray(numberChar, number.length() + 1); char cmd_sms[50]; sprintf(cmd_sms, "AT+CMGS=%c%s%c", 0x22, numberChar, 0x22); SIM900.println(cmd_sms); updateSIM900(); SIM900.print(content); updateSIM900(); SIM900.write(0x1A);}void connectGPRS(){ SIM900.println( F("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"") ); Verzögerung (1000); updateSIM900(); SIM900.println( F("AT+SAPBR=3,1,\"APN\",\"TeleXXX\"") ); Verzögerung (1000); updateSIM900(); SIM900.println( F("AT+SAPBR=1,1") ); Verzögerung (1000); updateSIM900(); SIM900.println( F("AT+SAPBR=2,1") ); Verzögerung (1000); updateSIM900();}void postDataThinger(char *httpDataLen, char* content){ SIM900.println( F("AT+HTTPINIT") ); Verzögerung (1000); updateSIM900(); SIM900.println( F("AT+HTTPPARA=\"CID\",1") ); Verzögerung (1000); updateSIM900(); SIM900.println( F("AT+HTTPPARA=\"URL\",\"http://backend.thinger.io/v3/users/tom/devices/CT/callback/data?authorization=eyJhbGciOiJIUzI1NiIsInR5cCI6lskjdflksjdfweruiowe19DVCIsInVzciI6InRvcm1vZCJ9.AR1gWvIZB9KmtI-5Z12YXKuchPTGn58AkwBJSZQIoxQ\"") ); Verzögerung (1000); updateSIM900(); SIM900.println( F("AT+HTTPPARA=\"CONTENT\",\"application/json\"") ); Verzögerung (1000); updateSIM900(); SIM900.println(httpDataLen); Verzögerung (1000); updateSIM900(); SIM900.println(content); Verzögerung (1000); updateSIM900(); SIM900.println( F("AT+HTTPACTION=1") ); Verzögerung (10000); updateSIM900(); SIM900.println( F("AT+HTTPTERM") ); Verzögerung (1000); updateSIM900();}// initialize SD card and retrieves stored distance valuevoid initializeSD(){ // first section read current distance from SD card char buf[10]; // buffer to hold retrieved distance value // Initialize SD card and file system. if (PF.begin(&fs)) Serial.println( F("error begin file") ); // Open file for read - saved accumulated total distance if (PF.open(filename)) Serial.println( F("error open file") ); while (1) { UINT nr; if (PF.readFile(buf, sizeof(buf), &nr)) Serial.println( F("error read file") ); if (nr ==sizeof(buf)) break; } // no close function for Petit FS. // retrieves stored distance value to program totalDistance =atof(buf); // second section read odometer notification trigger value char bufTrigger[10]; // buffer to hold trigger value if (PF.open(settings)) Serial.println( F("error open file") ); while (1) { UINT nr; if (PF.readFile(bufTrigger, sizeof(bufTrigger), &nr)) Serial.println( F("error read file") ); if (nr ==sizeof(bufTrigger)) break; } // retrieves odometer notification value triggerDistance =atof(bufTrigger);}// corrects time object with time zone offsetvoid updateTime(){ // set time from GPS data string setTime(timeFix.hours, timeFix.minutes, timeFix.seconds, timeFix.date, timeFix.month, timeFix.year); // calc current time zone time by offset value adjustTime(UTC_OFFSET * SECS_PER_HOUR); sprintf(datePrint, "%02d/%02d/%04d ", day(), month(), year()); sprintf(timePrint, "%02d:%02d:%02d ", hour(), minute(), second());}

Kundenspezifische Teile und Gehäuse

Top of casing for more space (taller). The mounting holes are closed and must be drilled after print (to make for easier printing)A compact version of the top casing (less space inside enclosure)Bottom part of casing - for SIM900 and Arduino board with cutouts for connectorsLocks SIM900 board in placeLocks SIM900 board in place (no mounting holes on SIM900 board)rename to "dist.txt" and place on SD card dist_1qOG9VMO2D.txtrename to "settings.txt" and place on SD card settings_iMpR6v81OB.txt

Schaltpläne


Herstellungsprozess

  1. Bügelbrett
  2. Surfbrett
  3. Was hat es mit der Outdoor-(GPS-)Asset-Tracking-Technologie auf sich?
  4. Raspberry Pi entwickelt seine eigene MCU zusammen mit einem $4-Board
  5. Integration von Sensordaten mit Raspberry Pi-Mikroprozessor
  6. Verwenden des PSoC 6 Pioneer Boards mit dem Pioneer IoT Add-on Shield
  7. Verwenden Sie sichere Medikamente mit BIOVIA Living Map
  8. Python map() Funktion mit BEISPIELE
  9. Arbeiten mit Inhouse-Integrationssystemen
  10. Was passiert, wenn ich mein Auto mit zu wenig Kühlmittel fahre?