How to use this file:
- Pick the top unchecked task in your current phase
- Do it in one session (15-30 min)
- Check it off, commit, push
- If you're on your phone, create a GitHub Issue with the task title and label
claude-code→ Claude Code can pick it up (see WORKFLOW.md)Tasks are ordered by dependency. Don't skip ahead unless marked "independent".
SKIPPED (2026-04-12): The
.possuffix bug in kinematics.py was the root cause of IK failures on hardware (see DECISIONS.md, 2026-04-08). With the fix applied and validated (10cm XY square traced correctly), placo FK/IK is accurate enough. Lookup table approach abandoned — high effort for marginal gain.
-
Create
calibration/record_grid.py— Interactive script: connects to leader+follower, prompts "move arm to position, press ENTER to record", reads joint angles viarobot.get_observation(), accepts manual position input (x, y, z in meters via ruler), saves tocalibration/calibration_data.json. Must support resuming (append to existing file) and display recorded count + workspace coverage.- Done when: Script runs, records one point with position + joints, saves JSON
- Time: 30 min
- Tag:
claude-code(scaffold), thenhardware(test on robot)
-
Record calibration grid — (skipped — Phase 5.5 abandoned, see DECISIONS.md 2026-04-12)
-
Create
control/joint_lookup.py— (skipped — Phase 5.5 abandoned, see DECISIONS.md 2026-04-12) -
Add RBF interpolation option — (skipped — Phase 5.5 abandoned, see DECISIONS.md 2026-04-12)
-
Create
control/trajectory.py— (skipped — Phase 5.5 abandoned, see DECISIONS.md 2026-04-12) -
Create
control/executor.py— (skipped — Phase 5.5 abandoned, see DECISIONS.md 2026-04-12)
-
Replace IK path with lookup — (skipped — Phase 5.5 abandoned, see DECISIONS.md 2026-04-12)
-
Build
calibration/validate_grid.py— (skipped — Phase 5.5 abandoned, see DECISIONS.md 2026-04-12)
- Run a manual pick-and-place — (skipped — Phase 5.5 abandoned, see DECISIONS.md 2026-04-12)
The axis-aligned primitive vocabulary is the root cause of segmenter infidelity.
move_to_delta(dx, dy, dz)fixes this by allowing diagonal moves in a single call. Axis-aligned primitives become aliases. See DECISIONS.md (2026-04-12).
-
Implement
move_to_delta(dx, dy, dz)in server.py — Read current joints → FK → add delta vector → IK → send joints. Single tool call, diagonal movement. Existing axis-aligned primitives (move_left, etc.) become thin wrappers that callmove_to_deltainternally.- Done when:
move_to_delta(0.05, -0.03, 0.0)moves the arm diagonally in sim, tests pass - Time: 30 min
- Tag:
claude-code
- Done when:
-
Refactor axis-aligned primitives as aliases —
move_left(d)→move_to_delta(0, d, 0), etc. Keep the old tool names registered (LLM still uses them), but the implementation is a one-liner.- Done when: All existing tests still pass, axis-aligned tools call
move_to_deltainternally - Time: 20 min
- Tag:
claude-code
- Done when: All existing tests still pass, axis-aligned tools call
-
Hardware validation — Test
move_to_deltaon the real arm. Diagonal move (e.g. 5cm forward + 3cm down) should trace a straight line, not a staircase.- Done 2026-04-19: Validated on hardware via
move_to_delta_validation.ipynb. Diagonal XZ (+5cm X, -3cm Z) reaches 87% on X (was 35% before fix). Y axis perfect (~1mm error). Down moves accurate. Bug found and fixed inmove_cartesian_delta: was reading mid-motionget_observation()between sub-steps + 200ms inner interpolation too fast for servo. Rewrote to plan all waypoints upfront from FK seed, chain IK seeds, use convergence-based wait + active-hold final pose. Residual ~6mm error is gravity sag (bounded). - Known limit: +Z up moves only reach ~25-50% (servo torque limit, not software). Filed as 6A.1.x below.
- Done 2026-04-19: Validated on hardware via
-
Z-up gravity compensation (follow-up to 6A.1 hardware validation) — Root cause: gravity droop (
q_actual = q_ref − τ_gravity / Kp_eff), not torque saturation. Fixed 2026-05-18 by P-gain sweep: P=28 gives 91.7% reach (was 69.8% at P=16). SetDECRAS_SERVO_P_GAIN=28in.mcp.json. Placo-based compliance correction infrastructure also built (gravity_torques_dict,SERVO_COMPLIANCE_DEG_PER_NM,LOG_GRAVITY_ERRORS) but not needed — P-gain alone clears the >80% target.- Done 2026-05-18: P=16→70%, P=24→88%, P=28→92%. Settled on P=28.
-
Rewrite segmenter core — Replaced greedy dominant-axis algorithm with waypoint detection. Direction changes (windowed velocity-vector angle), speed dips (local minima below fraction of v_max), and gripper events are all waypoints. Between waypoints, emits one
move_to_delta(dx, dy, dz). Gripper events still producegrasp()/release().- Done: sticks_v2 went from 19 v1 primitives (staircase) to 13 v2 primitives at medium / 7 at low — shorter and diagonals stay diagonal.
-
Add waypoint density parameter —
--density low|medium|highscales angle threshold, dip ratio, and min-segment distance together.- Done: sticks_v2 episode 0 produces 7 / 13 / 26 primitives at low / medium / high.
-
Visualize segmenter output —
scripts/visualize_trajectory.py --segment --density {low|medium|high}overlays raw trajectory (faded) + dashed straight-line segments + diamond waypoint markers.- Done: segments visually approximate the original curve; low is skeletal, high tracks the curves closely.
- Replay segmenter v2 output on hardware — sticks_v3 ep0, tested at 19/21/31/49 primitives. Structure correct (approach → descent → grasp zone → transit → release → retreat). PASSES. Gravity sag causes drift in extended-arm sections — tracked separately.
- Done 2026-05-17:
scripts/replay_sequence.py(new) reads starting joints from Parquet and replays viaLeRobotInterfacedirectly
- Done 2026-05-17:
The LLM observe-think-act loop must work end-to-end before optimizing any part. Expect the LLM to fail at planning — but the infrastructure must be there.
-
Install IP Webcam on phone — DONE (2026-04-19): stream at
http://192.168.129.1:8080/video, verified returning 1920×1080 BGR frames. -
Wire phone camera into perception pipeline — DONE (2026-04-19):
Camera(source)accepts int (USB) or string URL; barehost:portnormalized tohttp://host:port/video.CAMERA_SOURCEinconfig.pyreadsDECRAS_CAMERAenv var (digits → int, else URL)..mcp.jsonsetsDECRAS_CAMERA=192.168.129.1:8080. Live test:Camera(CAMERA_SOURCE).capture()returns a real frame from the phone; detector runs without error.
-
Test LLM loop with real hardware + camera — DONE (2026-05-18): full pick-and-place sequence executed. Arm moved correctly; perception was broken (CAMERA_TO_ROBOT_MATRIX=None → x=0.70m out-of-workspace). See EXPERIMENT_REPORT_2026_05_18.md.
-
Analyze failure modes — DONE (2026-05-18): root causes documented in EXPERIMENT_REPORT_2026_05_18.md. Failures: (1) uncalibrated camera transform, (2) no image in observe(), (3) false-positive grasp signal.
-
Fix: expose camera image in observe() — DONE (2026-05-18): observe() now returns [JSON, Image(jpeg)] so LLM can visually verify scene. Also fixed env propagation to MCP subprocess (SIMULATE etc. were being stripped by MCP's default env).
-
Fix: few-shot example + move_to_delta in prompt — DONE (2026-05-18): prompt.py updated with coordinate frame hints, move_to_delta (not move_to), and annotated sticks_v3 pick-and-place few-shot.
Camera calibration and visual servoing are dropped. Second experiment (2026-05-18) confirmed: camera is body-fixed → image doesn't change as EE moves → visual servoing is impossible without calibration, and calibration contradicts the architecture goal (no fixed camera dependency).
Decision: pixel-to-robot transform removed from observe(). Camera serves semantic grounding only (did the scene change?), not metric navigation. See DECISIONS.md 2026-05-18.
Next: Phase 6D — collect 30+ teleop demos. The LLM reactive loop returns in Phase 6F over a learned vocabulary, not over raw move_to_delta coordinates.
Schema + writer are built. Retriever / RAG / fine-tuning items now live in Phase 6F (RAG over discovered codes, not over raw
move_to_deltasequences). SeeEMERGENT_ROBOTICS_PLAN.mdand ARCHITECTURE.md decisions #8 and #9.
- Design demo store schema —
decras/imitation/retrieval.py—Demo,Primitive,DemoMetadatadataclasses. - Build demo store writer —
decras.imitation.store(save_demo/load_demo/list_demos/ingest_sequence), CLIscripts/add_demo.py, deterministic id, provenance fields.
30+ teleop demos with deliberate variation so the VQ-VAE can discover meaningful action structure. Plan reference: Phase 1 in
EMERGENT_ROBOTICS_PLAN.md.Gate: Test Zero (6A.3) must pass first. If delta replay fails on hardware, the conditioned policy in 6E will fail for the same reason.
-
Gripper force in observation — Plan wants
gripper.force. Decide: read force from Feetech if supported, or drop force and use gripper position deltas as the open/close signal. Document.- Tag:
research, thenclaude-code - Time: 30 min
- Tag:
-
Wire camera frames into recorder — Capture from
DECRAS_CAMERAat 5Hz (every 6th control frame), store aligned with Parquet rows. Needed for later JEPA / scene graph annotation.- Tag:
claude-code - Time: 30 min
- Tag:
-
Pick 2-3 task types — e.g. cup→plate, block→stack, stick→bin. 10 demos each. Document in
datasets/README.md.- Tag:
hardware
- Tag:
-
Vary starting positions deliberately — Object positions, arm start poses, approach angles. At least 3 distinct starting regions per task. The plan is explicit: uniform starts kill conditioned-policy generalization.
- Tag:
hardware - Time: 30-45 min per batch of 10
- Tag:
-
Coverage sanity check —
scripts/visualize_trajectory.pyover the new dataset. EE paths should span the workspace.- Tag:
claude-code
- Tag:
~300 LOC PyTorch. Plan reference: Phase 2.
-
Use segmenter v2 (medium) as segment source — Already built. Per demo: ordered list of (delta_sequence, start_state, end_state) segments.
- Tag:
claude-code
- Tag:
-
Segment-distribution viz — Histogram of segment lengths, directions, cause (gripper / direction change / speed dip). Informs choice of K.
- Tag:
claude-code
- Tag:
-
Build
decras/imitation/vqvae.py— 1D CNN or small GRU encoder, learnable codebook (K=8 first; try 12 and 16), decoder reconstructs delta sequence. Reconstruction + commitment losses.- Tag:
claude-code - Time: 2-3h
- Tag:
-
scripts/train_vqvae.py— Readdemos/segments, train, save checkpoint + codebook.- Tag:
claude-code
- Tag:
- Codebook usage report — Dead codes → reduce K. Wildly different members → increase K.
- Per-code member viz — Overlay all delta trajectories mapping to code k. Should look similar in direction + speed profile.
- Encode all demos to code sequences — Persist
segment_id → codeand per-democode_sequenceinto the demo store.
~200 LOC for the policy, rest is glue. Plan reference: Phases 3 + 4.
-
Build
decras/imitation/policy.py— Small MLP/GRU. Input: current joints + gripper + one-hot code. Output: next delta + gripper action. BC training on (state_t, gripper_t, code) → (delta_t, gripper_action_t).- Tag:
claude-code
- Tag:
-
scripts/train_policy.py- Tag:
claude-code
- Tag:
-
Held-out replay test — Held-out demo, encoded to codes, executed by the policy from the recorded starting state. Does it match the demo?
- Tag:
hardware
- Tag:
-
Generalization test — Same code from a different starting state. Sensible behavior?
- Tag:
hardware
- Tag:
- Collect before/after scene-graphs per code — For each code, gather scene graphs before/after every segment that maps to it. Feed to LLM, save the assigned name in codebook metadata.
- Tag:
research
- Tag:
-
Add
execute_code(code: int)MCP tool — Loads conditioned policy, runs at 50Hz from current state + code, returns post-execution scene graph.- Tag:
claude-code
- Tag:
-
Keep
move_to_deltaregistered — Useful for debugging and fallback.
-
Extend
Primitivedataclass — Add code-mode variant{code: int, name: str}alongside the current tool-call variant.- Tag:
claude-code
- Tag:
-
Code-sequence retriever — Cosine similarity over
(task_embedding, scene_features)where scene_features = object positions + gripper state + starting EE pose. Top-K past code sequences.- Tag:
claude-code
- Tag:
-
RAG integration — Inject retrieved code sequences into
llm_controller/prompt.py. Bootstrap by encoding all 30 Phase 6D demos.- Tag:
claude-code
- Tag:
-
End-to-end demo — Natural-language task → LLM plans code sequence (with RAG few-shot) → MCP executes via
execute_code→ reactive replan after each code. Film a full pick-and-place.- Tag:
hardware
- Tag:
- Extend deltas to (dx, dy, dz, dθ); retrain VQ-VAE + policy with 4D action space
- JEPA enters: encode (delta_sequence, latent_state_transition) pairs so vocabulary is grounded in what the world does, not just what the robot does
- Persistent memory across sessions (what worked, what failed, object locations)
- Error recovery loop (grasp failed → re-observe → retry with adjustment)
- Optional: fine-tune LLM on accumulated (task, scene, code_sequence) data if RAG hits a ceiling
- Refactor
scripts/intodecras/library (see PROJECT_STATUS.md for planned structure) - Upgrade calibration from ruler measurements to ArUco-based EE position measurement
| Label | Meaning |
|---|---|
claude-code |
Can be done entirely by Claude Code from a GitHub Issue |
hardware |
Requires physical robot access |
independent |
No dependencies — can do anytime |
research |
Requires thinking/design, not just coding |