Oxide GNSS — a Rust-based ROS 2 driver for u-blox ZED-F9P with NTRIP and integrity monitoring

Hi everyone,

I’d like to announce the first release of “oxide_gnss”, a ROS 2 driver for u-blox ZED-F9P receivers.

Its focus is on providing a clean, simple way to get GNSS position, velocity and optional heading data from an F9P device with minimal effort, while also providing some safety integrity monitoring.

Built on ros2-rust (rclrs). MIT licensed.

Repo: GitHub - greenforge-labs/oxide_gnss: A Rust-based ROS2 GNSS driver for u-blox ZED-F9P devices with integrated NTRIP client · GitHub

Highlights:

  • Mode-based config for standalone / rover (NTRIP or radio) / moving base / moving-base-rover / static base setups — no need to hand-edit UBX CFG-VAL keys.
  • Integrated NTRIP client (including VRS via GGA uplink).
  • Optional safety integrity monitoring: protection levels (NAV-PL), jamming/spoofing detection (SEC-SIG), antenna status, etc., aggregated into a ~/integrity topic and a simple ~/operational go/no-go Bool.
  • CI against Humble / Jazzy / Kilted on amd64 and arm64.
  • Includes a small admin CLI (oxide_gnss_assign_serial) for setting the F9P USB device serial string (useful when operating in moving base + rover mode).

A minimal rover with NTRIP config looks like:

mode: rover_ntrip

features:
  high_precision: true
  integrity: true

device:
  port: "/dev/gnss_f9p_rover"
  baud_rate: 460800
  frame: ENU
  navigation:
    rate_hz: 5

ntrip:
  host: "ntrip.data.gnss.ga.gov.au"
  port: 2101
  mountpoint: "SFLD00AUS0"
  username: "${NTRIP_USERNAME}"
  password: "${NTRIP_PASSWORD}"
  send_gga: true

Launch and you should see something like:

