Skip to content

Frame audit: declare the EE frame every checkpoint we serve speaks #558

Description

@vertix

Split out of #483, whose "Frame audit" work item #485 does not do. #485 builds the mechanism and deliberately
leaves every shipped deployment unset: "Zero impact when unused — no ee_frame declared → bit-for-bit today's
behaviour. Every shipped deployment is left unset pending the per-checkpoint frame audit."
This issue is that
audit, so the item does not vanish when #485 closes #483.

Background

After #485 every embodiment anchors on a frame named default: its model declares it, its driver reports
robot_state.ee_pose in it and accepts Cartesian commands in it. A checkpoint states the frame it speaks as
a Transform3D measured from default, and ChangeEEFrame(T) converts at the boundary — observations forward
(pose * T), commands back (pose * T⁻¹).

Two places declare it, and they are for different jobs:

  • Trainingcfg.codecs.compose(ee_frame=T) re-expresses the dataset and stamps ee_frame into the
    episode statics, so the checkpoint is trained in T.
  • Servingopenpi.server.pipeline(ee_frame=T) prepends ChangeEEFrame(T) outermost, so the wire and the
    server-side codec see poses already in T.

Setting neither is correct for a checkpoint trained in default, and for any checkpoint that speaks joints.
Setting the wrong one is silent: the arm goes to the wrong place, nothing errors, the eval score is just worse.

What needs deciding

For each checkpoint we serve: does it speak default, or a transform from it?

Deployment Pipeline Space ee_frame today Needs a decision?
phail ee EE unset Yes — trained on the phail dataset under the flange convention; correct today only because default coincides with the Franka tool frame. #550 moves default to the flange and breaks that coincidence.
sim_stack ee_flip_grip EE unset Yes — trained on sim recordings; the sim panda's default sits 45 mm from the FR3's along the approach axis (#485, "Known limit").
libero libero_pipe EE unset Yes, and blocked on #557 — LIBERO's gripper0_grip_site is 38.1 mm and 90° from what bundled_panda_model() calls default, so its episodes mislabel their poses before any checkpoint frame enters the picture.
droid droid_pipe joints unset No — droid_obs carries joint_position and gripper_position only, action is joint_delta_action. No pose crosses the wire.
droid_jointpos droid_jointpos_pipe joints unset No — same observation codec, absolute_joints_action.

The bare pipelines with no checkpoint bound (ee, ee_joints, ee_traj, ee_joints_traj, joints_traj,
ee_flip_grip) inherit whatever the operator passes, so they need documentation rather than a value.

An EE-space DROID checkpoint is the case #483 was opened for and the one we do not currently serve. Serving
one means openpi.server.pipeline(ee_frame=models.DROID_EE_FRAME); there is no shipped config for it, so it is
a hand-wire that someone has to remember.

The other half: nothing enforces agreement

ChangeEEFrame.meta publishes ee_frame in the session handshake, so the rig is told what frame it is being
served in. Nothing compares that against what the checkpoint was trained in. #483 requirement 2 asks for
exactly this — "the checkpoint itself declares what frame it speaks; nobody re-states it at serving time" — and
today the serving config re-states it. A serving pipeline that declares the wrong transform, or omits one the
training run set, fails silently.

Deciding whether the checkpoint's stamped ee_frame should reach the server (via ModelSource.meta, which
already carries per-model handshake facts) and be checked against the pipeline's declaration is part of this
work.

Only OpenPI has the knob

positronic/vendors/lerobot/server.py:58 and positronic/vendors/gr00t/server.py:321 build their pipelines
with no ee_frame parameter at all. Any EE-space checkpoint served through either cannot declare a frame.

Work items

  • Assign the correct frame to each EE-space deployment above; set it, or record in the config comment why
    unset is right
  • Decide whether the checkpoint's trained ee_frame should be carried in ModelSource.meta and checked
    against the serving pipeline's declaration
  • Give lerobot and gr00t pipelines the same ee_frame parameter, or state why they do not need one
  • Re-audit after Move Franka's default frame to the flange and migrate existing datasets #550 lands — it moves default to the flange, which changes the correct value for every
    EE-space checkpoint trained before it

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions