Skip to content

Add open_door: grip and swing the fridge door along its hinge arc#263

Merged
Nicolas Palpacuer (NickPPC) merged 12 commits into
mainfrom
worktree-fridge-door-open
Jul 21, 2026
Merged

Add open_door: grip and swing the fridge door along its hinge arc#263
Nicolas Palpacuer (NickPPC) merged 12 commits into
mainfrom
worktree-fridge-door-open

Conversation

@vijayvuyyuru

@vijayvuyyuru Vijay Vuyyuru (vijayvuyyuru) commented Jul 17, 2026

Copy link
Copy Markdown
Member

Summary

Adds an open_door command that grips the passive fridge door by its handle and pulls it open along its hinge arc, keeping motion planning collision-honest by re-placing the static door obstacle in the frame system at each swept angle. This is the first "coordinated obstacle + gripper sweep" in the codebase — unlike the existing pivot/circular primitives, the obstacle world changes between waypoints.

Changes

  • coffee/door.go (new): computeDoorSweep (θ waypoints), setDoorTheta (rotate the static door obstacle about its hinge via the lockFilterFrame remove/re-add so the handle chain and panel geometry ride along), and the openDoor orchestrator — grip → per-θ re-plan sweep → release → retract, gated by the running CAS and rebuilding the frame system on exit so the mutation can't leak.
  • coffee/config.go: door_open_angle_degs (default 90), door_pivot_degrees_per_step (default 10), door_grasp_frame_name (default fridge-handle-ball), and door_approach_relative_pose (required) with getters.
  • Approach/grasp/retract derived from the ball frame: reuses the cup-pickup RelativePose/composeCupPose pattern, resolved against the live grasp frame instead of a detected centroid — grasp aims grip-point at the ball center, approach/retract are the relative-pose standoff at the closed/open ball. No authored switch poses required.
  • coffee/collisions.go: doorOpenCollisions(graspFrame) allows gripper↔grasp-frame contact during the pull.
  • coffee/api.go: registers the open_door DoCommand.
  • README.md: documents the command and the four config fields.

