diff --git a/src/whisker/gps.rs b/src/whisker/gps.rs
index e0ee62fbc13928d92d452f9850290ee6ca0d5e4e..b15571a3d9320374a3d1b057ce2341cb8f71af2b 100644
--- a/src/whisker/gps.rs
+++ b/src/whisker/gps.rs
@@ -1,6 +1,6 @@
 use half::f16;
 
-#[derive(Debug, PartialEq, Clone)]
+#[derive(PartialEq, Clone)]
 pub struct Gps {
     latitude: i32,
     longitude: i32,
@@ -100,6 +100,43 @@ impl Gps {
     }
 }
 
+impl core::fmt::Debug for Gps {
+    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+        f.debug_struct("Gps")
+            .field("latitude", &DebugDegreesUnits(self.latitude()))
+            .field("longitude", &DebugDegreesUnits(self.longitude()))
+            .field("altitude", &DebugMeterUnits(self.altitude))
+            .field("max_error", &DebugMeterUnits(self.max_error))
+            .field("heading", &DebugDegreesUnits(self.heading()))
+            .field("speed", &DebugMeterPerSecondUnits(self.speed))
+            .finish()
+    }
+}
+
+struct DebugDegreesUnits<T>(T);
+
+impl<T: core::fmt::Display> core::fmt::Debug for DebugDegreesUnits<T> {
+    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+        write!(f, "{}°", self.0)
+    }
+}
+
+struct DebugMeterUnits<T>(T);
+
+impl<T: core::fmt::Display> core::fmt::Debug for DebugMeterUnits<T> {
+    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+        write!(f, "{} m", self.0)
+    }
+}
+
+struct DebugMeterPerSecondUnits<T>(T);
+
+impl<T: core::fmt::Display> core::fmt::Debug for DebugMeterPerSecondUnits<T> {
+    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+        write!(f, "{} m/s", self.0)
+    }
+}
+
 // no-std and it's not worth bringing in a library for this
 fn round(v: f64) -> u32 {
     let floor = v as u32;