guides
Intended Documentation
ROS2 Integration
Layer Intended Authority Tokens onto a ROS2 agent — cobot, AMR, drone, surgical — without writing HTTP plumbing.
Integrating Intended on ROS2 (DOC-P1)#
Audience: robotics engineers shipping ROS2-based agents (cobots, AMRs, drones, surgical robots) who want to gate state-changing actions on an Intended Authority Token.
Prereqs: ROS2 Humble or newer, Python 3.10+, an Intended tenant API key.
Status: SDK skeleton (v0.2). Cloud round-trip works end-to-end. Sub-50ms hot-path verification ships with the Rust edge verifier (TOK-P1, deferred — see the roadmap).
Why this exists#
ROS2 already has good primitives for what a robot is doing. It does not have a primitive for whether the robot is allowed to do it. The moment an LLM, planner, or operator command becomes the source of an action, you need:
- An auditable record of which OIL category the action falls under.
- A short-lived signed credential the controller checks before commanding motors.
- A safe-default fallback if the credential is denied or expires.
Intended is that layer. This guide shows how to wire it into a ROS2 agent without writing HTTP plumbing.
Architecture#
Intended runs as a ROS2 node in your robot's compute. Your agent never talks to our cloud directly — the node mediates. Your safety bus data never leaves your network — you implement a PhysicalStateProvider that surfaces it as structured predicates.
Install#
Configure#
The node reads its config from environment variables, so it bootstrappable from systemd / launch files / Docker without ROS2 parameter wiring.
INTENDED_ACTOR_IDENTITY SHOULD be the IEEE 802.1AR DevID of your robot once TOK-P5 ships. Until then any unique stable identifier works.
Launch#
That gives you a node exposing ~/classify_and_authorize as a std_srvs/srv/Trigger-shaped service (typed srv lands in v0.3).
Calling from your agent#
The v0.2 service contract is JSON-in / JSON-out, encoded through ROS2 parameters. From a Python lifecycle node:
Implementing PhysicalStateProvider#
Intended never reads your safety bus. You bridge it. The minimum you need is a node (Python or C++) that, given a predicate name, returns its current value with attestation metadata.
safety_rated=True and protocol="fsoe" are the load-bearing claims here. If your policy uses safety-rated predicates and the bus drops to an untrusted channel, the cloud will deny on attestation grounds (clause require-attested-safety-bus in the reference policy).
Verifying the token#
Today: the cloud verifies on each issuance — no edge verification yet. Your trajectory dispatcher trusts the token if decision == "ALLOW" and expires_at_ms > now().
When TOK-P1 ships: drop in the Rust edge verifier binary and your dispatcher links against it. The wire format and JWT claims do not change.
Common patterns#
Behavior-tree (BehaviorTree.CPP)#
Wrap the service call in a RetryNode over a ConditionNode so an ESCALATE decision pauses the tree until an operator approves. The operator approval ticket comes back in decision.escalation_ticket_id.
Real-time controllers (ros2_control)#
Don't call the service from the controller's update loop — the cloud round-trip will starve your real-time deadline. Pre-issue tokens from a non-RT planner and pass them down via the controller's command interface. Edge verifier (TOK-P1) collapses this to a single local check.
Multi-robot fleets#
Run one intended_authority_node per robot. Tokens bind to the robot's actor_identity, so a token issued for cobot-east-3 cannot be replayed on cobot-east-4 once TOK-P5 ships.
Troubleshooting#
| Symptom | Likely cause | Fix |
|---|---|---|
| Service times out | API key empty or wrong tenant | check INTENDED_API_KEY, see node logs |
Every request returns DENY with attestation reason | predicates marked protocol: untrusted but policy requires safety-rated | wire your safety bus, set safety_rated=True |
ESCALATE on every novel goal | classifier confidence below your policy floor | extend the LIM corpus (LIM-P2) or lower the floor in policy |
| Token expires before motion starts | deadline_ms too tight for your trajectory length | request fresh token from controller, not planner |
See also#
- REF-P1 pick-and-place reference — runnable example of this exact flow
- DOC-P5 safety-case writing — how to extend the Intended certified primitive to your machine's safety case
- DOC-P7 Authority API reference — every endpoint, every claim, every error