Action spaces
Policy output is either joint angles (JointState) or end-effector poses (EEFPose); EVA always commands the robot in joint angles and runs IK for poses.
Two spaces
Observation and action are each described by a type string under inference_cfg. Switching is a config edit.
| Space (type string) | Contents | Use when |
|---|---|---|
JointState | Flat list of joint angles, as the robot reads and writes them. | Default. Policy outputs joint angles. |
EEFPose | Per-arm hand pose. EVA runs IK to produce joint angles. | Policy outputs end-effector poses. |
Both default to JointState:
inference_cfg = dict( obs_space=dict(type='JointState'), # policy input action_space=dict(type='JointState'), # policy output publish_rate=30, # joint commands per second (Hz) )
publish_rate is the joint-command rate EVA sends to the robot. 30 Hz is the default; change it to match the robot's control loop.Switch to end-effector mode
Set both type fields to EEFPose and declare the pose layout in a deploy config — copy a preset such as configs/01_deploy/<your-robot>/openpi_eef.py and launch with eva --config <that file>. The robot must ship an IK solver (see the note at the end).
inference_cfg = dict( obs_space=dict( type='EEFPose', n_arms=<arms>, # 1 or 2 rotation='<rotation>', # see table below include_gripper=True, ), action_space=dict( type='EEFPose', n_arms=<arms>, # match obs_space rotation='<rotation>', # match obs_space include_gripper=True, ), )
rotation declares how orientation is encoded; the trailing number is its width.
| rotation | Meaning | Values |
|---|---|---|
quat | Quaternion. Default. | 4 |
euler | Roll/pitch/yaw. | 3 |
rotvec | Rotation vector. | 3 |
rot6d | Six-number form. | 6 |
The per-arm block is 3 (position) + rotation width + 1 (gripper) and repeats n_arms times. Set include_gripper=False if the policy emits no gripper value. Two arms with quat and grippers: (3+4+1) × 2 = 16 values per action.
agilex_AGILEX, dual_franka, agibot_g2, r1_lite, ur5e. Requesting EEF mode on a robot without IK fails with "EEF mode requires an IK solver but the robot does not provide one". Either run in JointState mode or add kinematics when adding the robot.Canonical per-arm layout
EVA rewrites every EEF action into a single canonical layout before downstream processing, so later stages see one shape.
position (3) + orientation as quaternion (4) + gripper (1) = 8 values per arm
The configured rotation is converted to a quaternion; position and gripper pass through. This happens automatically once action_space is EEFPose. The recorder writes the same 8-per-arm layout for EEF episodes.
Pose to joint command
The robot is always commanded in joint angles. Dispatch depends on action_space:
- Joint mode — joint angles pass through unchanged.
- EEF mode — actions are rewritten to the canonical pose layout, then IK solves for joint angles. The IK seed is the robot's most recent measured joint state, so the first command continues smoothly from the current configuration.
The IK solver is built once from the robot's kinematics and reused at publish_rate. FK is used in the reverse direction to populate pose values for the observation and recorder when EEF observations are requested without a pose sensor.
IK trajectory tracking
EVA's IK solver (PyRoki, on JAX and jaxls) converts a chunk frame by frame. Each frame is a small optimization chained to the previous frame.
Per-frame objectives:
- Target pose — match position and orientation.
- Joint limits — from the robot model file.
- Rest pose — gentle pull toward home; frozen joints held in place.
- Smoothness — penalize per-joint speed-limit violations; chain to the previous frame.
The first frame is seeded with the current measured joint state. EVA does not drop unreachable frames: if tracking error exceeds tolerance, EVA logs a warning and dispatches the closest joint angles found. Repeated tracking warnings indicate the policy is asking for unreachable poses.
Two-arm robots are split into per-arm blocks, solved independently, and recombined. Extra body joints (e.g. fixed head and torso) stay frozen while arm joints update.
Real robot vs simulation
Solved joint angles go to one of two targets:
- REAL — physical robot.
- SIM — simulation / 3D preview.
Console STEP mode previews a chunk in SIM and confirms it on REAL. Only joint angles at publish_rate leave EVA; poses do not.