Skip to content

Sending and Receiving Data

Beyond video, every Adamo participant can publish, subscribe, and query arbitrary key expressions. This page covers those primitives: publish, subscribe, one-shot get, and the priority / reliability knobs that decide how a message travels.

For control specifically, see Receiving Control.

For occasional values — config, single events, “I’m done” notifications.

import adamo
session = adamo.connect(api_key="ak_...")
session.put("my-arm/sensors/temperature", b"22.5")

For repeated puts on the same key (telemetry, joint state, etc.). Avoids re-resolving the key expression each time and lets you set declare-time options like express and reliability once.

import time, json
with session.publisher("my-arm/sensors/imu", express=True) as pub:
while True:
pub.put(json.dumps({"x": 0.1, "y": 0.0, "z": 9.8}).encode())
time.sleep(0.01)
with session.subscribe("my-arm/sensors/**") as sub:
for sample in sub:
print(sample.key, len(sample.payload))

The callback fires on a background receive thread. Keep it short — offload heavy work via a queue.

def on_sample(sample):
print(sample.key, sample.payload)
sub = session.subscribe("my-arm/sensors/**", callback=on_sample)

Two wildcards are supported in key expressions:

WildcardMeaning
*One path segment (no /).
**Zero or more path segments (including /).
my-arm/sensors/* — one level under sensors/
my-arm/sensors/** — everything under sensors/
*/sensors/imu — IMU from any robot in the org
**/control/joy — joy commands from anywhere

A query is a request/reply on a key — useful for “what’s the current value?” against persistent stores or for asking a robot to introspect itself.

for sample in session.get("my-arm/config/**", timeout_ms=2000):
print(sample.key, sample.payload)

Three knobs control how a message travels. The defaults are tuned for telemetry; control needs different settings.

KnobValuesWhat it controls
priority0–255 (mapped to 8 priority classes)Which queue the message lives in. Higher drains first.
congestion controlDROP (default) or BLOCKWhen the queue is full, drop the message vs. block the sender.
reliabilityBEST_EFFORT (default) or RELIABLERetransmit on loss vs. fire-and-forget.
expressfalse (default) or trueBypass batching for lower latency at the cost of more packets.

Conventions in this project:

  • Control commands → priority 250 (REAL_TIME), DROP, BEST_EFFORT, express=true. A late command is worse than no command.
  • Video → priority 200 (INTERACTIVE_HIGH), DROP, BEST_EFFORT. The encoder will recover from loss.
  • Telemetry → priority 128 (DATA, the default), DROP, BEST_EFFORT. Cheap to lose.
  • Configuration / commands that must arrive → priority ~140, BLOCK, RELIABLE. Use sparingly.

Robotics priority is the opposite of WebRTC — control beats video beats audio.