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 ApplicationToAgent 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 ApplicationToAgent 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 ApplicationToAgent variant. Shared building blocks (geometry, Value, spatial features, enums) live in Common Types.

The ApplicationToAgent envelope

ApplicationToAgent 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).

# ApplicationToAgent - from rover to fleet command.
struct ApplicationToAgent {
  union {
    missionRunStatus @0 :MissionRunStatus;
    spatialDirectiveStatus @1 :SpatialDirectiveStatus;  # reported by the agent by default
    globalMotionTelemetry @2 :GlobalMotionTelemetry;
    localMotionTelemetry @3 :LocalMotionTelemetry;
    statusTelemetry @4 :StatusTelemetry;
    sensorTelemetry @5 :SensorTelemetry;
    usageTelemetry @6 :UsageTelemetry;
    fault @7 :Fault;                          # Reliable
    event @8 :ApplicationEvent;               # must be declared in the capabilities manifest
    feature @9 :ReportedFeatureUpdate;        # Reliable
    object @10 :ObjectOp;
    consumableStatus @11 :ConsumableStatus;
    currentSettings @12 :List(SettingUpdate); # Snapshot of current settings. Re-sent.
    message @13 :Message;                     # Reliable; a message to show in the Rover Nexus UI
    runtimeCapabilities @14 :CapabilitiesManifest;  # added to the statically configured capabilities
    allowedCommands @15 :AllowedCommands;     # Reliable
    applicationInfo @16 :ApplicationInfo;
  }
}
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.
event ApplicationEvent Robot software A named, robot-defined event. Must be declared in the capabilities manifest.
message Message Robot software Human-readable message for the UI. Reliable.
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.
runtimeCapabilities CapabilitiesManifest Robot software Actions/sensors/settings/resource producers/events, merged onto the configured manifest.
allowedCommands AllowedCommands Agent (or robot) Which commands the robot accepts. Reliable.
currentSettings List(SettingUpdate) Robot software Snapshot of current settings. Re-sent.
applicationInfo ApplicationInfo Robot software Identity and version of the reporting application.
spatialDirectiveStatus SpatialDirectiveStatus Agent (or robot) Whether the robot is inside/applying a field rule.

Host health and agent version are not uplink variants. The agent collects host CPU/memory/disk/temperature/signal metrics and its own version information itself and reports them to the cloud over its control-plane link. Robot software neither sends nor overrides them. Use applicationInfo to report your software's identity and version, and sensorTelemetry for any host metric the agent cannot see. See Health Monitoring.

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;       # optional
  velocity @2 :VelTwist;  # optional
  gpsFix @3 :GpsFixType;  # optional: include for map accuracy/confidence
  hasGpsFix @4 :Bool;
  gpsSource @5 :GpsSource;
}
Field Type Notes
unixTimeMs Int64 Sample time, epoch ms.
pose GeoPose Optional world pose (lon/lat/alt/heading).
velocity VelTwist Optional forward (m/s) and angular (rad/s).
gpsFix / hasGpsFix GpsFixType Optional fix quality.
gpsSource GpsSource Origin of the fix (real / simulated / estimated).

pose and velocity are struct (pointer) fields, so they carry their own presence: leave the pointer unset to omit them. gpsFix is an enum, which has no null, so it pairs with hasGpsFix. See optional fields.

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
}
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 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;  # optional
  mode @2 :RobotMode;
  hasMode @3 :Bool;
  estop @4 :EStop;
  faulted @5 :Bool;
  acceptingMissions @6 :Bool;  # is the robot available to accept missions
  status @7 :Text;             # OEM-defined status string
  fuel @8 :FuelStatus;         # optional
  rangeRemainingM @9 :Float64;  # meters
  hasRangeRemainingM @10 :Bool;
  runtimeRemainingS @11 :Float64;  # seconds
  hasRuntimeRemainingS @12 :Bool;
}
Field Type Notes
unixTimeMs Int64 Sample time, epoch ms.
battery BatteryStatus Optional 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.
acceptingMissions Bool Whether the robot can accept missions. Mission progress is on missionRunStatus.
status Text OEM-defined free-text status string.
fuel FuelStatus Optional fuel state (below), for combustion platforms.
rangeRemainingM / hasRangeRemainingM Float64 Estimated remaining range, meters.
runtimeRemainingS / hasRuntimeRemainingS 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; the other numeric fields are scalars and 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;   # optional; liters, gallons, ...
  efficiency @6 :Float32;  # e.g. miles per gallon
  hasEfficiency @7 :Bool;
  efficiencyUnit @8 :Text;  # optional
  isRefueling @9 :Bool;
}

