Bir ESP32 GPS takip cihazı MQTT projesi, hareket eden bir cihazı çok az kodla neredeyse gerçek zamanlı olarak harita üzerinde gösterir. Bu eğitimde bir NEO-6M modülünü TinyGPSPlus ile okuyacak, konum, hız ve fix kalitesini yalnızca cihaz gerçekten hareket ettiğinde broker.connectmq.com'a yayınlayacak ve canlı rotayı güvenli WebSocket üzerinden subscribe olan bir Leaflet web haritasında çizeceksiniz.
Parçalar Nasıl Bir Araya Gelir
Veri akışının üç bölümü vardır:
- NEO-6M'den ESP32'ye. GPS modülü NMEA cümlelerini 9600 baud hızında bir UART üzerinden akıtır. TinyGPSPlus bunları enlem, boylam, hız ve daha fazlasına ayrıştırır.
- ESP32'den broker'a. ESP32, TCP 1883 portunda (production'da TLS 8883) MQTT üzerinden kompakt bir JSON konum yayınlar.
- Broker'dan tarayıcıya. Statik bir web sayfası, 8084 portunda,
/mqttyoluyla güvenli WebSocket üzerinden MQTT.js ile bağlanır ve haritadaki bir işaretçiyi hareket ettirir.
MQTT yayıncı ile subscriber'ı birbirinden ayırdığı için haritayı aynı anda birkaç cihazda açabilirsiniz; retained bir son konum mesajı da yeni açılan bir haritanın bir sonraki fix'i beklemek yerine takip cihazını hemen göstermesini sağlar. Tarayıcıda MQTT konusunda yeniyseniz WebSocket üzerinden MQTT bu aktarım katmanını açıklar.
Parçalar ve Bağlantı
- Bir ESP32 geliştirme kartı.
- Seramik yama antenli bir NEO-6M GPS modülü (yaygın GY-NEO6MV2 kartı).
- Kütüphaneler: Mikal Hart'ın TinyGPSPlus kütüphanesi ve PubSubClient.
| NEO-6M pini | ESP32 pini | Notlar |
|---|---|---|
| VCC | 3V3 (kartta regülatör varsa 5V) | Modülünüzü kontrol edin; çoğu GY-NEO6MV2 kartı ikisini de kabul eder |
| GND | GND | |
| TX | GPIO 16 (UART2 RX) | ESP32'ye giden GPS verisi |
| RX | GPIO 17 (UART2 TX) | Yalnızca yapılandırma komutları göndermek için gerekir |
ESP32'de üç donanım UART'ı vardır; bu yüzden GPS kendi portunu alır ve Serial hata ayıklama için boş kalır. Yazılımsal seri port kullanmayın.
İlk Fix'i Almak
Soğuk başlayan bir NEO-6M'in gökyüzünü açıkça görmesi gerekir ve ilk fix'i üretmesi birkaç dakika sürebilir. İç mekanda hiç fix alamayabilir. Çoğu modüldeki mavi LED, geçerli bir fix olduğunda saniyede bir yanıp söner. Pratik ipuçları:
- İlk testi dışarıda veya bir pencerenin yanında, anten yukarı bakacak şekilde yapın.
- ESP32'yi ve Wi-Fi antenini GPS anteninden birkaç santimetre uzakta tutun.
- Modüldeki küçük yedek pil almanak verilerini saklar; böylece bir sonraki başlatma çok daha hızlı olur. Yeniden başlatmalar her zaman yavaşsa pil bitmiş olabilir.
Yayın Stratejisi: Saate Göre Değil, Harekete Göre
Her saniye yayın yapmak, park halindeyken veri israf eder ve subscriber'ları mesaj yağmuruna tutar. Sketch şu durumlarda yayın yapar:
- cihaz son yayından bu yana bir eşik mesafeden (varsayılan 25 m) fazla hareket ettiğinde veya
- bir heartbeat aralığı (60 sn) geçtiğinde; böylece harita, takip cihazı sabitken de canlı olduğunu bilir.
| Topic | Retained | Payload |
|---|---|---|
connectmq/demo/gps6j1v/position |
Evet | {"lat":41.008238,"lng":28.978359,"speed":32.4,"course":118.2,"alt":44.1,"sats":8,"hdop":1.1} |
connectmq/demo/gps6j1v/status |
Evet | online, offline, no-fix |
ESP32 GPS Takip Cihazı MQTT Sketch'i
#include <WiFi.h>
#include <PubSubClient.h>
#include <TinyGPSPlus.h>
const char* WIFI_SSID = "YOUR_WIFI_SSID";
const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";
const char* MQTT_HOST = "broker.connectmq.com";
const uint16_t MQTT_PORT = 1883;
const char* PREFIX = "connectmq/demo/gps6j1v"; // kendi rastgele kimliğinizi kullanın
const int GPS_RX = 16, GPS_TX = 17;
const double MIN_MOVE_M = 25.0;
const uint32_t HEARTBEAT_MS = 60000;
const uint32_t MIN_GAP_MS = 2000; // asla bundan daha hızlı değil
TinyGPSPlus gps;
HardwareSerial gpsSerial(2);
WiFiClient net;
PubSubClient mqtt(net);
String clientId, tPosition, tStatus;
double lastLat = 0, lastLng = 0;
bool havePublished = false;
uint32_t lastPublishMs = 0;
bool fixReported = false;
void connectWifi() {
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(200);
while (gpsSerial.available()) gps.encode(gpsSerial.read()); // ayrıştırmaya devam et
}
Serial.printf("Wi-Fi OK, IP %s\n", WiFi.localIP().toString().c_str());
}
void connectMqtt() {
while (!mqtt.connected()) {
if (mqtt.connect(clientId.c_str(), tStatus.c_str(), 1, true, "offline")) {
mqtt.publish(tStatus.c_str(), "online", true);
Serial.println("MQTT connected");
} else {
Serial.printf("MQTT failed, state %d\n", mqtt.state());
delay(3000);
}
}
}
void publishPosition() {
char payload[220];
snprintf(payload, sizeof(payload),
"{\"lat\":%.6f,\"lng\":%.6f,\"speed\":%.1f,\"course\":%.1f,"
"\"alt\":%.1f,\"sats\":%lu,\"hdop\":%.1f}",
gps.location.lat(), gps.location.lng(),
gps.speed.isValid() ? gps.speed.kmph() : 0.0,
gps.course.isValid() ? gps.course.deg() : 0.0,
gps.altitude.isValid() ? gps.altitude.meters() : 0.0,
(unsigned long)gps.satellites.value(),
gps.hdop.isValid() ? gps.hdop.hdop() : 99.9);
if (mqtt.publish(tPosition.c_str(), payload, true)) {
lastLat = gps.location.lat();
lastLng = gps.location.lng();
lastPublishMs = millis();
havePublished = true;
Serial.println(payload);
}
}
void setup() {
Serial.begin(115200);
gpsSerial.begin(9600, SERIAL_8N1, GPS_RX, GPS_TX);
clientId = "esp32-gps-" + String((uint32_t)ESP.getEfuseMac(), HEX);
tPosition = String(PREFIX) + "/position";
tStatus = String(PREFIX) + "/status";
connectWifi();
mqtt.setServer(MQTT_HOST, MQTT_PORT);
mqtt.setBufferSize(512);
connectMqtt();
}
void loop() {
while (gpsSerial.available()) gps.encode(gpsSerial.read());
if (WiFi.status() != WL_CONNECTED) connectWifi();
if (!mqtt.connected()) connectMqtt();
mqtt.loop();
bool fixValid = gps.location.isValid() && gps.location.age() < 3000;
if (!fixValid) {
if (fixReported || millis() - lastPublishMs > HEARTBEAT_MS) {
mqtt.publish(tStatus.c_str(), "no-fix", true);
fixReported = false;
lastPublishMs = millis();
}
if (millis() > 10000 && gps.charsProcessed() < 10) {
Serial.println("No NMEA data: check GPS TX -> GPIO 16 wiring");
}
return;
}
if (!fixReported) {
mqtt.publish(tStatus.c_str(), "online", true);
fixReported = true;
}
uint32_t sinceLast = millis() - lastPublishMs;
if (sinceLast < MIN_GAP_MS) return;
double moved = havePublished
? TinyGPSPlus::distanceBetween(lastLat, lastLng, gps.location.lat(), gps.location.lng())
: 1e9;
if (moved >= MIN_MOVE_M || sinceLast >= HEARTBEAT_MS) {
publishPosition();
}
}
gps.location.age() kontrolü önemlidir: TinyGPSPlus, fix kaybolduktan sonra bile son geçerli konumu tutar; bu kontrol olmadan bayat bir konumu güncelmiş gibi yayınlamaya devam edersiniz.
Canlı Web Haritası
Bunu map.html olarak kaydedin ve bir tarayıcıda açın. OpenStreetMap karolarıyla Leaflet'i ve güvenli WebSocket üzerinden MQTT.js'i kullanır. Öneki sketch'inizle eşleşecek şekilde değiştirin.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>ESP32 GPS tracker</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
<style>html, body, #map { height: 100%; margin: 0; }</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="https://unpkg.com/mqtt@5.10.1/dist/mqtt.min.js"></script>
<script>
const PREFIX = "connectmq/demo/gps6j1v";
const map = L.map("map").setView([0, 0], 2);
L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
maxZoom: 19,
attribution: "© OpenStreetMap contributors"
}).addTo(map);
const marker = L.marker([0, 0]).addTo(map);
const track = L.polyline([], { weight: 4 }).addTo(map);
let first = true;
const client = mqtt.connect("wss://broker.connectmq.com:8084/mqtt", {
clientId: "gps-map-" + Math.random().toString(16).slice(2, 10),
protocolVersion: 5,
clean: true
});
client.on("connect", () => client.subscribe(PREFIX + "/#", { qos: 0 }));
client.on("message", (topic, payload) => {
if (topic === PREFIX + "/status") {
marker.bindTooltip("Status: " + payload.toString()).openTooltip();
return;
}
if (topic !== PREFIX + "/position") return;
const p = JSON.parse(payload.toString());
const pos = [p.lat, p.lng];
marker.setLatLng(pos).bindPopup(
`Speed ${p.speed} km/h<br>Satellites ${p.sats}<br>HDOP ${p.hdop}`);
track.addLatLng(pos);
if (first) { map.setView(pos, 16); first = false; } else { map.panTo(pos); }
});
</script>
</body>
</html>
Retained position mesajı sayfa subscribe olur olmaz gelir; bu yüzden işaretçi hemen bilinen son konuma atlar. Ardından yeni konumlar geldikçe çizgi (polyline) uzar. Leaflet'in işaretçi, açılır pencere ve çizgi seçenekleri Leaflet belgelerinde ele alınır.
ESP32 GPS Takip Cihazı MQTT Akışını Test Etmek
Ham mesajları haritanın yanında izleyin:
mosquitto_sub -h broker.connectmq.com -p 1883 -i gps-view-6j1v -t "connectmq/demo/gps6j1v/#" -v
Takip cihazı bir telefon hotspot'una bağlıyken mahallede bir tur atın; rota kendiliğinden çizilir. Konum kişisel bir veridir ve herkese açık alan, topic'i bilen veya tahmin eden herkes tarafından okunabilir; bu yüzden bunu kısa bir deney olarak görün ve orada asla insanları takip etmeyin. Herkese açık MQTT test broker'ı sayfası herkese açık alanın ne için olduğunu açıklar.
Payload'ları Küçük ve Yararlı Tutmak
Konum mesajındaki her alanın bir amacı vardır ve daha fazlasını ekleme isteğine direnmeye değer. Enlem ve boylamda altı ondalık basamak kabaca on santimetrelik bir çözünürlüğe karşılık gelir; bu zaten bir NEO-6M'in sağlayabileceğinden daha incedir, dolayısıyla daha fazla hane yalnızca bayt ekler. Hız ve yön, haritanın ardışık noktalardan hesaplamaya gerek kalmadan bir simgeyi döndürmesini veya bir hız etiketi göstermesini sağlar. Uydu sayısı ve HDOP fix kalitesini tanımlar: HDOP yüksek olduğunda veya beşten az uydu kullanıldığında bir tüketici işaretçiyi soluklaştırabilir ya da noktayı tamamen yok sayabilir.
Daha sonra her kilobaytın para tuttuğu bir hücresel modeme geçerseniz anahtarları kısaltın (la, lo, sp) veya sabit bir ikili düzen gönderin ve harekete dayalı yayını koruyun. Pille çalışan bir takip cihazında en büyük tüketici çoğu zaman GPS modülünün kendisidir; NEO-6M, RX pini üzerinden UBX komutlarıyla yapılandırılan enerji tasarrufu modlarını destekler. Temel sketch hiçbir şey göndermese de o kablonun tabloda yer almasının nedeni budur.
Sorun Giderme
- Hiç NMEA verisi yok. TX ve RX yer değiştirmiş veya baud hızı yanlış. NEO-6M varsayılan olarak 9600 kullanır.
- Veri var ama fix yok. İç mekandasınız veya anten gölgede kalıyor. Dışarı çıkın ve soğuk başlatmada birkaç dakika bekleyin.
- Park halindeyken konum zıplıyor. Normal GPS titreşimi.
MIN_MOVE_Mdeğerini artırın veya HDOP değeri yaklaşık 2,5'in üzerindeki fix'leri atlayın. - Harita 0,0'da kalıyor. Tarayıcı 8084 portuna ulaşamıyor veya
map.htmliçindeki önek eşleşmiyor. Tarayıcı konsolunu kontrol edin. - Araç kullanırken boşluklar oluşuyor. Yolda Wi-Fi yoktur. Gerçek bir araç takip cihazı hücresel bir modem gerektirir; MQTT kodu aynı kalır.
Production Kurulumu ve Gizlilik
Gerçek takip için app.connectmq.com adresinde bir broker oluşturun, ESP32'yi ISRG Root X1 sertifikasıyla 8883 portunda WiFiClientSecure kullanacak şekilde değiştirin ve YOUR_CLIENT_ID, YOUR_USERNAME ve YOUR_PASSWORD ile bağlanın. Production kimlik bilgilerini herkese açık bir web sayfasına gömmeyin: herkes onları sayfa kaynağından okuyabilir. Haritayı özel bir konumdan sunun veya broker ile herkese açık izleyiciler arasına küçük bir backend koyun. ConnectMQ portalında canlı topic gezgini her konum güncellemesini geldiği anda gösterir. Her fix'e zaman damgası eklemek için gps.date ve gps.time üzerinden GPS saatini kullanın veya ESP32 NTP zaman damgası rehberini izleyin. Yakındaki BLE etiketlerini dinleyen takip cihazları için ESP32 BLE MQTT gateway doğal bir uzantıdır.
Filonuzu ConnectMQ Üzerinde Takip Edin
Bir takip cihazı, hem cihazların hem de tarayıcıların güvenle ulaşabileceği bir broker'a ihtiyaç duyar. ConnectMQ; 8883 portunda TLS üzerinden MQTT ve 8084 portunda güvenli WebSocket, bilinen son konumlar için retained mesajlar ve kredi kartı gerektirmeyen ücretsiz bir Serverless plan sunan bir bulut MQTT broker hizmetidir. Takip cihazınızı ve haritanızı bağlayın, ardından daha fazla cihaz projesi için ESP32 IoT eğitimi serisine göz atın.
Sık Sorulan Sorular
Bir ESP32 GPS takip cihazı MQTT üzerinden ne sıklıkta yayın yapmalı?
Sabit ve hızlı bir saat yerine hareket artı heartbeat ile yayın yapın. Bir dakikalık heartbeat ile 25 m'lik bir eşik, yürüyüş ve yavaş araçlar için uygundur.
Konum için neden retained bir mesaj kullanmalı?
Yeni açılmış bir harita gibi yeni bir subscriber, cihazın hareket etmesini beklemek yerine bilinen son konumu hemen alır.
Web haritası broker'a doğrudan bağlanabilir mi?
Evet. Tarayıcılar güvenli WebSocket üzerinden MQTT kullanır; burada wss://broker.connectmq.com:8084/mqtt. Gizli veriler için kimlik bilgilerini herkese açık bir sayfada açığa çıkarmaktan kaçının.
NEO-6M iç mekanda çalışır mı?
Genellikle güvenilir şekilde çalışmaz. GPS sinyalleri zayıftır ve gökyüzünü görmeyi gerektirir. Dışarıda veya bir pencerenin yanında test edin.



