Set up a robot
Configure your robot
What arc setup writes to robot.toml, how settings sync with the console, which settings can be changed where, and the robot.toml keys.
A robot runs from one file, robot.toml. arc setup writes it from what it finds on the robot computer. On an enrolled robot the console keeps a copy of the file, and some settings can be changed there.
Do this after Enroll.
What setup finds and writes
Run setup in the directory that holds the robot's files, for example ~/robot:
arc setupFor MakerMods Metal arms, run arc setup --backend makermods. It writes ./robot.toml in five steps:
| Step | What it finds | What it asks | What it writes |
|---|---|---|---|
| Cameras | RealSense cameras by serial number, other USB cameras by device path. It saves one frame of each to setup-snapshots/. | Which camera is exo, wristL and wristR, or skip. | One [[cameras]] entry per role, with serial for a RealSense and index for a USB camera. |
| Arms | The CAN links that are up. | Which link is the left arm. With one link up: whether this is a single-arm robot, and which side. | [arms] backend, can_left and can_right. For Trossen arms it asks for the two IP addresses instead and writes left_address and right_address. |
| Relay | The enrolled identity. | Nothing on an enrolled robot. | host, cert and robot_id stay blank. They come from the identity. |
| Review | One confirmation. | ||
| Write | robot.toml. An existing file is kept as robot.toml.bak. |
Open the pictures in setup-snapshots/ to tell the wrist cameras apart. A role that no camera gets stays blank.
The arms step offers the arm type from the template. Enter keeps it. Type trossen there for Trossen arms. A side with no arm is written as "none".
The review step lists every value and where it came from. On an enrolled YAM robot with two CAN links, one RealSense camera and two USB cameras:
Values for ~/robot/robot.toml:
arms.backend = "yam" (template)
arms.can_right = "can0" (entered)
arms.can_left = "can1" (entered)
arms.gripper = "linear_4310" (template)
arms.gravity_comp = false (template)
arms.gripper_units = "joint_rad" (template)
relay.host = (blank, from the enrolled identity)
relay.port = 4433 (template)
relay.cert = (blank, from the enrolled identity)
relay.robot_id = (blank, from the enrolled identity)
relay.policy_port = 0 (template)
cameras.exo.serial = "123456789012" (entered)
cameras.wristL.index = 2 (entered)
cameras.wristR.index = 4 (entered)The source is template, probed (found on the machine), entered, or kept on a later run. Leave relay.port and arms.gripper_units as the template wrote them.
Setup does not open a CAN link, move an arm or connect to the relay. It cannot tell a swapped left and right arm, or swapped wrist cameras. Check that before the first run:
arc doctor --identify robot.tomlBlanks and running setup again
The file is written even when a value is still blank. Setup then names the blanks:
[arc] WARNING: 2 value(s) still blank in ~/robot/robot.toml: cameras.exo.serial, cameras.wristL.index. Fill them in (edit the file, or run arc setup again) or arc run will not start.Run arc setup again. It keeps the values that are set and asks only for the blanks. arc setup --force starts over from the template.
If your robot has fewer than three cameras, delete the [[cameras]] entry of each role you do not use. A role that is not in the file is off.
Without questions
For a scripted install, put the answers in a file. The keys have the same layout as robot.toml:
[arms]
can_right = "can0"
can_left = "can1"
[cameras.exo]
serial = "123456789012"
[cameras.wristL]
index = 2
[cameras.wristR]
index = 4arc setup --non-interactive --answers answers.tomlWith --non-interactive nothing is asked and the cameras are not searched for. A value with no answer stays blank.
How settings sync
This applies to a robot that uses its enrolled identity. A robot that was set up before enrollment, with cert filled in under [relay], does not sync.
- The robot always runs from
robot.toml. The console holds a copy. - Upload. Each time
arc runstarts, before it opens an arm or a camera, the robot compares its file with the console's copy and uploads the file if it changed.arc config syncuploads it at any time. - Change in the console. You edit settings on the robot's Robot settings page and push the change. The change waits there.
- Apply. The next time the robot starts, it writes the waiting change into
robot.tomland uploads the result. Nothing is applied while the robot is running.
The certificates and the private key are never uploaded. Comments and layout are not part of the copy, so a change to a comment does not count as a change to the file.
See the state
arc config status[arc] config: ~/robot/robot.toml
[arc] local hash: 9c3534ec...
[arc] baseline hash: 9c3534ec..., synced 2026-10-08T02:47:58.254604+00:00
[arc] pending change: none
[arc] state: in syncThe hashes are 64 characters long and are shortened here. The baseline is the console's copy. The state is one of:
| State | Meaning |
|---|---|
in sync | The file and the console's copy are the same, and no change is waiting. |
local changes not synced | The file changed since the last upload, or the robot has never uploaded. The next start uploads it, or run arc config sync. |
a change is waiting for the next start | A change was pushed from the console and the file is still the one it was made against. The next start applies it. |
out of sync: run arc config sync | A change is waiting, but the file was edited on the robot after the change was made. Nothing is applied until you sync and review. |
arc doctor shows the same state on its config sync line.
Upload now
arc config sync[arc] config sync: settings uploaded (9c3534ec...), synced 2026-10-08T02:47:58.254604+00:00Do this once after arc setup if you want the settings to show in the console before the first run.
Change a setting in the console
- On the Robots page, select the robot's name in the Robots table. The Robot settings page opens. If the robot has never uploaded, it says "No settings yet."
- The page lists the settings by section: Arms, Relay, one section per camera. Settings you can change are form fields. The others are shown with the note "set on the robot".
- Change what you need and select Review changes.
- The dialog lists each change with its current and new value. Select Push changes.
The page then shows Waiting for the robot's next start with the list of changes and a Discard button. The settings cannot be edited again until that change is applied or discarded.
Apply the change
The change is applied the next time arc run starts. To apply it without starting:
arc config pull[arc] config sync: applied 2 changes from the console to ~/robot/robot.toml (relay.record_fps = 20, relay.record_stream = true); the old file is kept as ~/robot/robot.toml.20261007-214820.bak- Only the lines of the changed settings change. A setting that was not in the file is added under its section. Comments and order stay.
- The old file is kept next to the new one as
robot.toml.<date>-<time>.bak. To go back, copy it overrobot.tomland runarc config sync. - If the robot cannot take the change, for example because the resulting file would not load, it changes nothing and reports why. The Robot settings page then shows The robot refused the last change with the reason.
- If the robot cannot reach Northstar within a few seconds, it starts from the file as it is and tries again at the next start.
arc run --local-config-only skips the whole check for one start.
When the file was edited on the robot
If someone edits robot.toml on the robot after a change was pushed and before it was applied, the two no longer fit. The robot applies nothing:
[arc] config sync: a change from the console is waiting, but ~/robot/robot.toml has changed since it was last synced. Nothing was applied. Run: arc config syncThe robot still starts, from its own file. To resolve it:
-
On the robot, upload the file as it is now:
arc config sync[arc] config sync: settings uploaded (38fd2f01...), synced 2026-10-08T02:48:21.543057+00:00 [arc] config sync: a change made in the console was waiting. It now needs review in the console (Robot settings): re-apply or discard it there -
On the Robot settings page, under Change needs review, the console shows each setting of the edit with two values: On the robot now and In the edit.
-
Tick the changes you still want and select Re-apply selected, or select Discard. A re-applied change waits for the next start like any other.
What can be changed where
| Setting | In the console | On the robot only |
|---|---|---|
Arm type (backend) | Yes | |
| CAN links or arm IP addresses | Yes | |
Mock arms (use_mock) | Yes | |
| Which cameras there are, and each one's serial number or device | Yes | |
The relay connection (host, cert, robot_id) | Set by arc enroll | |
Spool directories (record_spool_dir, depth_spool_dir) | Yes | |
| Gripper type (YAM) | Yes, with confirmation | |
| Gravity compensation | Yes, with confirmation | |
| Fault reset at start | Yes, with confirmation | |
| Release on exit | Yes, with confirmation | |
| Policy port | Yes, with confirmation when turned on | |
| Arm isolation and open timeout | Yes | |
| Link timeouts | Yes | |
| Recording stream: on or off, quality, frame rate, spool size, upload rate | Yes | |
| Depth: frame rate, size, spool size | Yes | |
| Per camera: isolation, restart, recording size | Yes | |
| Per RealSense camera: color format, depth on or off | Yes |
The settings marked "On the robot only" describe the machine: what is plugged in and where. The console shows their values so you can read them. To change one, edit robot.toml or run arc setup again.
A setting that can be changed in the console can also be edited in robot.toml. The next start uploads the edit.
Changes that ask for confirmation
Four settings change what the arms do the next time the robot starts: gripper type, gravity compensation, fault reset at start and release on exit. When a push includes one of them, the dialog adds a warning for it:
arms.release_on_exit: this changes what the arm does at its next start.Read what the setting does in the reference below before you confirm, and tell the people on site.
Two limits on gravity compensation:
- MakerMods Metal arms do not have it. It must stay off.
- On Trossen arms it cannot be turned on from the console. Set it in
robot.tomlon the robot.
Tighter limits in the console
The console accepts a narrower range than the file for a few numbers, so that a typing mistake cannot keep a robot from connecting:
| Setting | In the console | In robot.toml |
|---|---|---|
open_timeout_s | 15 to 600 | More than 0 |
idle_timeout_s | 5 to 60 | More than 0, up to 600 |
keepalive_s | 0.5 to 10 | 0 to 60 |
initial_rtt_s | 0.05 to 2 | More than 0, up to 5 |
robot.toml reference
These are the keys you would set. Keys that arc setup writes and that are not listed here should be left as they are.
A minimal file for an enrolled YAM robot:
schema_version = 1
[arms]
backend = "yam"
can_right = "can0"
can_left = "can1"
gripper = "linear_4310"
[relay]
host = ""
cert = ""
robot_id = ""
[[cameras]]
name = "exo"
serial = "123456789012"
[[cameras]]
name = "wristL"
index = 2
[[cameras]]
name = "wristR"
index = 4schema_version must be 1. Paths in the file are relative to the directory that holds the file.
An option on the arc run command line overrides the file for that run. See the CLI reference.
[arms]
| Key | Type | Default | Arms | Meaning |
|---|---|---|---|---|
backend | string | "yam" | all | "yam", "trossen" or "makermods". Must be the arm type the robot enrolled with. |
can_right | string | "can_right" | YAM, MakerMods | The CAN link of the right arm, as ip link shows it. "none" for no arm on that side. |
can_left | string | "can_left" | YAM, MakerMods | The CAN link of the left arm. |
right_address | string | "192.168.1.2" | Trossen | The IP address of the right arm, or "none". |
left_address | string | "192.168.1.3" | Trossen | The IP address of the left arm, or "none". |
gripper | string | "linear_4310" | YAM | The gripper on the arm: linear_4310, linear_3507, crank_4310, flexible_4310 or no_gripper. MakerMods Metal always uses metal_gripper. |
gravity_comp | bool | false | YAM, Trossen | true: the arms hold against gravity, are moved by hand, and ignore the operator's commands. For calibration work, not for sessions. Must be false for MakerMods Metal. |
startup_fault_reset | bool | false | YAM, MakerMods | Clear one latched communication-loss fault (0xD) per motor while the arms start. See below. |
release_on_exit | bool | true | YAM, MakerMods | On a clean stop, damp the arms until they settle, then switch the motors off. See below. |
isolation | string | "process" | YAM, MakerMods | "process" runs each arm's driver in its own process. "thread" runs both inside the main process. Leave it at "process". |
open_timeout_s | number | 60 | YAM, MakerMods | How long to wait for an arm to open before trying again. |
use_mock | bool | false | all | true: an arm that fails to open is replaced by a mock arm that never moves. For a bench with no arms only. |
With use_mock = true a robot with a real fault looks connected while its arms do not move. Leave it false on a robot with arms. With false, an arm that fails to open is tried again until it opens.
Fault reset at start. A YAM motor latches fault 0xD when it stops receiving commands for too long, for example when arc run is stopped while the arms stay powered. The next start then fails while enabling the arms. With startup_fault_reset = true that fault is cleared once per motor at start. Any other fault, or a second 0xD, still stops the start, and nothing is cleared while the arms are running. Turn it on when starts fail with 0xD after a restart and cycling the arm power each time is not practical. Otherwise leave it off, so that an unexpected fault is seen.
Release on exit. With release_on_exit = true, a clean stop such as Ctrl+C or systemctl stop damps the arm joints so that an extended arm sinks slowly, waits until the arm is still, then switches every motor off. The gripper keeps holding until the motors go off. After that the arms are limp and can be moved by hand, so fold or support them before you stop the robot. If an arm is still moving after 4.5 seconds, its motors are left on in damping mode and one line says so. With false, the motors keep holding their last position after the stop, until the arm power is cycled. After a crash or a kill nothing is released, with either value.
[relay]
On an enrolled robot host, cert and robot_id stay blank. They come from ~/.config/arc/identity/. Do not fill them in: with cert set, the robot stops using its enrollment and stops syncing.
| Key | Type | Default | Meaning |
|---|---|---|---|
record_stream | bool | false | While a recording runs, also keep a full quality copy of every camera frame on disk and send it to Northstar beside the live video. The live video is unchanged. Needs free disk space for the spool. |
record_quality | integer | 85 | JPEG quality of those frames, 1 to 100. |
record_fps | integer | 30 | The most frames per second kept per camera. |
record_spool_dir | path | ~/.cache/larp/record-spool | Where the frames wait to be sent. Emptied at every start. |
record_spool_max_mb | integer | 1024 | Limit on the size of that directory. Over it, the current recording stops being kept at full quality and is marked as cut short. |
record_upload_kbps | integer | 0 | Ceiling on the upload rate in kilobits per second. 0 is no ceiling. |
record_upload_adaptive | bool | true | The upload finds its own rate and backs off when live video or control need the link. With false, record_upload_kbps is a fixed rate. |
depth_fps | integer | 15 | Depth frames per second, for cameras with depth = true. The camera must offer that rate. |
depth_resolution | two integers | [640, 360] | Width and height of the depth frames. |
depth_spool_dir | path | ~/.cache/larp/depth-spool | Where depth frames wait to be sent. Kept across restarts until Northstar has them. |
depth_spool_max_mb | integer | 1024 | Limit on the size of that directory. |
idle_timeout_s | number | 15 | The link is treated as dead after this long with no traffic, and the robot reconnects. |
keepalive_s | number | 2 | How often an idle robot sends a keepalive. Must be below idle_timeout_s. |
initial_rtt_s | number | 0.3 | First estimate of the round trip time on a new connection. |
policy_port | integer | 0 | A port on the robot computer for a local policy program that drives the arms. 0 is off. See below. |
The link defaults are right for most networks. Change them only when Northstar asks.
Policy port. The port exists for running a policy program on the robot computer. arc setup writes policy_port = 0, which is off. Keep it off unless Northstar asks you to turn it on. It can only be turned on in robot.toml on the robot, not from the console.
[[cameras]]
One entry per camera. Each entry has a name and exactly one of serial or index.
| Key | Type | Default | Meaning |
|---|---|---|---|
name | string | required | "exo", "wristL" or "wristR". Each name at most once. |
serial | string | The serial number of a RealSense camera. | |
index | integer or path | A USB camera: the number of its /dev/video device, or a device path such as one under /dev/v4l/by-id/. A path stays the same when cameras are plugged in again. A number can change. | |
isolation | string | "process" | "process" runs the camera in its own process, so a stalled camera cannot hold up the arms. Leave it. |
restart | bool | true | Start a failed camera again by itself. |
restart_backoff_s | number | 5 | Wait before the first restart, in seconds, up to 60. Doubles per attempt, up to 60. |
color_format | string | "bgr8" | RealSense only: "bgr8" or "yuyv". "yuyv" uses less CPU. |
record_resolution | two integers | not set | A larger capture size for the recording stream, for example [1280, 720]. Used only with record_stream = true. The live video stays 640x360. |
depth | bool | false | RealSense only: record this camera's depth with every recording. Needs record_stream = true. |
record_resolution must be two even numbers in 16:9, no smaller than 640x360. The camera then runs at that size all the time. A camera that does not offer the size fails to open.
When a camera fails during a session, the arms hold, the operator is told which camera, and the camera restarts by itself. The operator resumes when the video is back.
Next
Run as a service to keep the robot online, or see the CLI reference.
NORTHSTAR