← L’AtelierBASSAM BEN SALEM / ARTICLE TECHNIQUE

Électronique / Développement web

Fabriquer son propre tracker GPS

De l’assemblage des composants à l’affichage des points sur une carte

L’idée m’est venue à moto, alors qu’on sillonnait la vallée de Courgoul tard dans la nuit avec un ami.

« T’inquiète, c’est une route tranquille. »

Et c’était vrai. On pouvait y crever sans que personne nous retrouve.

C’est à ce moment-là que je me suis demandé s’il était compliqué de fabriquer son propre tracker GPS.

L’objectif : récupérer ma position, l’envoyer à un serveur et retrouver mon trajet sur une carte. Sur le papier, ça semblait raisonnable. J’ai donc acheté des composants.

Les composants et le câblage

ComposantRéférence utiliséeFonction
Carte programmableNodeMCU ESP32 USB-CExécuter le firmware, lire les périphériques et piloter les communications
Récepteur GPSVelleman WPI430 / NEO-7MFournir les données de localisation
Carte cellulaireModem A7670E, LTE Cat 1Fournir la liaison mobile utilisée pour MQTT
Batterie externeUGREEN Nexode 20 000 mAh, 165 W, avec câble USB-C rétractableAlimenter l’ESP32 par son connecteur USB-C

L’ESP32 récupère les données du GPS, les formatte et les transmet au broker MQTT par l’intermédiaire du module 4G. J’ai aussi intégré au firmware une page de diagnostic : elle est hébergée directement sur l’ESP32 et consultable depuis mon smartphone en me connectant à son Wi-Fi.

Pour l’alimentation, je ne me suis pas pris la tête : une grosse batterie externe UGREEN et un câble USB-C vers l’ESP32. L'utilisation d'une batterie Li-Po suppose des connaissances en électronique que je n'ai pas encore acquises. On dépasse allégrement les 24h d'autonomie malgré les pics de consommation du modem.

Appréciez la compacité soviétique du dispositif

Alimentation du montage

Le GPS est alimenté depuis la broche 3V3 de l’ESP32 et la carte cellulaire depuis sa broche VIN. La batterie arrive sur le connecteur USB-C de l’ESP32.

SCHÉMA / TEXTE
Batterie externe UGREEN
        │
        └── USB-C → NodeMCU ESP32
                         │
                         ├── 3V3 → alimentation du GPS WPI430
                         │
                         └── VIN → alimentation de la carte A7670E

Communication entre les cartes

Le GPS et le modem sont chacun reliés à un port UART de l’ESP32. Cette liaison transmet les données un bit à la fois : TX sert à envoyer, RX à recevoir. Je relie donc le TX de chaque module au RX de l’ESP32, et inversement, avec les branchements suivants :

Signal du périphériqueBroche ESP32Port utilisé
TX du GPSGPIO 16, réception ESP32UART1
RX du GPSGPIO 17, émission ESP32UART1
TX du modemGPIO 26, réception ESP32UART2
RX du modemGPIO 27, émission ESP32UART2

Je relie aussi les broches GND (la masse) des trois cartes entre elles.

Dans le firmware, je règle chaque port au débit du module connecté : 9 600 bauds pour le GPS, 115 200 pour le modem. Il s'agit du débit d'envoi de données. Les deux utilisent le format SERIAL_8N1 : huit bits de données, sans parité et un bit de stop.

Pour creuser le fonctionnement de l’UART et ces réglages, le guide de SparkFun sur la communication série détaille tout ça avec des schémas.

Du GPS au serveur

Pour communiquer les positions, j’ai souscrit un forfait Sosh bloqué à 2 € pour ne pas finir en procédure de surendettement si mon code part dans une boucle frénétique et infinie.

Le firmware est écrit en C++ avec Arduino et PlatformIO. La bibliothèque TinyGPSPlus décode les données envoyées par le GPS : coordonnées, heure, vitesse et altitude.

