Skip to content

feat(rollout): node-based rollout pipeline - #588

Draft
ElmoPA wants to merge 4 commits into
elmo/pr586-dfotfrom
elmo/pr586-hnet-deployment
Draft

feat(rollout): node-based rollout pipeline#588
ElmoPA wants to merge 4 commits into
elmo/pr586-dfotfrom
elmo/pr586-hnet-deployment

Conversation

@ElmoPA

@ElmoPA ElmoPA commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

feat(rollout): node-based rollout pipeline

Rollout policy -- when to query the model, how many predicted actions to commit,
whether to blend overlapping plans -- lived as imperative code in two divergent
places: PipelineAlgo.inference_step (action queue + a PUSHSHAPES_PLAN_BLEND env
var read mid-function) and PolicyRollout.rollout_step (i %% query_frequency plus
hardcoded action slicing). Neither was configurable and they disagreed.

Training already solved this shape: an ordered list of stages over one dict,
where the list IS the control flow. Same contract here, node(state) -> state:

ObsCadence WHEN to query (on_queue_empty | every_n | always)
ObsAssemble obs -> model input (runs the training transform list)
PolicyStep algo.step, NOT forward_eval (which is teacher-forced)
ChunkCommit WHICH actions execute (n_keep, temporal-ensembling blend)
ActionDequeue one action per control step
ActionToRobot model action space -> robot interface

Defaults reproduce rollout.py exactly: QUERY_FREQUENCY=30 at 30 Hz, i.e. one
inference per second and 30 actions per plan. Verified the emitted action at
step i equals chunk row (i %% 30) of the plan made at (i//30)*30.

Nodes declare reads/writes and RolloutPipeline validates the key flow at build
time, so an ordering mistake fails at startup instead of surfacing as a None
mid-episode on hardware.

feat(robot): default rollout actions to base frame

rollout_step assumed the policy emits CAM-frame actions and undid that with the
extrinsics. That is right for a checkpoint trained through Eva.get_transform_list
(cartesian -> camframe; cartesian_wristframe_ypr -> camframe -> wrist frame), but
wrong for the fold pipeline, which applies no frame transform at all -- so the
model already predicts absolute base-frame poses. Undoing an encoding that was
never applied moves the arm smoothly to the wrong place with no error raised.

action_frame=base is now the default; cam restores the previous path for the
older checkpoints until those are refactored.

feat(robot): deploy graph policies on Python 3.10

feat(pipeline): port shared inference graph to consolidated runtime

ElmoPA added 4 commits August 26, 2026 14:56
Rollout policy -- when to query the model, how many predicted actions to commit,
whether to blend overlapping plans -- lived as imperative code in two divergent
places: PipelineAlgo.inference_step (action queue + a PUSHSHAPES_PLAN_BLEND env
var read mid-function) and PolicyRollout.rollout_step (i %% query_frequency plus
hardcoded action slicing). Neither was configurable and they disagreed.

Training already solved this shape: an ordered list of stages over one dict,
where the list IS the control flow. Same contract here, node(state) -> state:

  ObsCadence     WHEN to query      (on_queue_empty | every_n | always)
  ObsAssemble    obs -> model input (runs the training transform list)
  PolicyStep     algo.step, NOT forward_eval (which is teacher-forced)
  ChunkCommit    WHICH actions execute (n_keep, temporal-ensembling blend)
  ActionDequeue  one action per control step
  ActionToRobot  model action space -> robot interface

Defaults reproduce rollout.py exactly: QUERY_FREQUENCY=30 at 30 Hz, i.e. one
inference per second and 30 actions per plan. Verified the emitted action at
step i equals chunk row (i %% 30) of the plan made at (i//30)*30.

Nodes declare reads/writes and RolloutPipeline validates the key flow at build
time, so an ordering mistake fails at startup instead of surfacing as a None
mid-episode on hardware.
rollout_step assumed the policy emits CAM-frame actions and undid that with the
extrinsics. That is right for a checkpoint trained through Eva.get_transform_list
(cartesian -> camframe; cartesian_wristframe_ypr -> camframe -> wrist frame), but
wrong for the fold pipeline, which applies no frame transform at all -- so the
model already predicts absolute base-frame poses. Undoing an encoding that was
never applied moves the arm smoothly to the wrong place with no error raised.

action_frame=base is now the default; cam restores the previous path for the
older checkpoints until those are refactored.

ElmoPA commented Aug 26, 2026

Copy link
Copy Markdown
Contributor Author

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant