Skip to content

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 RobotUplinkMsg to a sub-key of robot/** on the local Zenoh session (e.g. robot/telemetry/motion); see Publishing
  • Encoding: Cap'n Proto over Zenoh
  • Envelope: every payload is a single RobotUplinkMsg union

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, and sensorTelemetry are 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. missionRunStatus is 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 StatusTelemetry via the optional battery / fuel fields.

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 runId from the originating mission command. Scheduled missions are fired by the agent with a fresh runId.

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 sensorTelemetry readings 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 feature uplink.
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.