Documentation
OpenRoadCode Navigation Runtime
Source:
docs/navigation_runtime.md
Purpose
This document describes the vehicle-side navigation runtime: service ownership, startup order, ZeroMQ responsibilities, routing, route guidance, and the intended turn-by-turn lifecycle.
Map generation and deployment are documented separately in docs/navigation_deployment.md. Public message schemas are documented under docs/idd/.
Route simulation
Start a route, then select Simulate to play its geometry at the selected time
scale. Android bridge and gpsd profiles support playback inside the navigation
service: their live receivers keep running, and the bridge continues reporting
real GPS. Only ORC’s delivered navigation positions switch to route-simulation.
The UI labels playback and offers Stop simulation. Stopping playback, ending
the route, or reaching its destination resumes fresh live reports. Service
shutdown clears playback; a restart always starts with the configured live source.
Browser and standalone simulation profiles retain their existing playback support.
No bridge configuration change or native renderer rebuild is required.
Runtime architecture
flowchart TD
startup["Vehicle startup"] --> gpsd["gpsd"]
startup --> broker["openroadcode-message-broker.service<br/>:5556 ingress / :5557 egress"]
gpsd --> valhalla["valhalla.service"]
broker --> valhalla
valhalla --> navService["openroadcode-navigation.service"]
navService --> solution["Navigation solution<br/>position / attitude"]
navService --> planning["Route planning<br/>Valhalla"]
navService --> session["Navigation session<br/>route + rerouting"]
solution --> guidance["Route guidance state"]
session --> guidance
guidance --> subscribers["ZeroMQ subscribers<br/>CarUi / CarTui / logs"]
classDef orcApp fill:#dbeafe,stroke:#2563eb,color:#172554;
classDef orcService fill:#ede9fe,stroke:#7c3aed,color:#2e1065;
classDef orcController fill:#dcfce7,stroke:#16a34a,color:#14532d;
classDef orcMessage fill:#ffedd5,stroke:#ea580c,color:#7c2d12;
classDef orcAdapter fill:#fee2e2,stroke:#dc2626,color:#7f1d1d;
classDef orcExternal fill:#f3f4f6,stroke:#6b7280,color:#1f2937;
class startup,gpsd,valhalla orcExternal;
class broker,guidance orcMessage;
class navService orcService;
class solution,planning,session orcController;
class subscribers orcApp;
Service ownership
openroadcode-message-broker.service
Owns the process-wide ZeroMQ XPUB/XSUB broker. Producers connect to the publisher ingress endpoint and consumers connect to the subscriber egress endpoint. The broker contains no navigation policy.
Runtime wrapper: scripts/runtime/start_zeromq_broker.sh
Installer: scripts/systemd/install_message_broker_systemd.sh
valhalla.service
Owns the local Valhalla HTTP routing engine and reads the deployed routing dataset. It calculates routes but does not own the active navigation session.
Runtime wrapper: scripts/runtime/start_valhalla.sh
Installer: scripts/systemd/install_valhalla_systemd.sh
openroadcode-navigation.service
Owns vehicle navigation state and the navigation command endpoint. It publishes normalized navigation telemetry and uses Valhalla when route planning is enabled.
The production target is for this same service to own the active NavigationSessionController and RouteGuidanceController. Keeping session and guidance ownership here prevents a second daemon from having to duplicate active-route state.
Runtime wrapper: scripts/runtime/start_navigation_service.sh
Installer: scripts/systemd/install_navigation_service_systemd.sh
Startup
Install the complete runtime stack from the repository root:
sudo scripts/systemd/install_navigation_runtime_systemd.sh
This installs the routing runtime—message broker, Valhalla, and navigation. The separately scoped telemetry installer adds navigation and automotive producers but does not install Valhalla; use the navigation-runtime installer when route calculation is required.
The installer creates and enables services in dependency order:
openroadcode-message-broker.servicevalhalla.serviceopenroadcode-navigation.service
The navigation unit orders itself after the broker and Valhalla so telemetry and routing dependencies are available before navigation starts. gpsd.service is also ordered before navigation when present.
Check the complete stack with:
systemctl --no-pager --full status \
openroadcode-message-broker \
valhalla \
openroadcode-navigation
Logs are available through journald:
journalctl -u openroadcode-message-broker -b
journalctl -u valhalla -b
journalctl -u openroadcode-navigation -b
Turn-by-turn lifecycle
The intended production lifecycle is:
flowchart TD
client["UI / client requests destination"] --> command["Navigation command service"]
command --> planner["Route planning controller"] --> valhalla["Valhalla HTTP API"]
planner --> session["NavigationSessionController<br/>destination + travel mode + active route"]
session --> guidance["RouteGuidanceController<br/>normalized geographic position"]
guidance --> maneuver["Maneuver + distance-to-turn"]
guidance --> progress["Route progress"]
guidance --> offroute["Off-route state"]
guidance --> arrival["Arrival state"]
guidance --> topic["route_guidance.state"] --> bus["ZeroMQ"] --> presentation["Presentation clients"]
classDef orcApp fill:#dbeafe,stroke:#2563eb,color:#172554;
classDef orcService fill:#ede9fe,stroke:#7c3aed,color:#2e1065;
classDef orcController fill:#dcfce7,stroke:#16a34a,color:#14532d;
classDef orcMessage fill:#ffedd5,stroke:#ea580c,color:#7c2d12;
classDef orcAdapter fill:#fee2e2,stroke:#dc2626,color:#7f1d1d;
classDef orcExternal fill:#f3f4f6,stroke:#6b7280,color:#1f2937;
class client,presentation orcApp;
class command orcService;
class planner,session,guidance orcController;
class valhalla orcExternal;
class maneuver,progress,offroute,arrival,topic,bus orcMessage;
NavigationSessionController owns rerouting policy. RouteGuidanceController derives route-relative state but does not decide when a replacement route should be calculated.
CarUi and other presentation clients must not call Valhalla directly or implement rerouting policy. They request navigation actions through the navigation command interface and subscribe to public navigation/guidance state.
Public messaging
Navigation telemetry and route guidance are presentation-neutral contracts transported through the ZeroMQ broker.
Route guidance is published on route_guidance.state. See docs/idd/route_guidance_state.md for the versioned JSON schema, SI units, nullable maneuver fields, and consumer requirements.
The broker is transport only. Coordinate-frame semantics, units, source identity, validation, and schema versioning belong to the individual messaging contracts and IDDs.
Failure behavior
Each systemd unit uses restart-on-failure semantics. A failed UI must not terminate navigation services. A failed navigation consumer must not affect the broker or producer.
If Valhalla is unavailable, navigation telemetry should remain independently useful even though route calculation cannot succeed. The navigation service owns graceful reporting of route-planning availability to command clients.
Port/address conflicts are configuration or deployment errors. Services should fail with a clear diagnostic rather than silently selecting another endpoint, because consumers rely on stable configured endpoints.
Testing
Controller behavior is covered by unit tests under:
controllers/route_guidance/unit_test/
controllers/navigation_session/unit_test/
Messaging contract tests live with their contracts. End-to-end navigation/guidance exercises live under apps/common/component_test/.
Static systemd/runtime wiring tests live under:
scripts/systemd/unit_test/
Before merging navigation runtime changes, run at minimum:
python -m pytest \
controllers/route_guidance/unit_test \
controllers/navigation_session/unit_test \
messaging/contracts/route_guidance \
services/navigation/unit_test \
scripts/systemd/unit_test -v
On a Raspberry Pi deployment target, also verify the real boot boundary:
sudo systemctl restart openroadcode-message-broker valhalla openroadcode-navigation
systemctl --no-pager --full status openroadcode-message-broker valhalla openroadcode-navigation
A reboot test is required before treating startup changes as deployment-ready.
Design rules
- ZeroMQ owns transport, not navigation policy.
- Valhalla owns route calculation, not active-route state.
- The navigation service owns normalized navigation state and navigation-session orchestration.
- Route guidance is derived state and is published through a versioned contract.
- Presentation clients subscribe; they do not own routing or rerouting logic.
- Startup dependencies must be explicit in systemd rather than relying on timing delays.
- Service endpoints remain stable and configuration-driven.
- Runtime services must be independently restartable and observable through journald.