While most puzzles were tested at a desk, the GPS challenge demanded real-world conditions, and quickly became the most technically unpredictable part of the system.

  1. GPS data doesn’t wait for you

Early implementations relied on blocking serial reads to capture a full NMEA sentence (e.g., “$GPRMC,…\r\n”). This led to severe bugs: the system would freeze waiting for a message, or display corrupted/incomplete coordinate data if a partial sentence was parsed.

To fix this, I rewrote the serial handling using an interrupt-driven ring buffer. Each character from the GPS module was read non-blocking via UART and stored until a full sentence was detected (\r\n). A gps_ready flag marked when a complete message was available. This allowed the game loop to remain responsive while waiting for valid GPS data in the background.

Raw NMEA GPS output captured on-device during debugging
  1. You only get one sentence at a time

Parsing the GPS stream was also trickier than expected. Multiple sentence types ($GPGGA, $GPRMC) arrived in unpredictable order. Fields could shift depending on the sentence type, and many fields (like coordinates) would be left blank until a satellite fix was acquired.

To handle this, I wrote a robust parser that accepted both sentence types, extracted latitude and longitude fields based on sentence format, and ignored invalid or zeroed-out coordinates until a fix was confirmed.

  1. Testing required… elevation

Because GPS reception was unreliable indoors, I often had to test outside. The most reliable results came from standing on top of a parking garage, holding the project box like a handheld scanner while watching the LCD slowly update with raw GPS data.

Late-night rooftop debugging
Late-night rooftop debugging