Skip to content

Actuators, joints and arms

The SDK names what it moves in two ways. A joint belongs to an arm: joint_4 is a joint of the left arm's chain, named as the arm's description names it. An actuator belongs to the robot: it is one entry of the lists the control loop reads and writes every tick, one per motor the loop drives, counted across every arm. The left arm's joint_4 and the right arm's joint_4 are two joints of the same name, and two actuators of different numbers.

How a robot numbers its actuators

Each arm owns a run of actuators, in the order the robot lists its arms: its chain joints first, in the order its description lists them, then its gripper. A bimanual openarm, whose arms each have seven chain joints and a gripper, comes out as:

actuators arm what they drive
0 to 6 left joint_1 to joint_7
7 left the gripper's motor
8 to 14 right joint_1 to joint_7
15 right the gripper's motor

RobotConfig.actuator_summary says the same in a line, and RobotConfig.layout gives each arm's actuators as numbers.

Two things follow from what an actuator is. A gripper the loop drives has an actuator but is no joint of the chain: kinematics never sees it, and its actuator reads its motor's angle in radians, not how far the jaws are open, which the gripper's GripperMap converts between. And a gripper or hand driven beside an arm, rather than by the loop, has no actuator at all: the loop's lists hold only what the loop drives, so a robot can have more motors than actuators.

Two ways to read the same snapshot

Everything the loop measured and wrote on a tick comes back as a Snapshot, whose lists, q, tau, status_names and the rest, are indexed by actuator. Snapshot.arm reads the same values by name instead: an ArmSnapshot holds each chain joint by the name its description gives it, and its gripper with the jaw opening already worked out. Application code that cares about one arm's joint or how far its jaws are open reads it that way, and never needs a number.

The numbers are for code that works on the whole robot at once. A JointCommand or a JointTrajectoryCommand states a position per actuator, a recorded episode stores one, and a guard's report names the actuators it clamped. Every by-name reading carries its actuator too, so the two are never more than a lookup apart.

The lists are a fixed size, MAX_ACTUATORS, so the loop never allocates; a robot uses the first of them, as many as it has actuators.