rpi pico_gps serial - dwilson2547/wiki_demo GitHub Wiki
Yes, absolutely! You can connect a GPS module to your Raspberry Pi Pico and read GPS coordinates. Here's how to do it with MicroPython:
Most GPS modules use UART (serial) communication. Common modules include:
- NEO-6M, NEO-8M (popular and affordable)
- NEO-9M (newer, faster acquisition)
GPS Module → Raspberry Pi Pico
VCC → 3.3V (Pin 36)
GND → GND (Pin 38)
TX → GP1 (Pin 2) - Pico RX
RX → GP0 (Pin 1) - Pico TX
Here's a complete example to read GPS coordinates:
import machine
import time
# Initialize UART for GPS
gps_uart = machine.UART(0, baudrate=9600, tx=machine.Pin(0), rx=machine.Pin(1))
def parse_gps_data(data):
"""Parse NMEA sentences and extract coordinates"""
lines = data.split('\n')
for line in lines:
if line.startswith('$GPGGA') or line.startswith('$GNGGA'):
# Parse GGA sentence (Global Positioning System Fix Data)
parts = line.split(',')
if len(parts) >= 15 and parts[2] and parts[4]: # Check if we have valid data
# Latitude
lat_raw = parts[2]
lat_dir = parts[3]
if lat_raw and lat_dir:
lat_deg = float(lat_raw[:2])
lat_min = float(lat_raw[2:])
latitude = lat_deg + (lat_min / 60.0)
if lat_dir == 'S':
latitude = -latitude
# Longitude
lon_raw = parts[4]
lon_dir = parts[5]
if lon_raw and lon_dir:
lon_deg = float(lon_raw[:3])
lon_min = float(lon_raw[3:])
longitude = lon_deg + (lon_min / 60.0)
if lon_dir == 'W':
longitude = -longitude
# Number of satellites
satellites = parts[7] if parts[7] else "0"
# Altitude
altitude = parts[9] if parts[9] else "0"
return {
'latitude': latitude,
'longitude': longitude,
'satellites': int(satellites),
'altitude': float(altitude),
'fix': True
}
return {'fix': False}
def main():
print("GPS Reader Starting...")
print("Waiting for GPS fix...")
buffer = ""
while True:
if gps_uart.any():
try:
# Read available data
data = gps_uart.read().decode('utf-8')
buffer += data
# Process complete lines
while '\n' in buffer:
line, buffer = buffer.split('\n', 1)
# Parse GPS data from complete sentences
gps_info = parse_gps_data(line + '\n')
if gps_info['fix']:
print(f"Latitude: {gps_info['latitude']:.6f}")
print(f"Longitude: {gps_info['longitude']:.6f}")
print(f"Satellites: {gps_info['satellites']}")
print(f"Altitude: {gps_info['altitude']:.1f}m")
print("-" * 40)
except UnicodeDecodeError:
# Skip invalid characters
pass
time.sleep(0.1)
if __name__ == "__main__":
main()
import machine
import time
import select
import sys
class GPSReader:
def __init__(self, uart_id=0, tx_pin=0, rx_pin=1, baudrate=9600):
self.uart = machine.UART(uart_id, baudrate=baudrate,
tx=machine.Pin(tx_pin), rx=machine.Pin(rx_pin))
self.buffer = ""
self.last_fix = None
def read_gps(self):
"""Read and parse GPS data"""
if self.uart.any():
try:
data = self.uart.read().decode('utf-8')
self.buffer += data
# Process complete NMEA sentences
while '\r\n' in self.buffer:
sentence, self.buffer = self.buffer.split('\r\n', 1)
self._parse_sentence(sentence)
except UnicodeDecodeError:
pass
def _parse_sentence(self, sentence):
"""Parse individual NMEA sentence"""
if sentence.startswith('$GPGGA') or sentence.startswith('$GNGGA'):
self._parse_gga(sentence)
elif sentence.startswith('$GPRMC') or sentence.startswith('$GNRMC'):
self._parse_rmc(sentence)
def _parse_gga(self, sentence):
"""Parse GGA sentence (detailed fix data)"""
parts = sentence.split(',')
if len(parts) >= 15 and parts[2] and parts[4] and parts[6] != '0':
try:
# Convert coordinates
lat = self._convert_coordinate(parts[2], parts[3])
lon = self._convert_coordinate(parts[4], parts[5])
self.last_fix = {
'latitude': lat,
'longitude': lon,
'satellites': int(parts[7]) if parts[7] else 0,
'altitude': float(parts[9]) if parts[9] else 0.0,
'time': parts[1],
'quality': int(parts[6]),
'timestamp': time.time()
}
except (ValueError, IndexError):
pass
def _convert_coordinate(self, raw_coord, direction):
"""Convert NMEA coordinate to decimal degrees"""
if not raw_coord:
return 0.0
# Determine if latitude (2 digits) or longitude (3 digits)
if len(raw_coord) >= 4:
if '.' in raw_coord:
decimal_pos = raw_coord.index('.')
if decimal_pos >= 4: # Longitude
degrees = float(raw_coord[:3])
minutes = float(raw_coord[3:])
else: # Latitude
degrees = float(raw_coord[:2])
minutes = float(raw_coord[2:])
else:
return 0.0
else:
return 0.0
decimal_degrees = degrees + (minutes / 60.0)
if direction in ['S', 'W']:
decimal_degrees = -decimal_degrees
return decimal_degrees
def get_location(self):
"""Get the most recent GPS fix"""
self.read_gps()
return self.last_fix
def has_fix(self):
"""Check if we have a recent GPS fix"""
if self.last_fix is None:
return False
# Consider fix valid if less than 10 seconds old
return (time.time() - self.last_fix['timestamp']) < 10
# Main program
def main():
gps = GPSReader()
print("GPS Reader initialized")
print("Waiting for GPS fix... (This may take 30-60 seconds outdoors)")
last_print = 0
while True:
# Check for user input (optional)
if select.select([sys.stdin], [], [], 0)[0]:
command = input().strip().lower()
if command == 'quit':
break
location = gps.get_location()
# Print status every 2 seconds
if time.time() - last_print > 2:
if gps.has_fix() and location:
print(f"Lat: {location['latitude']:.6f}, Lon: {location['longitude']:.6f}")
print(f"Satellites: {location['satellites']}, Alt: {location['altitude']:.1f}m")
print(f"GPS Time: {location['time']}")
else:
print("Searching for GPS satellites...")
last_print = time.time()
time.sleep(0.1)
if __name__ == "__main__":
main()
- GPS modules need clear sky view - won't work indoors reliably
- Cold start can take 30-60 seconds to get first fix
- Check your GPS module's specifications - some use different UART pins or baud rates
- Power consumption - GPS modules can be power-hungry
- NMEA sentences - GPS modules output various sentence types (GGA, RMC, etc.)
- Coordinate conversion - NMEA format uses degrees and decimal minutes
- Error handling - GPS data can be incomplete or corrupted
- Start outdoors with clear sky view
- LED indicators - Some modules have LED indicators for fix status
- Raw data testing - You can test with a serial terminal first to see raw NMEA data
- Backup battery - Consider adding one to GPS module for faster subsequent fixes
Would you like me to show you how to:
- Integrate this with sending coordinates over USB serial to your computer?
- Add logging capabilities?
- Calculate distances between coordinates?
- Add specific features like waypoint navigation?