Uplink Messages
Uplink messages carry everything your robot reports: telemetry, status, faults, mission feedback, detected objects, and capabilities. They flow from your robot software → the on-robot agent → the Rover Nexus cloud. Your robot software never talks to the cloud directly; it publishes to the agent, which holds the secure link and relays the data onward.
- Direction: Uplink (robot → cloud)
- Topic: publish a tagged
RobotUplinkMsgto a sub-key ofrobot/**on the local Zenoh session (e.g.robot/telemetry/motion); see Publishing - Encoding: Cap'n Proto over Zenoh
- Envelope: every payload is a single
RobotUplinkMsgunion
Local keys have no robot id. The keys you publish to on the local Zenoh session identify only the message, not the robot. The agent adds the robot's identity when it relays your data to the cloud.
This page documents every RobotUplinkMsg variant. Shared building blocks
(geometry, Value, spatial features, enums) live in
Common Types.
The RobotUplinkMsg envelope
RobotUplinkMsg is a tagged union, so each message you publish is exactly one
variant. The agent identifies the variant from the message itself, deserializes
it, updates its local robot state, and forwards the data to the cloud
(rate-limited per message type).
struct RobotUplinkMsg {
union {
missionRunStatus @0 :MissionRunStatus;
globalMotionTelemetry @1 :GlobalMotionTelemetry;
localMotionTelemetry @2 :LocalMotionTelemetry;
statusTelemetry @3 :StatusTelemetry;
sensorTelemetry @4 :SensorTelemetry;
capabilities @5 :Capabilities; # Re-sent by agent if needed
allowedCommands @6 :AllowedCommands; # Reliable
fault @7 :Fault; # Reliable
feature @8 :ReportedFeatureUpdate; # Reliable
object @9 :ObjectOp;
systemHealth @10 :SystemHealth;
usageTelemetry @11 :UsageTelemetry;
consumableStatus @12 :ConsumableStatus;
currentSettings @13 :List(SettingUpdate); # Snapshot of current settings. Re-sent.
message @14 :Message; # Reliable; a message to show in the Rover Nexus UI
agentInfo @15 :AgentInfo; # Filled by the agent; robot software does not send
spatialDirectiveStatus @16 :SpatialDirectiveStatus; # Reported by the agent by default
}
}
| Variant | Payload | Who sends it | Notes |
|---|---|---|---|
globalMotionTelemetry |
GlobalMotionTelemetry |
Robot software | High-frequency GPS pose/velocity. Marks the robot online. |
localMotionTelemetry |
LocalMotionTelemetry |
Robot software | High-frequency local-frame odometry. Marks the robot online. |
statusTelemetry |
StatusTelemetry |
Robot software | Mode, battery/fuel, e-stop, availability. Marks the robot online. |
sensorTelemetry |
SensorTelemetry |
Robot software | Arbitrary OEM key/value readings. |
missionRunStatus |
MissionRunStatus |
Robot software | Progress and outcome of a mission run. |
fault |
Fault |
Robot software | Raise/clear a fault. Reliable. |
message |
Message |
Robot software | Human-readable message for the UI. Reliable. |
systemHealth |
SystemHealth |
Agent (or robot) | CPU/mem/disk/temp/signal. Agent fills this by default. |
usageTelemetry |
UsageTelemetry |
Robot software | Cumulative distance/time/counters. |
consumableStatus |
ConsumableStatus |
Robot software | Tank/consumable level. |
feature |
ReportedFeatureUpdate |
Robot software | Report a covered/hazard area per producer channel. Reliable. |
object |
ObjectOp |
Robot software | Report a detected object. |
capabilities |
Capabilities |
Agent (or robot) | Services/sensors/settings/resource producers the UI shows. Re-sent if needed. |
allowedCommands |
AllowedCommands |
Agent (or robot) | Which commands the robot accepts. Reliable. |
currentSettings |
List(SettingUpdate) |
Robot software | Snapshot of current settings. Re-sent. |
agentInfo |
AgentInfo |
Agent only | Agent/OS/version info. Robot software does not send this. |
spatialDirectiveStatus |
SpatialDirectiveStatus |
Agent (or robot) | Whether the robot is inside/applying a field rule. |
Rate limiting.
globalMotionTelemetry,localMotionTelemetry,statusTelemetry, andsensorTelemetryare coalesced downstream (the latest value wins) and are not rate-bucketed. The other (channel-driven) variants, including those marked Reliable above, are each guarded by a per-type token bucket: under normal load nothing is delayed, but a sustained flood is dropped (never delayed) and logged at most once per second.missionRunStatusis exempt and is never dropped.
Telemetry
Motion telemetry comes in two flavors. Publish whichever frame your robot localizes in (or both): global (GPS / WGS84) and local (odometry). Publishing either one bumps the robot's last-seen time on Rover Nexus and marks the robot online.
Recommended publish rate: 1 Hz when idle, max 10 Hz in motion. The agent throttles above 10 Hz and always forwards the latest value.
globalMotionTelemetry: global pose and velocity
High-frequency GPS (WGS84) motion data.
struct GlobalMotionTelemetry {
unixTimeMs @0 :Int64;
pose @1 :GeoPose;
hasPose @2 :Bool;
velocity @3 :VelTwist;
hasVelocity @4 :Bool;
gpsFixType @5 :GpsFixType; # optional: include for map accuracy/confidence
hasGpsFixType @6 :Bool;
gpsSource @7 :GpsSource;
}
| Field | Type | Notes |
|---|---|---|
unixTimeMs |
Int64 |
Sample time, epoch ms. |
pose / hasPose |
GeoPose |
World pose (lon/lat/alt/heading). |
velocity / hasVelocity |
VelTwist |
Forward (m/s) and angular (rad/s). |
gpsFixType / hasGpsFixType |
GpsFixType |
Optional fix quality. |
gpsSource |
GpsSource |
Origin of the fix (real / simulated / estimated). |
localMotionTelemetry: local pose and velocity
High-frequency local-frame (odometry) motion data. If both are sent,
globalMotionTelemetry takes precedence for the robot's mapped position.
struct LocalMotionTelemetry {
unixTimeMs @0 :Int64;
pose @1 :LocalPose;
velocity @2 :VelTwist;
accuracyM @3 :Float32;
hasAccuracyM @4 :Bool;
frame @5 :Text; # optional, useful if the local frame can change
hasFrame @6 :Bool;
}
| Field | Type | Notes |
|---|---|---|
unixTimeMs |
Int64 |
Sample time, epoch ms. |
pose |
LocalPose |
Local-frame pose (x/y/alt/heading). |
velocity |
VelTwist |
Forward (m/s) and angular (rad/s). |
accuracyM / hasAccuracyM |
Float32 |
Optional position accuracy, meters. |
frame / hasFrame |
Text |
Optional local-frame id (useful if the frame can change). |
statusTelemetry: status and health
General status of the robot. Must be published by robot software. Publishing it bumps the last-seen time and marks the robot online.
Recommended publish rate: 1 Hz.
struct StatusTelemetry {
unixTimeMs @0 :Int64;
battery @1 :BatteryStatus;
hasBattery @2 :Bool;
mode @3 :RobotMode;
hasMode @4 :Bool;
estop @5 :EStop;
faulted @6 :Bool;
missionActive @7 :Bool; # is the robot available to accept missions
status @8 :Text; # OEM-defined status string
fuel @9 :FuelStatus;
hasFuel @10 :Bool;
rangeRemaining @11 :Float64; # meters
hasRangeRemaining @12 :Bool;
runtimeRemaining @13 :Float64; # seconds
hasRuntimeRemaining @14 :Bool;
}
| Field | Type | Notes |
|---|---|---|
unixTimeMs |
Int64 |
Sample time, epoch ms. |
battery / hasBattery |
BatteryStatus |
Battery state (below). |
mode / hasMode |
RobotMode |
Current operating mode. |
estop |
EStop |
Physical e-stop state (always present). |
faulted |
Bool |
Whether the robot is currently faulted. |
missionActive |
Bool |
Whether the robot can accept missions. Mission progress is on missionRunStatus. |
status |
Text |
OEM-defined free-text status string. |
fuel / hasFuel |
FuelStatus |
Fuel state (below), for combustion platforms. |
rangeRemaining / hasRangeRemaining |
Float64 |
Estimated remaining range, meters. |
runtimeRemaining / hasRuntimeRemaining |
Float64 |
Estimated remaining runtime, seconds. |
Battery and fuel live here. There is no separate battery or fuel uplink variant. Robots report both on
StatusTelemetryvia the optionalbattery/fuelfields.
EStop
The robot's physical e-stop state. There is intentionally no remote e-stop command; see Command Messages. Robots only ever report e-stop state here.
# Signal that the robot has been E-stopped and cannot take commands.
struct EStop {
unixTimeMs @0 :Int64;
active @1 :Bool;
ids @2 :List(Text); # which e-stop(s) are engaged
}
BatteryStatus
struct BatteryStatus {
socPct @0 :Float32; # state of charge, 0 to 100
voltageV @1 :Float32;
hasVoltageV @2 :Bool;
currentA @3 :Float32;
hasCurrentA @4 :Bool;
chargeAh @5 :Float32;
hasChargeAh @6 :Bool;
capacityAh @7 :Float32;
hasCapacityAh @8 :Bool;
designCapacityAh @9 :Float32;
hasDesignCapacityAh @10 :Bool;
temperature @11 :Float32; # Celsius
hasTemperature @12 :Bool;
powerSupplyStatus @13 :PowerSupplyStatus;
powerSupplyHealth @14 :PowerSupplyHealth;
powerSupplyTechnology @15 :PowerSupplyTechnology;
}
socPct is the only required value; all others use the hasX pattern. See the
power supply enums for status/health/
technology values.
FuelStatus
struct FuelStatus {
levelPct @0 :Float32; # 0 to 100
volumeRemaining @1 :Float32;
hasVolumeRemaining @2 :Bool;
capacity @3 :Float32; # how big is the tank
hasCapacity @4 :Bool;
volumeUnit @5 :Text; # liters, gallons, ...
hasVolumeUnit @6 :Bool;
efficiency @7 :Float32; # e.g. miles per gallon
hasEfficiency @8 :Bool;
efficiencyUnit @9 :Text;
hasEfficiencyUnit @10 :Bool;
isRefueling @11 :Bool;
}
sensorTelemetry: custom sensor values
Arbitrary scalar/status values published by the robot/OEM that aren't covered by
the standard motion/status messages. Each reading is a key, a typed
Value, and an optional per-reading
timestamp.
# Robot -> UI: frequent, minimal, just the data.
struct SensorReading {
key @0 :Text;
value @1 :Value;
unixTimeMs @2 :Int64; # per-reading timestamp
hasUnixTimeMs @3 :Bool;
}
struct SensorTelemetry {
unixTimeMs @0 :Int64;
# Example entries:
# "deck_rpm" -> 3120
# "hydraulic_temp_c" -> 64.2
# "camera_front_ok" -> true
# "tilt_deg" -> 18.5
kv @1 :List(SensorReading);
}
Rates & limits: OEMs may push at their chosen rate, but the server enforces rate caps, a per-message size limit, and a maximum key/value count. To make a reading render nicely in the UI, declare it as a sensor in
capabilities.
systemHealth
Host metrics for the robot's computer(s). The agent fills and publishes this once every 5 seconds; robot software may optionally publish its own to override the agent (e.g. for a device the agent can't see).
struct SystemHealth {
unixTimeMs @0 :Int64;
deviceId @1 :Text; # if multiple computers/CPUs: "cpu1", "gpu2", ...
cpuPct @2 :Float32;
memPct @3 :Float32;
diskPct @4 :Float32;
cpuTemp @5 :Float32; # Celsius
signalStrength @6 :Float32; # RSSI
signalQuality @7 :Float32; # standard wifi link quality
}
usageTelemetry
Cumulative robot usage statistics. The source of truth must be the robot software that talks to the agent.
struct UsageTelemetry {
unixTimeMs @0 :Int64;
totalDistanceM @1 :Float64;
autoDistanceM @2 :Float64;
manualDistanceM @3 :Float64;
uptimeTotalS @4 :Float64;
driveTimeTotalS @5 :Float64;
autoTimeTotalS @6 :Float64;
missionCountTotal @7 :UInt32;
chargeCyclesTotal @8 :UInt32;
rebootCount @9 :UInt32;
lastRebootUnixTimeMs @10 :Int64; # epoch ms
}
consumableStatus
Level/amount of a consumable carried on the robot (herbicide, water, seed, …).
struct ConsumableStatus {
unixTimeMs @0 :Int64;
kind @1 :Text; # "herbicide", "water", "seed"
tankId @2 :Text; # "main", "left", "right", ...
levelPct @3 :Float32; # 0–100
amountRemaining @4 :Float32; # quantity scalar
unit @5 :Text; # unit for amountRemaining
isCritical @6 :Bool; # precomputed by the robot if it wants
}
Mission feedback
missionRunStatus: mission feedback
Status of a mission as it progresses, sent from robot to server. Send this
periodically while a mission runs. The robot software is responsible for
reporting the final state of a mission in status.
struct MissionRunStatus {
unixTimeMs @0 :Int64;
missionId @1 :Text;
runId @2 :Text;
status @3 :MissionStatus;
statusMessage @4 :Text;
hasStatusMessage @5 :Bool;
progressX100 @6 :UInt16; # (0..=10000) = percent * 100
hasProgressX100 @7 :Bool;
currentPathId @8 :Text;
hasCurrentPathId @9 :Bool;
currentTarget @10 :GeoPose;
hasCurrentTarget @11 :Bool;
currentStep @12 :UInt32; # can be waypoints
hasCurrentStep @13 :Bool;
totalSteps @14 :UInt32;
hasTotalSteps @15 :Bool;
timeStartedMs @16 :Int64; # when this mission actually started running on the robot
hasTimeStartedMs @17 :Bool;
expectedEndTimeMs @18 :Int64; # robot's best guess of when it'll be done; can move
hasExpectedEndTimeMs @19 :Bool;
timeCompletedMs @20 :Int64; # set at a terminal state (complete / aborted / error)
hasTimeCompletedMs @21 :Bool;
name @22 :Text; # if the robot makes/renames a mission
hasName @23 :Bool;
}
| Field | Type | Notes |
|---|---|---|
missionId |
Text |
The mission template id from the command. |
runId |
Text |
The specific run id. Echo the runId from the assignMission command so the cloud can correlate. |
status |
MissionStatus |
Lifecycle state. |
progressX100 |
UInt16 |
Progress as percent × 100 (0..=10000). |
currentStep / totalSteps |
UInt32 |
Step counters (may be waypoints). |
currentPathId / currentTarget |
Text / GeoPose |
What the robot is currently following / heading to. |
timeStartedMs / expectedEndTimeMs / timeCompletedMs |
Int64 |
Start, estimated end, and terminal time (epoch ms). |
Tip. Always echo the
runIdfrom the originating mission command. Scheduled missions are fired by the agent with a freshrunId.
Faults and messages
fault
A fault report for a robot system fault. Reliable. Robot software must send
active = false when the fault clears, otherwise it persists on Rover Nexus.
struct Fault {
unixTimeMs @0 :Int64;
faultId @1 :Text; # stable code, e.g. "BATTERY_UNDERVOLT"
source @2 :Text; # node / sensor
severity @3 :FaultSeverity;
active @4 :Bool; # true on raise, false on clear
category @5 :Text; # power, comms, nav, safety, ...
description @6 :Text; # short human text
suggestedAction @7 :Text; # optional remediation hint
}
message
A human-readable message from the robot to display in the Rover Nexus UI. Reliable. This is not log storage; use your own logging infrastructure for logs.
A message can optionally require operator confirmation: set
needsConfirmation and a confirmationId, and the operator's reply arrives back
at the robot as a messageConfirmation
command echoing the same id.
struct Message {
unixTimeMs @0 :Int64;
level @1 :MessageLevel; # info / warn / error
message @2 :Text;
needsConfirmation @3 :Bool; # require the user to confirm or deny
confirmationId @4 :Text; # for confirming messages
}
Spatial reports
feature: reported spatial feature
For the robot to report a feature / geographic shape to Rover Nexus (e.g. an area
it covered, or a hazard it found). Reliable. The payload is a
ReportedFeatureUpdate: it
ties a ReportedFeatureOp (upsert or clear) to the resourceProducerId
channel the robot declared in capabilities.
Each producer channel holds at most one feature at a time. If the scope is
world or fleet, the feature is forwarded to all robots in the fleet.
struct ReportedFeatureUpdate {
resourceProducerId @0 :Text; # the producer channel this update belongs to
timestampMs @1 :Int64;
op @2 :ReportedFeatureOp; # upsert ReportedFeature | clear
}
See ReportedFeature for the geometry.
It uses a LayerRole and carries an expiresAtMs.
object: detected object
Report a tracked object to Rover Nexus. The payload is an
ObjectOp (upsert or delete).
scope determines whether it is forwarded to other robots in the fleet. See
Object for the fields.
# RobotUplinkMsg.object payload
struct ObjectOp {
union {
upsert @0 :Object;
delete @1 :Text; # id to delete
}
}
Capabilities and settings
capabilities: services, sensors, and settings
Tells Rover Nexus what the robot can do and what settings it has. The agent sends this on startup based on the robot config; robot software may optionally send its own. The agent re-sends it if needed.
- services become buttons in the UI.
- sensors describe which
sensorTelemetryreadings exist and how to display them. - settings become editable fields (sent together with a "Save Settings" button).
- resourceProducers declare the feature channels the robot can publish via
the
featureuplink.
struct Capabilities {
services @0 :List(ServiceCapability); # become buttons
sensors @1 :List(SensorCapability); # available values + how to display them
settings @2 :List(SettingDescriptor); # editable settings
resourceProducers @3 :List(ResourceProducerDescriptor); # feature channels the robot can publish
}
# Defines what a robot can do; these become buttons and can be tied to
# missions and areas.
struct ServiceCapability {
name @0 :Text; # "start_mowing"
description @1 :Text; # "Begin autonomous mowing routine"
capabilityType @2 :CapabilityType;
confirmationMessage @3 :Text; # optional custom warning text
hasConfirmationMessage @4 :Bool;
stateKey @5 :Text; # sensor key associated with this control (display together)
requiresRole @6 :Role; # minimum role, e.g. operator / admin
dangerLevel @7 :DangerLevel; # warning/critical require confirmation
}
# Robot -> UI: once on connect or when config changes.
struct SensorCapability {
key @0 :Text; # in-code key (unique)
label @1 :Text; # UI label
valueType @2 :ValueType;
unit @3 :Text; # empty string if none
rangeMin @4 :Float64; # for gauge coloring / display range
rangeMax @5 :Float64;
hasRange @6 :Bool;
displayHint @7 :DisplayHint;
}
# Robot -> UI: what settings exist and their constraints. The default also
# defines the expected type; validate at ingest that it matches valueType.
struct SettingDescriptor {
key @0 :Text;
label @1 :Text;
valueType @2 :ValueType;
default @3 :Value;
range @4 :Range;
hasRange @5 :Bool;
step @6 :Float64;
hasStep @7 :Bool;
}
# Feature channels the robot can produce for use in operations and missions.
struct ResourceProducerDescriptor {
resourceProducerId @0 :Text; # shared resource id
label @1 :Text; # display label; defaults to resourceProducerId when empty
layerRole @2 :LayerRole;
geometryType @3 :GeometryType;
description @4 :Text; # empty string if None
hasDescription @5 :Bool;
}
struct Range { min @0 :Float64; max @1 :Float64; }
See the UI display enums for ValueType,
CapabilityType, DangerLevel, DisplayHint, and Role, and
GeometryType /
LayerRole for resource producers.
allowedCommands
Declares which command variants this robot accepts, so the
UI can hide or disable controls the robot doesn't support. Reliable. Sent by
the agent (from the robot config) or by robot software. pause and resume are
intentionally absent: robots cannot opt out of receiving them.
struct AllowedCommands {
setMode @0 :Bool;
assignMission @1 :Bool;
controlMissionRun @2 :Bool;
invokeService @3 :Bool;
updateSettings @4 :Bool;
updateFeature @5 :Bool;
spatialDirective @6 :Bool;
object @7 :Bool;
goTo @8 :Bool;
velocityCmd @9 :Bool;
teleopJoy @10 :Bool;
agentTextRequest @11 :Bool;
sayTextRequest @12 :Bool;
messageConfirmation @13 :Bool;
}
currentSettings
A snapshot of the robot's current setting values, as a bare list of
SettingUpdate. Re-sent by the agent as
needed. Use this to confirm the values the robot is actually running after an
updateSettings command.
# RobotUplinkMsg.currentSettings payload
currentSettings @13 :List(SettingUpdate);
Agent and field rule status
agentInfo
Information about the agent itself. The agent fills and sends this; robot software does not. Re-sent if needed.
struct AgentInfo {
agentVersion @0 :Text;
softwareVersion @1 :Text;
hasSoftwareVersion @2 :Bool;
osInfo @3 :Text; # "Ubuntu 22.04 aarch64" (for debugging)
hasOsInfo @4 :Bool;
uptimeS @5 :UInt64; # seconds since boot (detect frequent reboots)
hasUptimeS @6 :Bool;
}
spatialDirectiveStatus
Robot → server feedback reporting whether the robot is inside a
SpatialDirective's zone and applying it.
Reported by the agent by default; robot software may report its own.
struct SpatialDirectiveStatus {
directiveId @0 :Text;
lastEvalTimeMs @1 :Int64;
active @2 :Bool; # currently inside + within time window + applicable
insideZone @3 :Bool; # robot's local evaluation
distanceToZoneM @4 :Float32; # optional local distance estimate
hasDistanceToZoneM @5 :Bool;
}
Publishing
Serialize each RobotUplinkMsg to Cap'n Proto and publish it on the local
Zenoh session. The topic does not determine the message type; the agent
inspects the RobotUplinkMsg union discriminant inside the payload. The per-type
topics below exist only so you can split publishers by type; in practice most
integrators publish every RobotUplinkMsg on the single wildcard topic
robot/** and ignore the per-type topics. The local keys do not include the
robot id; the agent adds the robot's identity when it relays to the cloud.
Default topics (the per-type keys are optional and configurable in the robot configuration):
| Topic | RobotUplinkMsg variant(s) carried |
|---|---|
robot/** (wildcard) |
all variants (recommended) |
robot/telemetry/motion |
globalMotionTelemetry, localMotionTelemetry |
robot/telemetry/status |
statusTelemetry |
robot/telemetry/sensor |
sensorTelemetry |
robot/fault |
fault |
robot/mission |
missionRunStatus |
robot/feature |
feature |
robot/object |
object |
robot/health |
systemHealth |
robot/usage |
usageTelemetry |
robot/consumable |
consumableStatus |
Variants without a dedicated key (capabilities, allowedCommands,
currentSettings, message, agentInfo, spatialDirectiveStatus) are
published on the wildcard topic.
- Native: publish directly (the wildcard
robot/**is simplest). See Custom Integrations. - ROS 2: the bridge maps your ROS 2 topics onto these messages. See Telemetry Mappings.
Related
- Command Messages: cloud → robot
- Common Types: shared structs and enums
- Zenoh transport
- Telemetry Mappings
- Client Libraries: the Cap'n Proto schema for these messages, plus language bindings