Skip to content

Per-robot embodiments

reflex serve --embodiment <name> reads a per-robot config from configs/embodiments/<name>.json. Three presets ship: franka, so100, ur5. Bring your own with --custom-embodiment-config <path>.

Terminal window
reflex serve ./my-export/ --embodiment franka

When --embodiment is unset, reflex serve returns raw, unscaled actions. Fine for a smoke test; never for production hardware.

{
"schema_version": 1,
"embodiment": "franka",
"action_space": { ... },
"normalization": { ... },
"gripper": { ... },
"cameras": [ ... ],
"control": { ... },
"constraints": { ... }
}

schema_version bumps only on removed/renamed fields. Additive changes don’t bump.

The robot’s commanded action vector.

FieldTypeRangeNotes
typeenumcontinuousdiscrete not supported in v1
dimint1–32Number of action dimensions (e.g. 7 for Franka 6-DOF arm + gripper)
rangesarray of [min, max]length = dimPer-dim hard limits

Action and state denormalization stats. The model is trained on normalized inputs; these undo the normalization at runtime.

FieldTypeConstraint
mean_actionarray of floatslength == action_space.dim
std_actionarray of floatssame length; each element > 0 and ≤ 100
mean_statearray of floatslength defines the state vector
std_statearray of floatslength == mean_state length
FieldTypeRange
component_idxint0 to action_space.dim − 1
close_thresholdfloat0.0–1.0
invertedboolIf true, low values close the gripper

List of camera streams the model expects, 1–8 cameras. Each:

FieldTypeNotes
namestringLogical name (wrist, front, etc.). Must be unique.
resolution[int, int]32–4096 px
fpsfloat0–240
color_spaceenumrgb8, bgr8, mono8, rgba8
FieldTypeRangeNotes
frequency_hzfloat0–1000Robot control loop rate
chunk_sizeint1–200Actions in a single inference chunk
rtc_execution_horizonint1–chunk_sizeNumber of actions to execute before requesting the next chunk
FieldTypeRange
max_ee_velocityfloat0–10 m/s
max_gripper_velocityfloat0–10 m/s
collision_checkboolRun per-step collision check

Two layers run on every config load: JSON Schema (types, enums, ranges) plus Python cross-field rules (length parity, gripper-idx bounds, RTC horizon sanity, camera uniqueness). Each failure carries a stable error slug — for example action-ranges-length-mismatch, gripper-idx-out-of-range — that downstream tools can map to docs or GitHub issues.

from reflex.embodiments import EmbodimentConfig
from reflex.embodiments.validate import validate_embodiment_config, format_errors
cfg = EmbodimentConfig.load_preset("franka")
ok, errors = validate_embodiment_config(cfg)
if not ok:
print(format_errors(errors))
  1. Add a new dict to scripts/emit_embodiment_presets.py (copy a similar robot’s preset; adjust DOFs, gripper index, normalization stats)
  2. Add the slug to the embodiment enum in src/reflex/embodiments/schema.json
  3. Add the slug to ALL_PRESETS in tests/test_embodiments.py
  4. Run python scripts/emit_embodiment_presets.py
  5. pytest tests/test_embodiments.py -v
  6. Commit JSON + script + schema + test changes in one commit
  • RTC adapter uses control.frequency_hz, control.rtc_execution_horizon, control.chunk_size
  • Action denormalization uses constraints.max_ee_velocity, gripper.*
  • reflex doctor validates gripper.inverted, control.chunk_size