Fabrication industrielle
Internet des objets industriel | Matériaux industriels | Entretien et réparation d'équipement | Programmation industrielle |
home  MfgRobots >> Fabrication industrielle >  >> Manufacturing Technology >> Processus de fabrication

Traqueur GPS de voiture avec intégration de carte thinger.io

Composants et fournitures

Arduino Leonardo
Utiliser Leonardo pour obtenir une série matérielle dédiée.
× 1
Carte de développement SIM900
× 1
module GPS u-blox NEO-6M
× 1
Antenne, GPS
× 1
Résistance 220 ohm
× 2
LED (générique)
× 2
Panneau à souder 7 x 5cm
J'ai utilisé une carte à souder qui s'adapte au boîtier imprimé en 3D pour le "circuit" des LED d'état. Vous pouvez cependant utiliser n'importe quelle planche à pain générique, ou l'ignorer complètement si vous ne voulez pas de voyants d'état
× 1
Module abaisseur 12V à 5V
Pour connecter l'alimentation à la batterie de la voiture (ou à la prise allume-cigare)
× 1
Lecteur de carte SD Adafruit
× 1
Carte mémoire flash, carte MicroSD
× 1

Outils et machines nécessaires

Fer à souder (générique)

Applications et services en ligne

Plateforme Thinger.io
Un service IoT gratuit avec Dashboards !

À propos de ce projet

Ce projet a commencé comme une simple « idée de traqueur GPS » et il s'est avéré être un « traqueur GPS polyvalent ». En tant que premier projet, la courbe d'apprentissage a été abrupte, et je suis donc toujours ouvert aux commentaires, aux commentaires et aux améliorations sur la conception ! :)

Le tracker est destiné à être placé dans ma voiture et présente les caractéristiques suivantes :

  • Suivez les coordonnées GPS et publiez le dernier emplacement connu sur le tableau de bord du cloud thinger.io IoT toutes les 2 minutes (affiché sur une carte). Publication sur thinger.io avec des requêtes HTTP POST.
  • Répond aux commandes SMS et renvoie un lien de carte Google vers la position actuelle ou la dernière position connue (dernière position connue si aucune position actuelle n'est disponible).
  • Envoyer une notification par SMS tous les XX kilomètres (l'idée est que le tracker me rappelle de vider mon bac de récupération d'huile tous les 4000 km). Cela fonctionne comme un "odomètre" logiciel personnalisable.

Au cours de ce projet, j'ai rapidement réalisé à quel point l'Arduino est "limité" en termes de mémoire disponible et j'ai dû apprendre des techniques pour réduire les frais généraux et créer un code efficace (du moins j'ai essayé). J'ai également utilisé des bibliothèques légères pour tout mettre sur la puce et la RAM disponible.

Les composants utilisés sont les suivants (comme dans la liste des composants) :

  • Appareil GPS NEO-6M. Cela semble être un appareil GPS très populaire disponible à bas prix sur Ebay et similaire. La communication avec le GPS se fera en série matérielle.
  • Antenne GPS. N'importe quel compatible fera l'affaire, cependant, j'ai trouvé que les moins chers d'Ebay ne fonctionnaient pas très bien, c'est-à-dire mauvaise réception / faible nombre de satellites. Peut-être n'ai-je pas eu de chance avec la première antenne, mais je devais en obtenir une autre de meilleure qualité pour une réception stable.
  • Carte de développement SIM900 pour la connectivité GSM et GPRS. Ce projet devrait également fonctionner avec les modules SIM800 et compatibles, aucune garantie cependant. La communication avec SIM900 sera une série logicielle.
  • Arduino Léonard Conseil. J'ai utilisé la carte Leonardo pour avoir une ligne série matérielle dédiée car nous avons besoin de deux lignes série. Bien qu'il soit également possible d'utiliser une carte UNO ordinaire, vous devez déconnecter le GPS pour télécharger le logiciel et vous n'aurez pas non plus de moniteur série pour le débogage. Nous avons besoin de deux lignes série (une pour le GPS et une pour la carte SIM900); une série logicielle et une série matérielle.
  • Lecteur de carte SD (j'ai utilisé le lecteur de carte Adafruit qui est compatible 5V (la connexion à l'en-tête SPI 5V est facile). D'autres modules moins chers pourraient tout aussi bien fonctionner. La carte Micro SD sera utilisée pour stocker la distance parcourue. Avertissement : assurez-vous que votre lecteur de carte SD prend en charge l'alimentation 5V si vous suivez mes schémas, de nombreux lecteurs de carte SD n'utilisent que 3,3V. L'utilisation de niveaux de tension incorrects endommagera très probablement l'électronique. La communication avec le lecteur de carte SD sera l'interface SPI.
  • LED et résistances pour faire des circuits indicateurs d'état (LED d'alimentation et de verrouillage GPS).
  • Carte SIM avec données.
  • J'ai également conçu un boîtier imprimable en 3D avec des fichiers STL joints qui peuvent être imprimés directement sur une imprimante 3D.

