Advanced Metal Research
GitHub Contact AMR

rtctl command reference

On this page
  1. Commands at a glance
  2. Exit codes
  3. Where rtctl finds rt-core
  4. Configuration commands
  5. compile
  6. validate
  7. run
  8. control-env
  9. Host commands
  10. hostcheck
  11. inventory
  12. recover-encoder
  13. Control commands
  14. Common flags
  15. Observation
  16. resources fetch
  17. Authority and machine control
  18. Trajectories and programs
  19. Telemetry
  20. telemetry dump-to-jsonl
  21. Related pages

rtctl is the operator CLI for rt-core. It compiles and validates machine configurations, launches the core, checks a cell host, and sends single requests to rt-control for inspection and administration.

cd rt-core
make control                                   # builds build/rtctl
build/rtctl describe --socket /run/rosie-rt-core/control.sock
build/rtctl status --json | head -c 400; echo

Note

rtctl is not a motion client. Each control command sends one request and exits. rtctl never renews the lease, and on the lan profile a lease lasts at most 500 ms, so it has lapsed before your next command runs and the core inhibits outputs. There is no jog or renew command. Use rtctl to observe, fetch resources, stop and recover. For anything that moves the robot, use the Go SDK or the C++ client, which renew in the background.

rtctl builds and runs on Linux only. There is no rosie command in this repository; READMEs that mention rosie … or ./rosie.sh … refer to an internal tool.

Commands at a glance#

GroupCommands
Configurationcompile, validate, run, control-env
Hosthostcheck, inventory, recover-encoder
Control APIdescribe, status, events, resources fetch, acquire, release, stop, halt, enable, arm, home, reset-fault, prepare, start, discard, program-prepare, program-start
Telemetrytelemetry dump-to-jsonl

Every command rejects positional arguments it does not expect.

Exit codes#

CodeConfiguration commandshostcheckinventoryControl commands
0SuccessEvery check passedEvery read matchedSuccess
1Compile or file error—Compile or file error—
2Usage errorA check failed, or usage errorA slave mismatched, the machine is not live, or usage errorRejected by rt-control, invalid options, or usage error
3—Required evidence was unreadable, or the rt-core root was not foundA slave or the I/O terminal was unreadableTransport, protocol or closed-connection failure

validate returns the daemon's own exit status.

Where rtctl finds rt-core#

Configuration and host commands need the rt-core root, the directory that holds config/drives/. rtctl looks beside its own executable first (<root>/build/rtctl or <root>/bin/rtctl), then walks up from the working directory to a directory containing both config/drives/ and go.mod. If neither works it prints cannot locate rt-core root and exits 1 (3 for hostcheck).

Configuration commands#

compile#

Validates a machine config and writes the compiled configuration. It never contacts drives.

build/rtctl compile --config config/machines/simulation/simulation-program.json --out build/config
# /…/build/config/<configuration_sha256>
FlagTypeDefaultDescription
--configpath—Machine config JSON. Required.
--profilesdir<root>/config/drivesDrive config directory.
--outdir—Output directory. Required. The compiled directory is <out>/<configuration_sha256>/.

It prints the compiled directory on stdout and any warning: lines on stderr. The files it writes and the three digests are described in Configuration files.

validate#

Compiles, then runs the daemon with --validate-config, so the daemon checks its own private format without starting a runtime session.

build/rtctl validate --backend simulation --config config/machines/simulation/simulation-program.json
# daemon exit status: 0
FlagTypeDefaultDescription
--configpath—Machine config JSON. Required.
--backendsimulation | ipc-only | live—Required. Selects the daemon binary.
--binarypath<root>/build/rosie-rt-core-sim, -ipc, or rosie-rt-coreDaemon executable to run.
--profilesdir<root>/config/drivesDrive config directory.
--outdir<root>/build/configWhere the compiled configuration is written.

run#

Compiles, then replaces itself (exec) with the selected daemon and the compiled argument list. This is how you start the core by hand in simulation.

build/rtctl run --backend simulation \
  --config config/machines/simulation/simulation-program.json \
  --out "$TMPDIR/config" --socket "$TMPDIR/ipc.sock"
FlagTypeDefaultDescription
--configpath—Machine config JSON. Required.
--backendsimulation | ipc-only | live—Required. Runs <root>/build/rosie-rt-core-sim, -ipc or rosie-rt-core.
--outdir<root>/build/configCompiled output directory.
--socketpath/run/rosie-rt-core/ipc.sockThe core's private IPC socket, passed as --socket-path. Must not be empty.

