Configuration files (drive, machine, cell)
On this page
rt-core reads one compiled configuration. You write it as JSON in rt-core/config/, and rtctl compile turns it into an immutable directory named after its digest. This page lists every field of the machine, drive and cell layers. Robot descriptions have their own page: Robot description files.
Compile a shipped simulation machine and print its digest directory:
cd rt-core
make control
build/rtctl compile --config config/machines/simulation/simulation-program.json --out build/config
# /…/rt-core/build/config/<configuration_sha256>How the layers fit together is explained in Cells, machines and positioners.
Templates#
rt-core/config/templates/ holds one annotated template per layer: machine.json, drive.json, cell.json and robot.json. Every field has a <field>_doc sibling that states its unit, allowed values and default. The tables below are drawn from those templates and the compiler.
The templates are class definitions, not deployable configs. They show mutually exclusive branches side by side (flat axes and robot-bound axes, for example), and <required> marks a value the example cannot choose. To use one, pick a branch, remove the _doc siblings and fill the values.
Tests in rt-core/tools/rtctl and rt-core/config/cells check the templates against the compiler's readers and compile their simulation branches. None of them touches hardware.
Provenance siblings#
Numeric robot facts and safety exceptions must say where they came from. Add a <field>_source ("cited: …") or <field>_unverified ("unverified: …") string beside the field. Missing provenance is a compile error. Free-text reasons (for example collision_watchdog.reason) must be non-empty.
What compile writes#
rtctl compile --out DIR writes DIR/<configuration_sha256>/:
| File | Contents |
|---|---|
argv.json | The core's command line, from the compiled configuration. |
axes.conf | Per-axis native profiles. |
configuration.identity | The canonical text the configuration digest is computed over. |
configuration.base.identity | Only for a machine with an io block: the identity before cell I/O was bound. The final digest covers that base digest plus the io block and its terminal profile. |
machine.identity, deployment.identity | Canonical texts for the machine and deployment digests. |
coordinate.identity.json | Per-axis coordinate identities and their SHA-256. |
robot.json | The robot binding, when the machine pins a robot description. |
resources.json, resources/<sha256> | The robot description files (and cell calibration) as content-addressed resources. rt-control serves them through Describe and GET /v1/resources/<sha256>. |
rt-control loads this directory through --compiled-config or ROSIE_RT_COMPILED_CONFIG.
Three digests#
The compiler produces three SHA-256 digests. Describe reports all three.
| Digest | Covers | Changes when |
|---|---|---|
configuration_sha256 | The original machine JSON and the resolved drive configs (and, for a robot-bound machine, the pinned description) | Any byte of meaning in the machine or its drives changes. This is the pin in cell configs, rt-control --configuration-sha256 and every acquire binding. |
machine_sha256 | Axis list and order, names, slave positions, units, scaling, gearing, sign, wrap; drive PDO, SDO, DC, Home, absolute, brake and coordinate blocks; limits, tolerances, jog durations, motor cap; cycle and lateness timing; bus bring-up policies | Anything that changes motion or drive behaviour. |
deployment_sha256 | Runtime CPU and priority, host, NIC, sockets, pair id, service users, backend and other non-motion metadata | Only where and how the core runs. |
Canonical identity text uses sorted keys, one key=value per line, %.17g doubles and decimal integers.
Machine config#
A machine config binds drives, and optionally a robot description, to bus positions, timing, limits, I/O and host policy. The shipped ones are in config/machines/, config/machines/bench/ and config/machines/simulation/.
A machine uses one of two axis forms:
- Flat axes declare their own scaling and limits. Simulation fixtures and bare-motor benches use them.
- Robot-bound axes name a
robot_jointin a pinned robot description. They inherit travel, velocity, acceleration, gearing and Home policy from the description, and must not redeclare them.
{
"schema_version": 1,
"backend": "simulation",
"cycle_ns": 1000000,
"robot": {
"robot_description": {
"path": "robot_description/robots/rosie_1400_v3",
"sha256": "sha256:<identity>",
"source": "cited: …"
}
},
"axes": [
{ "robot_joint": "J1", "slave_position": 0,
"limits": { "max_target_lead": 0.02, "following_error": 0.04, "following_error_timeout_ms": 100,
"completion_tolerance": 0.0002, "completion_timeout_ms": 500 } }
],
"max_cycle_lateness_ns": 20000000,
"runtime": { "cpu": 2, "priority": 90 }
}Note
On the simulated bus, simulation-rosie1400.json takes the real drive profile from the Rosie 1400 definition, and Home is refused on it, so nothing arms or jogs. For a simulated cell that homes, use the dev-stack machine described in Run everything in simulation.
Top level#
| Field | Type | Unit | Allowed | Default |
|---|---|---|---|---|
schema_version | integer | — | 1 | Required |
backend | string | — | simulation (synthetic drives) or live (hardware) | Live admission. rtctl run --backend live, control-env and inventory require live. |
cycle_ns | integer | ns | 250000 to 10000000, divisible by every nonzero drive DC quantum | Required. Shipped machines use 1000000 (1 kHz). |
max_cycle_lateness_ns | integer | ns | 1 to 249999999 | Required |
axes | array | — | 1 to 16 ordered axes | Required |
drive_speed_limit_motor_rpm | number | motor rpm | > 0; at most 6000 on the supported servo motor frame | 3000 for flat fixtures. Forbidden on robot-bound machines: their cap derives from the URDF velocity. |
max_motor_rpm | number | legacy wire rpm | > 0; exclusive with drive_speed_limit_motor_rpm | Omitted. Deprecated: compile warns. |
runtime | object | — | See runtime | Required |
robot | object | — | See robot | Absent for flat axes |
control | object | — | See control | lan profile |
bus | object | — | See bus | Unknown slaves refused |
bus_bringup | object | — | See bus_bringup | Defaults below |
io | object | — | See io | Absent |
axes[], flat form#
| Field | Type | Unit | Allowed | Default |
|---|---|---|---|---|
name | token | — | ASCII letters, digits, _; unique | Required |
slave_position | integer | EtherCAT position | 0 to 65535, unique across axes, I/O and unused slaves | Required |
profile | string | — | A drive config basename in config/drives/, without .json | Required |
type | string | — | rotary or linear | Required |
wire_counts_per_rev | integer | counts per wire revolution | 1 to 2147483647 | Required |
motor_encoder_counts_per_rev | integer | counts per motor revolution | 1 to 2147483647 | Required |
wire_revs_per_axis_rev | number | wire revolutions per axis revolution | > 0; single_turn_absolute requires 1 | Required |
gear_ratio.numerator, .denominator | integer | ratio | 1 to 2147483647 each | 1 for flat simulation |
lead_m_per_rev | number | m per revolution | > 0 for linear axes | 0 for rotary |
sign | integer | — | −1 or +1 | Required |
coordinate_evidence_mode | string | — | multi_turn or single_turn_absolute | Required on flat axes. A generic simulation drive uses multi_turn. |
position_tracking_mode | string | — | Identity token | continuous in simulation; required otherwise |
require_home | boolean | — | true requires the drive's native_home | Required on flat axes |
max_acceleration | number | rad/s² or m/s² | > 0 | Flat fixtures only |
limits | object | — | See limits | Required |
startup | object | — | Per-axis drive startup overrides, constrained by the drive's startup_schema | Drive startup_defaults |
jog, brake, collision_watchdog, diagnostics | object | — | See below | Omitted |
axes[], robot-bound form#
| Field | Type | Description |
|---|---|---|
robot_joint | token | Exactly one joint name from the pinned robot definition. No joint twice. |
slave_position | integer | EtherCAT position, as above. |
limits | object | Only the tracking fields: max_target_lead, following_error, following_error_timeout_ms, completion_tolerance, completion_timeout_ms. |
startup, jog, brake, collision_watchdog, diagnostics | object | As for flat axes. |
A robot-bound axis must omit limits.min, limits.max, limits.max_velocity, limits.jog_acceleration, max_acceleration and coordinate_evidence_mode. It inherits them:
- travel and maximum velocity from
robot.urdf - trajectory and jog acceleration from
config.json→planning.joints.<joint>.acceleration_rad_s2(required) - the per-axis drive speed cap, derived from the URDF velocity through the definition's gearing and encoder scale
- Home policy and coordinate evidence mode from the definition
Every joint in the definition needs an axis, unless you list it in robot.absent_joints.
limits#
| Field | Type | Unit | Allowed | Default |
|---|---|---|---|---|
min, max | number | rad (rotary) or m (linear) | Finite, min < max | Required on flat axes; inherited on robot-bound axes |
max_velocity | number | rad/s or m/s | > 0 | Flat fixtures only |
jog_acceleration | number | rad/s² or m/s² | > 0 | Flat fixtures only |
max_target_lead | number | rad or m | > 0 | Required |
following_error | number | rad or m | > 0 | Required |
following_error_timeout_ms | integer | ms | 1 to 1000 | Required |
completion_tolerance | number | rad or m | > 0 | Required |
completion_timeout_ms | integer | ms | 1 to 4294967295 | Required |
jog#
The ramp when jog input stops. Also settable per drive; the axis value wins.
| Field | Type | Unit | Allowed | Default |
|---|---|---|---|---|
arrest_ns | integer | ns | 1 to 65535 × cycle_ns | 200000000 (200 ms) |
quick_stop_ns | integer | ns | 1 to 65535 × cycle_ns | 300000000 (300 ms) |
brake and brake_override#
Brake fields are taken from the drive config first, then overridden per axis.
| Field | Type | Unit | Allowed | Default |
|---|---|---|---|---|
brake.present | boolean | — | false cannot keep gravity_axis or released_signal | false |
brake.gravity_axis | boolean | — | true only with present | false |
brake.release_delay_ms | integer | ms | 0 to 4294967295 | 100 |
brake.hold_delay_ms | integer | ms | 0 to 4294967295 | 100 |
brake.hold_displacement_tolerance_counts | integer | counts | 0 to 2147483647 | 1 |
brake.released_signal.semantic | string | — | An existing TX PDO semantic containing the bit | Required with released_signal |
brake.released_signal.bit | integer | bit | 0 to 31 for mapped brake feedback | Required with released_signal |
brake_override.present | boolean | — | false only | Required with brake_override |
brake_override.reason | string | — | Non-empty, with a validated bench hold policy | Required with brake_override |
brake_override exists for benches whose brake wiring is not yet verified. It disables brake handling on that axis and must say why.
collision_watchdog#
Faults the axis when torque or following error stays above a bound. It detects an impact after it happens; it does not avoid one. Also settable per drive.
| Field | Type | Unit | Allowed | Default |
|---|---|---|---|---|
torque_abs_max_raw | integer | raw drive torque units | 1 to 1000 | Required when enabled |
following_error_counts_max | integer | counts | 1 to 2147483647 | Required when enabled |
sustained_cycles | integer | cycles | 2 to 1000 | Required when enabled |
disabled | boolean | — | true needs a reason and no thresholds; false needs thresholds and a torque PDO | false |
reason | string | — | Non-empty | Required when disabled |
Both branches need _source and _unverified siblings. An axis with no watchdog at all compiles with a warning: axis <name>: collision_watchdog missing; disabled.
diagnostics#
| Field | Type | Allowed | Default |
|---|---|---|---|
external_enable_input.bit_index | integer | 0 to the mapped digital-input width minus 1, at most 31 | Required with the block |
external_enable_input.polarity | string | active_high or active_low | Required with the block |
This lets rt-core report the state of an external enable, such as an auxiliary contact on the cell's stop chain. It is a diagnostic only. It never gates motion and is not a safety function. See the safety model.
runtime#
| Field | Type | Unit | Allowed | Default |
|---|---|---|---|---|
cpu | integer | logical CPU | 0 to 1023 | Required |
priority | integer | SCHED_FIFO priority | 1 to 99 | Required |
telemetry.retention_ms | integer | ms | 100 to 3600000, within a 2 GiB ring ceiling | 100000 |
telemetry.dump_count | integer | files | 1 to 100 | 20 |
telemetry.dump_bytes | integer | bytes | 529680 or more | 536870912 |
telemetry.directory | string | absolute path | Non-root, no NUL | The runtime chooses |
The core writes telemetry dumps (a .bin file and its .json index) to telemetry.directory. Convert one with rtctl telemetry dump-to-jsonl.
robot#
| Field | Type | Description |
|---|---|---|
robot_description.path | path | Repository-relative robot_description/robots/<model_id>. The manifest must register rtcore_definition.json. |
robot_description.sha256 | sha256:<64 hex> | The description identity, as go run ./cmd/identity prints it. Compile refuses a mismatch with robot_description_mismatch. |
robot_description.source | string | Provenance. |
absent_joints | string[] | Definition joints this machine has no axis for. Default empty. |
bench_measurement_profile | string | Restricted to one bare-motor bench measurement profile. Omit otherwise. |
machine_planning_calibration.path | path | Component-relative config/... path to this machine's machine_planning_calibration.json. Every joint it corrects must exist and its frames must name known links. |
machine_planning_calibration.sha256 | 64 hex | SHA-256 of the file's exact bytes. |
machine_planning_calibration.source | string | Provenance: who measured it, how and when. |
Omit machine_planning_calibration and the cell serves the empty calibration document for its model.
control#
The per-cell lease and jog-age ceilings. See Control authority.
| Field | Type | Unit | Allowed | Default |
|---|---|---|---|---|
link_profile | string | — | lan or internet | lan |
max_grant_lease_ns | integer | ns | 1000000 to 10000000000, whole milliseconds | 500000000 on lan, 3000000000 on internet |
max_jog_input_age_ns | integer | ns | 1 to 2000000000 | 250000000 on lan, 750000000 on internet |
Warning
A longer lease or jog age delays the unattended stop after a client or link failure by the same amount. Keep the lan defaults unless you have measured a reason not to. The internet values are marked unverified in the code.
bus#
| Field | Type | Allowed | Default |
|---|---|---|---|
unknown_slaves | string | refuse, or hold (needs unknown_slaves_note) | refuse |
unknown_slaves_note | string | Why extra slaves may stay on the bus | — |
hold_on_robot_acknowledged | boolean | true plus hold_on_robot_note for a robot machine using hold | false |
unused_slaves[] | array | 0 to 256 entries: slave_position, vendor_id, product_code, revision, note | Empty |
hold leaves unknown slaves in PREOP without outputs. It is meant for test benches; an assembled robot cell must use refuse.
bus_bringup#
| Field | Type | Unit | Default |
|---|---|---|---|
startup_passive_ms | integer | ms | 0 |
explicit_pdo_config | boolean | — | false. true is incompatible with fixed drive PDO presets. |
disable_output_watchdog | boolean | — | false. Use true only with a declared machine failure policy. |
no_dc | boolean | — | false. true disables distributed-clock setup. |
wait_before_safeop_ms | integer | ms | 250 |
preop_safeop_timeout_ms | integer | ms | 5000 |
safeop_op_timeout_ms | integer | ms | 5000 |
io#
Cell I/O through a digital I/O terminal. See Process I/O and sensing.
| Field | Type | Unit | Allowed | Default |
|---|---|---|---|---|
profile | string | — | A terminal drive config in config/drives/ | Required |
slave_position | integer | EtherCAT position | 0 to 65535, unique | Required |
torch_qualified | boolean | — | false only | Required |
inputs[] | array | — | 0 to 8 unique bits | Required |
inputs[].name | token | — | Unique | Required |
inputs[].bit | integer | bit | 0 to 7 | Required |
inputs[].polarity | string | — | active_high or active_low | Required |
inputs[].class | string | — | fast or supervisory | Required |
outputs[] | array | — | 0 to 8 unique bits | Required |
outputs[].name, .bit | token, integer | —, bit | As for inputs | Required |
outputs[].safe_state | boolean | — | false (OFF) only | Required |
outputs[].expiry_ns | integer | ns | 1 to 1000000000 | Required |
outputs[].class | string | — | process or torch. Torch outputs are always refused at runtime. | Required |
outputs[].readback_bit | integer | bit | 0 to 7, unique per output | Required |
outputs[].readback_polarity | string | — | active_high or active_low | Required |
config/cell-io/simulation.json is a complete simulation machine with an io block, not a terminal descriptor.
Drive config#
A drive config describes one drive or I/O terminal model: its EtherCAT identity, PDO layout, scaling semantics, startup parameters, Home transaction and protective defaults. A machine axis selects one with profile; a robot definition with drive_profile. Names resolve only in config/drives/. The template is config/templates/drive.json.
| Field | Type | Description |
|---|---|---|
schema_version | integer | 1. |
id, label | string | Metadata only. profile selects the file, not id. |
simulation_only | boolean | true requires backend: simulation. Default false. |
ethercat.vendor_id, .product_code, .revision_no | integer | Expected slave identity. |
ethercat.rx_pdo, .tx_pdo, .rx_sync, .tx_sync | integer | PDO assignment object indices and sync managers. |
ethercat.dc_quantum_ns | integer | ns. A nonzero quantum must divide cycle_ns. |
ethercat.dc_assign_activate | integer | DC activation bit mask. |
ethercat.rx_layout[], .tx_layout[] | array | Mapped PDO entries: semantic, index, subindex, bits. At most 32 entries in total. RX must map cw, target_pos and mode; TX must map sw, pos and mode_disp. |
ethercat.restore_assignment_on_exit | boolean | Default false. |
home_truth_sign | −1 | +1 | Direction of the drive's Home reference. |
native_home | object | The Home transaction: steady_state_mode and commissioning_mode (CiA402 mode numbers), truth_source, and an ordered transaction[] of set_mode, restore_mode, write_sdo, wait_sdo, write_sdo_wrap_fraction, controlword_sequence, wait_statusword, refresh_truth and release_service_override steps. |
feedback_counts_wrap, command_counts_wrap | boolean | Whether position feedback and commands wrap. Linear axes require false. |
startup_schema, startup_defaults | object | Which startup parameters the drive accepts, their types and ranges, and the default written at startup. A machine axis overrides them under startup. |
absolute_feedback[], absolute_pair_field | array, string | Absolute encoder readbacks used for coordinate evidence. |
coordinate_evidence | object | Policy for accepting absolute position evidence. |
position_semantics.drive_native_ratio_enabled | boolean | true when the drive scales to the output shaft; false when software scales from the motor shaft. |
jog, brake, collision_watchdog | object | Defaults for the axis blocks above. |
max_acceleration | number | Synthetic fixtures only. Never applies to a robot-bound axis. |
The PDO semantics RX accepts are cw, target_pos, target_vel, target_torque, mode, tp_func and max_profile_vel. TX semantics include sw, pos, mode_disp, err, manufacturer_err, velocity_actual, following_error, torque, di and the drive's extended diagnostics.
Note
The shipped drive configs carry values measured on specific drive firmware. Treat them as the source of those values, and do not copy them into other documents.
Cell config#
A cell config binds one deployed cell to a machine config and its compiled digest. The template is config/templates/cell.json.
{
"name": "simulation-cell",
"nodes": [
{
"runtime": "rt-core",
"rt_core": {
"machine_config": "rt-core/config/machines/simulation/simulation.json",
"configuration_sha256": "<64 hex from rtctl compile>",
"pair_id": "simulation-cell",
"pair_revision": 1,
"remote_listen": "127.0.0.1:8443"
}
}
]
}| Field | Type | Allowed | Default |
|---|---|---|---|
name | string | Display text. Ignored by the validator. | Omitted |
nodes[] | array | Ordered nodes | Required |
nodes[].runtime | string | rt-core for a native node | — |
nodes[].rt_core.machine_config | path | Repository-relative path to an existing machine config, with no traversal or escaping symlink | Required |
nodes[].rt_core.configuration_sha256 | 64 lowercase hex | The exact rtctl compile digest | Optional to the reader. Pin it on every deployed cell. |
nodes[].rt_core.pair_id | token | Letters, digits, _, ., - | Required |
nodes[].rt_core.pair_revision | integer | Positive uint64 | Required |
nodes[].rt_core.remote_listen | host:port | IP or DNS host, port 1 to 65535 | Required |
The validator in Go package rosieos/rt-core/config/cells recompiles every node's machine config and refuses a mismatched digest, axis count, pair or listener:
cd rt-core
go test -count=1 ./config/cells -run TestRepositoryCompatibilityCell configs in config/cells/ also carry deployment fields for the deploy tooling. Those fields select and pin a configuration but never enter its digest.
Compile warnings#
Warnings go to stderr, prefixed warning:. The compile still succeeds.
| Warning | Meaning |
|---|---|
axis <name>: collision_watchdog missing; disabled | The axis has no collision watchdog. |
max_motor_rpm is accepted for one release … | Migrate to drive_speed_limit_motor_rpm (motor rpm). |
legacy flat axes are accepted for one release … | Migrate to a robot definition and robot_joint axes. |
axis <name> motor speed cap <n> rpm exceeds … rated 3000 rpm … | The axis speed cap is above the servo motor's rated speed but within its 6000 rpm maximum. Above the maximum, compile refuses. |
Robot compile refusals#
When a machine pins a robot description, compile refuses with <reason>: <detail>:
| Reason | Cause |
|---|---|
robot_description_unavailable | The description directory or its files cannot be read. |
robot_description_mismatch | The pinned identity differs from the files, the definition's robot_id differs from the directory, or the directory has a robot.urdf its manifest does not register. The detail gives both hashes. |
robot_definition_unavailable | The manifest does not register rtcore_definition.json. |
robot_definition_field | An unexpected field, or a restricted field used where it is not allowed. |
robot_duplicate_field | A JSON key appears twice. |
robot_reference_path | A path escapes the repository root or is not a valid relative path. |
robot_hash_invalid | A pinned hash is not lowercase SHA-256. |
robot_hash_mismatch | A pinned file hashes to something else. |
robot_joint_mapping | An axis names an unknown, duplicate or absent robot_joint. |
robot_joint_missing | A definition joint has no axis. Declare it in robot.absent_joints. |
robot_urdf_limits_required | An axis or definition tries to redeclare a limit, velocity or gearing it must inherit. |
robot_limit_widened | A requested value exceeds the model's bound. |
robot_acceleration_required | config.json has no planning.joints.<joint>.acceleration_rad_s2 for a mapped axis. |
robot_bench_inheritance | A bench machine redeclares a field it must inherit from the robot definition. |
machine_planning_calibration_invalid | The pinned calibration fails its rules, or the description has no geometry to calibrate. |
Other compile errors print a plain message and exit 1. Nothing is written until the whole configuration is valid.