Robot Configuration
robot.toml is the per-robot configuration the agent reads at startup. It declares
the robot's transport, ingest and command topics, command policy, and the UI
capabilities (services, sensors, settings, and resource producers) the robot
advertises to the fleet manager. This page documents every key the agent parses.
File location and loading
- Path:
{state_dir}/robot.toml, where the state directory defaults to/var/lib/rdyn/robot(override with theRDYN_STATE_DIRenvironment variable). So the default path is/var/lib/rdyn/robot/robot.toml. - Read once at startup. The agent loads the file a single time when it starts. Changes take effect on the next agent restart.
- Format: TOML. All config access goes through the agent's central loader; do not parse config files elsewhere in your own on-host tooling.
- Unknown keys are ignored silently, so a typo in a key name is dropped rather than reported.
- No secrets.
robot.tomlholds no keys, certificates, CA roots, or tokens; those live in separate files referenced by path fromagent.toml.
Every section below is optional. A minimal (even empty) robot.toml is valid: the
agent then uses local Zenoh with the robot/** uplink wildcard, the command
base topic, all commands allowed, and no advertised UI capabilities.
What lives in agent.toml instead
Some settings that relate to the robot are not part of robot.toml. The agent
reads them from agent.toml, and keys for them placed in robot.toml are ignored:
- The robot's identity (
robot_id), written intoagent.tomlduring enrollment. - Server and signaling URLs.
- TLS paths (
ca_root,device_cert,key_private) and Zenoh router endpoints.
See the agent Configuration reference for
those. The local coordinate origin is also not a robot.toml key: it is
delivered as onboard settings from the cloud and persisted by the agent. See
Coordinate Frames.
Naming convention. The top-level flags and the keys under
[zenoh_topics],[zenoh_command_topics],[local_transport], and[allowed_commands]usesnake_case. The capability-array fields under[[services]],[[sensors]],[[settings]], and[[resources]]usecamelCase(for examplecapabilityType,displayHint,geometryType). Enum-valued fields are case-insensitive.
System flags (top-level keys)
These keys sit at the top of the file, outside any section.
| Key | Default | What it controls |
|---|---|---|
use_ros2 |
true |
Detection-only flag. The agent always uses the local Zenoh Cap'n Proto path regardless of this value; ROS 2 systems run an external bridge onto the same topics. The value is logged at startup and reserved for future use. |
mission_catch_up_window_sec |
3600 |
Mission catch-up window, in seconds. At startup the scheduler deletes any persisted mission whose scheduled end time is older than now - window. Default is one hour. |
enforce_spatial_directives |
true |
Enables the agent-side field rule evaluator. See below. |
convert_commands_to_local |
false |
Delivers downlink geometry in your local ENU frame instead of WGS84. See below. |
allow_remote_config_read |
false |
Lets the fleet server fetch this file over the control plane. See below. |
allow_remote_config_write |
false |
Lets the fleet server overwrite this file over the control plane. See below. |
robot_link |
(unset) | Optional URL to the robot's local user interface or OEM UI. Reported to the fleet server at startup and shown in the fleet UI. See below. |
enforce_spatial_directives. When true, the agent compares the robot's WGS84
position against stored polygon field rules and, on zone enter/exit, reports status
to the server and applies the zone's settings and services to your robot software.
Set it to false to disable only the agent-side evaluator: field rules are
still persisted and queryable, and any status your robot software publishes itself
is still forwarded. (The key name mirrors the wire identifier; the customer-facing
concept is "field rules.") See Field Rules.
convert_commands_to_local. When true and a local origin is configured,
the agent converts geometry-bearing commands and query replies from WGS84 into your
robot's local ENU frame before delivering them. The default passes WGS84 through
unchanged. Inbound telemetry is always normalized to WGS84 regardless of this flag.
See Coordinate Frames.
Remote config access. When enabled, the fleet server can remotely read
(allow_remote_config_read) and/or overwrite (allow_remote_config_write) this
file over the control plane. Both default to false, so remote access is strictly
opt-in. A remote overwrite replaces the whole file and takes effect on the next
agent restart. Because robot.toml holds no secrets, exposing it is low-risk, but
it is still the operator's explicit choice.
robot_link. An optional URL pointing at the robot's on-device user interface
or OEM UI: a page an operator can open to reach the robot directly. When set, the
agent reports it to the fleet server at startup (over the control plane); the server
records it against the robot so the fleet UI can link to it. Leave it unset (the
default) to report no link. Unlike the flags above, this is a string, not a boolean,
and blank/whitespace-only values are treated as unset.
# robot.toml system flags (all shown with their defaults)
use_ros2 = true
# mission_catch_up_window_sec = 3600
# enforce_spatial_directives = true
# convert_commands_to_local = false
# allow_remote_config_read = false
# allow_remote_config_write = false
# robot_link = "https://192.168.1.50/ui" # optional; unset by default
[local_transport]
Selects the transport for the robot-software to agent hop on the same host. Absent
(the default) means local Zenoh. kind = "uds" switches to a Unix domain socket
carrying the same Cap'n Proto payloads.
[local_transport]
kind = "uds" # "zenoh" (default) | "uds"
uds_socket_path = "/run/rover-agent/agent.sock" # optional; this is the default
kind = "uds" requires the agent's local-uds build feature (on by default);
otherwise the agent logs a warning and falls back to Zenoh. See
Unix Domain Socket.
[zenoh_topics] (uplink ingest)
Your robot software (or the ROS 2 bridge) publishes Cap'n Proto
ApplicationToAgent messages to these local Zenoh keys, and the agent subscribes to
them. The keys carry no robot id; the agent adds identity when it relays to the
cloud.
By default the agent subscribes to a single wildcard key, wildcard_topic =
"robot/**", which receives every uplink type. While wildcard_topic is set, the
per-type keys are ignored. The per-type keys let you name individual subscriptions;
their default topic names (all sub-keys of robot/**) are:
| Key | Default local key | Message type |
|---|---|---|
motion_telemetry_topic |
robot/telemetry/motion |
GlobalMotionTelemetry, LocalMotionTelemetry |
status_telemetry_topic |
robot/telemetry/status |
StatusTelemetry |
extras_topic |
robot/telemetry/extras |
SensorTelemetry |
fault_topic |
robot/fault |
Fault |
mission_topic |
robot/mission |
MissionRunStatus |
geometry_topic |
robot/geometry |
ReportedFeatureUpdate |
path_topic |
robot/path |
(reserved; routes are server → robot) |
object_topic |
robot/object |
ObjectOp |
system_health_topic |
robot/health |
(retired; see below) |
usage_telemetry_topic |
robot/usage |
UsageTelemetry |
consumable_status_topic |
robot/consumable |
ConsumableStatus |
wildcard_topic |
robot/** |
all types (takes precedence when set) |
Because the payload is a self-describing union, the key does not select the message type: the agent dispatches on the union discriminant regardless of which of these keys a message arrives on. The per-type keys only let you split publishers.
system_health_topicno longer carries anything. Host health left the robot-software contract: the agent collects and reports it itself. The subscription still exists so an old configuration keeps parsing, but there is no longer an uplink variant to publish there. See Health Monitoring.
[zenoh_topics]
# Option A: one subscription for everything (the default behavior)
wildcard_topic = "robot/**"
# Option B: name topics per message type (omit wildcard_topic to use these)
# motion_telemetry_topic = "robot/telemetry/motion"
# fault_topic = "robot/fault"
For the full uplink message catalog and publishing conventions, see Uplink Messages and Telemetry Mappings.
[zenoh_command_topics] (downlink)
The agent publishes each downlink command as a Cap'n Proto AgentToApplication. A
command goes to the base command_topic unless a per-command subtopic is set, in
which case it goes to {command_topic}/{subtopic}. Every subtopic is optional.
| Key | Default | Command |
|---|---|---|
command_topic |
command |
Base topic; every command with no subtopic set. |
set_mode_topic |
(base) | SetRobotMode |
velocity_topic |
(base) | VelocityCmd |
stop_topic |
(base) | Pause |
resume_topic |
(base) | Resume |
service_topic |
(base) | InvokeAction |
mission_topic |
(base) | ControlMissionRun |
mission_command_topic |
(base) | AssignMission |
spatial_directive_topic |
(base) | SpatialDirective (field rules) |
geometry_topic |
(base) | UpdateFeature |
path_topic |
(base) | (reserved; no command routes here) |
object_topic |
(base) | Object |
setting_topic |
(base) | UpdateSettings |
teleop_joy_topic |
(base) | TeleopJoy |
agent_text_topic |
(base) | AgentTextRequest |
say_text_topic |
(base) | SayText |
message_confirmation_topic |
(base) | MessageConfirmation |
goto_topicis retired. TheNavigateTocommand was removed, so nothing routes to this key any more. Arobot.tomlthat still sets it parses fine and the key is ignored. Send a destination as a feature withlayerRole = target, or as a mission.
[zenoh_command_topics]
command_topic = "command" # base (default)
velocity_topic = "velocity" # VelocityCmd -> "command/velocity"
stop_topic = "stop" # Pause -> "command/stop"
# keys not listed fall through to the base "command" topic
Subscribe to the base command key (or command/** when you split by subtopic) to
receive all commands. See Command Messages.
[allowed_commands]
Gates which commands the fleet manager may send to this robot. Every command
defaults to allowed, so you list only the ones you want to restrict by
setting them to false. Omitting the section (or restricting nothing) leaves every
command allowed and sends no AllowedCommands message at startup. Pause and
Resume cannot be restricted.
Recognized keys, all defaulting to true:
set_mode, assign_mission, control_mission_run, invoke_service,
update_settings, update_feature, spatial_directive, object,
velocity_cmd, teleop_joy, agent_text_request, say_text_request,
message_confirmation.
Two keys to note.
invoke_servicekeeps its original name here even though the wire field it maps to is nowinvoke_action, so existing files keep working.go_towas dropped with theNavigateTocommand; a file that still sets it parses and the key is ignored.
# A robot that forbids manual teleop and raw velocity commands.
[allowed_commands]
teleop_joy = false
velocity_cmd = false
UI capabilities
The [[services]], [[sensors]], [[settings]], and [[resources]] arrays
describe what the fleet manager UI renders for this robot. They are bundled into a
CapabilitiesManifest sent to the server at startup. Each is a TOML array of
tables, so repeat the header to add entries. For the concept and how the cloud
matches work to robots, see Capabilities.
Robot software can add to this manifest at runtime by publishing
runtimeCapabilities;
the runtime manifest is layered on top of what this file declares.
[[services]]
The actions the robot advertises. Each entry becomes an ActionDescriptor in the
manifest, invokable with
invokeAction.
The TOML section and field names are unchanged from earlier versions.
| Field | Required | Purpose |
|---|---|---|
name |
yes | Unique identifier passed back in the invoke-action command. |
description |
yes | Human-readable description shown in the UI. |
capabilityType |
yes | trigger (one-shot button) or setbool (on/off toggle; alias switch). |
requiresRole |
no | Minimum role to invoke: viewer, operator, admin, or owner. Default operator. |
confirmationMessage |
no | If set, the UI shows a confirmation dialog with this text before invoking. |
dangerLevel |
no | normal, warning, or critical. Affects UI styling. Default normal. |
stateKey |
no | Links a toggle to a sensor key whose current bool value reflects the action's state. |
[[services]]
name = "start_mowing"
description = "Begin autonomous mowing routine"
capabilityType = "trigger"
requiresRole = "operator"
confirmationMessage = "This will start the blades. Proceed?"
dangerLevel = "warning"
[[services]]
name = "lights"
description = "Toggle work lights"
capabilityType = "setbool"
requiresRole = "viewer"
stateKey = "lights_on"
capabilityType = "missiontype"is retired. It declared a mission type rather than an invokable control and has no replacement. An entry that still uses it parses, but the agent drops it from the manifest and logs a warning, so it will not appear in the UI. Remove those entries.Events are runtime-only. The manifest also carries a list of event names the robot may emit (see
event).robot.tomlhas no key for it yet, so declare event names by publishing a runtime capabilities manifest from your robot software.
[[sensors]]
Read-only values shown in the UI.
| Field | Required | Purpose |
|---|---|---|
key |
yes | Unique identifier; matches the key the robot publishes in telemetry extras. |
label |
yes | Human-readable label shown in the UI. |
valueType |
yes | Simple type string, int, number, or bool; or an enumerated type { enum = { options = ["A", "B"] } }. |
unit |
no | Unit string displayed after the value (for example %, V). |
range |
no | [min, max] used for gauge bounds and validation. |
displayHint |
no | UI rendering hint: none, onOff, gauge, text, online, warningLight, temperature, or progress. Default none. |
[[sensors]]
key = "batteryPct"
label = "Battery"
valueType = "number"
unit = "%"
range = [0.0, 100.0]
displayHint = "gauge"
[[sensors]]
key = "mode"
label = "Mode"
valueType = { enum = { options = ["IDLE", "AUTO", "MANUAL"] } }
displayHint = "text"
[[settings]]
Configurable parameters the operator can edit from the UI. The agent seeds each default into its local settings store the first time it sees the key (insert-if-not-exists), then tracks updates from either the fleet manager or your robot software and persists them across restarts. Settings are queryable locally and remotely (see Zenoh queryables).
| Field | Required | Purpose |
|---|---|---|
key |
yes | Unique identifier used in settings-update messages. |
label |
yes | Human-readable label shown in the UI. |
default |
yes | Default value, tagged with its type (see below). |
range |
no | [min, max] bounds for numeric values. |
step |
no | Step increment for numeric sliders in the UI. |
The default is a tagged value. Use the form that matches the type:
default = { type = "string", data = "value" }
default = { type = "int", data = 42 }
default = { type = "number", data = 1.5 }
default = { type = "bool", data = true }
default = { type = "enum", data = { value = "MED", options = ["LOW", "MED", "HIGH"] } }
[[settings]]
key = "maxSpeedMps"
label = "Max speed"
default = { type = "number", data = 1.2 }
range = [0.0, 3.0]
step = 0.1
[[settings]]
key = "cutHeight"
label = "Cut height"
default = { type = "enum", data = { value = "MED", options = ["LOW", "MED", "HIGH"] } }
[[resources]]
Feature/resource channels this robot can produce: geographic features of a given type that Rover Nexus can then use in operations and missions (for example detected pallet locations, or mowed-area coverage).
| Field | Required | Purpose |
|---|---|---|
id |
yes | Stable resource-producer id. The robot references this id when reporting features for the channel. |
label |
no | Human-readable label shown in the UI. Defaults to id. |
description |
no | Human-readable description shown in the UI. |
geometryType |
yes | Geometry the producer emits: point, lineString, polygon, multiPoint, multiLineString, or multiPolygon. |
layerRole |
yes | Role of the produced features. One of: allowedArea, preferred, keepout, softExclusion, workArea, target, queue, controlZone, triggerZone, coverage, occupied, reserved, consumed, hazard, blocked, plannedPath. |
geometryType and layerRole are case-insensitive and ignore separators, so
workArea, work_area, and WorkArea are equivalent.
[[resources]]
id = "pallet_locations"
label = "pallet locations"
description = "Location of detected pallets"
geometryType = "point"
layerRole = "target"
[[resources]]
id = "coverage"
label = "Mowed area"
geometryType = "multiPolygon"
layerRole = "coverage"