Quickstart
Get a robot streaming video to operate.adamohq.com in under five minutes. Pick the language you want to write your robot in — Python, Rust, or C — install the SDK, write a short program that opens a camera, run it.
You don’t need to write an operator — operate.adamohq.com provides a gamepad, VR teleop, recording, and replay against any robot you’ve started. The Building Your Own Operator page covers the case when you want a custom one.
Install the SDK
Section titled “Install the SDK”pip install adamoRequires Python 3.10+. On the robot host you’ll also want the video extras:
pip install 'adamo[video]'cargo add adamoFor video capture (requires iceoryx2 on the host):
cargo add adamo --features videoCurrently published for aarch64-unknown-linux-gnu (Jetson / Ubuntu 22.04 arm64). For local dev on other hosts, build adamo-c from source and point at it via ADAMO_LIB_DIR=/path/to/dir/with/libadamo.{so,dylib}.
Build and install with CMake:
git clone https://github.com/adamohq/adamo-network.gitcd adamo-network/adamo-ccmake -S . -B build -DADAMO_BUILD_VIDEO=ONcmake --build build --target installThen in your project’s CMakeLists.txt:
find_package(Adamo REQUIRED)target_link_libraries(my_robot PRIVATE Adamo::adamo)# C++17 RAII wrapper is also available:# target_link_libraries(my_robot PRIVATE Adamo::adamo_cpp)Get an API Key
Section titled “Get an API Key”Sign up at operate.adamohq.com and go to Settings → API Keys. Create a key (it starts with ak_) and copy it. The SDK uses this key to find the right router for your organisation.
You can pass the key inline or read it from the ADAMO_API_KEY environment variable.
Write Your Robot Program
Section titled “Write Your Robot Program”A robot program does two things: declares the cameras it streams, then blocks driving the pipeline. That’s it.
import adamo
robot = adamo.Robot(api_key="ak_...", name="my-arm")robot.attach_video("main", device="/dev/video0")robot.run()use adamo::Robot;
fn main() -> adamo::Result<()> { let mut robot = Robot::new_default("ak_...", Some("my-arm"))?; robot.attach_v4l2("main", "/dev/video0", 1280, 720, 30, 4000, false)?; robot.run()}#include "adamo/adamo.h"#include <stdio.h>
int main(void) { adamo_robot_t *robot = adamo_robot_new_default("ak_...", "my-arm"); if (!robot) { fprintf(stderr, "adamo_robot_new: %s\n", adamo_last_error()); return 1; } if (adamo_robot_attach_video_v4l2( robot, "main", "/dev/video0", 1280, 720, 30, 4000, false) != 0) { fprintf(stderr, "attach: %s\n", adamo_last_error()); return 1; } return adamo_robot_run(robot);}Common Issues
Section titled “Common Issues”The robot starts but never connects
Section titled “The robot starts but never connects”The default transport is QUIC, which runs over UDP. Some corporate networks, lab firewalls, VPNs, and hotel Wi-Fi block outbound UDP even when normal HTTPS works. If the SDK logs connection timeouts or the robot never appears in the operator UI, retry with TCP.
robot = adamo.Robot(api_key="ak_...", name="my-arm", protocol="tcp")use adamo::{Protocol, Robot};
let mut robot = Robot::new("ak_...", Some("my-arm"), Protocol::Tcp)?;adamo_robot_t *robot = adamo_robot_new( "ak_...", "my-arm", adamo_protocol_t_ADAMO_PROTOCOL_TCP);TCP is usually a little less latency-efficient than QUIC, but it is the right choice when the network blocks UDP. For LAN or unreliable-tolerant traffic, you can explicitly choose UDP with protocol="udp" (Python), Protocol::Udp (Rust), or adamo_protocol_t_ADAMO_PROTOCOL_UDP (C).
Run It
Section titled “Run It”Run your program. On startup the SDK fetches your router endpoint and opens a session.
[adamo] connecting to router as my-arm…[adamo] connected (org: my-org)[adamo] streaming main: 1280x720 @ 30 fps, 4000 kbps (nvh264enc)See Your Robot
Section titled “See Your Robot”Open operate.adamohq.com and log in. Your robot appears in the grid with its live camera feed already playing. Click it to open the teleoperation view.
From there you have:
- Gamepad control — plug in a USB or Bluetooth controller; the web app publishes Joy messages that your robot can subscribe to. See Receiving Control.
- VR teleop — for stereo camera tracks, “View Stereo” launches a WebXR view with head + controller pose forwarded to the robot.
- Recording & replay — every session can be recorded and replayed later.
- Layouts — multi-camera grids you can configure once and reuse.
See The operate.adamohq.com Platform for the full tour.
To make the robot respond to gamepad or VR input, see Receiving Control.
Inspect Live Topics
Section titled “Inspect Live Topics”When you are not sure what is flowing through the network, subscribe to a wildcard and print the keys that arrive. This is the live equivalent of “list topics”: it observes traffic, so quiet topics appear only after they publish a sample.
import adamo
session = adamo.connect(api_key="ak_...")seen = set()
with session.subscribe("my-arm/**") as sub: for sample in sub: if sample.key not in seen: seen.add(sample.key) print(sample.key)Use my-arm/** for one robot, **/control/** for control traffic, or ** when you really want to see every sample in your org. See Robot and Topic Discovery for Python, Rust, C, and TypeScript versions.
Add More Cameras
Section titled “Add More Cameras”Most robots have more than one camera. Just call the attach method again — once per track.
import adamo
robot = adamo.Robot(api_key="ak_...", name="my-arm")robot.attach_video("wrist_left", device="/dev/video0")robot.attach_video("wrist_right", device="/dev/video1")robot.attach_video("head", shm="head_cam") # iceoryx2 SHMrobot.run()use adamo::Robot;
fn main() -> adamo::Result<()> { let mut robot = Robot::new_default("ak_...", Some("my-arm"))?; robot.attach_v4l2("wrist_left", "/dev/video0", 1280, 720, 30, 4000, false)?; robot.attach_v4l2("wrist_right", "/dev/video1", 1280, 720, 30, 4000, false)?; robot.run()}adamo_robot_t *robot = adamo_robot_new_default("ak_...", "my-arm");adamo_robot_attach_video_v4l2(robot, "wrist_left", "/dev/video0", 1280, 720, 30, 4000, false);adamo_robot_attach_video_v4l2(robot, "wrist_right", "/dev/video1", 1280, 720, 30, 4000, false);adamo_robot_run(robot);For the full set of input methods (V4L2 and shared memory), see Adding Cameras.