PyRaspBeta

GPS over serial

The NEO-6M GPS module in the shop talks over a UART, not I²C or SPI: it simply prints sentences once a second at 9600 baud. On the Pi that means the serial port, /dev/serial0, on the header's TXD (GPIO14) and RXD (GPIO15) pins. PyRasp provides a subset of pySerial and the real pynmea2 wheel for parsing.

The sentences use the NMEA 0183 format, which is plain ASCII lines with comma-separated fields and a checksum after a *. Wire the module's TX to the Pi's RXD and vice versa, plus power and ground (see the GPS part page):

circuit.py
from wiring import *

pi = Pi()
gps = GPS()
pi.V3_3 >> gps.vcc
gps.gnd >> pi.GND
gps.tx >> pi.RXD                 # module talks, Pi listens
gps.rx >> pi.TXD                 # Pi talks, module listens

Reading a position

Open the port at the module's 9600 baud and read line by line:

main.py
import pynmea2
import serial

port = serial.Serial("/dev/serial0", baudrate=9600, timeout=2)

while True:
    line = port.readline()
    if not line:
        continue
    try:
        msg = pynmea2.parse(line.decode("ascii", "ignore"))
    except pynmea2.ParseError:
        continue

    if isinstance(msg, pynmea2.RMC) and msg.status == "A":
        print(f"{msg.latitude:.5f}, {msg.longitude:.5f} "
              f"{msg.spd_over_grnd:.1f} kt")
    elif isinstance(msg, pynmea2.GGA):
        print(f"fix quality {msg.gps_qual}, {msg.num_sats} satellites")

msg.latitude and msg.longitude are decimal degrees, ready to print or store. readline() returns bytes, so decode before parsing.

The sentences the module sends

Once a second the simulator's module emits three standard sentences, each with a valid checksum:

SentenceContains
GPRMCtime, status (A = fix, V = no fix), latitude/longitude, speed in knots, course, date
GPGGAtime, position, fix quality, satellites in use, altitude
GPVTGcourse and speed (knots and km/h)

While there is no fix — for about the first 27 seconds after power-up — the position fields are empty and status is V, exactly as a real module reports a cold start. Your code should check the status before using coordinates.

Useful RMC/GGA attributes: timestamp, status, lat, lat_dir, lon, lon_dir, latitude, longitude, spd_over_grnd (knots), true_course, datestamp, gps_qual, num_sats, altitude. VTG has true_track, spd_over_grnd_kts and spd_over_grnd_kmph. Because every sentence carries a checksum, pynmea2 verifies it and raises pynmea2.ChecksumError for a corrupted one — a subclass of ParseError, so a single except covers both (and a partly read line raises the same).

The serial API

The simulator covers the parts of pySerial most projects use:

import serial

port = serial.Serial("/dev/serial0", baudrate=9600, timeout=1)
print(port.is_open, port.in_waiting)      # True, bytes waiting

port.write(b"$PCAS...\r\n")               # bytes reach the module's RX
line = port.read_until(b"\r\n")           # or readline()
chunk = port.read(10)
port.flush()
port.reset_input_buffer()                 # also flushInput()
port.close()

Only /dev/serial0, /dev/ttyS0 and /dev/ttyAMA0 can be opened — they are the same UART on this Pi. Opening anything else raises serial.SerialException. The board's baud rate starts at 115200 and is set when you open a port (or assign port.baudrate). The pyserial timeout is in simulated seconds.

Going deeper

Two modules can share the UART: the board transmits on TXD to whatever part's RX is wired there, and hears a part when its TX reaches RXD. Configuration commands the module receives are accepted and ignored, since the simulated module has no UBX state to change.

If the baud rates don't match — the module is fixed at 9600 — bytes arrive garbled with framing errors instead of arriving cleanly. Set the port to 9600.

Simulator vs real hardware

  • The position comes from the world. Sentences report the world's location, with metre-scale wander added to look like a real fix; the Lab's GPS feed can make the module stand still, walk or drive a loop, change the time-to-first-fix and satellite count. A real module would need actual sky view.
  • No UBX, no PPS pin. Only NMEA is produced. The module answers no binary configuration protocol, and the PPS state exists internally but there is no extra pin to wire. A real NEO-6M supports both UBX and a PPS pin.
  • No USB serial adapters. /dev/ttyUSB0 and /dev/ttyACM0 do not exist; the only ports are the three names for the header UART.
  • No driver-level details. Flow control (RTS/CTS), bytesize, parity, stopbits and write_timeout are accepted but do not affect the simulated bits beyond the baud check; readline() polls in small simulated-time steps instead of using a kernel buffer.
  • Sentences are generated, not received. The timestamp inside RMC/GGA is the simulated world clock, and the checksum is computed with an XOR exactly as NMEA defines it, so parsing, validation and logging code all behave as on hardware.