Quickstart
Get TraceHouse™ tracing your robot in minutes — the SDK way.
TraceHouse tracing has two halves:
- The agent (the "carrier") —
robot-agent, the on-robot binary that receives spans from the SDK over a local socket and forwards them to TraceHouse. It also keeps collecting logs, metrics, TF, and MCAP on its own. - The RobotOps Trace SDK — small libraries you add to your robot as normal dependencies (no forks, no framework rebuilds). They produce deterministic, in-process traces and hand them to the agent.
:::info Prerequisites
- Ubuntu 24.04 Noble (ROS 2 Jazzy) — or Ubuntu 22.04 Jammy (ROS 2 Humble, arm64 / Jetson). See system requirements
- ROS 2 installed and sourced
sudoaccess on the robot's onboard computer (not needed inside most containers, which run as root)- A TraceHouse account and API key — sign up at robotops.com :::
1. Install
Run the installer on your robot:
curl -fsSL https://tracehouse.robotops.com/install.sh | bash
The script adds the apt.robotops.com repository and installs, for your detected ROS distro:
robot-agent— the carrier (binary at/usr/bin/robot-agent)- The Trace SDK —
ros-<distro>-robotops-trace-cpp(the C++ core) plus therclcppandBehaviorTree.CPPintegrations and the shared semantic conventions - Env-default auto-init — a sourceable env file at
/etc/robotops/trace.envthat you apply to your ROS launch environment to turn tracing on (step 3). It is not a global preload.
Pass ROBOTOPS_SKIP_SDK=1 to install the agent only, or ROBOTOPS_SKIP_AUTOINIT=1
to install the SDK without writing the auto-init env file.
:::caution The legacy passive path is deprecated
Earlier versions installed rmw_robotops (the passive content-hash RMW shim) and
told you to set RMW_IMPLEMENTATION=rmw_robotops. That path is deprecated and
is no longer installed — tracing now comes from the SDK below. See
Related Libraries.
:::
What's in this script?
The installer performs these steps — no surprises:
# Add the RobotOps GPG key
curl -fsSL https://apt.robotops.com/robotops-public-key.asc \
| sudo gpg --dearmor -o /usr/share/keyrings/robotops-archive-keyring.gpg
# Add the apt repository (suite = your Ubuntu codename, e.g. noble)
echo "deb [signed-by=/usr/share/keyrings/robotops-archive-keyring.gpg] https://apt.robotops.com noble main" \
| sudo tee /etc/apt/sources.list.d/robotops.list
sudo apt update
# The carrier (Jazzy — amd64 + arm64; Jetson/Humble arm64: robot-agent-humble)
sudo apt install -y robot-agent-jazzy
# The Trace SDK + integrations (per distro)
sudo apt install -y ros-jazzy-robotops-trace-cpp \
ros-jazzy-robotops-trace-rclcpp \
ros-jazzy-robotops-trace-bt-cpp \
ros-jazzy-robotops-trace-semconv
You can also run these steps manually if you prefer not to pipe scripts.
Pick the integrations you use
The SDK core is framework-agnostic; the integrations are à-la-carte apt packages. Install only the ones matching your stack:
| Package | Covers |
|---|---|
ros-<distro>-robotops-trace-cpp | SDK core (required) — RAII span guard, ROBOTOPS_TRACE(), OTLP exporter |
ros-<distro>-robotops-trace-rclcpp | rclcpp executor callbacks + rclcpp_action goal-UUID stitching |
ros-<distro>-robotops-trace-bt-cpp | BehaviorTree.CPP tick callbacks (covers Nav2 + MoveIt Pro) |
ros-<distro>-robotops-trace-semconv | Shared robotics semantic conventions |
ros2_control and MoveIt integrations are available as additional packages; see
Instrumentation.
Python (rclpy)
The Python SDK ships to PyPI:
pip install robotops-trace robotops-trace-rclpy
:::note PyPI lane: coming soon
robotops-trace / robotops-trace-rclpy on PyPI are not published yet (the
PyPI org is being set up). The apt (dev channel) lane for the C++ SDK above is
live today. If you run rclpy nodes, instrument your C++ / rclcpp nodes now and
track the PyPI lane on this page. ROS-coupled fleets can also get robotops_trace_rclpy
as an ament_python deb via apt once published.
:::
2. Configure the agent (carrier)
The agent is configured entirely through environment variables — point it at TraceHouse:
| Variable | Required? | Value |
|---|---|---|
ROBOTOPS_API_KEY | Yes | Your key (sk_…) from the dashboard |
ROBOT_OPS_AGENT_BACKEND_URL | Recommended | https://backend.robotops.com (the production endpoint) |
:::note Why set ROBOT_OPS_AGENT_BACKEND_URL explicitly?
The agent's built-in default still points at the legacy api.robotops.com host. Setting the backend URL pins you to the canonical production endpoint, backend.robotops.com. It's a normal override — point it anywhere for self-hosted or local development (e.g. http://localhost:50051).
:::
3. Turn it on — env-default auto-init
Auto-init is the Datadog -javaagent model: set it once in the launch
environment and every node auto-instruments with zero per-node code.
- C++:
LD_PRELOADa constructor lib (librobotops_trace_autoinit.so) — it runsRobotOps::init()on load. - Python: set
ROBOTOPS_TRACE_AUTOINIT=1— an installed.pth/sitecustomizehook callsrobotops.init()on interpreter start.
The installer writes both into /etc/robotops/trace.env:
# /etc/robotops/trace.env (written by install.sh)
export LD_PRELOAD=/opt/ros/${ROS_DISTRO}/lib/librobotops_trace_autoinit.so${LD_PRELOAD:+:$LD_PRELOAD}
export ROBOTOPS_TRACE_AUTOINIT=1
export ROBOTOPS_OTLP_ENDPOINT=unix:///run/robotops/trace.sock
Apply that env file to your ROS launch environment — not globally — by picking the model that matches your deployment:
:::tip Scope it to your ROS nodes, not the whole machine
Auto-init belongs in the environment of the nodes you want traced. The installer
deliberately does not add a global /etc/profile.d preload by default (that
would LD_PRELOAD the tracer into every process — ssh, cron, system daemons).
If you really want preload-everything, re-run the installer with
ROBOTOPS_GLOBAL_AUTOINIT=1.
:::
- On-host (systemd)
- Container (Docker)
- ROS launch file
For nodes launched by their own systemd units, point each unit at the env file:
[Service]
EnvironmentFile=/etc/robotops/trace.env
Then run the agent (the carrier) with its key:
sudo systemctl edit robot-agent
[Service]
Environment=ROBOTOPS_API_KEY=sk_your_api_key_here
Environment=ROBOT_OPS_AGENT_BACKEND_URL=https://backend.robotops.com
sudo systemctl enable --now robot-agent
Inside a container, set the auto-init vars at the container level so every ROS 2 node in it auto-instruments, and run the agent as a plain process:
docker run --rm -it \
--net=host --ipc=host \
-e LD_PRELOAD=/opt/ros/jazzy/lib/librobotops_trace_autoinit.so \
-e ROBOTOPS_TRACE_AUTOINIT=1 \
-e ROBOTOPS_API_KEY=sk_your_api_key_here \
-e ROBOT_OPS_AGENT_BACKEND_URL=https://backend.robotops.com \
your-image robot-agent
If the agent runs in a separate container (no shared filesystem with your nodes), point the SDK at it over TCP — see step 4.
Set the auto-init vars for the nodes you want traced with a
SetEnvironmentVariable action, and
start the agent as a process from the same launch.
SetEnvironmentVariable('LD_PRELOAD', '/opt/ros/jazzy/lib/librobotops_trace_autoinit.so'),
SetEnvironmentVariable('ROBOTOPS_TRACE_AUTOINIT', '1'),
:::tip Nodes outside the auto-init env
A node launched outside that environment still works — call RobotOps::init()
(C++) or robotops.init() (Python) explicitly at startup. This is the override
path; everything downstream behaves identically.
:::
4. Transport — plug-and-play
The SDK exports spans to the agent as OTLP/HTTP + protobuf over a Unix domain socket by default:
-
Default socket:
unix:///run/robotops/trace.sock. The agent's systemdRuntimeDirectorycreates, owns, and cleans it; the SDK default matches, so the same-host case needs no configuration. -
Plug-and-play: default permissions let the robot's node processes connect out of the box. For locked-down fleets, opt into
0660+ arobotopsgroup (the debpostinstcreates it). -
Override:
ROBOTOPS_OTLP_ENDPOINTacceptsunix:///pathandhttp://host:port. -
Containerized split (agent in a separate container, no shared FS) — the one case that isn't automatic. Point the SDK at the agent over TCP loopback:
export ROBOTOPS_OTLP_ENDPOINT=http://agent:4318
5. Annotate (optional)
Auto-init gives you spans for every framework callback for free. To add first-party depth inside your own code, drop in one line:
// C++ — RAII span for this scope
void MyNode::plan() {
ROBOTOPS_TRACE("plan_grasp");
// ... your code ...
}
# Python — decorate a function
@robotops.trace
def plan_grasp(self):
...
These nest automatically under the surrounding callback span. See Instrumentation for more.
6. Verify
Bring up your nodes and the agent. Traces appear in your TraceHouse dashboard within a few seconds — as waterfalls with span attributes and events.
- On-host (systemd)
- Container (Docker)
sudo systemctl status robot-agent # is the carrier running?
sudo journalctl -u robot-agent -f # follow live logs
ls -l /run/robotops/trace.sock # the SDK→agent socket exists
docker logs -f <container> # agent logs go to the container's stdout
What you get
With the SDK installed and auto-init on, TraceHouse shows:
- Deterministic intra-process traces — exact parent/child causality within a process, not statistical sampling.
- Auto-spans per callback — every rclcpp / rclpy executor callback (and
BehaviorTree.CPP tick) becomes a span, tagged with
robot.callback.type. - Deterministic action-hop stitching — action client and server spans are
joined by
robot.action.goal_id(the goal UUID), so aNavigateToPoseshows up as one trace across the process boundary. - Best-effort topic/service stitching — pub/sub and service hops are correlated
via DDS content keys (
ros.publisher_gid,ros.source_timestamp). - Black-box spans for uninstrumented code — frameworks you haven't added an integration for still appear as opaque spans (a gap, never a failure or a crash).
All of it is described by the shared
robotics semantic conventions
(robot.* concept keys + ros.* mapping keys), so traces are queryable with the
same vocabulary across frameworks.
Manual install
If you prefer to install without piping the script, run each step individually:
# 1. Add the GPG key
curl -fsSL https://apt.robotops.com/robotops-public-key.asc \
| sudo gpg --dearmor -o /usr/share/keyrings/robotops-archive-keyring.gpg
# 2. Add the repository
echo "deb [signed-by=/usr/share/keyrings/robotops-archive-keyring.gpg] https://apt.robotops.com noble main" \
| sudo tee /etc/apt/sources.list.d/robotops.list
# 3. Install the carrier + the SDK (Jazzy; Jetson/Humble: swap jazzy→humble)
sudo apt update
sudo apt install robot-agent-jazzy \
ros-jazzy-robotops-trace-cpp \
ros-jazzy-robotops-trace-rclcpp \
ros-jazzy-robotops-trace-bt-cpp \
ros-jazzy-robotops-trace-semconv
# 4. Turn on auto-init (set wherever your nodes launch)
export LD_PRELOAD=/opt/ros/jazzy/lib/librobotops_trace_autoinit.so
export ROBOTOPS_TRACE_AUTOINIT=1
Then configure and run the agent using one of the models in step 3.
Installing via rosdep / ament
If your team manages dependencies declaratively, declare the SDK packages as run
dependencies in your package.xml instead of apt install-ing them directly. Add
the apt repository (step 1 of the manual install), then:
<exec_depend>robotops_trace_cpp</exec_depend>
<exec_depend>robotops_trace_rclcpp</exec_depend>
<exec_depend>robotops_trace_bt_cpp</exec_depend>
<exec_depend>robotops_trace_semconv</exec_depend>
rosdep install --from-paths src --ignore-src -y then resolves them from
apt.robotops.com. You keep stock upstream MoveIt / Nav2 / BehaviorTree.CPP /
ros2_control — the SDK adds tracing as a normal dependency, never a fork or rebuild.
The robot-agent daemon itself is infrastructure, not a ROS node — install it via
the script or apt, never as an ament dependency.
What's next
- Instrumentation — auto-init, annotation, integrations, and what each span carries
- System Requirements — hardware, OS, and distro details
- TraceHouse Agent Overview — what the carrier collects beyond traces
- ROSQL — query your telemetry with the open source query language