Two guards keep simulation away from hardware:

  • --backend live requires the machine config itself to say "backend": "live".
  • In an installed package (where <root>/bin/rtctl exists), run accepts only --backend live and runs <root>/bin/rosie-rt-core. It never resolves a simulation request to the hardware binary.

On WSL, keep sockets on a Linux tmpfs such as /dev/shm; they cannot bind on /mnt/c.

control-env#

Compiles a live machine config for installed systemd units and prints the environment file they read. host/generate-control-env.sh calls it during host installation.

rtctl control-env --config machine.json --pair-id cell-a --pair-revision 1 \
  --out /tmp/staging --installed-out /etc/rosie-rt-core/compiled
FlagTypeDefaultDescription
--configpath—Live machine config. Required. Must have "backend": "live".
--pair-idtoken—Deployment pair id: letters, digits, _, ., :, -.
--pair-revisionuint64—Positive decimal, no leading zeros.
--outdir—Private staging directory for the compiled output. Required.
--installed-outdir—Where the compiled directory will live once installed. Required; used in the paths it prints.

It prints these variables on stdout:

ROSIE_RT_PAIR_ID=cell-a
ROSIE_RT_PAIR_REVISION=1
ROSIE_RT_CONFIGURATION_SHA256=<64 hex>
ROSIE_RT_CORE_ARGS="<compiled argv>"
ROSIE_RT_COMPILED_CONFIG=/etc/rosie-rt-core/compiled/<64 hex>

It refuses an argument list containing characters that would be unsafe unquoted in an environment file.

Host commands#

hostcheck#

Read-only inspection of a cell host's real-time prerequisites. It never measures cycle latency, so passing it does not qualify timing: it always reports timing_qualification as not_applicable.

sudo rtctl hostcheck --config /etc/rosie-rt-core/machine.json
# pass rt_cpu: observed="2" expected="configured nonnegative runtime.cpu (or deployed --rt-cpu)"
# …
FlagTypeDefaultDescription
--configpath—Machine config to read runtime.cpu from. Without it, hostcheck reads --rt-cpu from ROSIE_RT_CORE_ARGS in /etc/rosie-rt-core/control.env.
--jsonboolfalsePrint a rosie-rt-core.hostcheck.v1 JSON report instead of lines.
--expected-releasepath—A rosie-rt-core.host-identity.v1 manifest. Also compares the installed services and loaded executables against it, read-only.

It checks, among others: the RT CPU; kernel version and build; PREEMPT_RT (/sys/kernel/realtime or PREEMPT_RT in uname -v); the loaded IgH ec_master version (1.6.9); /dev/EtherCAT0 permissions for the device group; the RT CPU in isolated and nohz_full; the CPU frequency governor (performance); EtherCAT NIC IRQ affinity; clock source, timer slack and resolution; service users, groups and directories.

Each line is <status> <id>: observed="…" expected="…", with status pass, fail or not_applicable.

VariableDefaultDescription
ROSIE_RT_ETHERCAT_GROUPethercatGroup expected on /dev/EtherCAT0.
ROSIE_RT_HOSTCHECK_ROOT/Alternate filesystem root. Used by tests.

The --expected-release manifest has schema and a services map for exactly rosie-rt-core, rosie-rt-control and rosie-rt-natspublisher. Each entry gives template_sha256, unit_files[] (path, sha256), argv, executable_sha256, environment_files and environment. No tool in the repository generates it; the cell owner supplies it.

inventory#

Compiles a live machine config, then reads the EtherCAT bus and compares each slave with what the configuration expects. It only issues read commands (ethercat slaves and SDO upload).

sudo rtctl inventory --config /etc/rosie-rt-core/machine.json
FlagTypeDefaultDescription
--configpath—Live machine config. Required.
--profilesdir<root>/config/drivesDrive config directory.
--ethercatpathethercatThe IgH ethercat tool to run.
--jsonboolfalsePrint the inventory JSON document.

Each axis reports match, mismatch or unreadable. A configured I/O terminal is reported too.

recover-encoder#

A maintenance procedure that clears an absolute-encoder alarm on a supported servo drive. It talks to the drive with the ethercat tool while the EtherCAT master is idle.

sudo systemctl stop rosie-rt-control rosie-rt-core
sudo rtctl recover-encoder --backend ethercat --slave 3
FlagTypeDefaultDescription
--slaveinteger—Absolute slave position on master 0, 0 to 65535. Required.
--backendethercat—Required.

It refuses to write unless master 0 is idle (stop the daemon first), the slave is identified as a supported drive, is in PREOP and is disabled, and shows the specific encoder alarm it can clear. It refuses on any unexpected alarm between steps. It never starts the daemon or Home.

