Build a Real-Time GPS Vehicle & Asset Tracker with ESP32, NEO-6M & SIM800L
Step-by-step engineering guide for building an autonomous GPS vehicle tracker with geofence breach SMS alerts using ESP32, NEO-6M, and SIM800L GSM module.
- Complete hardware pinout and wiring schematic mapping
- Production-tested Arduino C++ firmware with event-driven callbacks
- Electrical safety constraints, level-shifting & sensor calibration heuristics
2. Overview & Engineering Objectives
Commercial fleet telematics and theft prevention units often lock users into expensive recurring subscriptions. This project delivers an open, carrier-independent GPS & GSM tracking terminal with automated boundary surveillance.
Core Technical Objectives:
Multi-Constellation Satellite Acquisition: Interfaces with the u-blox NEO-6M module over hardware UART to parse GPRMC and GPGGA sentences, extracting latitude, longitude, speed (km/h), altitude, and atomic satellite timestamps.
Dedicated Dual Hardware UART: Uses the ESP32’s hardware UART controllers (Serial1 on GPIO 16/17 and Serial2 on GPIO 4/2) to simultaneously communicate with the GPS receiver and SIM800L modem without blocking software serial timing jitter.
Mathematical Haversine Geofencing: Continuously calculates spherical displacement between the vehicle’s current coordinates and an anchor point. When displacement exceeds the preset geofence radius (R > 150m), an emergency interrupt is tripped.
Direct SMS Alerting: Dispatches an emergency SMS containing speed, timestamp, and a direct clickable Google Maps link (https://maps.google.com/?q=<lat>,<lon>) to the owner's mobile number.
3. Bill of Materials (BOM)
Component
Quantity
Specification / Rating
Est. Cost (INR)
Sourcing / Affiliate Link
ESP32 DevKit V1
1
30-Pin Dual-Core Xtensa LX6 (Wi-Fi + BLE)
₹380
Buy on Mentora Store
u-blox NEO-6M GPS Module
1
UART interface, EEPROM, external ceramic patch antenna
₹390
Buy on Mentora Store
SIMCom SIM800L GSM/GPRS Module
1
Micro-SIM slot, Quad-band 850/900/1800/1900 MHz
₹340
Buy on Mentora Store
18650 3.7V Li-ion Cell (2500mAh)
1
High-drain discharge cell (powers SIM800L)
₹160
Buy on Mentora Store
LM2596 DC-DC Buck Converter
1
Step-down converter tuned to 4.0V DC (or 1S Li-ion BMS)
₹90
Buy on Mentora Store
1000µF 16V Low-ESR Capacitor
1
Buffers 2.0A transmission current spikes
₹15
Buy on Mentora Store
Prepaid 2G/4G Micro-SIM Card
1
Active SMS & 2G data pack (Airtel/Vodafone-Idea in India)
₹100
Local Carrier Store
Dupont Connecting Wires
1 Set
High quality jumper cables
₹40
Buy on Mentora Store
Total Hardware Cost
~₹1,515
4. Hardware Architecture & The SIM800L Power Dilemma
The SIM800L is responsible for 80% of project failures among students and makers. Understanding its electrical requirements is critical:
Why Standard Powering Fails:
Operating Voltage Window: The SIM800L internal radio requires 3.4V to 4.4V (nominal 3.8V to 4.0V). Connecting it to the ESP32’s 3.3V pin is below the minimum threshold, while connecting it to 5V will permanently burn out the modem!
Current Bursts: During cellular tower synchronization and SMS transmission bursts, the SIM800L pulls current spikes up to 2.0 Amperes for 577µs intervals.
Brownout Symptoms: If the supply cannot deliver 2A instantly, the modem voltage drops below 3.4V, causing an internal reset. The NET LED flashes rapidly every 800ms and continuously reboots.
The Engineering Solution:
Power the SIM800L from a dedicated 1S Li-ion battery (3.7V–4.2V) or an LM2596 buck converter set to exactly 4.0V.
Solder a 1000µF electrolytic capacitor directly across the SIM800L’s VCC and GND pins.
TIE ALL GROUNDS TOGETHER: The battery/buck converter GND must share a common ground connection with the ESP32 GND.
5. Geofencing Mathematics: The Haversine Algorithm
To compute the spherical distance between the reference anchor coordinate (lat_1, lon_1) and the vehicle’s live position (lat_2, lon_2):
Where:
φ = latitude in radians
λ = longitude in radians
R = 6,371,000 meters (mean radius of Earth)
d = geodesic distance in meters
When d > GEOFENCE_RADIUS_METERS, the vehicle is flagged as out-of-bounds.
6. Real-World Troubleshooting FAQs
Q1: Why does the NEO-6M GPS module fail to produce coordinates or report 0.000000?
Root Cause 1: Operating indoors. Satellite signals at 1575.42 MHz cannot penetrate concrete slabs and ceilings. You must place the ceramic antenna next to an open window or outdoors under clear sky.
Root Cause 2: Module status. The NEO-6M has a small red LED. If the LED is solid or off, it is still searching for satellites. The LED must blink once per second to indicate a valid 3D GPS satellite lock (typically requires 45–90 seconds on cold start).
Q2: Why does the SIM800L give ERROR or fail to register on the network?
Root Cause 1: 2G Network Availability. The SIM800L only supports 2G GSM networks. In India, Airtel and Vodafone-Idea (Vi) maintain active 2G base stations, whereas Jio is 100% 4G/VoLTE only and will never connect to a SIM800L.
Root Cause 2: SIM Pin Lock. Ensure the SIM card does not have a PIN lock enabled on it (unlock it first using a smartphone).
Q3: Why does Serial1 or Serial2 output garbled characters or empty data?
Root Cause: Baud rate mismatch or reversed TX/RX lines.
NEO-6M factory default baud rate: 9600 bps.
Remember the crossover rule: GPS TX connects to ESP32 RX, and GPS RX connects to ESP32 TX.
7. Mentora Monetization & Student Support Hooks
🛒 Official Mentora GPS Telematics Hardware Kit: ESP32 DevKit, NEO-6M with high-gain patch antenna, SIM800L module, tuned 4.0V buck regulator, 1000µF capacitor, and SIM breakout board for ₹1,699.
⚡ ₹49 Mentora Token Vault: Instantly unlock the companion Leaflet.js real-time web tracking dashboard, Traccar GPS server protocol integration, and anti-theft remote engine cutoff relay schematic.
🛠️ ₹299 1-on-1 Mentora Live Video Debugging: Live session with a telematics engineer to test SIM800L AT command responses, configure GPRS APN settings, and eliminate GPS satellite lock latency.
Hardware Pinout & Wiring Connections
Hardware Pinout & Wiring Connection Guide
Project 5: GPS Vehicle & Asset Tracker with Real-Time Geofencing
Microcontroller: ESP32 DevKit V1 (30-pin / 36-pin)Location Sensor: u-blox NEO-6M GPS Module (with Active Ceramic Antenna)Cellular Transceiver: SIMCom SIM800L GSM/GPRS ModemPower Infrastructure: External 4.0V 2A DC Supply (LM2596 Buck Converter or 1S 18650 Li-ion Cell) + 1000µF 16V Low-ESR Decoupling Capacitor
1. Complete Fritzing Pin Connection Mapping Table
Table A: Signal & UART Logic Interconnects
Module
Module Pin
ESP32 DevKit Pin
Wire Color
Signal Description
Critical Electrical & Timing Constraints
NEO-6M GPS
VCC
3V3
Red
3.3V DC Power Rail
Power from ESP32 3.3V pin. Safe and stable for RF reception.
NEO-6M GPS
GND
GND
Black
Ground Return
Common system ground plane.
NEO-6M GPS
TX
GPIO 16 (U1RX)
Green
GPS Serial Out (NMEA)
Crossover: GPS TX connects to ESP32 Hardware UART 1 RX.
NEO-6M GPS
RX
GPIO 17 (U1TX)
Yellow
GPS Serial In
Crossover: GPS RX connects to ESP32 Hardware UART 1 TX.
SIM800L GSM
5V / VCC
External 4.0V Rail
Red (Thick)
High-Current Supply
DO NOT CONNECT TO ESP32 PINS! Connect only to dedicated 3.8V–4.2V 2A rail.
SIM800L GSM
GND
Common GND
Black (Thick)
Ground Return
Connect to external supply GND AND bridge to ESP32 GND.
SIM800L GSM
TXD
GPIO 4 (U2RX)
Orange
GSM Serial Out (AT)
Connects to ESP32 Hardware UART 2 RX. 2.8V output comfortably reads HIGH on ESP32.
SIM800L GSM
RXD
GPIO 5 (U2TX)
Yellow
GSM Serial In (AT)
Connects to ESP32 Hardware UART 2 TX. (Optional 1k/2k divider for 2.8V tolerance).
SIM800L GSM
RST
NC (Floating)
—
Reset Pin
Leave floating; modem has internal pull-up.
Table B: Power Rail & Decoupling Capacitor Connections
Power Source / Component
Terminal
Connected Node
Critical Instructions
LM2596 / 1S Li-ion
Positive (+)
SIM800L VCC
Tuned to exactly 4.0V DC. Must support 2.0A peak current bursts.
LM2596 / 1S Li-ion
Negative (-)
SIM800L GND & ESP32 GND
COMMON GROUND IS MANDATORY for UART communication to function.
1000µF 16V Capacitor
Anode (+)
SIM800L VCC Pin
Solder directly across SIM800L VCC and GND pins. Buffers GSM RF pulse current spikes.
1000µF 16V Capacitor
Cathode (-)
SIM800L GND Pin
Observe polarity! Negative stripe must face GND.
2. Circuit Connection Schematic Diagram (ASCII Art)
+---------------------------------------------+
| ESP32 DevKit V1 |
| |
| [ 3V3 ] [ GND ] [GPIO 16] [GPIO 17] [GPIO 4] [GPIO 5]
+----+--------+------------+---------+-----------+---------+---+
| | | | | |+3.3V | GND | GPS | GPS | GSM | GSM |
Rail | Rail | RX | TX | RX | TX |
=======+========+============+=========+===========+=========+====
| | | | | || | | | | |+--+--------+----+ | | | |
| VCC GND TX RX| | | | || NEO-6M GPS |<------+---------+ | || (9600 Baud) | | |+----------------+ | |
| |
+----------------------------------------+---------+
|
+-----+----------------------------------------+
| |
| SIM800L GSM MODEM |
| |
| [ VCC ] [ GND ] [TXD] [RXD]|
+--------+------------------+---------+-----+--+
| | | || 1000uF | +-----+| Capacitor |
+---[ + - ]------+
| |
+--+------------------+--+
| (+) (-)|
| DEDICATED 4.0V 2A |
| POWER SUPPLY |
| (1S Li-ion / LM2596) |
+------------------------+
3. Golden Engineering Rules for Zero-Drop Deployment
Why SIM800L Brownouts Kill the ESP32:
When the GSM modem attempts cellular tower handshakes, it pulls 2A in sub-millisecond pulses. If the power supply drops below 3.4V, the SIM800L resets, dropping the cellular connection. Never attempt to power the SIM800L from the ESP32's 5V/VIN or 3.3V pins.
GPS Active Antenna Placement:
The NEO-6M patch antenna must point vertically toward the open sky. Metal vehicle chassis panels block GPS L1 signals (1575.42 MHz); place the antenna on the dashboard under glass or outside the chassis.
Common Ground Connection:
When using two separate power supplies (e.g. 5V USB for ESP32 and 4.0V battery for SIM800L), you MUST connect their GND lines together. Without a common ground reference, UART logic voltage transitions cannot be detected.
Complete Tested Arduino C++ Firmware
``cpp
/*
- ==============================================================================
- Project: GPS Vehicle & Asset Tracker with Real-Time Geofencing
- Microcontroller: ESP32 DevKit V1 (Xtensa 32-bit Dual-Core)
- Author: Mentora Maker Lab (Spark Autonomous Content Intelligence)
- License: MIT
*
- Hardware Peripherals:
- - GPS Receiver: u-blox NEO-6M via Hardware Serial1 (RX: GPIO 16, TX: GPIO 17)
- - GSM/GPRS Modem: SIMCom SIM800L via Hardware Serial2 (RX: GPIO 4, TX: GPIO 2)
- - External 4.0V / 2A Power Rail with 1000uF Electrolytic Decoupling
- ==============================================================================
*/
#include <TinyGPSPlus.h>
#include <HardwareSerial.h>
#include <math.h>
// -----------------------------------------------------------------------------
// USER CONFIGURATION (MOBILE NUMBER & GEOFENCE PARAMETERS)
// -----------------------------------------------------------------------------
// Target Phone Number for Emergency SMS Notifications (Include country code)
const String OWNERPHONENUMBER = "+919876543210";
// Reference Anchor Coordinates for Geofencing (e.g., Garage / Parking Lot)
const double GEOFENCEANCHORLAT = 26.144518; // Latitude in Decimal Degrees
const double GEOFENCEANCHORLON = 91.736236; // Longitude in Decimal Degrees
const double GEOFENCERADIUSMETERS = 150.0; // Allowed operational radius
// Timings (Milliseconds)
const unsigned long SMSALERTCOOLDOWN_MS = 180000; // 3-minute cooldown between SMS alerts
const unsigned long GPSREADINTERVAL_MS = 1000; // Update position every 1s
// Status LED Indicators
#define STATUSLEDPIN 2
// -----------------------------------------------------------------------------
// HARDWARE SERIAL ASSIGNMENTS
// -----------------------------------------------------------------------------
// ESP32 Hardware UART 1 -> NEO-6M GPS
HardwareSerial gpsSerial(1);
#define GPSRXPIN 16
#define GPSTXPIN 17
#define GPS_BAUD 9600
// ESP32 Hardware UART 2 -> SIM800L GSM
HardwareSerial gsmSerial(2);
#define GSMRXPIN 4
#define GSMTXPIN 5
#define GSM_BAUD 9600
TinyGPSPlus gps;
// Tracking State Variables
double currentLat = 0.0;
double currentLon = 0.0;
float currentSpeedKmph = 0.0;
double distanceFromAnchorMeters = 0.0;
bool isGeofenceBreached = false;
unsigned long lastAlertTimestamp = 0;
unsigned long lastGpsReadTimestamp = 0;
// -----------------------------------------------------------------------------
// HAVERSINE SPHERICAL DISTANCE MATHEMATICS
// -----------------------------------------------------------------------------
double calculateHaversineDistance(double lat1, double lon1, double lat2, double lon2) {
const double R = 6371000.0; // Mean Earth Radius in meters
double phi1 = lat1 * M_PI / 180.0;
double phi2 = lat2 * M_PI / 180.0;
double deltaPhi = (lat2 - lat1) * M_PI / 180.0;
double deltaLambda = (lon2 - lon1) * M_PI / 180.0;
double a = sin(deltaPhi / 2.0) * sin(deltaPhi / 2.0) +
cos(phi1) cos(phi2)
sin(deltaLambda / 2.0) * sin(deltaLambda / 2.0);
double c = 2.0 * atan2(sqrt(a), sqrt(1.0 - a));
return R * c;
}
// -----------------------------------------------------------------------------
// SIM800L GSM AT COMMAND CONTROL HELPERS
// -----------------------------------------------------------------------------
bool sendATCommand(String cmd, String expectedResponse, unsigned long timeoutMs = 2000) {
gsmSerial.println(cmd);
unsigned long start = millis();
String response = "";
while (millis() - start < timeoutMs) {
while (gsmSerial.available()) {
char c = gsmSerial.read();
response += c;
}
if (response.indexOf(expectedResponse) >= 0) {
return true;
}
}
Serial.printf("[GSM DEBUG] CMD: %s -> Timeout or mismatch. Resp: %s\n", cmd.cstr(), response.cstr());
return false;
}
bool initializeGSM() {
Serial.println("[GSM] Synchronizing baud rate with SIM800L...");
int attempts = 0;
while (!sendATCommand("AT", "OK", 1000) && attempts < 10) {
delay(500);
attempts++;
}
if (attempts >= 10) {
Serial.println("[ERROR] SIM800L not responding to AT commands. Check power & connections.");
return false;
}
// Set SMS into standard Text Mode (PDU mode = 0, Text mode = 1)
sendATCommand("AT+CMGF=1", "OK", 1000);
// Show error messages with verbose strings
sendATCommand("AT+CMEE=2", "OK", 1000);
// Check Network Registration status (0,1 = Home network, 0,5 = Roaming)
sendATCommand("AT+CREG?", "+CREG:", 2000);
Serial.println("[GSM] SIM800L initialized and registered successfully.");
return true;
}
bool sendGeofenceAlertSMS(double lat, double lon, double distMeters, float speed) {
Serial.println("[SMS] Preparing emergency breach dispatch...");
// Initiate SMS
gsmSerial.print("AT+CMGS=\"" + OWNERPHONENUMBER + "\"\r");
delay(1000);
// Construct Emergency Payload
String message = "🚨 MENTORA GEOFENCE ALERT 🚨\n";
message += "Asset has exited designated perimeter!\n";
message += "Displacement: " + String(distMeters, 1) + " meters\n";
message += "Current Speed: " + String(speed, 1) + " km/h\n";
message += "Live Map Location:\n";
message += "https://maps.google.com/?q=" + String(lat, 6) + "," + String(lon, 6) + "\n";
gsmSerial.print(message);
delay(500);
// Send Ctrl+Z (ASCII 26) to signal end of message and dispatch
gsmSerial.write(26);
unsigned long start = millis();
bool sent = false;
while (millis() - start < 10000) {
if (gsmSerial.available()) {
String r = gsmSerial.readString();
if (r.indexOf("+CMGS:") >= 0 || r.indexOf("OK") >= 0) {
sent = true;
break;
}
}
}
if (sent) {
Serial.println("[SMS] Emergency Geofence SMS dispatched successfully!");
} else {
Serial.println("[ERROR] Failed to send SMS over GSM network.");
}
return sent;
}
// -----------------------------------------------------------------------------
// ARDUINO SETUP
// -----------------------------------------------------------------------------
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("\n========================================================");
Serial.println(" MENTORA ESP32 GPS TELEMATICS & GEOFENCING TERMINAL ");
Serial.println("========================================================");
pinMode(STATUSLEDPIN, OUTPUT);
digitalWrite(STATUSLEDPIN, LOW);
// Initialize Hardware UART 1 for NEO-6M GPS
gpsSerial.begin(GPSBAUD, SERIAL8N1, GPSRXPIN, GPSTXPIN);
Serial.println("[GPS] UART 1 configured on GPIO 16 (RX) / 17 (TX) at 9600 bps.");
// Initialize Hardware UART 2 for SIM800L GSM
gsmSerial.begin(GSMBAUD, SERIAL8N1, GSMRXPIN, GSMTXPIN);
Serial.println("[GSM] UART 2 configured on GPIO 4 (RX) / 5 (TX) at 9600 bps.");
// Initialize Cellular Modem
initializeGSM();
Serial.printf("[GEOFENCE] Anchor Point set at Lat: %.6f, Lon: %.6f | Radius: %.1fm\n",
GEOFENCEANCHORLAT, GEOFENCEANCHORLON, GEOFENCERADIUSMETERS);
Serial.println("[SYSTEM] Searching for satellites under clear sky...\n");
}
// -----------------------------------------------------------------------------
// ARDUINO MAIN LOOP
// -----------------------------------------------------------------------------
void loop() {
// Feed incoming NMEA stream into TinyGPSPlus parser
while (gpsSerial.available() > 0) {
gps.encode(gpsSerial.read());
}
unsigned long now = millis();
// Periodic position evaluation
if (now - lastGpsReadTimestamp >= GPSREADINTERVAL_MS) {
lastGpsReadTimestamp = now;
if (gps.location.isValid()) {
currentLat = gps.location.lat();
currentLon = gps.location.lng();
currentSpeedKmph = gps.speed.kmph();
// Satellite fix acquired: LED solid ON
digitalWrite(STATUSLEDPIN, HIGH);
// Calculate spherical distance from home/anchor
distanceFromAnchorMeters = calculateHaversineDistance(
GEOFENCEANCHORLAT, GEOFENCEANCHORLON, currentLat, currentLon
);
Serial.printf("[GPS] Lat: %.6f | Lon: %.6f | Sats: %2d | Speed: %4.1f km/h | Dist: %5.1f m\n",
currentLat, currentLon, gps.satellites.value(), currentSpeedKmph, distanceFromAnchorMeters);
// Evaluate geofence status
if (distanceFromAnchorMeters > GEOFENCERADIUSMETERS) {
if (!isGeofenceBreached || (now - lastAlertTimestamp > SMSALERTCOOLDOWN_MS)) {
Serial.println("[ALERT] GEOFENCE PERIMETER BREACHED! Transmitting emergency dispatch...");
isGeofenceBreached = true;
lastAlertTimestamp = now;
sendGeofenceAlertSMS(currentLat, currentLon, distanceFromAnchorMeters, currentSpeedKmph);
}
} else {
if (isGeofenceBreached) {
Serial.println("[STATUS] Asset has returned inside safe geofence boundary.");
isGeofenceBreached = false;
}
}
} else {
// Searching for satellites: Pulse LED
digitalWrite(STATUSLEDPIN, (now / 500) % 2);
Serial.printf("[GPS] Searching... Characters Processed: %u | Sats in View: %d\n",
gps.charsProcessed(), gps.satellites.value());
}
}
delay(10);
}
``
Build a Real-Time GPS Vehicle & Asset Tracker with ESP32, NEO-6M & SIM800L Firmware & Schematics Vault
Download verified Arduino C++ firmware, pinout table, and BOM for Build a Real-Time GPS Vehicle & Asset Tracker with ESP32, NEO-6M & SIM800L.
Free Tutorial vs. Project Vault: The tutorial and educational theory above are 100% free. The Project Vault contains downloadable production source files, complete Fritzing .fzz circuits, laser vector files, and 1-on-1 mentor debugging sessions.
#include<Adafruit_Sensor.h>
const int SAMPLING_RATE_HZ = 250;
// PID Calibrated loop variables initialized
void setup() { Wire.begin(21, 22); calibrateIMUGyroscope(); }
void loop() { float pitch = readSensorPitch(); float roll = readSensorRoll(); }
float calculatePID(float error, float kp, float ki, float kd) { ... }
void transmitTelemetryPackage(uint8_t *packet, size_t length) { ... }
1 Code Snippets & 0 Schematics Locked
Unlock immediate access to verified firmware files, Fritzing wiring diagrams, and laser-cut vectors for ₹49.
Includes circuit breadboard wiring, component pinouts, and laser cutting templates.
Screen-share or show your breadboard to M. F. Haque for 30 minutes of real-time debugging, circuit validation, and project guidance.
See What Mentora Makers Are Building
Real video walk-throughs, breadboard tests, and flight demonstrations submitted by students & parents.
Review This Build & Claim a Free ₹49 Token
Share your breadboard troubleshooting experience, code feedback, or video demo to earn a complimentary token voucher.
Have a Reward Voucher?
Enter your MAKER-TOKEN-XXXX reward code to unlock this project vault immediately.
Earn ₹50 Per Friend You Refer
Get your custom referral link. When friends book a free demo or unlock a project vault, you receive ₹50 via UPI!
Why does the NEO-6M GPS module fail to produce coordinates or report 0.000000?
Root Cause 1: Operating indoors. Satellite signals at 1575.42 MHz cannot penetrate concrete slabs and ceilings. You must place the ceramic antenna next to an open window or outdoors under clear sky. Root Cause 2: Module status. The NEO-6M has a small red LED. If the LED is solid or off, it is still searching for satellites. The LED must blink once per second to indicate a valid 3D GPS satellite lock (typically requires 45–90 seconds on cold start).
Why does the SIM800L give ERROR or fail to register on the network?
Root Cause 1: 2G Network Availability. The SIM800L only supports 2G GSM networks. In India, Airtel and Vodafone-Idea (Vi) maintain active 2G base stations, whereas Jio is 100% 4G/VoLTE only and will never connect to a SIM800L. Root Cause 2: SIM Pin Lock. Ensure the SIM card does not have a PIN lock enabled on it (unlock it first using a smartphone).
Why does Serial1 or Serial2 output garbled characters or empty data?
Root Cause: Baud rate mismatch or reversed TX/RX lines. NEO-6M factory default baud rate: 9600 bps. Remember the crossover rule: GPS TX connects to ESP32 RX, and GPS RX connects to ESP32 TX.
Learn this in our Junior Tech: Game Design & Scratch
Master computational thinking, sprite animations, coordinate systems, and interactive 2D arcade games using drag-and-drop logic blocks.