Saturday, July 18, 2026

GPS Waypoint Logger with NEO-6M and Raspberry Pi — Part 22: Never Get Lost Again

New here? This part builds a standalone GPS waypoint logger using a NEO-6M GPS module and a Raspberry Pi 3B. No internet required, no phone signal needed — the device records your coordinates to a file, and when you're back home, a Python script plots your route on a map. If the Raspberry Pi setup feels unfamiliar, Part 12 has the full walkthrough.


Why Build This?

Think about the last time you went somewhere off the beaten path — hiking, camping, exploring somewhere new. Your phone's GPS works great until it doesn't: no signal, dead battery, or the map app needs internet to load tiles.

A self-contained GPS logger solves all of that. Mark your starting point. Walk wherever you want. The device quietly records every coordinate along the way. When you need to find your way back, you have a file with every step you took. When you get home, Python draws the whole route on a graph.

Practical uses:

Camping: Mark your tent's location before heading into the woods for firewood. No more wandering in circles trying to find camp as it gets dark.

Hiking: Log the entire trail — every fork, every rest stop, every water source. Export the data afterward to share with friends or analyze your pace.

Exploring: Stamp interesting spots as you find them. That perfect viewpoint, the unusual tree, the flat clearing that would make a great campsite next time — all saved, all retrievable.

No subscription. No cloud. No phone signal required. Just a $10 GPS module, a Raspberry Pi, and a text file.


How GPS Actually Works

The NEO-6M module communicates with satellites using a system called triangulation: by measuring the time it takes for signals to arrive from at least 3–4 satellites, the receiver calculates your exact latitude, longitude, and altitude.

Once the module has a "fix" — meaning it's locked onto enough satellites — it continuously outputs position data as NMEA sentences: standardized text strings that look like $GPRMC,170431.00,A,3352.12345,N,11745.67890,W,...

Our Python script reads these strings, extracts the coordinates from $GPRMC sentences, and writes them to a CSV file. One line per second, as long as the script is running.

The key indicator: the module's LED. Fast blinking = searching for satellites. Slow blink every ~15 seconds = fix acquired, coordinates are reliable.


Hardware

ComponentNotes
NEO-6M GPS moduleComes with ceramic antenna
Raspberry Pi 3BAlready set up from Phase 2
4x Female-to-Female jumper wires
Power source for PiPower bank or Treedix UPS
LaptopFor viewing and plotting data afterward

A note on the NEO-6M's "pins": The module ships with 4 holes, not pin headers. To connect jumper wires properly, you need actual pins in those holes. Options:

  • Solder pin headers — most reliable, permanent
  • DIY: Cut 4 pins from a spare Arduino Nano header strip and insert them into the holes — works, but connections can be loose. If the LED doesn't light up, a loose VCC or GND connection is the most likely culprit.

Loose connections were the first bug encountered in this project. Solder if you can.






Wiring

Connect the NEO-6M to the Raspberry Pi 3B GPIO pins:

NEO-6M PinRaspberry Pi Pin
VCCPin 1 (3.3V) or Pin 2/4 (5V)
GNDPin 6, 9, 14, or any GND pin
TXPin 10 (GPIO15 / RXD)
RXPin 8 (GPIO14 / TXD)

Note: if the module doesn't light up on 3.3V, switch to 5V — the NEO-6M tolerates both.




Configuring the Raspberry Pi Serial Port

By default on Pi 3B, the hardware UART is used by Bluetooth. We need to reclaim it for GPS.

bash
sudo raspi-config

Interface OptionsSerial → "Would you like a login shell to be accessible over serial?" → No → "Would you like the serial port hardware to be enabled?" → Yes → Finish → Reboot


Installing Libraries


source my_project_env/bin/activate
pip install pyserial pynmea2

Verify:


python3 -c "import pynmea2; print('OK')"

If you see No module named pynmea2 when running from Thonny even after installing: go to Tools → Options → Interpreter → Python executable and set it to /home/pi3/my_project_env/bin/python3. This is the same interpreter issue that came up with other libraries in earlier parts — the fix is always the same.


The GPS Logger Script

Create gps_logger.py on the Pi:


import serial
import pynmea2
import time