volumeUnit and efficiencyUnit are Text (pointer) fields: leave them unset to omit them. The numeric optionals keep their hasX companions.

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 the capabilities manifest.

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;
}

Reboot counters moved. rebootCount and lastRebootUnixTimeMs are no longer part of UsageTelemetry. The agent tracks and reports its own restart counters over the control plane; robot software does not send them.

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;
  missionRunId @1 :Text;
  status @2 :MissionStatus;
  statusMessage @3 :Text;  # optional
  progressX100 @4 :UInt16;  # (0..=10000) = percent * 100
  hasProgressX100 @5 :Bool;
  currentTarget @6 :GeoPose;  # optional
  currentStep @7 :UInt32;  # can be waypoints
  hasCurrentStep @8 :Bool;
  totalSteps @9 :UInt32;
  hasTotalSteps @10 :Bool;
  timeStartedMs @11 :Int64;       # when this mission actually started running on the robot
  hasTimeStartedMs @12 :Bool;
  expectedEndTimeMs @13 :Int64;   # robot's best guess of when it'll be done; can move
  hasExpectedEndTimeMs @14 :Bool;
  timeCompletedMs @15 :Int64;     # set at a terminal state (completed / aborted / failed)
  hasTimeCompletedMs @16 :Bool;
  name @17 :Text;                 # optional; if the robot makes a mission the server did not assign
}
Field Type Notes
missionRunId Text The run id. Echo the missionRunId from the assignMission command so the cloud can correlate.
status MissionStatus Lifecycle state.
statusMessage Text Optional human-readable detail.
progressX100 UInt16 Progress as percent × 100 (0..=10000).
currentStep / totalSteps UInt32 Step counters (may be waypoints).
currentTarget GeoPose Optional pose the robot is currently heading to.
timeStartedMs / expectedEndTimeMs / timeCompletedMs Int64 Start, estimated end, and terminal time (epoch ms).
name Text Optional display name, for a run the robot created itself.

One id per run. A mission run is keyed by a single missionRunId. The separate missionId / runId pair and the currentPathId field are gone. Always echo the missionRunId from the originating mission command. Scheduled missions are fired by the agent with the id the server assigned.

Faults, events, 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 :Severity;
  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
}

See Severity for the severity buckets.

event: robot-defined event

A discrete, named occurrence the robot wants the cloud to know about. A declared event is recorded against the robot and pushed to connected clients.

The event name must be declared in CapabilitiesManifest.events via runtimeCapabilities. An event whose name is not declared is dropped: nothing is recorded and nothing is forwarded. Declare your event names before you emit them.

# ApplicationEvent - robot-defined event. The event name must be declared in
# CapabilitiesManifest.events to be processed by the server.
struct ApplicationEvent {
  event @0 :Text;
  severity @1 :Severity;
  detail @2 :Text;
}
Field Type Notes
event Text The declared event name.
severity Severity info, minor, major, or critical.
detail Text Free-text detail for the operator.

Event vs fault vs message. Use an event for a discrete, named occurrence the cloud should act on; a fault for a condition that is raised and later cleared; and a message for free text aimed at a human.

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 :Severity;  # info / minor / major / critical
  message @2 :Text;
  needsConfirmation @3 :Bool;  # require the user to confirm or deny
  confirmationId @4 :Text;     # for confirming messages
}

level is a Severity. It uses the same four buckets as Fault.severity (info / minor / major / critical). The separate three-value message level is gone.

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 its capabilities manifest. 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.

# ApplicationToAgent.object payload
struct ObjectOp {
  union {
    upsert @0 :Object;
    delete @1 :Text;  # id to delete
  }
}

Capabilities and settings

runtimeCapabilities: actions, sensors, and settings

Tells Rover Nexus what the robot can do and what settings it has. The payload is a CapabilitiesManifest.

