Robotics Quickstart

Get the AutonomyOps ROS2 governance demo running in 10 minutes.

This quickstart targets the Community Edition distribution of the autonomy CLI on a single-node setup. (adk_ce_<version>_<os>_<arch>.tar.gz is the CE package name; once installed the command is on PATH simply as autonomy.) No orchestrator, fleet, or paid-tier deployment is required to complete every step on this page. Advanced flows that depend on a running autonomy-orchestrator are called out explicitly under “Advanced”.

What you will do

  1. Build the demo ROS2 image

  2. Run the governed arm-demo stack

  3. Watch PASS markers to confirm governance checkpoints

  4. Query the /arm/get_status service through the container

  5. Inspect the demo bundle that carries the safety policy

Prerequisites

Tool

Version

Purpose

Docker

24+

Container execution path

autonomy CLI

latest

Governance and bundle commands

ROS2 Humble

optional

Native fallback path only

Install the autonomy CLI:

bash scripts/install-ce.sh

Verify:

autonomy version

Step 1 — Build the demo image

From the repository root:

docker build -t ghcr.io/autonomyops/adk-ros2-runtime:local \
    -f demo/ros2-runtime/Dockerfile .

The trailing . (repo root as build context) is required: the Dockerfile’s preload-builder stage COPYs runtime/preload/src/ to compile the LD_PRELOAD shim baked into the image (#960 Phase 4b-2).

The Dockerfile uses ghcr.io/autonomyops/adk-runtime:latest as the base and builds the demo_robot workspace via colcon build at image-build time. The entrypoint adk_ros2_entrypoint.sh sources both the Humble base overlay and the workspace overlay.

Expected: Successfully tagged ghcr.io/autonomyops/adk-ros2-runtime:local

Step 2 — Run the governed arm demo

Both tiers require --image whenever Docker is available on the host. The container path is selected automatically when the Docker daemon is reachable; without --image the container path returns ErrImageRequired. Pass --image to both commands below:

CE-tier (dispatch via autonomy run)

The full arm-controller demo (arm_demo.launch.py) is the canonical first run:

autonomy run \
    --image ghcr.io/autonomyops/adk-ros2-runtime:local \
    ros2.launch launch demo_robot arm_demo.launch.py

Two additional mirrored single-node demos prove the launcher is language-agnostic. Same shared policy, same launcher-level PASS markers (including the host-side ros2-launch-allowed gate marker), same persisted autonomy.decision frame, same order — different language, different sibling package. The same decision-frame shape is produced by the paid autonomy ros2 run entry point too (runtime-layer emission via evaluatePreExec), and that path also wires an in-process tool server so the nodes exercise node-level POST /v1/tool governance. Either is a valid first-run robotics demo; pick the language you already write your robot’s nodes in. Tracked under issue #720 (Tier 4):

# Python (ament_python — demo_robot package):
autonomy run \
    --image ghcr.io/autonomyops/adk-ros2-runtime:local \
    ros2.launch launch demo_robot     governed_arm_python.launch.py

# C++ (ament_cmake — demo_robot_cpp package):
autonomy run \
    --image ghcr.io/autonomyops/adk-ros2-runtime:local \
    ros2.launch launch demo_robot_cpp governed_arm_cpp.launch.py

The two mirrored single-node demos each print a deterministic pair of process-local PASS markers in addition to the launcher-level ones:

Language

Process-local markers (printed by the node itself)

Python

PASS ros2-python-startPASS ros2-python-wal-written

C++

PASS ros2-cpp-startPASS ros2-cpp-wal-written

These prove the launched node was reached and ran a ROS 2 API call. The launcher-level markers (Step 3 below) prove the host-side governance contract fired. On both entry points each node also POSTs two requests to the in-process tool server (one safe, one unsafe) and emits two further per-language PASS markers:

Language

Tier 4 node-level markers (both entry points)

Python

PASS ros2-python-safe-action-allowedPASS ros2-python-unsafe-action-denied

C++

PASS ros2-cpp-safe-action-allowedPASS ros2-cpp-unsafe-action-denied

Tier 4 honest framing: today’s demo proves launcher instrumentation equivalence, a persisted autonomy.decision frame for tool.ros2.launch (allow + deny, both entry points), the C++ runtime libs + curl pinned in the runtime image via INV-ARCH-12 / INV-ARCH-13, and node-level POST /v1/tool governance with one allow + one deny per node on both the CE (autonomy run ros2.launch) and paid (autonomy ros2 run) entry points. The complete #720 series — including every deferred sub-task — is captured in ROS2 Governance → Mirrored Python + C++ demo.

On a host without Docker and with ros2 in PATH, the native fallback path is taken and --image may be omitted. The governance posture is reduced in that case (see ROS2 Governance).

Step 3 — Watch PASS markers

The governance stack emits PASS markers to stdout at each checkpoint. You should see all six within the first 5–10 seconds:

PASS ros2-telemetry-active context=container
PASS ros2-runtime-container-ready context=container
PASS ros2-launch-allowed context=container
PASS ros2-stack-start context=container
PASS ros2-policy-enforced context=container
PASS ros2-wal-recording context=container

If any marker is missing, check the Markers and Observability guide for diagnostic steps.

Shortly after, the demo nodes start logging:

[arm_demo] launching in mode=sim — governed by AutonomyOps ROS2 policy
[distance_sensor]: distance_sensor ready — rate=10.0 Hz  range=[0.05, 2.0] m
[arm_controller]: arm_controller ready — max_velocity=1.0 m/s  safety_stop_distance=0.3 m
...
[arm_controller]: PROXIMITY STOP — obstacle at 0.192 m (threshold=0.3 m)
...
[arm_controller]: proximity cleared — obstacle at 0.352 m, resuming

The proximity stop fires once per 8-second obstacle cycle generated by the distance_sensor sine-wave model. No hardware is required.

Step 4 — Query the arm status service

While the stack is running, open a second terminal and run:

container=$(docker ps -q -f ancestor=ghcr.io/autonomyops/adk-ros2-runtime:local)

docker exec "$container" bash -c "
  source /opt/ros/humble/setup.bash
  source /opt/ros2_ws/install/setup.bash
  ros2 service call /arm/get_status std_srvs/srv/Trigger
"

The response depends on where the 8-second proximity-stop cycle is when you call. success is True when the arm is idle or moving and False when in the e_stopped state (proximity stop active). Both are valid outputs during a normal demo run:

# Idle or moving — no active stop
response: std_srvs.srv.Trigger_Response(
  success=True,
  message='state=idle  joint[0]=0.000 rad  e_stop=False'
)

# During a proximity stop
response: std_srvs.srv.Trigger_Response(
  success=False,
  message='state=e_stopped  joint[0]=0.000 rad  e_stop=True'
)

Wait a few seconds and call again if the first response shows success=False; the proximity stop clears automatically when the simulated obstacle recedes.

The /arm/get_status service is the only service permitted by the demo policy; any other service call is denied by the fail-closed default.

Step 5 — Inspect the demo bundle

The demo bundle (demo/bundles/ros2.tar) carries the safety policy that governs this run. Inspect it without a registry:

autonomy bundle inspect demo/bundles/ros2.tar --local

Expected output (key fields):

name:       ros2-demo
version:    0.1.0
channel:    dev
entrypoint: ros2 launch demo_robot arm_demo.launch.py
policy_ref: policies/ros2_safety.rego

To view the policy itself:

autonomy bundle inspect demo/bundles/ros2.tar --local --show-policy

Step 6 — Stop the demo and inspect the local WAL

Press Ctrl-C in the terminal running autonomy run ros2.launch (or autonomy ros2 run).

The governance stack flushes the local WAL before exit. To inspect what was recorded — every PASS marker, every policy decision — read the local WAL directly. No orchestrator required:

autonomy wal status
autonomy wal inspect --limit 20
autonomy wal inspect --kind PASS --limit 20

autonomy wal inspect reads the local telemetry WAL on this machine. The output includes the six ros2-* PASS markers and the persisted autonomy.decision frame for tool.ros2.launch plus any further policy-evaluation events that occurred during the run.

Troubleshooting

No PASS markers appear

  • Confirm Docker is running: docker info

  • Confirm the image was built: docker image inspect ghcr.io/autonomyops/adk-ros2-runtime:local

  • If Docker is absent the native fallback path is taken; ros2-runtime-container-ready will not appear.

ErrImageRequired

Both autonomy ros2 run and autonomy run ros2.launch require --image when the Docker daemon is reachable. If --image is omitted on a Docker-capable host you will see:

ros2: container path selected but no image specified

Pass --image ghcr.io/autonomyops/adk-ros2-runtime:local to either command.

ErrNeitherAvailable

Docker is absent and ros2 is not in PATH. Install Docker for full governance or install ROS2 Humble for the native fallback path.

Next steps

CE-tier follow-ups (single-node, no orchestrator):

I want to …

Read

Understand policy governance

ROS2 Governance

Run the Gazebo simulation stack

Gazebo Simulation

Use NVIDIA GPU inference

NVIDIA GPU Integration

Inspect, stage, and verify bundles offline

Bundle Workflows

Understand PASS markers and the local WAL

Markers and Observability

Adapt the demo to real hardware

Hardware Adaptation