Skip to main content
Skills read sensor data — camera frames, odometry, the map, and more — as typed ambient state. Declare what you read as a class-level type annotation and the system injects it, then keeps it updated at 50Hz while your skill runs.

Declaration

One rule covers everything: annotate what you read.
A plain annotation is required — the server waits for the first value and fails the run up front if none arrives, so no None guards are needed inside execute(). The wait is 3 s for cameras, 6 s for the battery (it only publishes at ~0.2 Hz), 2 s for everything else. Appending | None makes the feed best effort instead: injected when available, None otherwise, and every read must be guarded. Reading an undeclared feed raises with a hint (declare it on the class with a type annotation), and your editor flags it before you ship.

Available State

Camera Frames

Cameras must be declared — the server starts them per run (frame encoding is too expensive to keep warm). A required camera fails the run if no frame arrives within a short grace period; an optional (| None) camera never delays the start — wait for it in execute() if you need to (self.wait_for(lambda: self.image)). An Image is the base64 JPEG text (it subclasses str, so anything that treated frames as base64 strings keeps working); .jpeg is the decoded bytes:
DepthMap is a (height, width) numpy array (uint16 mm or float32 m), declared as depth: DepthMap.

Odometry

A flat 2D snapshot — MARS is a differential-drive base on flat ground, so its pose is fully (x, y, theta):
pose: Pose has the same shape in the map frame — the coordinates navigate_to_position targets. Which one you want depends on the frame: odom resets every boot but is always there. pose reads None until the robot is localized, so declare it Pose | None unless localization is guaranteed.

Map

The occupancy grid:

Other feeds

arm: Arm is the ambient 50 Hz feed; self.manipulation.pose returns the same Arm type on demand (and raises if the FK feed is down) — see Body Control Interfaces.

Example: CaptureImages

Capture images while rotating. The camera and mobility are declared with bare annotations, so both are guaranteed inside execute():

Example: MonitorPosition

Track how far the robot moves over a window. self.sleep() is what makes the loop interruptible: