NEO-6M GPS Live Tracker with ESP32 and Python Map Display

Table of Contents ▼
01 Overview
In this tutorial, one can learn how to create a program that receives GPS data from a NEO-6M GPS module, reads and parses incoming NMEA sentences through serial communication, extracts useful information such as latitude, longitude, time, and signal status, and formats the processed data into CSV format for easy storage and analysis. It also explains how to display the current GPS coordinates on a digital map by pinning a live location whenever the module obtains a valid signal fix.</span></p>
<p dir="ltr"><span> In addition, the project includes a reusable class that handles NMEA parsing, CSV formatting, and live map updating, allowing users to easily integrate these functions into future GPS-based projects without rebuilding the system from scratch.
Project Use Case
The project can be used for basic vehicle tracking, outdoor navigation, delivery monitoring, and real-time location tracking systems. It can also serve as a foundation for IoT and GPS-based monitoring applications.
02 Hardware and Software Components
Hardware Components
| Component | Description |
|---|---|
| NEO 6M GPS module | a satellite-based positioning device used to determine geographic location coordinates such as latitude and longitude. It communicates with GPS satellites to obtain real-time location data, speed, altitude, date, and time information. |
| ESP32 | a low-cost microcontroller board that is commonly used in IoT and embedded systems projects. |
| Jumper Wires | Electrical connections |
Software Tools
| Software | Version / Details |
|---|---|
| Arduino IDE | 2.3.7 |
| Visual Studio Code | Latest Version |
| Python | Latest Version |
Project Files
| File | Description |
|---|---|
| test_with_gps_device.ino | Main Arduino sketch |
| GPS Tracker.py | Python code responpsible for live mapping |
| GPSLogger.h | Custom made library that allows users to call any specific output of the GPS sensor |
03 Application Discussion
Here is what each component does and why it is part of this project.
ESP32S
In this project, the ESP32S acts as the main controller that receives and processes GPS data from the GPS module.
NEO-6M GPS Module
In this project, the Neo 6M module provides the GPS data that is processed and displayed by the ESP32S.
Project Files
| File | Description |
|---|---|
| test_with_gps_device.ino | Main Arduino sketch |
| GPS Tracker.py | Python code responpsible for live mapping |
| GPSLogger.h | Custom made library that allows users to call any specific output of the GPS sensor |
03 Application Discussion
Here is what each component does and why it is part of this project.
ESP32S
In this project, the ESP32S acts as the main controller that receives and processes GPS data from the GPS module.
NEO-6M GPS Module
In this project, the Neo 6M module provides the GPS data that is processed and displayed by the ESP32S.
04 Hardware Setup
Wire the NEO 6M GPS Module to the ESP32 using the table below.
NEO 6M GPS Module to ESP32 Connections
| DHT11 Pin | ESP32 Pin | Description |
|---|---|---|
| VCC | 3.3V | Power Supply |
| GND | GND | Ground |
| RX | GPIO 17 | Receiver |
| TX | GPIO 16 | Transmitter |
Assembly Instructions
- Connect the VCC pin to the 3.3V pin of the ESP32.
- Connect the GND pin to any GND pin on the board.
- Connect the TX pin to GPIO 16.
- Connect the RX pin to GPIO 17.
05 Software Setup
Follow these steps in order. Do not skip the file replacement steps — they are required for this board to work correctly.
Step 1 — Python Setup
1: Go to python.org and download Python

2: Open Visual Studio Code and click extensions

3: Type Python

4: Install all Python related extensions

5: Click file to open a drop down menu and click new file

6: Clicking new file leads to a center drop down menu then select Python file

7:Clicking Python file opens a coding screen

After copying and pasting the Python script above into the VSCode, click the "Play" button located at the upper right of the screen. Make sure that the LED in the GPS Module is blinking first, before running the program.

After clicking the "Play" button in VSCode, it should redirect you into a link where it displays the current location of the GPS in a real time map.

Step 2 — Arduino IDE Setup
1: Install Arduino IDE from arduino.cc
2: Install TinyGPSPlus.h library

