Configuration

EVA configs are Python .py files, not YAML. --config selects the file; _base_ chains them.

Prerequisites

Open-loop replay

Open-loop replays a recorded episode through the full pipeline — no robot, no policy server:

bash
eva --config configs/00_openloop/ur5e_openloop.py

Other open-loop files: arx_r5_openloop.py, dual_agilex_AGILEX_openloop.py, dual_franka_openloop.py, r1lite_openloop.py, all under configs/00_openloop/. EVA prints the console URL on success; failures stop with a Python traceback naming the cause (commonly a bad --config path or a missing dataset).

--config is required. There is no preset menu — behavior comes entirely from the file. Use --web-port to change the console port.

How configs work

File layout

PathUse it for
configs/00_base/defaults.pyDefaults for every setting. Read for reference; do not edit.
configs/00_openloop/<robot>_openloop.pyDataset replay. No robot or policy server required.
configs/01_deploy/<robot>/_base.pyShared deploy settings for one robot: type, transport, gripper limits.
configs/01_deploy/<robot>/openpi_qpos.py · openpi_eef.pyLive-robot deploy presets. Copy one as a starting point.
configs/02_collection/<robot>.pyTeleop recording. See Data collection.
configs/03_evaluation/<robot>_eval.pyCheckpoint sweep. See Eval configs.

Inheritance and overrides

EVA merges parent and child setting by setting:

Chains may be several levels deep, e.g. ur5e_eval.pyur5e/openpi_qpos.py00_base/defaults.py. Fields marked below are the ones a user typically edits.

configs/01_deploy/<robot>/openpi_qpos.py
_base_ = ['_base.py']          # inherit this robot's shared deploy settings.

policy = dict(
    type='openpi',        # backend: openpi / openpi_rtc / starvla / gr00t / mock / replay.
    host='<policy-server-ip>',  # ← omit to keep 127.0.0.1.
    port=<policy-server-port>,    # ← policy server port.
)

inference_cfg = dict(
    debug_tasks=['<task prompt>'],  # ← task instruction.
    # Omit obs_space / action_space to keep joint-angle control.
)

Default control is joint-angle (JointState). For end-effector control (EEFPose), override both spaces — set n_arms to the robot's arm count:

python
inference_cfg = dict(
    obs_space=dict(type='EEFPose', n_arms=<arm count>, rotation='quat', include_gripper=True),    # ← 1 or 2.
    action_space=dict(type='EEFPose', n_arms=<arm count>, rotation='quat', include_gripper=True),  # ← same arm count.
)

Settings reference

robot

SettingDefaultMeaning
type"agilex_AGILEX"One of agilex_AGILEX / arx_r5 / dual_franka / agibot_g2 / r1_lite / ur5e.
initial_qposNoneStarting joint pose. None uses the robot's built-in default.
eef_reference_frame"base_link"Reference frame for end-effector poses.
gripper_threshold0.5Open/closed cutoff. None disables.
gripper_open / gripper_close1.0 / 0.0Fully-open / fully-closed command values (robot-specific units).

transport

Channel EVA uses to read sensors and publish actions. See Transport.

SettingDefaultMeaning
type"ros1"ros1 / ros2 / zmq / dataset.
node_name"eva_client"EVA's name on the ROS graph.
convert_bgr_to_rgbTrueReorder camera channels before the model sees them.
image_height / image_width224 / 224Image size delivered to the model.
resize_padTrueAspect-preserving resize with edge padding; otherwise stretch.
image_layout"chw"chw or hwc.
sub_endpoint / pub_endpointtcp://127.0.0.1:5555 / :5556ZMQ endpoints when type='zmq'.
dataset_dir / episode_id"" / 0Recording folder and episode when type='dataset'.
dataset_keysstate / eef / action + camera mapColumn and camera mapping for the recording.
disabled_cameras / disabled_groups[] / []Cameras or sensor groups to ignore at runtime.
topics{}ROS topics. Pre-filled per robot in each deploy _base.py.

policy

Connection to the policy server. See Backends.

SettingDefaultMeaning
type"openpi"openpi / openpi_rtc / starvla / gr00t / mock / replay.
host / port127.0.0.1 / 9000Policy server address. Presets usually change only port.
backend_options{}Backend-specific extras.

inference_cfg

obs_space and action_space switch between JointState and EEFPose; see Action spaces.

SettingDefaultMeaning
obs_spacedict(type='JointState')State representation passed to the model.
action_spacedict(type='JointState')Action interpretation. EEFPose adds n_arms / rotation / include_gripper.
inference_rate3.0Plan requests per second.
publish_rate30Commands per second to the robot.
setup_warmup_chunks2Warm-up chunks before execution. Open-loop sets 0.
debug_tasks['pour soybean', 'put cup']Starter prompts in the DEBUG console.

inference_strategies

Five named strategies are shipped and switchable live in the console. Reference the strategy by the name in the left column; see Strategies.

NameDefault tuning
syncexecute_horizon=5
async(none)
naivelatency_k=4
actexp_weight_m=0.01
rtc(none)

collection · eval_cfg · work_dir

collection configures teleop recording (columns, cameras, arms); presence of this section marks the config as a recording config — see Data collection. eval_cfg configures the checkpoint sweep (next section). work_dir (default "work_dirs") is the output root.

Eval configs

An eval config runs several checkpoints on the same tasks for a multi-checkpoint comparison. It inherits a deploy preset and adds an eval_cfg section listing checkpoints and tasks; EVA loads each checkpoint's deploy config and points it at the right server.

configs/03_evaluation/<robot>_eval.py
_base_ = ['../01_deploy/<robot>/openpi_qpos.py']   # ← deploy preset for this robot.

eval_cfg = dict(
    trials_per_prompt=5,           # trials per task per model.
    cli_mode='real',             # 'real' or 'sim'.
    inference_strategy='async',    # strategy name from the table above.
    reset_after_each_trial=False,  # True returns to start pose after each trial.
    checkpoints=[
        dict(
            name='<checkpoint name>',              # ← real checkpoint name, shown next to the slot letter.
            config='../01_deploy/<robot>/openpi_qpos.py',  # ← relative to THIS file.
            port=<policy-server-port>,            # ← this model's port.
        ),
        # One dict per model.
    ],
    tasks=[
        dict(prompt_en='<task in English>'),  # ← one entry per task.
    ],
)
python
enable_ssh_forward=True,
ssh=dict(
    host='<remote host>',
    user='<ssh user>',
    port=<remote port>,    # policy server port on the remote.
    # remote_sync_dir='<remote results path>',  # optional: copy results back.
),

Startup pipeline

What eva --config does, in order:

Startup failures print a Python traceback identifying the section or file at fault — most often a mistyped --config or checkpoint config path, or a recording config missing a required column.