Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion configs/embodiments/franka.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
"control": {
"frequency_hz": 20.0,
"chunk_size": 50,
"rtc_execution_horizon": 0.5
"rtc_execution_horizon": 25
},
"constraints": {
"max_ee_velocity": 1.0,
Expand Down
2 changes: 1 addition & 1 deletion configs/embodiments/so100.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
"control": {
"frequency_hz": 15.0,
"chunk_size": 30,
"rtc_execution_horizon": 0.4
"rtc_execution_horizon": 12
},
"constraints": {
"max_ee_velocity": 0.5,
Expand Down
2 changes: 1 addition & 1 deletion configs/embodiments/ur5.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
"control": {
"frequency_hz": 20.0,
"chunk_size": 50,
"rtc_execution_horizon": 0.5
"rtc_execution_horizon": 25
},
"constraints": {
"max_ee_velocity": 1.0,
Expand Down
9 changes: 5 additions & 4 deletions docs/embodiment_schema.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Embodiment config schema (v1)

`tether serve --embodiment <name>` reads a per-robot config from `configs/embodiments/<name>.json`. Three presets ship out of the box: **franka**, **so100**, **ur5**. You can also point at a custom config with `--custom-embodiment-config <path>`.
`tether serve --embodiment <name>` loads a per-robot config by name. Four presets ship out of the box: **franka**, **so100**, **ur5**, **quadcopter**. The canonical preset files live inside the package at `src/tether/embodiments/presets/<name>.json`; the copies in `configs/embodiments/` are editable dev fallbacks (checked only if the in-package presets are missing). You can also point at a custom config with `--custom-embodiment-config <path>`.

The authoritative schema is at `src/tether/embodiments/schema.json` (JSON Schema draft-07). This doc is a human-readable mirror — if they drift, the JSON is canonical.

Expand Down Expand Up @@ -83,10 +83,11 @@ List of camera streams the model expects (1–8 cameras).
|---|---|---|---|
| `frequency_hz` | float | 0–1000 (exclusive 0) | Robot control loop rate. |
| `chunk_size` | int | 1–200 | Actions in a single inference chunk. |
| `rtc_execution_horizon` | float | 0–5.0 (exclusive 0) | Seconds of chunk to execute before requesting next inference. |
| `rtc_execution_horizon` | int | 1–`chunk_size` | Integer count of actions to lock during RTC replan. Legacy fractional values (0 < v < 1) auto-migrate to `round(v × chunk_size)` (minimum 1) at load with a one-time deprecation warning; schema v2 will reject them. |

**Cross-field rule (warning, not blocking):**
- `frequency_hz × rtc_execution_horizon ≥ 1` (else `rtc-horizon-too-short` warning — RTC degenerates if the horizon is shorter than one control step).
**Cross-field rules (warnings, not blocking):**
- `rtc_execution_horizon < 1` (else `rtc-horizon-too-short` warning — RTC degenerates below one action)
- `rtc_execution_horizon > chunk_size` (else `rtc-horizon-exceeds-chunk` warning — can't lock more actions than the chunk holds)

## `constraints`

Expand Down
12 changes: 9 additions & 3 deletions scripts/emit_embodiment_presets.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@
"control": {
"frequency_hz": 20.0,
"chunk_size": 50,
"rtc_execution_horizon": 0.5,
# Integer count of actions locked during replan (ADR 2026-04-25 #8 —
# the legacy fractional form auto-migrates with a deprecation warning).
"rtc_execution_horizon": 25,
},
"constraints": {
"max_ee_velocity": 1.0,
Expand Down Expand Up @@ -118,7 +120,9 @@
# TECHNICAL_PLAN line 1987. Customers with desktop GPU can override.
"frequency_hz": 15.0,
"chunk_size": 30,
"rtc_execution_horizon": 0.4,
# Integer count of actions locked during replan (ADR 2026-04-25 #8 —
# the legacy fractional form auto-migrates with a deprecation warning).
"rtc_execution_horizon": 12,
},
"constraints": {
"max_ee_velocity": 0.5,
Expand Down Expand Up @@ -165,7 +169,9 @@
# UR native is ~125 Hz; we run at 20 Hz to match our action chunk cadence
"frequency_hz": 20.0,
"chunk_size": 50,
"rtc_execution_horizon": 0.5,
# Integer count of actions locked during replan (ADR 2026-04-25 #8 —
# the legacy fractional form auto-migrates with a deprecation warning).
"rtc_execution_horizon": 25,
},
"constraints": {
# UR5 rated for 1.0 m/s; conservative cap at 1.2 with collision check on
Expand Down
18 changes: 13 additions & 5 deletions scripts/verify_embodiment_structure.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
# Sanity check for per-embodiment configs (B.1).
#
# Verifies:
# - 3 preset JSON files exist at configs/embodiments/{franka,so100,ur5}.json
# - the arm preset JSON files exist at configs/embodiments/{franka,so100,ur5}.json
# - each parses as valid JSON
# - the embodiments package imports + load_preset works for all 3
# - the embodiments package imports and every shipped package preset
# (whatever list_presets() returns — not a hard-coded list) loads + validates
#
# Run from repo root:
# bash scripts/verify_embodiment_structure.sh
Expand Down Expand Up @@ -41,9 +42,16 @@ from tether.embodiments import EmbodimentConfig, list_presets
from tether.embodiments.validate import validate_embodiment_config

presets = list_presets()
expected = ["franka", "so100", "ur5"]
if presets != expected:
print(f" ✗ list_presets() returned {presets}, expected {expected}")
# Two checks, not one: a required-minimum SUBSET (catches an accidentally
# dropped preset file — an equality check broke when quadcopter shipped,
# but no check at all lets packaging omissions pass silently) plus dynamic
# validation of everything else that ships. New presets validate
# automatically in the loop below; add them to REQUIRED when they should
# be omission-protected too.
REQUIRED = {"franka", "so100", "ur5", "quadcopter"}
missing = REQUIRED - set(presets)
if missing:
print(f" ✗ required package presets missing: {sorted(missing)}")
sys.exit(1)

for name in presets:
Expand Down
2 changes: 1 addition & 1 deletion src/tether/embodiments/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@
"type": "number",
"minimum": 0,
"maximum": 1000,
"description": "Integer count of actions to lock during RTC replan. Per ADR 2026-04-25-auto-calibration-architecture decision #8. Legacy fractional values (0 < value < 1) auto-migrate to int(value * chunk_size) at load time with a one-time deprecation warning. Schema v2 will reject fractional values."
"description": "Integer count of actions to lock during RTC replan. Per ADR 2026-04-25-auto-calibration-architecture decision #8. Legacy fractional values (0 < value < 1) auto-migrate to round(value * chunk_size), minimum 1, at load time with a one-time deprecation warning. Schema v2 will reject fractional values."
}
}
},
Expand Down
Loading