4: Copy the sample code into the sketch files| Setting | Value |
|---|---|
| Board | ESP32 Dev Module |
Step 3 — Upload the Code
- Open the project .ino file in Arduino IDE.
- Go to Tools → Board and select ESP32 Dev Module.
- Go to Tools → Port and select the correct COM port.
- Confirm that all libraries are installed and ensure that the GPS module has a clear view of the sky.
- Click Upload. After uploading, the GPS module should start locking onto a signal. It will start blinking when it has a valid signal.
Step 4 — Run Python Code
- Open the project .py file in Visual Studio Code.
- Wait for the GPS module to blink, then close the Arduino IDE sketch file
- Select the run Python file in the top right portion of the screen.
06 Code
Copy each code block below into its respective sketch file and paste the Python code into a Python file as described in the Software Setup Section. Read the Code Breakdown section to understand what each part does.
Main Sketch — test_with_gps_device.ino
# include TinyGPSPlus.h TinyGPSPlus gps; # define gpsSerial Serial2 void setup() { Serial.begin(115200); gpsSerial.begin(9600, SERIAL_8N1, 16, 17); Serial.println("Waiting for GPS fix and satellites..."); } void loop() { while (gpsSerial.available() > 0) if (gps.encode(gpsSerial.read())) displayLocationInfo(); if (millis() > 5000 && gps.charsProcessed() < 10) { Serial.println(F("No GPS detected: check wiring.")); while (true); } delay(1000); } void displayLocationInfo() { static bool headerPrinted = false; if (!headerPrinted) { Serial.println("Latitude,Longitude,Fix,Satellites,HDOP,Altitude_m,Speed_kmph,Course_deg,Date,Time"); headerPrinted = true; } Serial.print(gps.location.isValid() ? String(gps.location.lat(), 6) : "NA"); Serial.print(","); Serial.print(gps.location.isValid() ? String(gps.location.lng(), 6) : "NA"); Serial.print(","); Serial.print(gps.location.isValid() ? "1" : "0"); Serial.print(","); Serial.print(gps.satellites.isValid() ? String(gps.satellites.value()) : "NA"); Serial.print(","); Serial.print(gps.hdop.isValid() ? String(gps.hdop.hdop()) : "NA"); Serial.print(","); Serial.print(gps.altitude.isValid() ? String(gps.altitude.meters()) : "NA"); Serial.print(","); Serial.print(gps.course.isValid() ? String(gps.course.deg()) : "NA"); Serial.print(","); if (gps.date.isValid()) { Serial.printf("%02d/%02d/%04d", gps.date.day(), gps.date.month(), gps.date.year()); } else { Serial.print("NA"); } Serial.print(","); if (gps.time.isValid()) { Serial.printf("%02d:%02d:%02d", gps.time.hour(), gps.time.minute(), gps.time.second()); } else { Serial.print("NA"); } Serial.println(); }
Live Mapping — GPS Tracker.py
Paste this code into a Python file in Visual Studio Code
import serial
import time
import webbrowser
import folium
import os
SERIAL_PORT = 'COM7'
BAUD_RATE = 115200
MAP_FILE = 'map.html'
ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1)
print("Waiting for GPS data...")
printed_once = False
def create_map(lat, lon):
m = folium.Map(location=[lat, lon], zoom_start=18)
folium.Marker([lat, lon], tooltip="Current Location").add_to(m)
m.save(MAP_FILE)
while True:
try:
line = ser.readline().decode('utf-8', errors='ignore').strip()
if not line or "Latitude" in line:
continue
parts = line.split(',')
if len(parts) < 3:
continue
lat, lon, fix = parts[0], parts[1], parts[2]
if lat == "NA" or lon == "NA":
continue
if fix == "1" and not printed_once:
lat = float(lat)
lon = float(lon)
print(f"Valid Fix: {lat}, {lon}")
create_map(lat, lon)
webbrowser.open('file://' + os.path.realpath(MAP_FILE))
printed_once = True
break
except Exception as e:
print("Error:", e)
time.sleep(1)
GPS Logger Class (OPTIONAL) — GPSLogger.h
This is an additional class that you may use to call any value that the GPS sensor outputs.
#ifndef GPS_LOGGER_H
#define GPS_LOGGER_H
#include
class GPSLogger {
private:
TinyGPSPlus gps;
Stream* gpsSerial;
public:
// Constructor
GPSLogger(Stream& serial) : gpsSerial(&serial) {}
bool read() {
bool newData = false;
while (gpsSerial->available() > 0) {
if (gps.encode(gpsSerial->read())) {
newData = true;
}
}
return newData;
}
bool hasValidLocation() {
return gps.location.isValid();
}
double GetLatitude() {
return gps.location.lat();
}
double GetLongitude() {
return gps.location.lng();
}
double GetAltitude() {
return gps.altitude.meters();
}
double GetHDOP() {
return gps.hdop.hdop();
}
int GetSatelliteCount() {
return gps.satellites.value();
}
char GetLatitudeDirection() {
return gps.location.rawLat().negative ? 'S' : 'N';
}
char GetLongitudeDirection() {
return gps.location.rawLng().negative ? 'W' : 'E';
}
String GetCSV() {
if (!gps.location.isValid()) {
return "GPS location is Invalid!";
}
String csvFormat = String(GetLatitude(), 6) + GetLatitudeDirection() + ", ";
csvFormat += String(GetLongitude(), 6) + GetLongitudeDirection() + ", ";
csvFormat += String(GetSatelliteCount()) + ", "
+ String(GetHDOP()) + ", "
+ String(GetAltitude());
return csvFormat;
}
void displayLocationInfo() {
Serial.println(F("-------------------------------------"));
Serial.println("\n Location Info:");
Serial.print("Latitude: ");
Serial.print(gps.location.lat(), 6);
Serial.print(" ");
Serial.println(gps.location.rawLat().negative ? "S" : "N");
Serial.print("Longitude: ");
Serial.print(gps.location.lng(), 6);
Serial.print(" ");
Serial.println(gps.location.rawLng().negative ? "W" : "E");
Serial.print("Fix Quality: ");
Serial.println(gps.location.isValid() ? "Valid" : "Invalid");
Serial.print("Satellites: ");
Serial.println(gps.satellites.value());
Serial.print("HDOP: ");
Serial.println(gps.hdop.hdop());
Serial.print("Altitude: ");
Serial.print(gps.altitude.meters());
Serial.println(" m");
Serial.print("Speed: ");
Serial.print(gps.speed.kmph());
Serial.println(" km/h");
Serial.print("Course: ");
Serial.print(gps.course.deg());
Serial.println("°");
Serial.print("Date: ");
if (gps.date.isValid()) {
Serial.printf("%02d/%02d/%04d\n",
gps.date.day(),
gps.date.month(),
gps.date.year());
} else {
Serial.println("Invalid");
}
Serial.print("Time (UTC): ");
if (gps.time.isValid()) {
Serial.printf("%02d:%02d:%02d\n",
gps.time.hour(),
gps.time.minute(),
gps.time.second());
} else {
Serial.println("Invalid");
}
Serial.print("CSV Format: ");
Serial.println(GetCSV());
Serial.println(F("-------------------------------------"));
}
};
#endif
07 Code Breakdown
Here is what each part of the code does. Read this after uploading so you understand how it works.
Libraries
| Library | Purpose |
|---|---|
| test_with_gps_device.ino | Activates the GPS module and allows it to begin locking onto a signal. |
| GPS Tracker.py | Uses the valid signal of the GPS module to put a pin on the digital map of the current location of the GPS module. |
| GPSLogger.h | Optional class that allows users to display the specific NMEA output of the GPS module. |
Key Functions
setup()
Runs once at startup. This part of the code handles the initialization of the serial monitor and the necessary pins to be used on the ESP32S. Pins 16 and 17 are the RX & TX pins of the ESP32, which are responsible for sending & receiving data from the sensor.
loop()
Runs continuously. This part of the code handles the display of the serial monitor, whether the GPS module has locked onto a signal or not. It contains an if/else statement that changes the display of the serial monitor depending on the data it gathered.
Code Components in GPSLogger.h
| Component / Function | Purpose |
|---|---|
| GPSLogger(Stream& serial) | Allows the library to work with different serial ports like Serial2. |
| gps.encode(gpsSerial->read()) | Processes incoming GPS characters and converts them into usable data. |
| GetLatitude() and GetLongitude() | Returns the current GPS coordinates from the module. |
| GetHDOP() | Returns the accuracy value of the output signal from the GPS Module. |
| GetSatelliteCount() | Returns the total number of detected satellites. |
| analytics_create() | Builds the CHARTS tab with temperature and humidity trend charts. |
| GetLatitudeDirection() and GetLongitudeDirection() | Returns the current GPS direction based on its position (North, South, East, West). |
| GetCSV() | Combines GPS data into CSV format for easier logging and exporting. |
| displayLocationInfo() | Displays GPS information in a clean format through the serial monitor. |
General Program Workflow
- Initialize Serial and wait for GPS module to blink.
- Once the GPS module is blinking, run the Python Live Mapping Code.
- Run the Python code manually to get a live lock on the location.
- The Python file creates an html file on a specified path in the computer that can be viewed via browser.
08 Testing and Calibration
After uploading, verify each of the following to confirm the system is working correctly.
Valid Signal Lock
On startup, the GPS module does not start blinking but should take from 1-5 minutes then it will begin to blink, indicating it has a locked onto a valid signal.
Validating Sensor Readings
Open Google Maps and look up the accurate coordinates of the current location of the GPS module then compare it with the sensor output for validation of the sensor's accuracy.
09 System Demonstration
Video Demonstration
10 Conclusion
The project successfully received and processed GPS data from the Neo 6M GPS module while continuously updating the current location in real time. The system was able to display the live position on a digital map and output readable GPS information such as latitude and longitude. This shows that the project can be used for basic tracking, navigation, and location monitoring applications. The project also provided a good foundation for future GPS-based systems through data formatting and reusable code implementation. However, the GPS module performs best in open areas since buildings, roofs, and indoor environments can weaken satellite signals and affect location accuracy.
Possible Improvements and Future Enhancements
- Automated real-time live mapping function (no need to rerun the Python live mapping whenever location is changed)
11 References
- Youtube-How to use NEO-6M GPS module with ESP32 , Live gps tracker
12 Project Authors
- Matthew Vincent G. Bacaling
- Japhet Prince J. Pesic
