# Cells, machines and positioners

> How drive, robot, machine and cell configuration layer and pin each other, how a cell's identity is checked, and how the Rosie 1400 H-frame positioner is modelled.

URL: https://advancedmetalresearch.com/docs/concepts/cells-and-positioners
Section: RosieOS docs / Concepts
Last updated: 2026-10-10

A running cell is described by four layers of configuration. Each layer pins the one below it by content hash, so every process can tell whether it is talking to the cell it expects. This page explains the layers, how they compile into one identity, and how the Rosie 1400's two-table positioner fits in.

## Four layers

| Layer | Where | What it holds |
|---|---|---|
| **Drive config** | `rt-core/config/drives/<name>.json` | One drive or I/O terminal model: EtherCAT identity, PDO layout, scaling semantics, startup parameters, Home transactions, brake and jog policy, collision bounds. |
| **Robot description** | `robot_description/robots/<model_id>/` | The robot: `robot.urdf` and meshes, the planner's `config.json`, collision `spheres.json`, and rt-core's `rtcore_definition.json` (joint mapping and mechanics). A manifest registers the files, and the description's identity is a SHA-256 over them. |
| **Machine config** | `rt-core/config/machines/`, `machines/bench/`, `machines/simulation/` | Binds drives and, optionally, a robot description to bus positions, cycle timing, limits, cell I/O, control timing and host runtime policy. |
| **Cell config** | `rt-core/config/cells/<cell>.json` | Binds one deployed cell: which machine config, its compiled digest, the pair identity, and the remote listener. |