Startup output
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [oxide_gnss_node-1]: process started with pid [1145820]
[oxide_gnss_node-1] 2026-04-20T07:14:34.518326Z  INFO oxide_gnss::logging: Log files: /home/cmp/.ros/log/oxide_gnss
[oxide_gnss_node-1] 2026-04-20T07:14:34.518438Z  INFO oxide_gnss_node: oxide_gnss v0.1.0
[oxide_gnss_node-1] 2026-04-20T07:14:34.518469Z  INFO oxide_gnss_node: Starting GNSS driver node...
[oxide_gnss_node-1] 2026-04-20T07:14:34.620382Z  INFO oxide_gnss_node: Loading configuration from /home/cmp/ros2_ws/src/oxide_gnss/config/rover_ntrip.yaml
[oxide_gnss_node-1] 2026-04-20T07:14:34.625385Z  INFO oxide_gnss::config: Configuration mode: rover_ntrip
[oxide_gnss_node-1] 2026-04-20T07:14:34.625562Z  INFO oxide_gnss::config: Mode description: RTK rover with NTRIP corrections via network
[oxide_gnss_node-1] 2026-04-20T07:14:34.625640Z  INFO oxide_gnss::config: Features: ["high_precision", "integrity"]
[oxide_gnss_node-1] 2026-04-20T07:14:34.625720Z  INFO oxide_gnss::config: Enabled topics: ["~/fix", "~/velocity", "~/time_reference", "~/integrity", "~/operational"]
[oxide_gnss_node-1] 2026-04-20T07:14:34.625876Z  INFO oxide_gnss::config: UBX messages (USB): ["NAV_HPPOSLLH", "MON_COMMS", "NAV_SAT", "NAV_PVT", "SEC_SIG", "NAV_PL", "MON_RF"]
[oxide_gnss_node-1] 2026-04-20T07:14:34.625984Z  INFO oxide_gnss::config: NTRIP: enabled
[oxide_gnss_node-1] 2026-04-20T07:14:34.629255Z  INFO oxide_gnss::ros::publishers: Creating ~/integrity publisher
[oxide_gnss_node-1] 2026-04-20T07:14:34.629967Z  INFO oxide_gnss::ros::publishers: Creating ~/operational publisher
[oxide_gnss_node-1] 2026-04-20T07:14:34.630505Z  INFO oxide_gnss_node: Node is ready, spinning...
[oxide_gnss_node-1] 2026-04-20T07:14:34.630513Z  INFO oxide_gnss::device::task: Starting device task port=/dev/gnss_f9p_rover
[oxide_gnss_node-1] 2026-04-20T07:14:34.630505Z  INFO oxide_gnss::ntrip::task: Starting NTRIP task host=ntrip.data.gnss.ga.gov.au mountpoint=SFLD00AUS0
[oxide_gnss_node-1] 2026-04-20T07:14:34.630569Z  INFO oxide_gnss::ros::task: ROS publisher task starting
[oxide_gnss_node-1] 2026-04-20T07:14:34.630610Z  INFO oxide_gnss::ntrip::task: NTRIP state transition from=Disabled to=Connecting
[oxide_gnss_node-1] 2026-04-20T07:14:34.630613Z  INFO oxide_gnss::device::task: Device state transition from=Waiting to=Connecting
[oxide_gnss_node-1] 2026-04-20T07:14:34.630696Z  INFO ntrip_core::client: Connecting to NTRIP caster addr=ntrip.data.gnss.ga.gov.au:2101
[oxide_gnss_node-1] 2026-04-20T07:14:34.630787Z  INFO oxide_gnss::ros::task: Device state changed state=Connecting
[oxide_gnss_node-1] 2026-04-20T07:14:34.630918Z  INFO oxide_gnss::ros::task: NTRIP state changed state=Connecting
[oxide_gnss_node-1] 2026-04-20T07:14:34.631441Z  INFO oxide_gnss::device::serial: Serial port opened port=/dev/gnss_f9p_rover baud=460800
[oxide_gnss_node-1] 2026-04-20T07:14:34.631556Z  INFO oxide_gnss::device::task: Connected to device port=/dev/gnss_f9p_rover
[oxide_gnss_node-1] 2026-04-20T07:14:34.631611Z  INFO oxide_gnss::device::task: Device state transition from=Connecting to=Configuring (1/3)
[oxide_gnss_node-1] 2026-04-20T07:14:34.631718Z  INFO oxide_gnss::device::config: Starting device configuration sequence
[oxide_gnss_node-1] 2026-04-20T07:14:34.631757Z  INFO oxide_gnss::ros::task: Device state changed state=Configuring (1/3)
[oxide_gnss_node-1] 2026-04-20T07:14:34.631804Z  INFO oxide_gnss::config::ublox: Configuration validation: all essential and recommended messages enabled
[oxide_gnss_node-1] 2026-04-20T07:14:34.631992Z  INFO oxide_gnss::device::config: Using u-blox config from YAML (105 settings)
[oxide_gnss_node-1] 2026-04-20T07:14:34.732777Z  INFO oxide_gnss::device::config: Device configuration complete (105 values set in 2 packets)
[oxide_gnss_node-1] 2026-04-20T07:14:34.733088Z  INFO oxide_gnss::device::config: Issued UBX-CFG-RST (GNSS-only); waiting 3s for receiver to reacquire
[oxide_gnss_node-1] 2026-04-20T07:14:34.772569Z  INFO ntrip_core::client: Connected to NTRIP caster mountpoint=SFLD00AUS0 protocol=V2Chunked
[oxide_gnss_node-1] 2026-04-20T07:14:34.772858Z  INFO oxide_gnss::ntrip::task: NTRIP state transition from=Connecting to=Streaming
[oxide_gnss_node-1] 2026-04-20T07:14:34.773307Z  INFO oxide_gnss::ros::task: NTRIP state changed state=Streaming
[oxide_gnss_node-1] 2026-04-20T07:14:37.735455Z  INFO oxide_gnss::device::task: Device state transition from=Configuring (1/3) to=Active
[oxide_gnss_node-1] 2026-04-20T07:14:37.736554Z  INFO oxide_gnss::ros::task: Device state changed state=Active

Released as-is from internal automation use — plans for continued feature development are limited, but bug-fix PRs and forks are welcome.

Feedback / issues / PRs: Issues · greenforge-labs/oxide_gnss · GitHub