Le programme publie une position toutes les dix secondes, uniquement si les coordonnées, la date et l’heure sont valides.

Pour ces envois, j’ai choisi MQTT, conçu pour l’envoi régulier de petits payloads. Une requête HTTPS pour chaque position ajoute un overhead inutile et inadapté à cet usage. MQTT utilise des en-têtes compacts et maintient une connexion ouverte avec un serveur appelé broker qui limite la consommation du forfait mobile. Le comparatif MQTT et HTTP de HiveMQ détaille les différences entre les deux protocoles et le fonctionnement par abonnement.

Le tracker publie ses positions sur un topic, par exemple trackers/esp32-01-bassam/position. Chaque message contient un JSON avec l’identifiant du tracker, celui de l’observation, l’heure et les données GPS. Exemple de payload avec des coordonnées de démonstration :

JSON
{
  "clientId": "550e8400-e29b-41d4-a716-446655440000",
  "trackerId": "esp32-01-bassam",
  "recordedAt": "2026-05-21T10:15:30.000Z",
  "latitude": 48.856600,
  "longitude": 2.352200,
  "speedMps": 1.25,
  "altitudeMeters": 35.40,
  "heading": 90.00,
  "satellites": 8,
  "hdop": 1.20
}

Le champ clientId identifie l’observation. Le backend NestJS s’abonne au topic et reçoit les messages transmis par le broker.

Sur mon serveur, Mosquitto tourne dans Docker derrière Traefik. Les échanges passent par TLS, des comptes distincts séparent le droit de publier du droit de lire les positions.

SCHÉMA / TEXTE
GPS → ESP32 → réseau mobile → MQTT → backend → PostgreSQL → carte

Debugguer le dispositif

Quand aucun point n'arrive sur le serveur, plusieurs suspects :

  • Le module GPS mal branché ou qui ne trouve pas de satellites
  • L'ESP32 notamment son firmware
  • Le réseau mobile qui ne fonctionne pas
  • Le broker MQTT qui peut être down

J’ai donc ajouté une petite page de diagnostic directement sur l’ESP32 accessible en se connectant en Wi-Fi.

Depuis mon téléphone, je me connecte à son point d’accès Wi-Fi Tracker-Debug pour consulter les coordonnées, les satellites et l’état MQTT.

Cette page reste accessible même quand le tracker ne joint plus le serveur. Je peux déjà voir si le GPS donne une position, puis chercher du côté de l’envoi MQTT et de l’enregistrement en base.

Côté serveur et carte

Le backend utilise NestJS, Prisma et PostgreSQL. Avant d’enregistrer un message, il vérifie que le tracker existe, que son identifiant correspond au canal MQTT, que les coordonnées sont dans les limites possibles et que la date est exploitable.

En base ne sont gardées que les informations du tracker, sa dernière position et l’historique de ses déplacements. L’API permet de récupérer les points sur une période donnée, sans charger tout l’historique.

Pour le frontend, j’ai utilisé Next.js avec MapLibre GL JS. On choisit une période et on retrouve le trajet sur une carte, coloré selon la vitesse. L'aspect frontend a été généré essentiellement avec Codex.

Ça fonctionne !

J'embarque le prototype et l'emmène direction la vallée de Courgoul. Un point me contrarie : ont-il du réseau ? Je sais que le GPS communique avec les satellites mais j'espèrais que le module 4G trouverait des antennes.

Miracle le prototype passe dans le coffre : batterie, ESP32, modem et GPS.

Coffre refermé, les antennes restent à l’extérieur pour les essais.

Ça fonctionne ! Le tracker a su communiquer sa position jusqu'à la vallée de Courgoul. En cliquant sur les points je dispose de la vitesse, le cap, l'altitude et le denivelé.

Même dans la maudite vallée !

Les références aux fichiers désignent le code du projet. Les dépôts correspondants ne sont pas publics.