Each layer has an annotated template in `rt-core/config/templates/` (`drive.json`, `robot.json`, `machine.json`, `cell.json`). Every field there has a `_doc` sibling giving its unit, allowed values and default. The field-by-field tables are in [Configuration files](https://advancedmetalresearch.com/docs/reference/configuration).

## Compiling a machine into an identity

`rtctl compile` resolves a machine config, the drive configs it names and any robot description it pins. It writes one immutable directory named after the result, the **configuration digest**:

```bash
cd rt-core
build/rtctl compile --config config/machines/simulation/simulation.json --out build/config
# build/config/<configuration_sha256>
```

The directory holds `axes.conf`, `argv.json` (the core's command line), the identity artifacts and `resources.json`, the robot files that `rt-control` serves to clients. Machine, deployment and configuration digests are distinct, and Describe reports all three.

The digest travels with the cell:

- `rt-control` is started with `--configuration-sha256` and refuses a core that reports another identity.
- Every `acquire` must present the same digest in its binding, with the pair id and revision.
- OLP refuses a cell whose deployed digest differs from its catalogue entry, with `cell_configuration_mismatch`.

Change any layer and the digest changes. You then recompile, and update every pin that referred to the old digest.

### Robot-bound limits

For an axis mapped to a robot joint, the compiler takes travel and maximum velocity from `robot.urdf`, and acceleration from `config.json` (`planning.joints.<joint>.acceleration_rad_s2`). A machine config cannot override those values. The per-axis drive speed cap is derived from the same URDF velocity.

A cell can narrow its limits further with a per-cell `machine_planning_calibration.json`. That file lives with the cell, not in the repository, and the machine config pins it by path and hash. It can narrow joint limits and apply small, capped kinematic corrections. It can never widen a limit.

## Cell config

The cell config is the deployment pin. Its native binding has these fields:

| Field | Type | Description |
|---|---|---|
| `name` | string | Display name. Ignored by the validator. |
| `nodes[].runtime` | string | `rt-core` for a native node. |
| `nodes[].rt_core.machine_config` | path | Repository-relative path to the machine config. |
| `nodes[].rt_core.configuration_sha256` | 64 hex | The exact `rtctl compile` digest. Pin it on every deployed cell. |
| `nodes[].rt_core.pair_id` | string | Deployment pair identity: letters, digits, `_`, `.` or `-`. |
| `nodes[].rt_core.pair_revision` | uint64 | Positive pair revision. Raise it to retire old authority. |
| `nodes[].rt_core.remote_listen` | host:port | The mutual-TLS listener, for example `127.0.0.1:8443`. |

The validator in `rt-core/config/cells` recompiles every cell's machine config and refuses the cell if the digest, axis count, pair or listener is wrong, or if the compiler printed warnings:

```bash
cd rt-core
go test -count=1 ./config/cells -run TestRepositoryCompatibility
```

## Robot models

| Model | Axes | Base, tool, work frames | Notes |
|---|---|---|---|
| `rosie_1400_v3` | J1–J6 arm, J7–J9 positioner | `world`, `tool0`, `positioner_table_a_top` | Rosie 1400 on an H-frame two-table positioner, the layout of the War Machine cell |
| `rosie_1420_v1` | J1–J6 | `world`, `tool0`, `world` | Rosie 1420 six-axis arm on a pedestal |
| `bench_one_motor_1to1`, `bench_nine_motors_1to1` | 1 or 9 bare motors | — | Motor benches: a manifest and an rt-core definition, no URDF. OLP does not list or plan for them. |

Frames, joint chains and units are covered in [Robot description and coordinate frames](https://advancedmetalresearch.com/docs/concepts/robot-description-and-frames).

## The H-frame positioner

The Rosie 1400 description models the positioner as three revolute joints. They are driven by the same core as the arm, at the same 1 kHz cycle.

| Joint | Parent → child | Axis | URDF limit | Role |
|---|---|---|---|---|
| J9 | `floor` → `h_frame` | +z (vertical) | ±π rad, 3.14 rad/s | Turns the whole H-frame |
| J7 | `h_frame` → `positioner_table_a` | +y (horizontal) | ±π rad, 3.14 rad/s | Rotates table A |
| J8 | `h_frame` → `positioner_table_b` | −y (horizontal) | ±π rad, 3.14 rad/s | Rotates table B |

The two tables sit either side of the H-frame. `rosie_1400_v3/config.json` sets what the planner uses:

- **Driven axes:** J1 to J7. The planner moves the arm and table A together.
- **Held axes:** J8 = 0 and J9 = 0. The planner keeps them fixed.
- **Work frame:** `positioner_table_a_top`, a surface on `positioner_table_a` at `xyz_m` [0, −0.622, 0.1]. Weld geometry is expressed on table A.

Dense programs always carry nine axis columns in the order J1–J6, J7/J8, J9. The header's axis mask is `0x1ff` for `rosie_1400_v3` and `0x3f` for `rosie_1420_v1`. See [Dense trajectory format](https://advancedmetalresearch.com/docs/reference/rdt-format).

> [!NOTE] Gear ratios, encoder resolution and drive parameters live in each model's `rtcore_definition.json` and in the drive configs. These docs describe their schema, not their values.

## Simulation machines

`rt-core/config/machines/simulation/` holds machine configs for the simulated backend:

| File | Axes | Use |
|---|---|---|
| `simulation-program.json` | 9 flat axes J1–J9, no Home requirement | Direct SDK examples. `dev-stack.sh` also starts from it, adds the Rosie 1400 URDF limits and requires Home on every axis. |
| `simulation-rosie1400.json` | 9 axes bound to `rosie_1400_v3` | Serves the real robot description to OLP. Its Home is refused on the simulated bus, so nothing arms on it yet. |
| `simulation.json`, `simulation-linear.json`, `simulation-scalars.json`, `simulation-home.json` | 1–2 flat axes | Small fixtures for tests and compile examples |

Choose the dev-stack machine with `DEV_STACK_MACHINE_CONFIG`. See [Run everything in simulation](https://advancedmetalresearch.com/docs/guides/run-in-simulation).

## Sources

Written from these files in the RosieOS repository (https://github.com/advanced-metal-research/RosieOS):

- `rt-core/ipcclient/client_linux.go:369-370,816`
- `offline-programming/v1/internal/targets/cells.go:168,218`
- `offline-programming/v1/internal/denseexec/rt_core.go:1459`
- `robot_description/go/cell.go:6-14,188-196`
- `rt-core/tools/rtctl/robot_definition.go:658`
- `rt-core/config/templates/cell.json`
- `rt-core/config/templates/machine.json:228-233`
- `rt-core/config/cells/compatibility.go:20-24,41-170`
- `rt-core/tools/rtctl/command.go:25-45`
- `rt-core/cmd/rt-control/main.go:27,58-66`
- `rt-core/adapters/rosie/control/api_generated.go:385-390`
- `rt-core/ipcclient Description (configuration_sha256, machine_sha256, deployment_sha256)`
- `robot_description/robots/rosie_1400_v3/config.json`
- `robot_description/robots/rosie_1400_v3/robot.urdf:196-218`
- `robot_description/robots/rosie_1420_v1/config.json`
- `robot_description/go/cell.go:39-114`
- `weld_planner/v1/python/weld_motion_planner/io/dense_output.py:142-166`
- `motion-server/joint-trajectory/v1/src/dense_joint_trajectory_format.hpp:38`
- `rt-core/config/machines/simulation/*.json`
- `motion-server/v1/local-rt-core.sh:17-60`