The agent sends a manifest built from the robot configuration at startup. Robot software may publish its own manifest at runtime; the two are merged, with the runtime manifest layered on top of the configured one. Publishing a runtime manifest replaces the whole runtime layer, so a name your software stops reporting is removed.

  • actions become buttons in the UI and can be attached to missions and zones.
  • 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.
  • events declare the names the robot may emit as an event uplink.
struct CapabilitiesManifest {
  actions @0 :List(ActionDescriptor);    # trigger/boolean controls, become buttons
  settings @1 :List(SettingDescriptor);  # editable settings
  sensors @2 :List(SensorDescriptor);    # available values + how to display them
  resourceProducers @3 :List(ResourceProducerDescriptor);  # feature channels the robot can publish
  events @4 :List(Text);                 # event names the robot may emit
}

# Defines what a robot can do; these become buttons and can be tied to
# missions and areas.
struct ActionDescriptor {
  name @0 :Text;         # "start_mowing"
  description @1 :Text;  # "Begin autonomous mowing routine"
  actionType @2 :ActionType;
  confirmationMessage @3 :Text;  # optional custom warning text
  stateKey @4 :Text;     # sensor key associated with this control (display together)
  requiresRole @5 :Role; # minimum role, e.g. operator / admin
  dangerLevel @6 :DangerLevel;  # warning/critical require confirmation
}

# Robot -> UI: once on connect or when config changes.
struct SensorDescriptor {
  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;  # optional
  step @5 :Float64;
  hasStep @6 :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;  # optional human-readable description
}

struct Range { min @0 :Float64; max @1 :Float64; }

See the UI display enums for ValueType, ActionType, DangerLevel, DisplayHint, and Role, and GeometryType / LayerRole for resource producers.

"Capabilities" are now "actions". The invokable controls a robot advertises are ActionDescriptor entries under actions, invoked with invokeAction. The robot [[services]] config section still uses its original key names; see Robot Configuration.

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;
  invokeAction @3 :Bool;
  updateSettings @4 :Bool;
  updateFeature @5 :Bool;
  spatialDirective @6 :Bool;
  object @7 :Bool;
  velocityCmd @8 :Bool;
  teleopJoy @9 :Bool;
  agentTextRequest @10 :Bool;
  sayTextRequest @11 :Bool;
  messageConfirmation @12 :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.

# ApplicationToAgent.currentSettings payload
currentSettings @12 :List(SettingUpdate);

Application info and field rule status

applicationInfo

Identity and version of the robot application or software component that is talking to the agent. Publish this once at startup (and again if it changes) so the fleet UI can show what is actually running on the robot.

struct ApplicationInfo {
  applicationId @0 :Text;  # stable identifier for this application or software component
  name @1 :Text;           # human-readable name
  version @2 :Text;        # product version, preferably semantic versioning
  buildId @3 :Text;        # optional build identifier, such as a CI build number
  gitRevision @4 :Text;    # optional source revision
  protocolVersion @5 :Text;  # optional; version of the agent/application protocol implemented
}
Field Type Notes
applicationId Text Stable id for this application/component.
name Text Human-readable name.
version Text Product version.
buildId / gitRevision / protocolVersion Text Optional; leave the pointer unset to omit.

This describes your software, not the agent. The agent reports its own version to the cloud separately, over its control-plane link.

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 ApplicationToAgent to Cap'n Proto and publish it on the local Zenoh session. The topic does not determine the message type; the agent inspects the ApplicationToAgent 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 ApplicationToAgent 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 ApplicationToAgent variant(s) carried
robot/** (wildcard) all variants (recommended)
robot/telemetry/motion globalMotionTelemetry, localMotionTelemetry
robot/telemetry/status statusTelemetry
robot/telemetry/extras sensorTelemetry
robot/fault fault
robot/mission missionRunStatus
robot/geometry feature
robot/object object
robot/usage usageTelemetry
robot/consumable consumableStatus

Variants without a dedicated key (runtimeCapabilities, allowedCommands, currentSettings, message, event, applicationInfo, spatialDirectiveStatus) are published on the wildcard topic.

robot/health is retired. It used to carry a host-health uplink. Host health is now collected and reported by the agent itself, so there is no uplink variant for it. See Health Monitoring.