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


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

  1. Connect the VCC pin to the 3.3V pin of the ESP32.
  2. Connect the GND pin to any GND pin on the board.
  3. Connect the TX pin to GPIO 16.
  4. 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

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.

Image

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.

Image1

Step 2 — Arduino IDE Setup

1: Install Arduino IDE from arduino.cc

2: Install TinyGPSPlus.h library

3: Select TinyGPSPlus by Mikal Hart
4: Copy the sample code into the sketch files
Setting Value
Board ESP32 Dev Module

Step 3 — Upload the Code

  1. Open the project .ino file in Arduino IDE.
  2. Go to Tools → Board and select ESP32 Dev Module.
  3. Go to Tools → Port and select the correct COM port.
  4. Confirm that all libraries are installed and ensure that the GPS module has a clear view of the sky.
  5. 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

  1. Open the project .py file in Visual Studio Code.
  2. Wait for the GPS module to blink, then close the Arduino IDE sketch file
  3. 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

Arduino / C++

# 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

Python

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. 

C / C++

#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

  1. Initialize Serial and wait for GPS module to blink.
  2. Once the GPS module is blinking, run the Python Live Mapping Code.
  3. Run the Python code manually to get a live lock on the location.
  4. 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
NEO-6M GPS Live Tracker with ESP32 and Python Map Display


ArduinoArduino ideC++Esp32Esp32 dev boardFoliumGoogle mapsGpsGps trackerLive mappingPython

Leave a comment

All comments are moderated before being published