Nous devons d'abord installer les bibliothèques nécessaires. J'ai utilisé les bibliothèques suivantes pour ce projet :

  • NéoGPS pour le suivi et le décodage GPS. Peut être installé directement depuis le gestionnaire de bibliothèque dans Arduino IDE. Plus d'infos :https://github.com/SlashDevin/NeoGPS
  • Temps bibliothèque (utilisée pour la conversion de fuseau horaire UTC) :https://github.com/PaulStoffregen/Time
  • PetitFS pour lire/écrire sur la carte SD :https://github.com/greiman/PetitFS Bibliothèque SD FAT légère.

Pourquoi ne pas utiliser la bibliothèque disponible pour Arduino par thinger.io ?

Bien que la bibliothèque fournie par thinger.io soit très simple d'utilisation et simplifierait considérablement les choses, pour ne pas dire déjà intégrée dans l'IDE, elle consomme près de 80% de stockage sur l'Arduino Leo, laissant peu ou pas d'espace pour le code restant. Il est donc tout simplement trop gros pour ce projet et nous devrons le faire à la dure. Pour communiquer avec le cloud thinger.io, nous utiliserons des requêtes HTTP POST.

SMS commandes

Les commandes disponibles sur SMS sont les suivantes (toutes en majuscules). Ce sont les commandes prises en charge dans le code fourni ; vous pouvez ajouter/supprimer des commandes pour votre propre projet/exigences :

  • "POS" renvoie les coordonnées avec le lien Google Maps, si les coordonnées sont disponibles. Sinon, le dernier emplacement connu est renvoyé.
  • "GETKM" renvoie la distance actuelle depuis la dernière « réinitialisation ».
  • "RESETKM" met le compteur de distance à 0 (remise à zéro du compteur kilométrique).

Configuration du NeoGPS

Nous utilisons la bibliothèque NeoGPS pour les performances et l'utilisation des ressources par rapport à des alternatives comme TinyGPS++. Il consomme très peu de RAM, et c'est nécessaire; sinon, nous recevrons des avertissements pour une mémoire faible et une stabilité.

Une fois la bibliothèque installée, modifiez le fichier GPSPort.h dans le chemin d'installation de la bibliothèque (l'exemple donné est pour OS X - pour Windows, vous trouverez la bibliothèque à un emplacement différent)

Remplacez tout le contenu de GPSPort.h par ce qui suit :

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

Ce fichier contient les définitions utilisées par la bibliothèque NeoGPS. Si vous utilisez une autre carte Arduino, c'est ici que vous définissez la ligne série vers le récepteur GPS, par ex. "Serial2", "Serial3" pour Arduino MEGA.

Remarques sur la précision

Il convient de noter que le GPS n'est pas le moyen le plus précis de mesurer et d'accumuler la distance, car la position dérivera légèrement même à l'arrêt. Vous pouvez tester cela en restant immobile au même endroit et observer que les coordonnées GPS seront différentes pour chaque lecture. Pour cette application, la précision est moins importante et donc des écarts plus petits sont acceptables.

J'ai cependant essayé de tenir compte des petites dérives de coordonnées et le logiciel n'ajoute de distance que pour les mouvements supérieurs à 10 m (tous les mouvements inférieurs à 10 m sont supposés stationnaires) sur 15 secondes.

