Advanced Metal Research
GitHub Contact AMR

Robot description and coordinate frames

On this page
  1. What is in a description
  2. Bench descriptions
  3. Identity
  4. How the identity travels
  5. Load refusals
  6. Cell calibration
  7. Coordinate frames
  8. Units
  9. Rosie 1400
  10. Rosie 1420
  11. Which limit applies where
  12. Related pages

A robot description is one directory that says everything intrinsic to a robot model: its kinematics and meshes, its limits, the planner's policy, its collision spheres and what rt-core needs to drive it. Every cell that mounts that model shares the directory. How one particular cell differs from the model lives on that cell, in a separate calibration file.

The description is hashed. A plan records the hash it was made against, and the cell refuses a plan whose hash does not match its own. This page explains what the files are, how that identity moves through the system, and the frames and joints you program against.

For the exact file schemas see Robot description files. To create a new model see Add a robot model.

What is in a description#

A description lives at robot_description/robots/<model_id>/. The directory name is the model id, and every file in it must state the same id.

FileRead byHolds
robot_description_manifest.jsoneveryoneWhich files the robot is made of. Schema rosie.robot-manifest.v1.
robot.urdfplanner, OLP, rt-core compilerLinks, joints, meshes, joint limits (rad, rad/s), the torch link. The URDF robot name must equal the model id.
robot.srdfTesseract planningThe manipulator planning group and its named home state.
config.jsonplanner, OLP, rt-core compilerWhat URDF cannot say: frames, planning rates and accelerations, driven and held axes, reset pose, torch convention, calibration caps. Schema rosie.robot-config.v1.
spheres.jsonweld plannerThe arm's collision spheres, in each link's own frame, with the hashes of the URDF and meshes they were fitted to.
rtcore_definition.jsonrt-core onlyHow each joint maps to a drive: drive profile, gearing, encoder scale, direction, Home policy. Schema rosie.robot-definition.v1.
meshes/planner, viewersThe link meshes the URDF names, plus any fixture bodies the planner uses.
provenance/, README.mdpeopleHow the files were made. Not registered, so not part of the identity.

The planner never reads rtcore_definition.json, and rt-core never reads spheres.json. The two halves meet only through the shared URDF, config.json and the identity.

Note

rtcore_definition.json holds the drive gearing and encoder scale for each joint. These docs describe its fields, not its values.

Bench descriptions#

bench_one_motor_1to1 and bench_nine_motors_1to1 describe bare motors on a table. They have only a manifest and rtcore_definition.json, with no URDF. rt-core can run them. OLP does not list them and the planner cannot plan for them.

Identity#

The description's identity is a SHA-256 over the manifest and every file it registers, written sha256:<64 hex>. Files that are not registered, such as a CAD export or a measurement report, are outside the identity: changing them never makes a plan stale. Registering a file, or changing a registered one, changes the identity. That is deliberate: the robot changed.

Print the identity of any description:

cd robot_description/go
go run ./cmd/identity ../robots/rosie_1400_v3
# sha256:<64 hex> ../robots/rosie_1400_v3

The exact byte layout is in the reference.

How the identity travels#

How a robot description's identity travels: a machine config pins the description, rtctl compile snapshots it, rt-control serves it, OLP plans against it, the .rdt header records it, and OLP Load compares the header with what the cell describes. IN THE REPOSITORY PLANNING Robot description robot_description/robots/<model>/ manifest + registered files → sha256:… Machine config robot.robot_description{path, sha256} pinned by path and identity ON THE CELL HOST Compiled configuration rtctl compile snapshots every registered file, plus the cell's machine_planning_calibration.json rt-control Describe robot.resources · /v1/resources/<sha256> OLP robot config Opens the description and the cell's calibration Seam worker and weld planner Receive settled numbers, never the files .rdt header: robot_cell robot_description_sha256 machine_planning_calibration_sha256 OLP Load compares the identities Describes the cell fresh, then checks the plan's model, description and calibration identities. Any difference refuses the program before a byte reaches the robot: robot_cell_missing · robot_cell_unavailable · robot_cell_mismatch
  1. A machine config pins it. robot.robot_description names the directory and its identity. rtctl compile refuses a pin that does not match the files on disk.
  2. The compiled configuration snapshots it. Compiling copies every registered file into the compiled directory as a content-addressed resource. The cell no longer needs the checkout.
  3. rt-control serves it. Describe lists the model id, the identity and each resource's SHA-256. Clients fetch the bytes with GET /v1/resources/<sha256>, or with rtctl resources fetch.
  4. OLP plans against it. OLP's robot configuration is the one place that opens a description and a cell's calibration. The seam worker and the weld planner receive the resulting numbers, never the files.
  5. The program records it. Every dense trajectory carries a robot_cell block in its header with model_id, robot_description_sha256 and machine_planning_calibration_sha256. See Dense trajectory format.
  6. Load checks it. Before sending a program, OLP describes the cell again (it never trusts a cached answer) and compares those three fields.

Load refusals#

ReasonWhen
robot_cell_unavailableThe cell binds no robot description, or its robot identity is not valid.
robot_cell_missingThe program's header names no robot or cell. It was planned before this check existed. Plan it again.
robot_cell_mismatchThe model, description identity or calibration identity differs. The message lists each field, with the plan's value and the cell's.

A machine with flat axes and no robot binding has nothing to compare a plan against, so Load does not run this check on it.

The header can also record the machine's whole configuration digest, machine_configuration_sha256. That is a record, not a check: the digest also changes for things no plan depends on, such as a CPU number or a bus timeout. When it differs, Load adds a note and continues.

Cell calibration#