Danger

An encoder reset invalidates the axis's saved Home anchor. Home the axis again before you enable it, and do not restore an old anchor.

Control commands#

These send one request to rt-control through the Go SDK and print the result as indented JSON (compact with --json). describe and status print the description or status document itself; the other commands print the response envelope (schema, operation, sequence, handle, data, error).

Common flags#

FlagTypeDefaultDescription
--socketpath/run/rosie-rt-core/control.sockLocal control socket.
--remoteURL—Mutual-TLS HTTPS origin, for example https://rosie.local:8443. Exclusive with --socket.
--ca, --cert, --keypath—Server CA, client certificate and client key PEM files. Only with --remote. See Remote access.
--sessionstring—Session token from acquire.
--generationuint640Control generation from acquire.
--timeoutduration10sDeadline for the HTTP operation. Must be positive.
--request-idstringgeneratedReuse only to retry an identical request. See idempotent retries.
--jsonboolfalseCompact JSON output.

Observation#

CommandFlagsSends
describe—describe
status—status
events--after N (default 0), --followsubscribe_events. With --follow, streams one JSON event per line until Ctrl-C, then exits 0. --timeout does not apply to the stream.
build/rtctl events --after 0 --follow --socket "$TMPDIR/control.sock"

resources fetch#

Downloads the cell's robot description files, verified by digest.

sha=$(build/rtctl describe --json | jq -r '.robot.resources[0].sha256')
build/rtctl resources fetch "$sha" --out ./cell-model
# ./cell-model/resources.json
Argument or flagDescription
<definition-sha256>A 64-hex, lowercase digest that is a member of the cell's current resource set, as listed by Describe.
--out DIROutput directory. Required.

It writes every resource as DIR/<sha256> and then the manifest DIR/resources.json, last, so an incomplete set never looks complete. It never overwrites an existing file. A digest the cell does not list is refused with resource_unknown.

Authority and machine control#

CommandFlagsSends
acquire--pair-id, --pair-revision, --configuration-sha256, --controller (default rtctl)acquire. Prints the response envelope; its data is the grant, whose session and generation are the fence. rtctl does not set a requested lease, so the cell's ceiling applies.
releasefencerelease
stopfencestop. A known session still stops after its lease expired.
haltfencehalt
enablefence, --axis-maskenable
armfencearm
homefence, --axis-maskhome
reset-faultfencereset_fault (interim capability)

"Fence" means --session and --generation. The axis mask is a bit per axis, 0 to 0xffffffff.

# Take authority, then stop and give it back. Each call is one request.
build/rtctl acquire --pair-id readme --pair-revision 1 --configuration-sha256 "$digest"
build/rtctl stop    --session "$session" --generation "$generation"
build/rtctl release --session "$session" --generation "$generation"

Because rtctl does not renew, commands after acquire that need a live lease are usually refused with an authority reason once the lease lapses. See authority reasons.

Trajectories and programs#

Warning

Energised motion. This moves the robot. RosieOS has no software E-stop: keep the hardware E-stop within reach and clear the cell before you arm. Jog, moves and Home are checked against joint limits only, not against collisions. See the safety model.

CommandFlagsSends
preparefence, --axis-mask, --file points.jsonprepare_trajectory. The file is a JSON array of Point: time_ns, position (rad or m), optional velocity.
startfence, --handlestart_trajectory
discardfence, --handlediscard_trajectory
program-preparefence, --file program.rdtPOST /v1/program with the binary .rdt. See Dense trajectory format.
program-startfence, --file identity.jsonstart_program. The file is an Identity object.

rtctl commands bypass the weld planner's verifier: the core admits them against joint limits, velocity and continuity only. And because the lease lapses between commands, a prepared trajectory or program usually cannot be started from a second rtctl call. Drive motion from an SDK client instead.

Telemetry#

telemetry dump-to-jsonl#

Converts a raw telemetry dump written by the core (runtime.telemetry.directory) into JSON Lines, one record per cycle.

build/rtctl telemetry dump-to-jsonl /dev/shm/rt-core/telemetry/<dump>.bin > cycles.jsonl

Each line has the cycle time t_ns, seq, cycle, work_ns, cycle-level state (armed, grant and jog generations, safety_fault_mask, execution_fault_reasons, I/O words) and an ax array per axis (position p and target tp in counts, statusword sw, error codes, velocity and following error in counts, readiness and diagnostic fields). Values are in drive counts and ns, not rad. Keep the .bin file with its .json index.

Usage: rtctl telemetry dump-to-jsonl <file>. Exit 2 on wrong arguments.