Robot description and coordinate frames
On this page
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.
| File | Read by | Holds |
|---|---|---|
robot_description_manifest.json | everyone | Which files the robot is made of. Schema rosie.robot-manifest.v1. |
robot.urdf | planner, OLP, rt-core compiler | Links, joints, meshes, joint limits (rad, rad/s), the torch link. The URDF robot name must equal the model id. |
robot.srdf | Tesseract planning | The manipulator planning group and its named home state. |
config.json | planner, OLP, rt-core compiler | What URDF cannot say: frames, planning rates and accelerations, driven and held axes, reset pose, torch convention, calibration caps. Schema rosie.robot-config.v1. |
spheres.json | weld planner | The arm's collision spheres, in each link's own frame, with the hashes of the URDF and meshes they were fitted to. |
rtcore_definition.json | rt-core only | How each joint maps to a drive: drive profile, gearing, encoder scale, direction, Home policy. Schema rosie.robot-definition.v1. |
meshes/ | planner, viewers | The link meshes the URDF names, plus any fixture bodies the planner uses. |
provenance/, README.md | people | How 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_v3The exact byte layout is in the reference.
How the identity travels#
- A machine config pins it.
robot.robot_descriptionnames the directory and its identity.rtctl compilerefuses a pin that does not match the files on disk. - 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.
- 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 withrtctl resources fetch. - 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.
- The program records it. Every dense trajectory carries a
robot_cellblock in its header withmodel_id,robot_description_sha256andmachine_planning_calibration_sha256. See Dense trajectory format. - 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#
| Reason | When |
|---|---|
robot_cell_unavailable | The cell binds no robot description, or its robot identity is not valid. |
robot_cell_missing | The program's header names no robot or cell. It was planned before this check existed. Plan it again. |
robot_cell_mismatch | The 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_mandrpy_rad, each component capped by the description'skinematic_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:
| Frame | Key | Meaning |
|---|---|---|
| Base | frames.base | What everything is measured in. world on both Rosie models. |
| Tool | frames.tool and torch.tool_frame | The tool centre point: tool0. |
| Work | frames.work | What a workpiece is fixtured to. On a positioner this is a surface on a table link, not the link origin. |
| Work surface | frames.work_surface | Optional. 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_min metres andrpy_radin 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| Joint | Parent → child | Axis | Limits (rad) | URDF velocity (rad/s) | Planning velocity (rad/s) | Planning acceleration (rad/s²) |
|---|---|---|---|---|---|---|
| J1 | floor → link_1 | +z | −π to π | 3.14 | 0.785 | 5.0 |
| J2 | link_1 → link_2 | +y | −1.9 to 1.9 | 3.14 | 0.785 | 5.0 |
| J3 | link_2 → link_3 | +y | −1.57 to 1.53 | 3.14 | 0.785 | 5.0 |
| J4 | link_3 → link_4 | +x | −π to π | 17.45 | 1.571 | 10.0 |
| J5 | link_4 → link_5 | +y | −3.37 to 1.3 | 23.27 | 1.571 | 10.0 |
| J6 | link_5 → link_6 | +z | −2.094 to 3.14 | 31.42 | 1.571 | 10.0 |
| J7 | h_frame → positioner_table_a | +y | −π to π | 3.14 | 0.785 | 2.5 |
| J8 | h_frame → positioner_table_b | −y | −π to π | 3.14 | 0.785 | 2.5 |
| J9 | floor → h_frame | +z | −π to π | 3.14 | 0.785 | 2.5 |
- Frames: base
world, tooltool0, workpositioner_table_a_top, a surface onpositioner_table_aatxyz_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
homestate 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| Joint | Axis | Limits (rad) | URDF velocity (rad/s) | Planning velocity (rad/s) | Planning acceleration (rad/s²) |
|---|---|---|---|---|---|
| J1 | +z | −6.266 to 6.266 | 3.14 | 3.0 | 2.094 |
| J2 | −y | −1.9 to 1.9 | 3.14 | 3.0 | 2.094 |
| J3 | +y | −4.2 to 1.53 | 3.14 | 3.0 | 2.094 |
| J4 | +x | −6.266 to 6.266 | 17.45 | 10.0 | 4.189 |
| J5 | +y | −6.266 to 6.266 | 3.14 | 3.0 | 4.189 |
| J6 | −z | −10 to 10 | 31.42 | 10.0 | 4.189 |
- Frames: base
world, tooltool0, workworld. - 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'svelocityis 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.
Related pages#
- Robot description files: every field and the identity algorithm
- Add a robot model
- Cells, machines and positioners
- Configuration files: how a machine config pins a description
- Dense trajectory format: the
robot_cellheader block