Two cells built from the same model are never quite identical. A cell states its own deviation in machine_planning_calibration.json (schema rosie.machine-planning-calibration.v1). It is per cell and is not stored in the repository. When a cell has one, its machine config pins it by path and SHA-256, and the compiled configuration serves it beside the description.

The calibration can:

  • narrow a joint's lower and upper limit and its velocity, never widen them
  • hold a joint at a value inside its limits
  • set a speed ceiling no higher than the URDF's fastest joint
  • apply a small kinematic correction to a joint origin, xyz_m and rpy_rad, each component capped by the description's kinematic_correction_caps

Every key is checked. An unknown key, a joint the URDF does not have, a widened limit or an over-cap correction is an error, not something quietly ignored. A cell with no calibration serves a fixed empty document for its model, and a plan made against that empty document matches it exactly.

The calibration's identity is the SHA-256 of its exact bytes. Reformatting the file changes the identity, so plans made against the old bytes are refused.

Coordinate frames#

config.json names the frames the URDF cannot:

FrameKeyMeaning
Baseframes.baseWhat everything is measured in. world on both Rosie models.
Toolframes.tool and torch.tool_frameThe tool centre point: tool0.
Workframes.workWhat a workpiece is fixtured to. On a positioner this is a surface on a table link, not the link origin.
Work surfaceframes.work_surfaceOptional. Adds the work frame as a fixed child of parent, offset by xyz_m.

The torch's electrode axis is torch.electrode_axis, a unit vector in the tool frame. On both Rosie models it is [1, 0, 0]: the wire points along +x of tool0.

OLP's robot catalogue also reports two positions it computes from the URDF at the zero pose: work_world_m, the work frame's origin in world, and arm_base_world_m, the child link of the first driven joint. The Cartesian motion server expresses TCP poses relative to the arm base, while viewers use world, so clients convert with that offset.

Units#

  • Revolute positions are in rad, prismatic positions in m.
  • Velocities are in rad/s, accelerations in rad/s².
  • Offsets are xyz_m in metres and rpy_rad in radians. URDF rotations compose as Rz(yaw)·Ry(pitch)·Rx(roll).
  • A calibration correction is applied as T' = T_origin · Trans(xyz) · R(rpy).

Rosie 1400#

Model rosie_1400_v3: a six-axis arm and an H-frame two-table positioner, nine axes in all. This is the layout of the War Machine cell.

world ─ floor ─┬─ J1 ─ link_1 ─ J2 ─ link_2 ─ J3 ─ link_3 ─ J4 ─ link_4 ─ J5 ─ link_5 ─ J6 ─ link_6 ─ end_effector ─ tool0
               └─ J9 ─ h_frame ─┬─ J7 ─ positioner_table_a ─ positioner_table_a_top (work)
                                └─ J8 ─ positioner_table_b
JointParent → childAxisLimits (rad)URDF velocity (rad/s)Planning velocity (rad/s)Planning acceleration (rad/s²)
J1floor → link_1+z−π to π3.140.7855.0
J2link_1 → link_2+y−1.9 to 1.93.140.7855.0
J3link_2 → link_3+y−1.57 to 1.533.140.7855.0
J4link_3 → link_4+x−π to π17.451.57110.0
J5link_4 → link_5+y−3.37 to 1.323.271.57110.0
J6link_5 → link_6+z−2.094 to 3.1431.421.57110.0
J7h_frame → positioner_table_a+y−π to π3.140.7852.5
J8h_frame → positioner_table_b−y−π to π3.140.7852.5
J9floor → h_frame+z−π to π3.140.7852.5
  • Frames: base world, tool tool0, work positioner_table_a_top, a surface on positioner_table_a at xyz_m [0, −0.622, 0.1].
  • Driven axes: J1 to J7. Held axes: J8 = 0 and J9 = 0. The planner moves the arm and table A together and keeps table B and the H-frame turn fixed.
  • Planning speed ceiling: 1.571 rad/s.
  • Reset pose: all driven joints at 0. The SRDF home state is all nine joints at 0.

How the positioner is built and why the planner holds J8 and J9 is covered in Cells, machines and positioners.

Rosie 1420#

Model rosie_1420_v1: a six-axis arm on a pedestal.

world ─ pedestal ─ base ─ J1 ─ link_1 ─ J2 ─ link_2 ─ J3 ─ link_3 ─ J4 ─ link_4 ─ J5 ─ link_5 ─ J6 ─ link_6 ─ end_effector ─ tool0
JointAxisLimits (rad)URDF velocity (rad/s)Planning velocity (rad/s)Planning acceleration (rad/s²)
J1+z−6.266 to 6.2663.143.02.094
J2−y−1.9 to 1.93.143.02.094
J3+y−4.2 to 1.533.143.02.094
J4+x−6.266 to 6.26617.4510.04.189
J5+y−6.266 to 6.2663.143.04.189
J6−z−10 to 1031.4210.04.189
  • Frames: base world, tool tool0, work world.
  • Driven axes: J1 to J6. No held axes.
  • Planning speed ceiling: 10.0 rad/s.

Which limit applies where#

The same description feeds two consumers, and they use different numbers:

  • The planner uses config.json's planning velocity and acceleration, narrowed further by the cell calibration. A description may lower a planning rate below the URDF rating, never raise it: a planning velocity above the URDF's velocity is refused when the description loads.
  • rt-core takes each robot-bound axis's travel and maximum velocity from the URDF, and its trajectory and jog acceleration from config.json. A machine config cannot override them. rt-core's limit check is therefore the URDF rating, which is higher than the planning rate on most joints.

Warning

rt-core checks joint position, velocity and continuity. It does not check collisions. Only planned weld programs are verified against the cell model before they can be loaded. See What is verified before motion.