Testing

  • coffee/door_test.go: unit tests for computeDoorSweep (count/endpoints/reverse), setDoorTheta (ball sweeps the arc, hinge fixed, panel geometry preserved), the rigid grasp offset riding rotation, the ball-relative approach derivation, and the config getters.
  • coffee/api_test.go: open_door routes to the running-gate guard.
  • go build ./..., go test ./coffee/..., go vet all green. make lint was not run (env has golangci-lint v1 vs the repo's v2 config) — needs a clean pass on a v2-linter machine.
  • Remaining physical verification (needs the live machine): set door_approach_relative_pose and tune the standoff/orientation; confirm the open direction (sign of door_open_angle_degs); live-run {"open_door": true} and watch the arm + motion-viz door track together.

Known follow-ups (flagged as ponytail: deferrals)

  • The relative-pose offset resolves in world axes; a door that starts ajar or swings far enough could expose the world-vs-ball-local difference. A ball-local offset would follow the swing.
  • Longer term: model the fridge as a component with kinematics + a revolute joint, which would delete setDoorTheta entirely and make θ a plan input.

Claude Code Prompts Used

  • "I want to design a new feature... I have an obstacle called fridge door... Setting the theta... creates a pivot about the hinges... We will need a pivot constraint for opening the door... allowed collision between the fridge ball and the arm gripper. Explore this code, tell me how you plan to do it."
  • "Also, we could define the root frame of the door the pivot point right? Also we need to define a plane that we are rotating about..."
  • "I think its a static obstacle at this time... update our fs in place for now but a later improvement would be have the fridge as a component w/ kinematics and a revolute joint."
  • "Give me the config fields that need to be filled in for this."
  • "Actually, the door grasp pose we should just make the center of the ball. So make that a config param (the name of the frame we aim for). We will still have approach/retreat"
  • "Question, so what is approach? is it secretly a relative pose to the coffee ball frame?"
  • "Can we make the approach from the ball? and w. similar thing to relative pose. but it resolves differently... fine if this is one offish for now"
  • "Wait so I still need the exit? what config does that need"
  • "Also, we need to open before the retreat is that implemented?"
  • "Open a pr"

🤖 Generated with Claude Code

Coordinated obstacle+gripper sweep: arm pulls the passive door by its
handle while software sweeps the door angle, re-placing the static door
obstacle per step so collision-checking stays honest.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Six tasks: fetch/verify frame system, config, computeDoorSweep,
setDoorTheta, openDoor orchestrator, DoCommand wiring.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
- DoorOpenAngleDegs / DoorPivotDegreesPerStep config + getters (default 90/10)
- computeDoorSweep: inclusive θ waypoints, direction-aware
- setDoorTheta: rotate the static door obstacle about its hinge (origin)
  via the lockFilterFrame remove/re-add, handle chain rides along, panel
  geometry preserved

Frame names are constants (fridge-door, fridge-handle-ball) per the live
frame-system dump recorded in the plan's Task 0 findings.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
openDoor grips the fridge handle, sweeps the door open by re-placing the
static door obstacle per θ step and tracking the ball with a rigid grasp
offset, then releases and retracts. Gated by the running CAS like
run_cup_flow; rebuilds the frame system on exit so the door mutation
can't leak.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Registers open_door in the dispatch table, documents the command and the
door_open_angle_degs / door_pivot_degrees_per_step config fields, and
tests that the command routes to openDoor's running-gate.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
…pose

The grasp target is now the configured grasp frame's center
(door_grasp_frame_name, default fridge-handle-ball) with the approach
pose's orientation, so the gripper lands dead-on the handle and
co-rotates with it through the swing. Removes the door-grasp switch
pose; approach/retract stay authored. Collision set and sweep-tracked
frame both derive from the same config param.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
door_approach_relative_pose is a RelativePose offset resolved against the
live grasp frame (reusing composeCupPose / relativePoseToSpatial, the cup
pickup pattern) instead of an authored switch pose. Its orientation is the
grasp orientation; the standoff is its translation off the ball center. The
gripper commands grip-point at the ball center and holds it through the
swing. Drops the door-approach switch pose; door-retract stays authored.

ponytail: retract still an authored pose and the offset resolves in world
axes at the closed pose — fine for a first cut; revisit when integrating a
general "relative-to-a-live-frame" pose concept.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Retract now reuses door_approach_relative_pose resolved against the ball's
open pose (composeCupPose on the swept ball center), commanding grip-point
to the standoff. Removes the door-retract switch pose — open_door now needs
zero authored poses, just door_approach_relative_pose. Gripper release still
precedes the retract move.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
…oor an action

Two fixes on top of the open_door work:

- Keep the grip-point orientation constant while pulling the door. The
  sweep loop was riding a rigid grasp offset (Compose(ballNow,
  gripperInBall)), so the commanded tool orientation rotated with the
  door panel and twisted the wrist off the handle. Track only the ball's
  point and hold the grasp orientation (from door_approach_relative_pose)
  fixed instead. The handle knob is spherical, so the grasp doesn't
  constrain wrist roll and a fixed orientation is correct.

- Convert open_door from a bespoke top-level DoCommand into a proper
  execute_action action. openDoor now has the action signature
  (ctx, cancelCtx) error and drops the running-gate/cancelCtx-capture/
  refreshFrameSystemIfClean boilerplate that the executeAction wrapper
  already provides, keeping only the door-specific context merge and
  resetFrameSystem defer. Invoke via {"execute_action": "open_door"}.

Tests and README updated accordingly.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@NickPPC
Nicolas Palpacuer (NickPPC) merged commit b6e058d into main Jul 21, 2026
4 checks passed
@NickPPC
Nicolas Palpacuer (NickPPC) deleted the worktree-fridge-door-open branch July 21, 2026 13:39
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.

2 participants