None. Append | None (battery: Battery | None) to make a feed best effort instead — injected when available, None otherwise, and the run starts either way.
Every state type is a frozen dataclass with no ROS in it, so you can import and unit-test them off the robot.
Available state
Odometry and pose
MARS is a differential-drive base on flat ground, so its pose is fully(x, y, theta) — no quaternions to unpack.
If you genuinely need the full ROS message — covariances,
z, the real quaternion — odom.raw hands it over as plain data.
Camera frames
AnImage is the base64 JPEG string, so it drops straight into a vision API body, and .jpeg gives you the raw bytes:
depth: DepthMap gives a (height, width) numpy array of depth from the stereo pipeline, in uint16 millimetres.
Lidar
One sweep, with a sector helper so you don’t have to do the angle arithmetic:Arm and joints
arm: Arm is the same type Manipulation returns from a motion, so a servoing loop reads the ambient feed and the move result in one shape.
Map
Grid metadata arrives immediately; the cells are decoded lazily, so a skill that only wants the resolution never pays to unpack thousands of them.Example: capture images while rotating
mobility.rotate() raises SkillCancelled the moment a Stop lands, and the framework reports it.
Example: monitor how far the robot moves
Skills written against 0.6.x read state as dictionaries (
odom["theta_degrees"], odom["pose"]["pose"]["position"]["x"]). That still works — the typed values keep a mapping shim — but it is deprecated. New skills should use the attributes.