# Open the Pi's hardware serial port
ser = serial.Serial('/dev/serial0', 9600, timeout=1)
filename = "gps_log.txt"

with open(filename, "w") as f:
    f.write("Time,Latitude,Longitude\n")
    f.flush()
    print("Logging coordinates... (Ctrl+C to stop)")

    try:
        while True:
            data = ser.readline().decode('utf-8', errors='ignore')
            if data.startswith('$GPRMC'):
                msg = pynmea2.parse(data)
                if msg.status == 'A':  # 'A' = Active = GPS fix confirmed
                    lat = msg.latitude
                    lng = msg.longitude
                    current_time = time.strftime("%Y-%m-%d %H:%M:%S")
                    log_data = f"{current_time},{lat},{lng}\n"
                    f.write(log_data)
                    f.flush()  # Write to disk immediately — critical
                    print(f"Saved: {lat}, {lng}")
            time.sleep(1)

    except KeyboardInterrupt:
        print("Logging stopped.")

Why f.flush() matters: Without it, Python holds data in memory and only writes to disk when the file closes. If you stop the script with Ctrl+C or the Pi loses power, everything buffered in RAM is lost. flush() after every line ensures each coordinate hits the disk immediately.

Run the script, take the Pi outside, wait for the LED to slow-blink (fix acquired), and walk your route. Press Ctrl+C when done.


Transferring the Data to Your Laptop

Once back inside, copy gps_log.txt from the Pi to your laptop. Easiest method:

On Windows (using WinSCP or SCP):

cmd
scp pi3@192.168.1.42:/home/pi3/my_project_env/gps_log.txt C:\Users\[username]\Desktop\

Or through VNC: open the file manager, navigate to the file, copy it to a USB drive.


Plotting the Route

Install the required libraries on your laptop:


pip install matplotlib pandas

Create plot_route.py on your laptop:


import pandas as pd
import matplotlib.pyplot as plt

# Load the GPS log
df = pd.read_csv('gps_log.txt')
df = df.dropna(subset=['Latitude', 'Longitude'])

plt.figure(figsize=(10, 6))
plt.plot(df['Longitude'], df['Latitude'],
         marker='o', color='b', linestyle='-',
         linewidth=1, markersize=3)

# Mark start and end points
plt.scatter(df['Longitude'].iloc[0], df['Latitude'].iloc[0],
            color='green', s=100, label='Start')
plt.scatter(df['Longitude'].iloc[-1], df['Latitude'].iloc[-1],
            color='red', s=100, label='End')

plt.title('GPS Route', fontsize=16)
plt.xlabel('Longitude', fontsize=12)
plt.ylabel('Latitude', fontsize=12)
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()

Run it. A window opens showing your route as a blue line — green dot for where you started, red dot for where you stopped. Every recorded coordinate is a point on the line.




Bugs Encountered (The Honest Version)

"No module named pynmea2" despite installing it — Thonny was using system Python instead of the virtual environment. Fix: set the interpreter path in Thonny's settings to /home/pi3/my_project_env/bin/python3.

GPS module LED not lighting up — loose pin connections. The NEO-6M's holes without soldered headers make for unreliable contact. Cutting pins from a spare Arduino Nano header and inserting them worked, but any vibration or movement could break the connection. Soldering pin headers is the proper fix.

gps_log.txt exists but is completely empty — Python was buffering writes in RAM and hadn't flushed to disk yet. Adding f.flush() after every f.write() solved it immediately.

No coordinates logged despite script running — GPS hadn't acquired a fix. The module needs open sky to lock onto satellites. Indoors, even near a window, fix acquisition can take several minutes or fail entirely. Take the hardware outside, wait for the LED to slow down to one blink every ~15 seconds, then start logging.


What We Built

A GPS coordinate logger that:

  • Runs entirely on local hardware, no internet required
  • Records one coordinate per second to a CSV file
  • Works for as long as the battery holds
  • Produces a route map with two lines of matplotlib

The data file is standard CSV — compatible with Google Earth (import as KML after conversion), GPS analysis tools, or anything else that reads lat/lon pairs. The route plot is basic, but the underlying data is the real output. Everything else is just a visualization of it.


Next up: Part 23 — Smart Security Camera with Person Detection and Alerts.