Gardez également à l'esprit que la distance est calculée en ligne droite, alors que la distance réelle parcourue par la voiture dépend de la route, des virages, etc. J'ai réglé le taux d'échantillonnage à 15 secondes, vous pouvez cependant le baisser si vous voulez plus précision.

Mise en place de PetitFS

Cette bibliothèque est une bibliothèque ultra-légère pour la lecture/écriture sur des cartes SD au format FAT. Il m'a fallu un certain temps pour comprendre comment cela fonctionne, car la documentation est pratiquement inexistante et certains endroits sont même erronés / obsolètes. L'exemple de code de bibliothèque fourni ne sera même pas compilé. Il est livré avec un lot de restrictions (par opposition à une bibliothèque "normale" comme la bibliothèque SD d'Arduino ou SDFat) :

  • Impossible de créer le fichier. Seul le fichier existant peut être écrit.
  • Impossible d'augmenter la taille du fichier.
  • Impossible de mettre à jour l'horodatage du fichier.
  • Impossible d'ajouter des données au fichier (le fichier réécrit à chaque fois).
  • Un seul fichier ouvert à la fois.

Pourquoi utiliser une bibliothèque petite et limitée avec beaucoup de bizarreries ?

La taille, en gros. J'ai essayé quelques bibliothèques, dont la bibliothèque Arduino SD, SDFat et aussi fat16lib. Ils sont tous trop gros pour faire tenir tout le code sur la puce, donc pour ne pas supprimer les fonctionnalités, j'ai utilisé cette bibliothèque (la bibliothèque Arduino SD standard prend environ 12% d'espace en plus). Même avec toutes les bizarreries et limitations, il fournit toujours ce dont nous avons besoin pour cette application :une simple lecture et écriture d'une valeur unique pour le stockage.

Si vous n'utilisez pas tout le code et qu'il y a suffisamment d'espace pour en insérer un peu plus, il est beaucoup plus facile de travailler avec des bibliothèques comme la bibliothèque SD standard.

Ouvrez le fichier pffArduino.h du dossier de la bibliothèque PetitFS. Modifiez le SD_CS_PIN à 10. Il s'agit de la broche SS utilisée pour communiquer avec la carte SD avec SPI.

Ouvrez le fichier pffconf.h du dossier de la bibliothèque. Désactiver les options suivantes en commutant la valeur définie de 1 à 0 :

  • _USE_DIR
  • _USE_LSEEK
  • _FS_FAT12
  • _FS_FAT16

En désactivant ces options, le programme compilé prend moins d'espace - ce qui est nécessaire; Le croquis final prend env. 96 % du stockage.

Lors de la première importation de la bibliothèque, vous obtiendrez une erreur de compilation qui *peut* être ignorée (deuxième compilation, l'erreur ne s'affiche pas - vous ne comprenez toujours pas pourquoi). Cependant, si vous souhaitez résoudre ce problème (il réapparaîtra à chaque fois que vous démarrerez Arduino IDE -> compiler), ajoutez le paramètre de retour de fonction manquant "FRESULT" comme indiqué dans la capture d'écran ci-dessus. C'est dans le fichier pff.cpp dans le dossier de la bibliothèque.

J'ai fait de mon mieux pour comprendre comment fonctionne cette bibliothèque et bien que tout fonctionne, je suis presque sûr que les choses peuvent aussi être améliorées. Si vous trouvez des erreurs ou des améliorations dans les routines que j'ai écrites, n'hésitez pas à partager ! J'aimerais beaucoup apprendre et acquérir plus d'expérience.

Préparez la carte SD

J'ai utilisé une carte Micro SD pour ce projet. Étant donné que la bibliothèque ne peut pas créer le(s) fichier(s) elle-même, il est important de créer le fichier "dist.txt" et "settings.txt" sur la carte avant utilisation. Je recommande de copier les fichiers "dist.txt" et "settings.txt" ci-joints à partir de cette page de projet, car ces fichiers ont déjà le bon format et fonctionnent (la bibliothèque est très pointilleux sur le format et le contenu du texte).

Avant de mettre le fichier sur la carte Micro SD, assurez-vous de formater la carte correctement (en FAT32 ). Je recommande d'utiliser le " SD Card Formatter " officiel de SD Association :https://www.sdcard.org/downloads/formatter/.

S'assurer que la carte SD fonctionne (lecture/écriture dans le fichier correctement)

La bibliothèque PetitFS est très pointilleux sur les fichiers d'entrée. Si vous démarrez le périphérique et qu'aucune sortie n'est affichée sur le moniteur série (juste vide), il est très probablement bloqué dans la "boucle" où il essaie de lire le fichier à partir de la carte mais ne peut pas pour une raison quelconque (fonction initializeSD()). J'ai eu d'innombrables fichiers texte où, pour une raison quelconque, il n'a pas pu être lu, j'ai donc inclus les fichiers texte référencés que j'ai utilisés et qui fonctionnent. Placez ces références les fichiers sur la carte SD et elle devrait être capable à la fois de lire et d'écrire correctement dessus.

Une autre option peut être de remplir le fichier texte avec un nombre plus grand que celui de son écriture. Je n'ai pas testé cela, mais comme la bibliothèque ne peut pas étendre la taille du fichier elle-même, je suppose que cela pourrait être un problème.

PetitFS écrira toute la longueur du tableau de caractères dans le fichier, vous verrez donc des espaces vides devant le nombre réel (à moins que le nombre ne soit assez grand pour remplir le tableau - la longueur du "tableau" est définie dans le code). Ces espaces doivent être conservés lors de la modification du fichier - comme PetitFS ne peut pas modifier la taille du fichier, cela peut causer des problèmes si le nombre de caractères est modifié.

Définissez le fichier « dist.txt » sur « 0 » si vous souhaitez que le compteur kilométrique commence à « 0 », ou tout autre nombre pour faciliter la vérification de son fonctionnement, par ex. envoyer la commande "GETKM" pour vérifier la réponse SMS.

Dans "settings.txt", vous définissez la distance de déclenchement de la notification, la distance à laquelle le compteur kilométrique déclenche le SMS de notification (en mètres).

Préparez la carte SIM900

Quelques éléments doivent être configurés sur la carte SIM900 avant de pouvoir l'utiliser. Pour plus de détails, il existe une excellente ressource sur https://lastminuteengineers.com/sim900-gsm-shield-arduino-tutorial/ pour la configuration de cette carte.

Source d'alimentation

La carte Arduino n'est pas capable de fournir suffisamment de puissance, nous devons donc utiliser une alimentation externe. Comme les pointes peuvent consommer jusqu'à 2 A, assurez-vous d'utiliser une alimentation pouvant fournir au moins 2 A à 5 V-9 V CC ; il utilise le connecteur canon de 5,5 mm.

Sélecteur de source d'alimentation

À côté de la prise CC se trouve un sélecteur de source d'alimentation . Pour utiliser une source d'alimentation externe, déplacez le curseur comme indiqué dans l'image ci-dessus.

Sélecteur de série

Configurez la carte pour utiliser Software Serial en alignant les cavaliers comme indiqué ci-dessus.

Déclencheur logiciel

Au lieu d'appuyer manuellement sur la touche marche/arrêt à chaque fois, vous pouvez allumer/éteindre le SIM900 dans le logiciel. Pour ce faire, le cavalier nommé R13 doit être soudé. La carte est ensuite mise sous tension en connectant la broche SIM900 #9 à la broche Arduino #7 (comme indiqué dans les schémas).

Si vous conservez la fonctionnalité "mise sous tension manuelle", la fonction "SIM900power()" dans le code peut être supprimée.

Supprimer le verrou PIN de la carte SIM

Assurez-vous de supprimer le verrou PIN sur la carte SIM avant utilisation. Cela peut être fait en l'insérant dans n'importe quel téléphone ordinaire et en supprimant le verrou à broche du menu des paramètres applicables.

Notez également que le module SIM900 dans les schémas peut sembler différent de la carte réelle, cependant, la disposition des broches est correcte, ce qui est la partie la plus importante.

Version du micrologiciel SIM900 (Important !)

Il est très important d'avoir la bonne version du firmware chargé sur la puce. En effet, l'une des commandes permettant de configurer correctement l'en-tête HTTP POST n'est pas prise en charge avant la version B10 du micrologiciel. Cela signifie que vous devez avoir au moins la version B10 ou supérieure pour que la communication http fonctionne. Plus précisément, avec une version de firmware inférieure, il ne pourra pas définir "Content-type" dans l'en-tête http. Si le type de contenu n'est pas défini sur "application/json" dans la demande de publication, il sera rejeté par le serveur.

Pour vérifier la version de votre firmware, utilisez la commande AT suivante :

AT+CGMR 

La puce SIM900 vous donnera alors la version actuelle du firmware dans la console de sortie. Mettez ce qui suit à la fin de la section setup() pour imprimer la version du firmware au démarrage :

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

Dans mon cas, cela afficherait ceci (avant la mise à jour) :

Révision:1137B01SIM900M64_ST_AM 

Il s'agissait de la plus ancienne version de firmware possible pour cette puce ("B01"), j'ai donc mis à jour vers la version B10 :1137B10SIM900M64_ST . Les firmwares plus récents devraient également fonctionner.

Je ne vais pas expliquer comment mettre à jour le firmware dans ce guide, il existe déjà un excellent guide sur la façon de procéder :mise à jour du firmware SIM900 - ACOPTEX (bien qu'un processus quelque peu pénible).

Je ne sais pas si ce sera le cas pour d'autres puces comme la SIM800, cependant, il s'agit d'une puce plus récente, je dirais qu'il est plus probable qu'elle soit déjà en place là-bas.

Ajustements de code

Pour adapter le code à votre propre projet, quelques ajustements sont nécessaires :

  • Modifier les informations APN (fournisseur de réseau).
  • Modifiez l'URL thinger.io pour qu'elle corresponde à la vôtre (l'URL lie la demande de mise à jour à votre propre "seau" avec jeton d'accès). Ceci est couvert dans le chapitre "Intégration de thinger.io".
  • Définir le fuseau horaire correct.
  • Définir la distance de déclenchement pour la notification par SMS
  • Définir (ou désactiver) le texte de notification par SMS.
  • Définir le numéro de téléphone par défaut pour la notification.

Fournisseur APN

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

Sous le connectGPRS() fonction, vous trouverez le nom APN donné par votre fournisseur de réseau, indiqué ci-dessus comme "TeleXXX". Remplacez-le par votre propre nom APN.

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

Ci-dessus :sortie de la fonction connectGPRS() lorsque la connexion fonctionne. Toutes les commandes doivent renvoyer le statut "OK".

Fuseau horaire

#define UTC_OFFSET 1 // définir le décalage horaire, c'est-à-dire 1 =UTC+1 

Dans la section « définir », définissez le fuseau horaire en fonction de vos besoins. Le code est défini sur UTC+1 .

Notification SMS

J'ai mis en place une notification tous les 4000km pour vider mon bac de récupération d'huile. Comme je me rends compte que la plupart des gens n'ont pas de réservoir de récupération d'huile, cette notification doit ensuite être modifiée en ce que vous voulez (ou complètement désactivée).

void loop() {... // envoie une notification par SMS si la distance totale dépasse 4000km if (totalDistance> triggerDistance) { char sms_msg[160]; car distanceTotalMsg[10] ; itoa( (distance totale / 1000) , distanceTotalMsg, 10); sprintf(sms_msg, "Réservoir vide ! Distance actuelle :%skm", distanceTotalMsg); textMessage =""; Distance totale =0 ; // définit le numéro de téléphone par défaut pour déclencher la notification number =DEFAULT_NUMBER; envoyerSMS(sms_msg); } ...} 

Ci-dessus :section de code qui déclenche la notification (à l'intérieur de la boucle principale() ).

Commentez/supprimez cette section si vous ne voulez pas de notifications déclenchées. Vous pouvez également remplacer le texte par quelque chose d'utile.

La notification est déclenchée une fois que le "compteur kilométrique" (distance cumulée) atteint la distance configurée définie dans le fichier "settings.txt".

Numéro de téléphone par défaut

Il s'agit du numéro de téléphone auquel la notification déclenchée est envoyée (car la notification n'a pas de numéro « expéditeur » auquel répondre)

// numéro de téléphone pour la notification déclenchée#define DEFAULT_NUMBER "+4712345678"  

Attendez la connexion série

C'est aussi une bonne idée de décommenter la ligne suivante dans le code. Cela fait que la carte Arduino attend que la connexion série devienne active, c'est-à-dire le moniteur série pour le débogage. De cette façon, vous ne manquez aucun message de débogage au début du code avant que la ligne série ne devienne active.

N'oubliez pas de supprimer/commenter la ligne avant d'alimenter l'Arduino à partir de sources d'alimentation externes, car sinon il s'arrêtera dans une boucle infinie jusqu'à ce qu'il se connecte à un PC.

 // while (!Serial); // attend que le port série se connecte - pour ATmega32u4 (Leonardo) 

Intégration de Thinger.io

Je n'entrerai pas dans les détails de la configuration de thinger.io car c'est assez simple ; vous devez créer un compte et un « seau » pour recevoir les données via leur site Web, ainsi qu'un « appareil » auquel nous nous connecterons. Un "seau" est la base de données pour recevoir des données. Le « device » est le point de connexion de notre code où nous décidons quoi faire avec les données (dans notre cas, remplissez la base de données « bucket »).

Créez un "seau" comme indiqué ci-dessus avec votre propre nom et description.

Maintenant, allez-y et créez un « Périphérique HTTP » comme décrit dans la documentation officielle :https://docs.thinger.io/quick-sart/devices/http-devices.

Utilisez un court appareil nom . Comme le nom de l'appareil fait partie de l'algorithme qui génère la clé d'autorisation, j'ai constaté qu'un nom de périphérique plus long génère également une clé d'autorisation plus longue. Le problème? La clé d'autorisation est rapidement devenue plus longue que le tampon de 256 caractères utilisé pour envoyer la chaîne depuis Arduino. Il existe probablement de meilleures façons de résoudre ce problème, mais j'ai trouvé l'approche la plus simple pour garder le nom de l'appareil court et éviter le problème.

Dans le rappel de l'appareil > paramètres Assurez-vous que le paramètre "write bucket" pointe vers le bucket créé précédemment. Cela indique au "périphérique" d'écrire les données entrantes dans notre base de données.

Dans le rappel de l'appareil > présentation section notez la méthode URL et en-tête d'autorisation (chaîne longue sans le mot-clé "Bearer").

Pour envoyer des données à un thinger.io, nous utilisons une "URL d'autorisation" dans la requête HTTP POST. Vous devez ensuite remplacer l'URL et la clé d'autorisation du code par les vôtres.

Dans le postDataThinger() fonction, vous trouverez l'appel (clé d'autorisation réelle brouillée) :

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

Vous devez ensuite remplacer l'URL et autorisation clé dans le code avec le vôtre, généré en suivant les instructions du lien fourni ci-dessus.

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

Par défaut, l'URL d'autorisation générée sera https . Le SIM900 ne pas soutien SSL (au moins je n'ai pas réussi à le faire fonctionner), alors assurez-vous de changer "https ://" à "http://". L'API thinger prend également en charge les connexions non SSL. C'est très important. Si vous conservez "https", cela ne fonctionnera pas. Lorsque tout fonctionne, le moniteur série devrait donner un "200 - Réponse "OK" lors de la transmission de la demande de publication http.

Après la commande AT "AT+HTTPACTION=1" (envoyer une requête HTTP POST) vous devriez recevoir une réponse comme celle-ci dans le moniteur série :

+HTTPACTION : 1,200,0 

Si vous recevez une réponse "400 - mauvaise demande" ou similaire.

+HTTPACTION :0,400,51  

..il y a très probablement quelque chose qui ne va pas avec l'URL, par ex. "https" au lieu de "http", mauvaise syntaxe de la "clé d'autorisation", etc. Lorsque vous recevez un message "200 - OK", les données doivent apparaître dans le seau de choses comme indiqué ci-dessous. Vous pouvez également recevoir un 400 - "mauvaise demande" si vous n'avez pas le bon firmware comme mentionné précédemment.

Ci-dessus, une vue du compartiment une fois les données arrivées (brouillées pour des raisons de confidentialité). Le contenu (colonnes de données) est défini par la syntaxe de la requête HTTP POST dans le code, aucune configuration sur thinger.io n'est nécessaire.

Vous trouverez ci-dessous une sortie série de la requête HTTP POST telle qu'elle devrait apparaître lorsque tout fonctionne. +HTTPACTION:1, 200, 0 indique que la mise à jour a réussi.

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

Le tableau de bord peut ensuite être facilement configuré avec le widget de cartes en utilisant le seau comme source de données.

Plus de données à faire ?

Voulez-vous pousser plus de données que la longitude, la latitude et la date/heure ? Ajoutez simplement plus de champs de données à la requête http comme indiqué ci-dessous.

Le format est { "field1 name" :field1, "field2 name" :field2, "field3 name" :field3 }

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

La commande sprintf ci-dessus compile la chaîne de données envoyée à thinger. La syntaxe est *très* stricte et vous devez ajouter de nouveaux champs de données exactement de la même manière. Un exemple est donné dans le code (section commentaire). Une bonne idée est de noter l'impression du moniteur série de la commande qui affichera la chaîne. Vous ajoutez ensuite "field4" et ainsi de suite..

Enceinte

J'ai joint un boîtier imprimable en 3D complet. Il est conçu pour s'adapter aux PCB exacts utilisés pour ce projet. Des vis M3 sont utilisées pour le montage.

Il est conçu pour une carte à souder 7x5cm pour le "circuit" LED et non pour une maquette. Si vous utilisez une planche à pain, utilisez simplement de la colle à la place. Le GPS et la carte à souder ("planche à pain") sont montés dans le boîtier supérieur. Utilisez de petites entretoises pour un meilleur montage des PCB dans le boîtier supérieur.

I have also kept the mounting points in the top casing solid (no holes) to make for easier printing without supports. Open these with a 3mm drill bit.

It prints well on 0.2mm without supports.

Connection to car battery / power source

There are probably hundreds of ways of doing this, so I don't have the only answer, or best answer for that matter; 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, SORTIE); 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); retard(1000); digitalWrite(PWRPin, HIGH); retard (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\"") ); retard(1000); updateSIM900(); SIM900.println( F("AT+SAPBR=3,1,\"APN\",\"TeleXXX\"") ); retard(1000); updateSIM900(); SIM900.println( F("AT+SAPBR=1,1") ); retard(1000); updateSIM900(); SIM900.println( F("AT+SAPBR=2,1") ); retard(1000); updateSIM900();}void postDataThinger(char *httpDataLen, char* content){ SIM900.println( F("AT+HTTPINIT") ); retard(1000); updateSIM900(); SIM900.println( F("AT+HTTPPARA=\"CID\",1") ); retard(1000); updateSIM900(); SIM900.println( F("AT+HTTPPARA=\"URL\",\"http://backend.thinger.io/v3/users/tom/devices/CT/callback/data?authorization=eyJhbGciOiJIUzI1NiIsInR5cCI6lskjdflksjdfweruiowe19DVCIsInVzciI6InRvcm1vZCJ9.AR1gWvIZB9KmtI-5Z12YXKuchPTGn58AkwBJSZQIoxQ\"") ); retard(1000); updateSIM900(); SIM900.println( F("AT+HTTPPARA=\"CONTENT\",\"application/json\"") ); retard(1000); updateSIM900(); SIM900.println(httpDataLen); retard(1000); updateSIM900(); SIM900.println(content); retard(1000); updateSIM900(); SIM900.println( F("AT+HTTPACTION=1") ); delay(10000); updateSIM900(); SIM900.println( F("AT+HTTPTERM") ); retard(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());}

Pièces et boîtiers personnalisés

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

Schémas


Processus de fabrication

  1. Planche à repasser
  2. Planche de surf
  3. Quoi de neuf avec la technologie de suivi des ressources en extérieur (GPS) ?
  4. Raspberry Pi conçoit son propre MCU avec une carte à 4 $
  5. L'intégration des données du capteur avec le microprocesseur Raspberry Pi
  6. Utilisation de la carte PSoC 6 Pioneer avec le Pioneer IoT Add-on Shield
  7. Fonction Python map() avec EXEMPLES
  8. Travailler avec des systèmes d'intégration internes
  9. Que se passe-t-il si je conduis ma voiture avec un niveau de liquide de refroidissement bas ?