GPS parts provide location tracking using NMEA GPS receivers and waypoint-based navigation.
GPS Position Reading
GpsNmeaPositions
Converts NMEA sentences to UTM positions.
Constructor:
GpsNmeaPositions(debug=False)
Methods:
Convert list of (timestamp, nmea_sentence) tuples to (timestamp, x, y) positions in UTM coordinates
Threaded version of run()
Output: List of tuples (timestamp, easting, northing) in UTM meters
Usage Example:
from donkeycar.parts.gps import GpsNmeaPositions
gps_reader = GpsNmeaPositions(debug=True)
# Process NMEA sentences
nmea_lines = [
(1234567890, '$GPRMC,003918.00,A,3806.92281,N,12235.64362,W,0.090,,060322,,,D*67')
]
positions = gps_reader.run(nmea_lines)
# Returns: [(1234567890, 546789.12, 4215432.56)]
GpsLatestPosition
Returns the most recent valid GPS position.
Constructor:
GpsLatestPosition(debug=False)
Methods:
run
(positions: list) -> tuple
Returns the last position from the list, or None if empty
Usage Example:
from donkeycar.parts.gps import GpsLatestPosition
latest = GpsLatestPosition()
position = latest.run(positions)
# Returns: (timestamp, x, y)
GpsPosition
Complete GPS part that reads serial NMEA and outputs position.
Constructor:
GpsPosition(serial, debug=False)
Serial port connected to GPS module
Methods:
Returns current position (timestamp, x, y) in UTM meters
Returns cached position from update thread
Continuously reads GPS in background thread
Usage Example:
from donkeycar.parts.gps import GpsPosition
from donkeycar.parts.serial_port import SerialPort
# Create serial connection
serial_port = SerialPort('/dev/ttyUSB0', baudrate=9600)
# Create GPS part
gps = GpsPosition(serial_port, debug=True)
# Add to vehicle (threaded)
V.add(gps,
outputs=['gps/timestamp', 'gps/x', 'gps/y'],
threaded=True)
GPS Playback
GpsPlayer
Replays recorded GPS NMEA sentences.
Constructor:
CSV logger containing recorded NMEA sentences
Methods:
run
(playing: bool, nmea_sentences: list) -> (bool, list)
Play recorded NMEA if playing=True, otherwise pass through live NMEA
Usage Example:
from donkeycar.parts.gps import GpsPlayer
from donkeycar.parts.text_writer import CsvLogger
# Load recorded NMEA data
nmea_log = CsvLogger('data/gps_log.csv')
# Create player
player = GpsPlayer(nmea_log)
player.start()
# Use in vehicle loop
playing, nmea = player.run(playing=True, nmea_sentences=[])
NMEA Parsing
parseGpsPosition
Low-level function to parse NMEA sentence to position.
Function:
parseGpsPosition(line, debug=False)
Returns: (longitude, latitude) tuple in UTM meters, or None if invalid
Supported Messages:
GPRMC: GPS Recommended Minimum
GNRMC: GNSS Recommended Minimum
Usage Example:
from donkeycar.parts.gps import parseGpsPosition
nmea = '$GPRMC,003918.00,A,3806.92281,N,12235.64362,W,0.090,,060322,,,D*67'
position = parseGpsPosition(nmea)
# Returns: (546789.12, 4215432.56)
Utility Functions
Extract checksum from NMEA sentence
Calculate checksum for NMEA sentence validation
nmea_to_degrees
(gps_str: str, direction: str) -> float
Convert NMEA coordinate format (DDDMM.MMMMM) to decimal degrees
Coordinate Systems
GPS coordinates in NMEA sentences use:
- Latitude: DDMM.MMMMM (degrees + minutes)
- Longitude: DDDMM.MMMMM (degrees + minutes)
- Direction: N/S for latitude, E/W for longitude
Example: 3806.92281,N = 38° 06.92281’ N
UTM Coordinates
Donkeycar converts GPS positions to UTM (Universal Transverse Mercator):
- Easting (X): Meters east from zone origin
- Northing (Y): Meters north from equator
- Advantages: Cartesian coordinates in meters, easier for navigation
Conversion:
import utm
# Convert lat/lon to UTM
easting, northing, zone_num, zone_letter = utm.from_latlon(latitude, longitude)
Serial Connection
Required Hardware
- GPS module with UART/serial output (e.g., u-blox, Adafruit GPS)
- USB-to-serial adapter or direct UART connection
Connection Setup
from donkeycar.parts.serial_port import SerialPort
serial_port = SerialPort(
port='/dev/ttyUSB0', # or '/dev/ttyAMA0' for Pi UART
baudrate=9600,
timeout=1.0
)
Configuration
Typical GPS configuration in myconfig.py:
# GPS Settings
GPS_SERIAL_PORT = '/dev/ttyUSB0'
GPS_BAUDRATE = 9600
GPS_TIMEOUT = 1.0
GPS_DEBUG = False
# Recording
RECORD_GPS = True
Integration Example
Basic GPS Logging
from donkeycar.parts.gps import GpsPosition
from donkeycar.parts.serial_port import SerialPort
# Setup GPS
serial_port = SerialPort(
port=cfg.GPS_SERIAL_PORT,
baudrate=cfg.GPS_BAUDRATE,
timeout=cfg.GPS_TIMEOUT
)
gps = GpsPosition(serial_port, debug=cfg.GPS_DEBUG)
# Add to vehicle
V.add(gps,
outputs=['gps/timestamp', 'gps/x', 'gps/y'],
threaded=True)
# Record GPS data
if cfg.RECORD_GPS:
inputs.extend(['gps/timestamp', 'gps/x', 'gps/y'])
types.extend(['float', 'float', 'float'])
GPS-Based Navigation
import numpy as np
class GpsNavigator:
def __init__(self, waypoints):
"""
waypoints: list of (x, y) UTM coordinates
"""
self.waypoints = waypoints
self.current_waypoint = 0
self.waypoint_threshold = 5.0 # meters
def run(self, gps_x, gps_y):
if self.current_waypoint >= len(self.waypoints):
return 0.0, 0.0 # Done
# Get current waypoint
target_x, target_y = self.waypoints[self.current_waypoint]
# Calculate distance
dx = target_x - gps_x
dy = target_y - gps_y
distance = np.sqrt(dx**2 + dy**2)
# Check if reached waypoint
if distance < self.waypoint_threshold:
self.current_waypoint += 1
if self.current_waypoint >= len(self.waypoints):
return 0.0, 0.0
target_x, target_y = self.waypoints[self.current_waypoint]
dx = target_x - gps_x
dy = target_y - gps_y
# Calculate steering angle to target
angle = np.arctan2(dy, dx)
return angle, 0.3 # Return angle and constant throttle
# Add to vehicle
waypoints = [(x1, y1), (x2, y2), (x3, y3)]
nav = GpsNavigator(waypoints)
V.add(nav,
inputs=['gps/x', 'gps/y'],
outputs=['pilot/angle', 'pilot/throttle'])
Troubleshooting
No GPS Fix
Symptoms: Position returns None or (0, 0)
Solutions:
- Ensure GPS has clear view of sky
- Wait for GPS to acquire satellites (can take 1-5 minutes)
- Check NMEA sentences contain ‘A’ (valid) not ‘V’ (warning)
- Verify antenna connection
Serial Connection Issues
Symptoms: No data from serial port
Solutions:
- Check device path:
ls /dev/ttyUSB* or ls /dev/ttyAMA*
- Verify baudrate matches GPS module (usually 9600)
- Check serial permissions:
sudo usermod -a -G dialout $USER
- Test with:
cat /dev/ttyUSB0
Coordinate Accuracy
Note: GPS accuracy is typically 2-10 meters for consumer modules. For better accuracy:
- Use RTK GPS modules
- Implement differential GPS
- Filter positions with Kalman filter
Requirements
pip install pyserial utm pynmea2