The navigation service is the single owner of the active navigation sensor pipeline. It publishes normalized navigation telemetry and accepts acknowledged navigation commands without requiring applications to know which IMU, GPS, or route-planning implementation is installed.
Applications should subscribe to public navigation topics for state and use command/request interfaces for acknowledged operations. They should not construct navigation hardware merely to display telemetry, request calibration, or calculate a route.
Route following is composed separately from raw sensor ownership:
NavigationSessionController owns the active destination, travel mode, and route lifecycle. RouteGuidanceController owns route-relative geometry/state only. ReroutePolicy decides when a sustained off-route condition warrants recalculation; it does not call a route planner itself.
Navigation composition is selected through runtime TOML. There is no separate simulation code path in the service CLI.
Physical example:
Simulation example:
Both configurations run the same controller and publication path. Only the concrete input sources change.
Start the ZeroMQ broker first:
Then start the navigation service with the desired runtime file:
For a simulation runtime:
The telemetry publisher endpoint comes from [messaging].publisher_endpoint. The navigation command endpoint defaults to tcp://127.0.0.1:5560 unless overridden in runtime configuration.
The service publishes one controller snapshot across the normalized navigation contracts:
openroad.navigation.positionopenroad.navigation.motionopenroad.navigation.attitudeopenroad.navigation.imuRoute following additionally publishes derived guidance state on:
route_guidance.stateSee messaging/README.md, docs/messaging/message_bus_idd.md, and docs/idd/ for subscriber examples and wire-contract details.
Commands use ZeroMQ REQ/REP rather than the PUB/SUB telemetry bus because callers need acknowledgement, result data, and error reporting.
Supported operations include:
navigation.calibrate_stationarynavigation.reset_headingnavigation.route.calculatenavigation.route.startnavigation.route.cancelnavigation.route.simulatenavigation.route.simulation.stopnavigation.route.calculate accepts an origin, destination, and travel mode and returns a RouteResult representation. NavigationCommandClient.calculate_route() is the normal programmatic client used by navigation-session rerouting.
navigation.route.start also activates guidance. Origin may be omitted to use the current fix; destination may be coordinates or a geocoded address. Cancellation ends the active session and stops playback. Request fields, responses, units, and failures are documented in the Navigation command IDD.
With an active route, navigation.route.simulate plays its shape at a positive finite time_scale (default 60). Android and gpsd sources are wrapped by RoutePlaybackPositionSource inside service composition: the receiver keeps running, while ORC delivers route-generated positions tagged route-simulation. The Android bridge continues reporting real GPS and needs no simulation mode.
navigation.route.simulation.stop resumes fresh live reports. Cancellation, replacement, arrival, and shutdown also stop playback; restarting starts with normal configured input. Late callbacks from old playback sessions are rejected. Browser and standalone simulation sources retain their existing route playback. The UI uses its existing request contracts and labels simulation explicitly. See Navigation runtime.
Application code for calibration/heading operations should normally depend on the toolkit-independent NavigationRequestHandlerIf. Route/session orchestration should depend on a route-calculation callable or client rather than constructing the route planner directly.
The service executes commands against the same controller/service composition used for navigation ownership. This prevents UI processes from creating competing hardware or route-planning instances.
RouteGuidanceController projects geographic positions onto the active route and reports progress, remaining distance, maneuver state, arrival, and route deviation. It uses separate off-route and on-route thresholds to provide hysteresis and avoid state flapping from ordinary GPS noise.
ReroutePolicy adds time-domain policy above that state. By default, an off-route condition must persist before a reroute is requested, and a cooldown prevents repeated recalculation attempts.
When recalculation succeeds, NavigationSessionController installs the replacement RouteResult into RouteGuidanceController and can notify map/presentation composition through its route-changed callback.
Applications that need a latest-value cache can use:
Register its setters with MessageDispatcher, then read snapshot() from the UI thread. common.telemetry.vehicle_bus_state.VehicleBusState provides the equivalent pattern for vehicle telemetry.
Portable unit and component coverage includes route planning, route/map presentation, navigation messaging, route guidance, off-route hysteresis/recovery, navigation-session lifecycle, and simulated rerouting through the real ZeroMQ command boundary.
Some integration tests are intentionally platform/environment dependent. Tests involving the Python gps binding, real gpsd/GNSS input, a live Valhalla service, or the graphical MapLibre renderer belong on the Raspberry Pi or another host with those dependencies installed.
The service writes structured JSON Lines to the shared ORC log store and stderr. Route requests, results, and failures carry operation IDs that reach the native map renderer. See ORC logging for live viewing, level configuration, rotation, and CI validation.