Reading additional input from stdin... OpenAI Codex v0.163.0 -------- workdir: /Users/shimazueiichi/r2r2r-scripts model: gpt-6.1-sol provider: openai approval: never sandbox: read-only reasoning effort: none reasoning summaries: none session id: 01a1da87-96a1-7d20-8a44-a8e6fabb2f24 -------- user 依頼196のレビューをお願いします。pi05/build_correction_episodes.py に 1 コマごとの state の出どころ state_source (int8: 0 実測 / 1 動いた抜けを埋めた値 / 2 動かなかった抜けを埋めた値) を足しました。差分は /tmp/req196.diff。新しいファイル pi05/test_state_source.py と pi05/diag_fill_flags.py も見てください。条件: state/actions/t の値は 1 つも変えないこと、既存データセットは書き換えないこと、印は fill_motion_gaps が埋めたコマと一致すること。正しさの不具合を P1/P2/P3 で日本語で短く挙げてください。 codex 差分と追加ファイルを確認し、既存の補間処理と照合して、値の不変性と印の一致をレビューします。 exec /bin/zsh -lc 'cat /tmp/req196.diff' in /Users/shimazueiichi/r2r2r-scripts succeeded in 0ms: diff --git a/pi05/build_correction_episodes.py b/pi05/build_correction_episodes.py index e5bce79..ae813b3 100644 --- a/pi05/build_correction_episodes.py +++ b/pi05/build_correction_episodes.py @@ -16,6 +16,7 @@ - 使うのは 結果が「成功」(y) の run だけ - 時間軸は 10Hz. state は実測角の線形補間 + グリッパーは指令の時刻で 0/1 (build_demo_episodes と同じ) 実測角の抜け (送信中) は --gap-fill で埋める (linear = corr_v1 / speed20 = corr_v2. 依頼 46) + 埋めたコマには episode.npz の state_source で印を残す (0 実測 / 1 動いた抜け / 2 動かなかった抜け. 依頼 196) - 学習に使うのは状態が model / correct のステップだけ. rewind / home / wait (確認の入力待ち. 人がブロックを置き直すと手が写る) / regrip (補正の R で開いてから閉じ終わるまで. 2026-10-30 依頼 35) のステップと, @@ -176,6 +177,26 @@ def fill_motion_gaps(t, at, aq, mode="speed20", gap_sec=GAP_SEC, speed=SPEED20_D return q, gaps +# ---- 1 コマごとの state の出どころ (state_source. int8. 2026-11-14 依頼 196) ---- +# 関節 6 列が実測角か, fill_motion_gaps が抜けを埋めた値かの印. 爪の列は指令なのでどれでも同じ +SRC_MEASURED = 0 # 実測角 (0.25 秒以内の前後の実測角の線形補間. ふだんは 0.1 秒おき) +SRC_FILLED_MOVE = 1 # 動いた抜け (前後の実測角の差 > GAP_MOVE_MIN_DEG) の中を埋めた値 +SRC_FILLED_STILL = 2 # 動かなかった抜け (差 <= GAP_MOVE_MIN_DEG. 爪の送信など) の中を埋めた値 +STATE_SOURCE_CODES = {SRC_MEASURED: "measured", SRC_FILLED_MOVE: "filled_motion_gap", + SRC_FILLED_STILL: "filled_still_gap"} + + +def gap_fill_flags(t, at, aq, gap_sec=GAP_SEC, min_move=GAP_MOVE_MIN_DEG): + """時刻 t のコマごとの state_source (int8). fill_motion_gaps と同じ「抜け」(実測角の間が gap_sec より長い + [ta, tb]) の中 (ta < t < tb) が埋めた値. 埋め方 (linear / speed20) によらず同じ印になる.""" + src = np.zeros(len(t), dtype=np.int8) + for i in np.flatnonzero(np.diff(at) > gap_sec): + ta, tb = at[i], at[i + 1] + moved = float(np.max(np.abs(aq[i + 1] - aq[i]))) > min_move + src[(t > ta) & (t < tb)] = SRC_FILLED_MOVE if moved else SRC_FILLED_STILL + return src + + def logged_sends(log): """log.jsonl から, 送った目標とそのときの時刻の手がかりを集める. @@ -443,9 +464,12 @@ def build_one(run_dir, out_dir, args): return {"run": stem, "used": False, "reason": f"フレーム抽出不足 written={written} steps={len(tt)} (mp4 と frame_log の不一致)"} + state_source = gap_fill_flags(t, at, aq)[sel["idx"]] np.savez_compressed(out_dir / "episode.npz", t=(np.arange(len(tt)) / FPS).astype(np.float64), - t_orig=tt - tt[0], state=sel["state"], actions=sel["actions"]) + t_orig=tt - tt[0], state=sel["state"], actions=sel["actions"], + state_source=state_source) + filled = int((state_source != SRC_MEASURED).sum()) c = sel["counts"] meta = { "run_stem": stem, "task": bde.TASK, "fps": FPS, "steps": int(len(tt)), @@ -475,6 +499,11 @@ def build_one(run_dir, out_dir, args): "gap_fill": {"mode": gap_fill, "gap_sec": GAP_SEC, "speed_deg_per_sec": SPEED20_DEG_PER_SEC if gap_fill == "speed20" else None, "gaps": len(gaps), **gap_match}, + # 依頼 196: episode.npz の state_source (コマごとの印) の数 + "filled_steps": filled, + "filled_motion_steps": int((state_source == SRC_FILLED_MOVE).sum()), + "filled_ratio": round(filled / len(tt), 4), + "state_source_codes": {str(k): v for k, v in STATE_SOURCE_CODES.items()}, "max_step_deg": [round(float(v), 2) for v in (np.abs(np.diff(sel["state"][:, :6], axis=0)).max(axis=0) if len(sel["state"]) > 1 else np.zeros(6))], @@ -506,7 +535,8 @@ def check_compat(ours, ref): for ep in a: m = json.loads((ep / "meta.json").read_text()) z = np.load(ep / "episode.npz") - if sorted(z.files) != sorted(rz.files): + # 依頼 196: state_source (コマごとの印) はお手本にないキー. 読む側は state / actions しか使わないので比べない + if sorted(set(z.files) - {"state_source"}) != sorted(set(rz.files) - {"state_source"}): probs.append(f"{ep.name}: npz のキー {sorted(z.files)} != お手本 {sorted(rz.files)}") for k in ("state", "actions"): if z[k].dtype != rz[k].dtype or z[k].shape[1:] != rz[k].shape[1:]: @@ -554,6 +584,11 @@ def write_readme(ds, results, args): + ("前後の実測角をまっすぐ結ぶ (linear)" if args.gap_fill == "linear" else f"抜けの頭から速度 20 の速さ ({SPEED20_DEG_PER_SEC:.0f}°/秒. いちばん大きく動く関節) で前後の実測角を結ぶ" "直線を進み, 着いたら止まる (speed20)"), + "- 1 コマごとの state の出どころを episode.npz の `state_source` (int8. state と同じ長さ) に残す: " + "0 = 実測角 (0.25 秒以内の前後の実測角の線形補間) / 1 = 動いた抜け (前後の実測角の差が " + f"{GAP_MOVE_MIN_DEG}° を超える) の中を上の埋め方で埋めた値 / 2 = 動かなかった抜け (爪の送信など) の中を埋めた値。" + "印は関節 6 列のもの (爪の列はいつも指令)。actions の関節は次のコマの state なので, その出どころは次のコマの印。" + "meta.json の filled_steps (1 と 2 のコマの数) / filled_motion_steps (1 の数) / filled_ratio (全コマに対する 1 と 2 の割合)", "- 戻りきれなかった巻き戻しがある run は使わない (前後の姿勢が続かない)", ] if getattr(args, "max_protrude_px", None) is not None: exec /bin/zsh -lc 'cat pi05/test_state_source.py pi05/diag_fill_flags.py' in /Users/shimazueiichi/r2r2r-scripts succeeded in 0ms: #!/usr/bin/env python3 """test_state_source.py — 1 コマごとの state の出どころ (state_source. 依頼 196) の確かめ. python3 pi05/test_state_source.py -v 前半はファイルを読まない部分だけ. 後半 (TestSameAsBefore) は KIOXIA の runs/pi05_policy を読み, 直す前のコード (git の HEAD) と今のコードで /tmp に作り, state / actions / t がバイト単位で同じことを見る (KIOXIA がなければ飛ばす. データセットにもアームにも触らない). """ import importlib.util import json import subprocess import sys import tempfile import unittest from pathlib import Path from types import SimpleNamespace import numpy as np _HERE = Path(__file__).resolve().parent sys.path.insert(0, str(_HERE)) import build_correction_episodes as bce # noqa: E402 def samples(still=False): """0〜1 秒は 0.1 秒おき → 1.0〜2.6 秒は抜け (j1 が 6° 動く. still なら動かない) → 2.6〜3.6 秒は 0.1 秒おき.""" a = np.round(np.arange(0.0, 1.01, 0.1), 3) b = np.round(np.arange(2.6, 3.61, 0.1), 3) at = np.concatenate([a, b]) aq = np.zeros((len(at), 6)) if not still: aq[len(a):, 1] = 6.0 return at, aq def runs_of_nonzero(src): nz = np.r_[0, (np.asarray(src) != 0).astype(int)] return int((np.diff(nz) == 1).sum()) class TestFlags(unittest.TestCase): def test_motion_gap_is_1(self): at, aq = samples() t = np.arange(0.0, 3.6, 0.1) src = bce.gap_fill_flags(t, at, aq) self.assertEqual(src.dtype, np.int8) inside = (t > 1.0) & (t < 2.6) self.assertTrue(np.all(src[inside] == bce.SRC_FILLED_MOVE)) self.assertTrue(np.all(src[~inside] == bce.SRC_MEASURED)) def test_still_gap_is_2(self): at, aq = samples(still=True) t = np.arange(0.0, 3.6, 0.1) src = bce.gap_fill_flags(t, at, aq) self.assertEqual(set(np.unique(src)), {bce.SRC_MEASURED, bce.SRC_FILLED_STILL}) def test_flags_mark_exactly_what_speed20_changes(self): """speed20 が線形補間から変えたコマは, すべて印が 0 でないコマ.""" at, aq = samples() t = np.arange(0.0, 3.6, 0.1) q_lin, _ = bce.fill_motion_gaps(t, at, aq, mode="linear") q_sp, _ = bce.fill_motion_gaps(t, at, aq, mode="speed20") src = bce.gap_fill_flags(t, at, aq) changed = np.any(np.abs(q_lin - q_sp) > 1e-9, axis=1) self.assertTrue(changed.any()) self.assertTrue(np.all(src[changed] != bce.SRC_MEASURED)) def test_no_gap_no_flag(self): at = np.round(np.arange(0.0, 3.01, 0.1), 3) aq = np.cumsum(np.ones((len(at), 6)), axis=0) self.assertEqual(int(bce.gap_fill_flags(np.arange(0.0, 3.0, 0.1), at, aq).sum()), 0) def test_compat_ignores_state_source(self): """お手本にない state_source のキーがあっても check_compat はキーの違いとして数えない.""" with tempfile.TemporaryDirectory() as d: import cv2 for name, extra in (("ours", True), ("ref", False)): ep = Path(d) / name / "e0" (ep / "frames").mkdir(parents=True) cv2.imwrite(str(ep / "frames" / "000000.jpg"), np.zeros((4, 6, 3), np.uint8)) kw = {"state_source": np.zeros(1, np.int8)} if extra else {} np.savez_compressed(ep / "episode.npz", t=np.zeros(1), t_orig=np.zeros(1), state=np.zeros((1, 7), np.float32), actions=np.zeros((1, 7), np.float32), **kw) (ep / "meta.json").write_text(json.dumps({"fps": 10, "image_size": [6, 4], "state_dim": 7, "state_names": [], "task": "x"})) self.assertEqual(bce.check_compat(Path(d) / "ours", Path(d) / "ref"), []) def _old_module(): """直す前の build_correction_episodes.py (git の HEAD) を別の名前で読み込む.""" src = subprocess.run(["git", "show", "HEAD:pi05/build_correction_episodes.py"], cwd=_HERE, capture_output=True, text=True, check=True).stdout tmp = Path(tempfile.mkdtemp()) / "bce_old.py" tmp.write_text(src) spec = importlib.util.spec_from_file_location("bce_old", tmp) mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) return mod # 補正の多い本・巻き戻しのある本など. 依頼 196 の時点で KIOXIA にあるもの SAMPLE_RUNS = ("pi05_20261031_175527", "pi05_20261031_180435") @unittest.skipUnless(Path("/Volumes/KIOXIA").is_mount() and bce.RUNS_ROOT.is_dir(), "KIOXIA がない") class TestSameAsBefore(unittest.TestCase): @classmethod def setUpClass(cls): cls.old = _old_module() def _build(self, mod, run, d, gap_fill, trim_hold): args = SimpleNamespace(gap_fill=gap_fill, trim_hold=trim_hold, no_trim_mid_idle=False, max_protrude_px=None, force=True) out = Path(d) / mod.__name__ / f"{gap_fill}_{trim_hold}" / run res = mod.build_one(bce.RUNS_ROOT / run, out, args) self.assertTrue(res.get("used"), res) z = np.load(out / "episode.npz") return {k: z[k] for k in z.files}, json.loads((out / "meta.json").read_text()) def test_bytes_and_counts(self): with tempfile.TemporaryDirectory() as d: for run in SAMPLE_RUNS: if not (bce.RUNS_ROOT / run).is_dir(): self.skipTest(f"{run} がない") for gap_fill, trim_hold in (("linear", False), ("speed20", False), ("speed20", True)): with self.subTest(run=run, gap_fill=gap_fill, trim_hold=trim_hold): a, _ = self._build(self.old, run, d, gap_fill, trim_hold) b, meta = self._build(bce, run, d, gap_fill, trim_hold) self.assertNotIn("state_source", a) for k in ("t", "t_orig", "state", "actions"): self.assertEqual(a[k].dtype, b[k].dtype, k) self.assertEqual(a[k].tobytes(), b[k].tobytes(), k) src = b["state_source"] self.assertEqual(src.dtype, np.int8) self.assertEqual(len(src), len(b["state"])) self.assertTrue(set(np.unique(src)) <= set(bce.STATE_SOURCE_CODES)) gf = meta["gap_fill"] filled = int((src != 0).sum()) self.assertEqual(meta["filled_steps"], filled) self.assertEqual(meta["filled_motion_steps"], int((src == 1).sum())) self.assertAlmostEqual(meta["filled_ratio"], filled / len(src), places=4) # 印のつながりの数は抜けの数を超えない (1 つの抜けが印を 2 つに分けることはない) self.assertLessEqual(runs_of_nonzero(src), gf["gaps"]) self.assertLessEqual(runs_of_nonzero(src == 1), gf["motion_gaps"]) if gf["gaps"] == 0: self.assertEqual(filled, 0) if __name__ == "__main__": unittest.main() #!/usr/bin/env python3 """diag_fill_flags.py — 既存の補正データセットで, 実測角の抜けを埋めたコマの割合を測る (2026-11-14 依頼 196). datasets/ の名前に corr / deep_even10 が入るデータセットの, 補正エピソード (meta.json の source が pi05_policy) ごとに, 元の runs/pi05_policy/{run_stem}/ から build_correction_episodes.build_one を meta.json と同じ条件 (gap_fill の mode・trim_mid_idle・trim_hold) で /tmp に作り直し, state_source (コマごとの印) を数える. 作り直した state / actions / t がデータセットの episode.npz と一致しない本は数えない (理由を CSV に残す). データセット・元の記録は読むだけ (書かない). 書くのは /tmp と diag/fill_flags_20261114/ だけ. python3 pi05/diag_fill_flags.py """ import argparse import csv import json import sys from pathlib import Path from types import SimpleNamespace import numpy as np _HERE = Path(__file__).resolve().parent sys.path.insert(0, str(_HERE)) import build_correction_episodes as bce # noqa: E402 import build_demo_episodes as bde # noqa: E402 OUT_NAME = "fill_flags_20261114" TMP_ROOT = Path("/tmp") / OUT_NAME # 学習に使ったことがあるデータセットを先に並べる (依頼 196) TRAINED_FIRST = ("mecharm_redblock_box_teach_v1_trim2_corr_v5", "mecharm_redblock_box_deep_even10_v1", "mecharm_redblock_box_teach_v1_trim2_corr_v5_deep") def target_datasets(ds_root): names = sorted(p.name for p in ds_root.iterdir() if p.is_dir() and not p.name.startswith(".") and ("corr" in p.name or "deep_even10" in p.name)) return sorted(names, key=lambda n: (n not in TRAINED_FIRST, TRAINED_FIRST.index(n) if n in TRAINED_FIRST else 0, n)) def rebuild(run_stem, meta, cache): """meta.json と同じ条件で /tmp に作り直す. 戻り値: (npz の中身 dict / None, 理由).""" gf = meta.get("gap_fill") or {} key = (run_stem, gf.get("mode"), bool(meta.get("trim_mid_idle")), meta.get("trim_hold") is not None) if key in cache: return cache[key] out = TMP_ROOT / "rebuild" / "_".join(str(k) for k in key) / run_stem args = SimpleNamespace(gap_fill=gf.get("mode") or "linear", trim_hold=key[3], no_trim_mid_idle=not key[2], max_protrude_px=None, force=True) res = bce.build_one(bce.RUNS_ROOT / run_stem, out, args) if not res.get("used"): cache[key] = (None, f"作り直せない: {res.get('reason')}") else: z = np.load(out / "episode.npz") cache[key] = ({k: z[k] for k in z.files}, "ok") return cache[key] def main(): ap = argparse.ArgumentParser() ap.add_argument("--dataset", action="append", help="このデータセットだけ (複数可)") args = ap.parse_args() bde.ensure_ssd() ds_root = bde.DATA_ROOT / "datasets" out_dir = bde.DATA_ROOT / "diag" / OUT_NAME if out_dir.exists(): sys.exit(f"[ABORT] 出力先がもうある: {out_dir}") names = args.dataset or target_datasets(ds_root) rows, cache = [], {} for name in names: for mp in sorted((ds_root / name / "raw_episodes").glob("[!.]*/meta.json")): meta = json.loads(mp.read_text()) if not str(meta.get("source", "")).startswith("pi05_policy"): continue ep = mp.parent stem = meta.get("run_stem", ep.name) z = np.load(ep / "episode.npz") row = {"dataset": name, "episode": ep.name, "run_stem": stem, "gap_fill": (meta.get("gap_fill") or {}).get("mode"), "trim_hold": meta.get("trim_hold") is not None, "steps": len(z["state"]), "filled_steps": "", "filled_motion_steps": "", "filled_ratio": "", "gaps": (meta.get("gap_fill") or {}).get("gaps"), "motion_gaps": (meta.get("gap_fill") or {}).get("motion_gaps"), "status": ""} new, why = rebuild(stem, meta, cache) if new is None: row["status"] = why elif not all(k in new and new[k].shape == z[k].shape and new[k].tobytes() == z[k].tobytes() for k in ("state", "actions", "t")): row["status"] = "state が一致しない (数えない)" else: src = new["state_source"] n_f = int((src != bce.SRC_MEASURED).sum()) row.update(filled_steps=n_f, filled_motion_steps=int((src == bce.SRC_FILLED_MOVE).sum()), filled_ratio=round(n_f / len(src), 4), status="ok") rows.append(row) print(f"{name} {ep.name} {row['status']} {row['filled_steps']}/{row['steps']}") out_dir.mkdir(parents=True) with (out_dir / "episodes.csv").open("w", newline="") as f: w = csv.DictWriter(f, fieldnames=list(rows[0].keys())) w.writeheader(); w.writerows(rows) summ = [] for name in names: rs = [r for r in rows if r["dataset"] == name] ok = [r for r in rs if r["status"] == "ok"] steps = sum(r["steps"] for r in ok); filled = sum(r["filled_steps"] for r in ok) top = max(ok, key=lambda r: r["filled_ratio"]) if ok else None summ.append({"dataset": name, "corr_episodes": len(rs), "counted": len(ok), "not_counted": len(rs) - len(ok), "steps": steps, "filled_steps": filled, "filled_motion_steps": sum(r["filled_motion_steps"] for r in ok), "filled_ratio": round(filled / steps, 4) if steps else "", "max_episode": top["episode"] if top else "", "max_episode_ratio": top["filled_ratio"] if top else ""}) with (out_dir / "summary.csv").open("w", newline="") as f: w = csv.DictWriter(f, fieldnames=list(summ[0].keys())) w.writeheader(); w.writerows(summ) (out_dir / "README.md").write_text( "# fill_flags_20261114 (依頼 196)\n\n" "既存の補正データセットで, 実測角の抜けを埋めたコマ (state_source が 1 または 2) の数と割合。\n" "`python3 pi05/diag_fill_flags.py` で作った。データセットは読むだけ。作り直しは /tmp。\n\n" "- state_source: 0 = 実測角 / 1 = 動いた抜けを埋めた値 / 2 = 動かなかった抜けを埋めた値\n" "- filled_ratio = (1 と 2 のコマ) / 全コマ。filled_motion_steps は 1 のコマの数\n" "- status が ok でない本 (作り直した state / actions / t がデータセットと一致しない・作り直せない) は数えない\n" "- episodes.csv: 本ごと / summary.csv: データセットごと (max_episode = 割合がいちばん多い本)\n") print(f"→ {out_dir}") return 0 if __name__ == "__main__": sys.exit(main()) exec /bin/zsh -lc "sed -n '65,180p' pi05/build_correction_episodes.py; sed -n '310,470p' pi05/build_correction_episodes.py; rg -n 'trim_mid_idle|trim_hold|sel\\[|idx|out_dir|force' pi05/build_correction_episodes.py" in /Users/shimazueiichi/r2r2r-scripts succeeded in 0ms: # 角度を読み直す間 (約 1.6 秒. 動いている間は読めずにやり直す) 返ってこないので, その間は実測角が残らない. # 腕はこの抜けの頭で動き出し, 抜けの終わりの実測角 (着いた姿勢) で止まっている. # linear : 抜けの前後の実測角をまっすぐ結ぶ (corr_v1. 1.6 秒かけてゆっくり動いたことになる) # speed20 : 抜けの頭から, 速度 20 の速さで前後の実測角を結ぶ直線 (関節空間. 全関節が同時に着く) を進み, # 着いたら抜けの終わりまで止まる. 速さは trim2 の元の記録 (run_pick_place 19 本. 速度 20 で # 0.32 秒おきに動いている間も読めていた) の, 動いている途中の先頭の関節の速さ 128 区間の中央値 29.8°/秒 GAP_FILL_MODES = ("linear", "speed20") GAP_SEC = 0.25 # 実測角の間がこれより長いところを「抜け」とみなす (ふだんは 0.1 秒おき) SPEED20_DEG_PER_SEC = 30.0 # 速度 20 で動いている間の先頭の関節の速さ (上の 29.8°/秒) GAP_MOVE_MIN_DEG = 0.5 # 抜けの前後でこれより動いていれば「動いた抜け」として数える # ---- 着いたあとの止まりの詰め方 (--trim-hold. 2026-10-31 依頼 48. corr_v3) ---- # 推論・補正では 1 回の send_angles ごとに daemon の読み直し (約 1.6 秒) を待つので, 中継点・補正の 1 刻みの # たびに「動いて止まる」をくり返す. trim2 の決まり (止まりの区間ごとに先頭 2 コマ) では, 区間が 2〜3 コマ # おきに来るため止まりが約 50% 残る (corr_v2). この止まりは送信の確かめを待つだけで, 動作の意味はない. # model の区間 : 残さない (中継点の動きだけをつなぐ) # correct の区間 : 先頭 1 コマ (補正のコマを減らしすぎない. 補正は 1 刻みが 1 コマで動き終わる) # 爪の切り替えの直前・直後の区間 : trim2 と同じ先頭 2 コマ (爪が動き終わるのを待つ意味がある) + gripper_guard HOLD_KEEP_MODEL = 0 HOLD_KEEP_CORRECT = 1 HOLD_KEEP_GRIP = bde.MID_IDLE_KEEP_STEPS def _rmtree(path): """exFAT では本体を消すと macOS が ._ (AppleDouble) も一緒に消すため, 後から ._ を消そうとして FileNotFoundError になる. もう無いものは飛ばして消す.""" def _skip_missing(func, p, exc): exc = exc[1] if isinstance(exc, tuple) else exc # onerror (3.11 まで) は exc_info if not isinstance(exc, FileNotFoundError): raise exc if sys.version_info >= (3, 12): shutil.rmtree(path, onexc=_skip_missing) else: shutil.rmtree(path, onerror=_skip_missing) def load_stage_times(path): """states.csv の stage 行 (状態の切り替わり) と, 各行の stage 列.""" ts, modes = [], [] with path.open(newline="") as f: for row in csv.DictReader(f): if row.get("event_type") != "stage": continue try: ts.append(float(row["ts"])); modes.append(row.get("stage") or MODE_MODEL) except Exception: continue return np.array(ts), modes def load_log(path): out = [] if not path.exists(): return out for line in path.read_text().splitlines(): line = line.strip() if line: try: out.append(json.loads(line)) except Exception: continue return out def idle_keep_mask(state, actions): """build_demo_episodes.build_one の「停止区間を詰める」(IDLE_*) と同じ決まり. 戻り値: (keep, 詰めた数).""" n = len(state) motion = np.max(np.abs(actions - state), axis=1) keep = np.ones(n, dtype=bool) i, trimmed = 0, 0 while i < n: if motion[i] < bde.IDLE_EPS_DEG: j = i while j < n and motion[j] < bde.IDLE_EPS_DEG: j += 1 if (j - i) / FPS > bde.IDLE_MAX_SEC: cut_from = i + int(bde.IDLE_KEEP_SEC * FPS) keep[cut_from:j] = False trimmed += j - cut_from i = j else: i += 1 guard = bde.gripper_guard_mask(state) trimmed -= int((~keep & guard).sum()) keep |= guard return keep, trimmed def fill_motion_gaps(t, at, aq, mode="speed20", gap_sec=GAP_SEC, speed=SPEED20_DEG_PER_SEC): """10Hz の時刻 t の関節角を, 実測角 (at, aq) から作る. 実測角があるところは実測角の線形補間. 実測角の間が gap_sec より長い「抜け」[ta, tb] だけ, mode で埋め方を変える: linear : qa → qb を ta〜tb でまっすぐ結ぶ (np.interp と同じ) speed20 : ta から qa → qb の直線を, いちばん大きく動く関節が speed (°/秒) になる速さで進み, 着いたら tb まで qb で止まる. 着くまでの時間が抜けより長いときは抜けいっぱいを使う (linear と同じ) 戻り値: (q (len(t), 6), 抜けの一覧 [{ta, tb, move_deg, move_sec}]) """ if mode not in GAP_FILL_MODES: raise ValueError(f"gap fill mode: {mode}") q = np.stack([np.interp(t, at, aq[:, k]) for k in range(6)], axis=1) gaps = [] for i in np.flatnonzero(np.diff(at) > gap_sec): ta, tb, qa, qb = at[i], at[i + 1], aq[i], aq[i + 1] d = float(np.max(np.abs(qb - qa))) dur = min(d / speed, tb - ta) if mode == "speed20" else tb - ta gaps.append({"ta": float(ta), "tb": float(tb), "move_deg": d, "move_sec": float(dur)}) if mode == "linear": continue m = (t > ta) & (t < tb) if not m.any(): continue frac = np.ones(int(m.sum())) if dur <= 0 else np.clip((t[m] - ta) / dur, 0.0, 1.0) q[m] = qa + frac[:, None] * (qb - qa) return q, gaps # ---- 1 コマごとの state の出どころ (state_source. int8. 2026-11-14 依頼 196) ---- def select_steps(t, q, g, mode_ts, modes, windows, trim_mid_idle=True, trim_hold=False): """学習に使うステップを選び, state / actions を作る (ファイルを読まない部分. テストで使う). 戻り値: dict(idx=元の t の添字, state, actions, modes, counts) """ state_all = np.concatenate([q, g[:, None]], axis=1).astype(np.float32) keep, m_all = step_keep_mask(t, mode_ts, modes, windows) idx = np.flatnonzero(keep) counts = {"grid_steps": int(len(t)), "excluded_mode": int((~np.isin(m_all, (MODE_MODEL, MODE_CORRECT))).sum()), "excluded_window": int((np.isin(m_all, (MODE_MODEL, MODE_CORRECT)) & ~keep).sum())} if len(idx) == 0: return {"idx": idx, "state": state_all[:0], "actions": state_all[:0], "modes": [], "counts": counts} state = state_all[idx] # 除いたあとに残ったステップでつなぐ. actions は「つないだ並びでの次の state」 actions = next_state_actions(state) k1, idle_trimmed = idle_keep_mask(state, actions) idx, state, actions = idx[k1], state[k1], actions[k1] counts["idle_trimmed"] = int(idle_trimmed) counts["steps_before_mid_trim"] = int(len(idx)) mid = 0 if trim_mid_idle and len(idx): if trim_hold: mk = hold_keep_mask(state, actions, [str(m_all[k]) for k in idx]) else: mk = bde.mid_idle_keep_mask(state, actions) mid = int((~mk).sum()) idx, state, actions = idx[mk], state[mk], actions[mk] # trim2 と同じ: 関節 6 列は残ったステップで作り直す. グリッパー列は元の (次の) 指令のまま actions = actions.copy() actions[:-1, :6] = state[1:, :6] actions[-1, :6] = state[-1, :6] counts["mid_idle_trimmed"] = mid sel_modes = [str(m_all[k]) for k in idx] counts["model_steps"] = sel_modes.count(MODE_MODEL) counts["correct_steps"] = sel_modes.count(MODE_CORRECT) return {"idx": idx, "state": state, "actions": actions, "modes": sel_modes, "counts": counts} def build_one(run_dir, out_dir, args): stem = run_dir.name trial_p = run_dir / f"{stem}.json" rec = run_dir / "recording" if not trial_p.exists(): return {"run": stem, "used": False, "reason": f"missing:{trial_p.name}"} trial = json.loads(trial_p.read_text()) if trial.get("recording_enabled") is not True: return {"run": stem, "used": False, "reason": "no_recording"} if trial.get("outcome") != "success": return {"run": stem, "used": False, "reason": f"outcome={trial.get('outcome')}"} need = [rec / "states.csv", rec / "top.mp4", rec / "top_frame_log.csv"] missing = [p.name for p in need if not p.exists()] if missing: return {"run": stem, "used": False, "reason": "missing:" + ",".join(missing)} log = load_log(run_dir / "log.jsonl") unfinished = [r for r in log if r.get("type") == "rewind" and not r.get("finished", True)] unfinished += [r for r in log if r.get("type") == "correction" and r.get("action") == "cancel" and not r.get("finished", True)] if unfinished: # 戻りきれなかった巻き戻しがあると, つないだ前後で姿勢が続かない return {"run": stem, "used": False, "reason": f"rewind_unfinished x{len(unfinished)}"} at, aq, gt, gs = bde.load_states(rec / "states.csv") if len(at) < bde.MIN_ACTUAL_SAMPLES: return {"run": stem, "used": False, "reason": f"actual 実測が少ない ({len(at)})"} order = np.argsort(at); at, aq = at[order], aq[order] at, aq = bde.drop_spikes(at, aq) try: tm = json.loads((rec / "top_meta.json").read_text()) except Exception: tm = {} if tm.get("status") != "ok": return {"run": stem, "used": False, "reason": f"recording_status={tm.get('status')}"} fidx, fts = bde.load_frame_log(rec / "top_frame_log.csv") if len(fts) < FPS: return {"run": stem, "used": False, "reason": f"top フレームが少ない ({len(fts)})"} t0, t1 = max(fts[0], at[0]), min(fts[-1], at[-1]) if t1 - t0 < 3.0: return {"run": stem, "used": False, "reason": "記録の重なりが短い"} t = np.arange(t0, t1, 1.0 / FPS) gap_fill = getattr(args, "gap_fill", "linear") q, gaps = fill_motion_gaps(t, at, aq, mode=gap_fill) for g in gaps: k = int(np.searchsorted(at, g["tb"])) g["qb"] = aq[k] gap_match = match_gaps_to_sends(gaps, log) g = np.zeros(len(t)) if len(gt): go = np.argsort(gt); gt, gs = gt[go], gs[go] for i, ti in enumerate(t): k = np.searchsorted(gt, ti, side="right") - 1 g[i] = gs[k] if k >= 0 else 0.0 mode_ts, modes = load_stage_times(rec / "states.csv") windows = excluded_windows(log) trim_hold = getattr(args, "trim_hold", False) sel = select_steps(t, q, g, mode_ts, modes, windows, trim_mid_idle=not args.no_trim_mid_idle, trim_hold=trim_hold) if len(sel["idx"]) < FPS: return {"run": stem, "used": False, "reason": f"使えるステップが少ない ({len(sel['idx'])})"} tt = t[sel["idx"]] # 依頼 117: つかみの深さで採否を決める (--max-protrude-px のときだけ. 既定では測らない) depth = None max_pr = getattr(args, "max_protrude_px", None) if max_pr is not None: import grasp_depth drop, why, depth = grasp_depth.judge(run_dir, max_pr, grasp_depth.first_close_label_time(tt, sel["state"][:, 6])) if drop: if out_dir.exists(): why += " (前に作ったエピソードが残っている. 消していない)" return {"run": stem, "used": False, "reason": why, "grasp_depth": depth} # codex R1-4: 画像の候補も同じ決まりで絞る (除いた区間・rewind / home の画像を, 境界の # 最近傍として拾わない). 候補から選ぶので, 除いた時刻の画像は入らない fkeep, _ = step_keep_mask(fts, mode_ts, modes, windows) fidx, fts = fidx[fkeep], fts[fkeep] if len(fts) < 2: return {"run": stem, "used": False, "reason": "使える画像が少ない"} nearest = np.clip(np.searchsorted(fts, tt), 1, len(fts) - 1) left = fts[nearest - 1]; right = fts[nearest] nearest = np.where(np.abs(tt - left) <= np.abs(right - tt), nearest - 1, nearest) want = {} for step, n in enumerate(nearest): want.setdefault(int(fidx[n]), []).append(step) if out_dir.exists(): if not args.force: return {"run": stem, "used": True, "reason": "既存 (スキップ・--force で再生成)", "steps": int(len(tt))} _rmtree(out_dir) (out_dir / "frames").mkdir(parents=True) cap = cv2.VideoCapture(str(rec / "top.mp4")) fi, written, max_need, size = 0, 0, max(want), None while fi <= max_need: ok, frame = cap.read() if not ok: break if fi in want: h, w = frame.shape[:2] s = bde.IMG_LONG / max(h, w) small = cv2.resize(frame, (round(w * s), round(h * s)), interpolation=cv2.INTER_AREA) size = small.shape[1], small.shape[0] for step in want[fi]: # codex R3 P2: 保存に失敗したコマは数えない (欠けたエピソードを採用しない) if cv2.imwrite(str(out_dir / "frames" / f"{step:06d}.jpg"), small, [cv2.IMWRITE_JPEG_QUALITY, bde.JPEG_QUALITY]): written += 1 fi += 1 cap.release() if written != len(tt): _rmtree(out_dir) return {"run": stem, "used": False, "reason": f"フレーム抽出不足 written={written} steps={len(tt)} (mp4 と frame_log の不一致)"} state_source = gap_fill_flags(t, at, aq)[sel["idx"]] np.savez_compressed(out_dir / "episode.npz", t=(np.arange(len(tt)) / FPS).astype(np.float64), t_orig=tt - tt[0], state=sel["state"], actions=sel["actions"], 39: python3 pi05/build_correction_episodes.py --run pi05_20261030_101500 --force 311:def select_steps(t, q, g, mode_ts, modes, windows, trim_mid_idle=True, trim_hold=False): 314: 戻り値: dict(idx=元の t の添字, state, actions, modes, counts) 318: idx = np.flatnonzero(keep) 322: if len(idx) == 0: 323: return {"idx": idx, "state": state_all[:0], "actions": state_all[:0], "modes": [], "counts": counts} 324: state = state_all[idx] 328: idx, state, actions = idx[k1], state[k1], actions[k1] 330: counts["steps_before_mid_trim"] = int(len(idx)) 332: if trim_mid_idle and len(idx): 333: if trim_hold: 334: mk = hold_keep_mask(state, actions, [str(m_all[k]) for k in idx]) 338: idx, state, actions = idx[mk], state[mk], actions[mk] 344: sel_modes = [str(m_all[k]) for k in idx] 347: return {"idx": idx, "state": state, "actions": actions, "modes": sel_modes, "counts": counts} 350:def build_one(run_dir, out_dir, args): 384: fidx, fts = bde.load_frame_log(rec / "top_frame_log.csv") 406: trim_hold = getattr(args, "trim_hold", False) 407: sel = select_steps(t, q, g, mode_ts, modes, windows, trim_mid_idle=not args.no_trim_mid_idle, 408: trim_hold=trim_hold) 409: if len(sel["idx"]) < FPS: 410: return {"run": stem, "used": False, "reason": f"使えるステップが少ない ({len(sel['idx'])})"} 411: tt = t[sel["idx"]] 419: grasp_depth.first_close_label_time(tt, sel["state"][:, 6])) 421: if out_dir.exists(): 428: fidx, fts = fidx[fkeep], fts[fkeep] 436: want.setdefault(int(fidx[n]), []).append(step) 438: if out_dir.exists(): 439: if not args.force: 440: return {"run": stem, "used": True, "reason": "既存 (スキップ・--force で再生成)", 442: _rmtree(out_dir) 443: (out_dir / "frames").mkdir(parents=True) 457: if cv2.imwrite(str(out_dir / "frames" / f"{step:06d}.jpg"), small, 463: _rmtree(out_dir) 467: state_source = gap_fill_flags(t, at, aq)[sel["idx"]] 468: np.savez_compressed(out_dir / "episode.npz", 470: t_orig=tt - tt[0], state=sel["state"], actions=sel["actions"], 473: c = sel["counts"] 478: "trim_mid_idle": not args.no_trim_mid_idle, 479: "trim_hold": ({"keep_model": HOLD_KEEP_MODEL, "keep_correct": HOLD_KEEP_CORRECT, 480: "keep_grip": HOLD_KEEP_GRIP} if trim_hold and not args.no_trim_mid_idle else None), 508: (np.abs(np.diff(sel["state"][:, :6], axis=0)).max(axis=0) if len(sel["state"]) > 1 510: "step_modes": sel["modes"], 512: (out_dir / "meta.json").write_text(json.dumps(meta, indent=2, ensure_ascii=False)) 567: + ("" if not args.no_trim_mid_idle else " --no-trim-mid-idle") 569: + (" --trim-hold" if getattr(args, "trim_hold", False) else "") 580: + ("" if not getattr(args, "trim_hold", False) else 630: ap.add_argument("--force", action="store_true", help="既存エピソードを作り直す") 644: if args.trim_hold and args.no_trim_mid_idle: exec /bin/zsh -lc 'PYTHONDONTWRITEBYTECODE=1 python3 -m unittest pi05.test_state_source.TestFlags.test_motion_gap_is_1 pi05.test_state_source.TestFlags.test_still_gap_is_2 pi05.test_state_source.TestFlags.test_flags_mark_exactly_what_speed20_changes pi05.test_state_source.TestFlags.test_no_gap_no_flag -v' in /Users/shimazueiichi/r2r2r-scripts succeeded in 2020ms: python3: warning: confstr() failed with code 5: couldn't get path of DARWIN_USER_TEMP_DIR; using /tmp instead python3: error: couldn't create cache file '/tmp/xcrun_db-5TP6ATAD' (errno=Operation not permitted) python3: warning: confstr() failed with code 5: couldn't get path of DARWIN_USER_TEMP_DIR; using /tmp instead python3: error: couldn't create cache file '/tmp/xcrun_db-IQ6Btzl5' (errno=Operation not permitted) test_motion_gap_is_1 (pi05.test_state_source.TestFlags) ... ok test_still_gap_is_2 (pi05.test_state_source.TestFlags) ... ok test_flags_mark_exactly_what_speed20_changes (pi05.test_state_source.TestFlags) speed20 が線形補間から変えたコマは, すべて印が 0 でないコマ. ... ok test_no_gap_no_flag (pi05.test_state_source.TestFlags) ... ok ---------------------------------------------------------------------- Ran 4 tests in 0.002s OK exec /bin/zsh -lc "nl -ba pi05/diag_fill_flags.py | sed -n '109,138p'; git status --short" in /Users/shimazueiichi/r2r2r-scripts succeeded in 0ms: 109 "not_counted": len(rs) - len(ok), "steps": steps, "filled_steps": filled, 110 "filled_motion_steps": sum(r["filled_motion_steps"] for r in ok), 111 "filled_ratio": round(filled / steps, 4) if steps else "", 112 "max_episode": top["episode"] if top else "", 113 "max_episode_ratio": top["filled_ratio"] if top else ""}) 114 with (out_dir / "summary.csv").open("w", newline="") as f: 115 w = csv.DictWriter(f, fieldnames=list(summ[0].keys())) 116 w.writeheader(); w.writerows(summ) 117 (out_dir / "README.md").write_text( 118 "# fill_flags_20261114 (依頼 196)\n\n" 119 "既存の補正データセットで, 実測角の抜けを埋めたコマ (state_source が 1 または 2) の数と割合。\n" 120 "`python3 pi05/diag_fill_flags.py` で作った。データセットは読むだけ。作り直しは /tmp。\n\n" 121 "- state_source: 0 = 実測角 / 1 = 動いた抜けを埋めた値 / 2 = 動かなかった抜けを埋めた値\n" 122 "- filled_ratio = (1 と 2 のコマ) / 全コマ。filled_motion_steps は 1 のコマの数\n" 123 "- status が ok でない本 (作り直した state / actions / t がデータセットと一致しない・作り直せない) は数えない\n" 124 "- episodes.csv: 本ごと / summary.csv: データセットごと (max_episode = 割合がいちばん多い本)\n") 125 print(f"→ {out_dir}") 126 return 0 127 128 129 if __name__ == "__main__": 130 sys.exit(main()) git: warning: confstr() failed with code 5: couldn't get path of DARWIN_USER_TEMP_DIR; using /tmp instead git: error: couldn't create cache file '/tmp/xcrun_db-2alXXSXW' (errno=Operation not permitted) git: warning: confstr() failed with code 5: couldn't get path of DARWIN_USER_TEMP_DIR; using /tmp instead git: error: couldn't create cache file '/tmp/xcrun_db-xU66tj9U' (errno=Operation not permitted) M dynamic_tracking_limits/diag/j4_probe.py M dynamic_tracking_limits/drag_teaching/waypoint_streaming_replay.py M dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_pick_02.json M dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_pick_03.json M dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_pick_04.json M dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_pick_06.json M dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_pick_07.json M dynamic_tracking_limits/place/place_modules/06f_top_white_box_detect_v7.py M observe/emit.py M observe/static/index.html M pi05/DEEP_DEMOS.md M pi05/build_correction_episodes.py M pi05/policy_recorder.py M visual_servo_pick.py ?? AGENTS.md ?? DAY181_FIX_BENCH_MAC.md ?? DAY181_FIX_BENCH_MAC_SHELL.md ?? DAY181_FIX_DAEMON_STDOUT.md ?? DAY181_TASK_BENCH_MAC.md ?? analyze_rotation_log06.py ?? archive/ ?? block_positions.csv ?? calibrate_homography.py.bak_DAY168_pre_unified ?? calibrate_visual_servo.py ?? calibrate_z_axis_DAY189.py ?? calibrate_z_axis_DAY191_descend.py ?? calibration_reference.md ?? calibration_visual_servo_20260428_184513.csv ?? calibration_visual_servo_20260428_190234.csv ?? calibration_visual_servo_20260428_190453.csv ?? calibration_visual_servo_20260428_191234.csv ?? calibration_z_axis_DAY189_20260505_184248.csv ?? calibration_z_axis_DAY189_20260505_184444.csv ?? calibration_z_axis_DAY189_20260505_185644.csv ?? calibration_z_axis_DAY191_descend_pose_20260506_192217.csv ?? calibration_z_axis_DAY191_descend_pose_20260621_173245.csv ?? calibration_z_axis_DAY191_descend_pose_20260621_173839.csv ?? calibration_z_axis_DAY191_descend_pose_20260621_174508.csv ?? camera_check.py ?? camera_judge.py ?? capture_top_frames.py ?? capture_top_frames_log06.py ?? capture_top_frames_log07.py ?? capture_top_frames_log08.py ?? capture_white_box_templates.py ?? check_camera.py ?? claude_code_reports/ ?? close_gripper.py ?? collect_block_positions.py ?? debug_auto/ ?? debug_calib/ ?? debug_camera_orientation.py ?? debug_detection.png ?? debug_detection.py ?? debug_mat_corner/ ?? debug_mat_corners.py ?? debug_noise_test/ ?? debug_snapshots/ ?? debug_visual_servo/ ?? detect_block_position.py ?? detect_blue_markers.py ?? detect_cover_corners_log07.py ?? detect_cover_edges_log07.py ?? detect_on_mat.py ?? detection_noise_test.py ?? diag_stage2_send.py ?? docs/diff_20261019_items1-8.txt ?? docs/diff_20261019_minabort.txt ?? docs/diff_20261019_r10_gripper.txt ?? docs/diff_20261019_r10fix.txt ?? docs/diff_20261019_r11fix.txt ?? docs/diff_20261019_shoulderfix.txt ?? docs/investigation_20261019_stageC_daemon_latency.md ?? docs/procedure_20261019_stageC_record_teach_demo.md ?? docs/review_request_20261018_wpsr_grip_push_hold.md ?? docs/review_request_20261019_r11_mainline_alignment.md ?? docs/review_request_20261019_record_teach_demo.md ?? docs/review_request_20261101_servo_check.md ?? docs/review_request_20261101_servo_check_r2.md ?? docs/review_result_20261018_wpsr_grip_push_hold_codex.md ?? docs/review_result_20261019_r11_codex.md ?? docs/review_result_20261019_r11b_codex.md ?? docs/review_result_20261019_r12_codex.md ?? docs/review_result_20261019_r13_codex.md ?? docs/review_result_20261019_record_teach_demo_codex.md ?? docs/review_result_20261019_record_teach_demo_codex_r10.md ?? docs/review_result_20261019_record_teach_demo_codex_r10b.md ?? docs/review_result_20261019_record_teach_demo_codex_r2.md ?? docs/review_result_20261019_record_teach_demo_codex_r3.md ?? docs/review_result_20261019_record_teach_demo_codex_r4.md ?? docs/review_result_20261019_record_teach_demo_codex_r6.md ?? docs/review_result_20261019_record_teach_demo_codex_r7.md ?? docs/review_result_20261019_record_teach_demo_codex_r8.md ?? docs/review_result_20261019_record_teach_demo_codex_r9.md ?? docs/review_result_20261101_servo_check_codex.md ?? dryrun_check.py ?? dynamic_pick_correct_20260428_121924.csv ?? dynamic_pick_correct_20260428_124241.csv ?? dynamic_pick_verify_20260428_105412.csv ?? dynamic_pick_verify_auto_20260428_111229.csv ?? dynamic_pick_verify_auto_20260428_111649.csv ?? dynamic_pick_verify_auto_20260428_113234.csv ?? dynamic_tracking_limits/VLM_REPO_INVENTORY.md ?? dynamic_tracking_limits/diag/j4_home_only.py ?? dynamic_tracking_limits/diag/j4_probe.py.bak_DAY239_pre_oneway ?? dynamic_tracking_limits/diag/logs/ ?? dynamic_tracking_limits/drag_teaching/_archive/ ?? dynamic_tracking_limits/drag_teaching/check_teaching_pose.py ?? dynamic_tracking_limits/drag_teaching/grasp_lift_pick_then_place.py ?? dynamic_tracking_limits/drag_teaching/grasp_lift_test.py ?? dynamic_tracking_limits/drag_teaching/record_teach_demo.py ?? dynamic_tracking_limits/drag_teaching/record_teach_demo.py.bak_pre_req121_20261108 ?? dynamic_tracking_limits/drag_teaching/record_teach_demo.py.bak_pre_req152_20261111 ?? dynamic_tracking_limits/drag_teaching/record_teach_demo.py.bak_pre_req156_20261112 ?? dynamic_tracking_limits/drag_teaching/replay_z_postures.py ?? dynamic_tracking_limits/drag_teaching/replay_z_postures.py.bak_DAY243_pre_none_safe ?? dynamic_tracking_limits/drag_teaching/replay_z_simple.py ?? dynamic_tracking_limits/logs/j0_sweep/_INDEX.md ?? dynamic_tracking_limits/logs/j0_sweep/j0_pick_sweep20_01.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_pick_sweep20_02.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_pick_sweep20_03.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_adopted/ ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_pick_01.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_pick_05.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_pick_08.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_pick_09.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_pick_10.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_pick_11.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_place_01.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_place_02.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_place_03.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_place_04.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_place_05.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_place_06.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_place_07.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_place_08.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_place_09.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_place_10.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_place_11.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_place_12.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_place_13.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_place_14.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_place_15.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_place_16.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_place_17.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_place_18.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_place_19.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_place_20.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_place_21.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_place_22.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_place_23.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_classified/ ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_pick_01.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_pick_02.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_pick_03.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_pick_04.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_pick_05.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_pick_06.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_pick_07.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_pick_08.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_pick_09.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_pick_10.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_pick_11.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_pick_12.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_pick_13.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_pick_14.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_pick_15.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_pick_16.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_pick_17.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_pick_18.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_pick_19.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_pick_20.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_pick_21.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_pick_22.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_pick_23.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_pick_24.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_pick_25.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_pick_simple_01.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_pick_simple_02.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_place_01.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_place_02.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_place_03.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_place_04.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_place_05.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_place_06.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_place_07.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_place_08.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_place_09.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_place_10.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_place_11.json ?? dynamic_tracking_limits/logs/j0_sweep/j0_sweep_place_12.json ?? dynamic_tracking_limits/logs/place_capture_20260521_150159_side_1.png ?? dynamic_tracking_limits/logs/place_capture_20260521_150159_side_2.png ?? dynamic_tracking_limits/logs/place_capture_20260521_150159_side_3.png ?? dynamic_tracking_limits/logs/place_capture_20260521_150159_side_4.png ?? dynamic_tracking_limits/logs/place_capture_20260521_150159_side_5.png ?? dynamic_tracking_limits/logs/place_capture_20260521_150159_top_1.png ?? dynamic_tracking_limits/logs/place_capture_20260521_150159_top_2.png ?? dynamic_tracking_limits/logs/place_capture_20260521_150159_top_3.png ?? dynamic_tracking_limits/logs/place_capture_20260521_150159_top_4.png ?? dynamic_tracking_limits/logs/place_capture_20260521_150159_top_5.png ?? dynamic_tracking_limits/logs/run_pick_place/ ?? dynamic_tracking_limits/logs/vlm_framing_test/ ?? dynamic_tracking_limits/place/diag_scripts/ ?? dynamic_tracking_limits/place/place_modules/30mm ?? dynamic_tracking_limits/place/place_modules/J0_SWEEP_HOWTO.md ?? dynamic_tracking_limits/place/place_modules/_archive/ ?? dynamic_tracking_limits/place/place_modules/corr_map_server.py ?? dynamic_tracking_limits/place/place_modules/diag_place_z_move.py ?? dynamic_tracking_limits/place/place_modules/handover_pose_step.py ?? dynamic_tracking_limits/place/place_modules/j0_lookup.py ?? dynamic_tracking_limits/place/place_modules/j4_isolation_test.py ?? dynamic_tracking_limits/place/place_modules/place_j0_sweep_20_scan.py ?? dynamic_tracking_limits/place/place_modules/preview_place_delta.py ?? dynamic_tracking_limits/place/place_modules/recorder.py.bak_20261015_pre_top_camera ?? dynamic_tracking_limits/place/place_modules/run_pick_place.py.bak_20261015_pre_record_demo ?? dynamic_tracking_limits/place/place_modules/run_pick_place.py.bak_20261016_pre_freeze_height ?? dynamic_tracking_limits/place/place_modules/run_pick_place.py.bak_DAY239_pre_observe_emit ?? dynamic_tracking_limits/place/place_modules/run_pick_place.py.bak_DAY239_pre_revert_skip6 ?? dynamic_tracking_limits/place/place_modules/run_pick_place.py.bak_DAY239_pre_stage7_tol ?? dynamic_tracking_limits/place/place_modules/run_pick_place.py.bak_DAY241_pre_block_place ?? dynamic_tracking_limits/place/place_modules/run_pick_place.py.bak_DAY241_pre_blockbox_emit ?? dynamic_tracking_limits/place/place_modules/run_pick_place.py.bak_DAY241_pre_codex_fix ?? dynamic_tracking_limits/place/place_modules/run_pick_place.py.bak_DAY241_pre_dry_skip_ledger ?? dynamic_tracking_limits/place/place_modules/run_pick_place.py.bak_DAY241_pre_in_box ?? dynamic_tracking_limits/place/place_modules/run_pick_place.py.bak_DAY241_pre_ledger ?? dynamic_tracking_limits/place/place_modules/run_pick_place.py.bak_DAY241_pre_place_skip_unknown ?? dynamic_tracking_limits/place/place_modules/run_pick_place.py.bak_DAY241_pre_regrasp_block_sync ?? dynamic_tracking_limits/place/place_modules/run_pick_place.py.bak_DAY241_pre_stage_emit ?? dynamic_tracking_limits/place/place_modules/run_pick_place.py.bak_DAY241_pre_swept_tol ?? dynamic_tracking_limits/place/place_modules/run_pick_place.py.bak_DAY241_pre_tip_measure ?? dynamic_tracking_limits/place/place_modules/run_pick_place.py.bak_DAY241_pre_verdict_emit ?? dynamic_tracking_limits/place/place_modules/run_pick_place.py.bak_DAY242_pre_aggregate ?? dynamic_tracking_limits/place/place_modules/run_pick_place.py.bak_DAY242_pre_caps ?? dynamic_tracking_limits/place/place_modules/run_pick_place.py.bak_DAY242_pre_tip_panel ?? dynamic_tracking_limits/place/place_modules/run_pick_place.py.bak_DAY243_pre_lift_back_tol ?? dynamic_tracking_limits/place/place_modules/static_corr_map/ ?? dynamic_tracking_limits/place/place_modules/teach_place_poses.py ?? dynamic_tracking_limits/place/place_modules/vlm_framing_test.py ?? "dynamic_tracking_limits/place/place_modules/\347\240\264\347\266\273\351\226\276\345\200\244" ?? dynamic_tracking_limits/place/scan_input_place_lowz_DAY281.csv ?? dynamic_tracking_limits/place/templates/ ?? dynamic_tracking_limits/place/templates_old_rough/ ?? dynamic_tracking_limits/place/templates_skewed/ ?? evaluate_matches_log07.py ?? experiments/grip_hold_capture_diag.py ?? experiments/hand_view_check.py ?? experiments/place_hole_fill_in_DAY265.py ?? experiments/place_hole_map_DAY265.py ?? experiments/place_hole_map_v3_merge_DAY265.py ?? experiments/place_seed_clusters_DAY265.py ?? fk_calibration_result_20260428_101335.csv ?? fk_calibration_result_20260428_102305.csv ?? fk_scan_calibration.csv ?? fk_scan_calibration.py ?? fk_scan_lowerleft_dense.csv ?? fk_scan_motion_based.csv.bak_DAY154 ?? fk_scan_motion_based.csv.bak_DAY155 ?? fk_scan_motion_based.csv.bak_DAY170_pre_overwrite_20260425_151008 ?? fresh_mode_bench_mac.py ?? fresh_mode_bench_pi.py ?? fresh_mode_daemon.py ?? fresh_mode_sweep_pi.py ?? generate_grid_angles.py ?? grid_angles.csv ?? gripper_check.py ?? homography.npy.bak_20260420_181438 ?? homography.npy.bak_20260424_194547 ?? interpolate_motion.py ?? j0_send_test.py ?? judge_frame.jpg ?? logs/20260417_1500.md ?? logs/20260417_summary.md ?? logs/20260417_verify_y_fix.md ?? logs/20260803_0006.md ?? logs/20260807_0757.md ?? logs/20260807_0801.md ?? logs/20260807_0808.md ?? logs/20260807_0831.md ?? logs/20260807_0836.md ?? logs/20260807_0840.md ?? logs/20260807_0859.md ?? logs/20260807_0939.md ?? logs/20260807_0959.md ?? logs/20260807_1013.md ?? logs/20260807_1034.md ?? logs/20260807_1055.md ?? logs/20260807_1224.md ?? logs/20261018_1901.md ?? logs/20261019_1139.md ?? logs/20261019_1826.md ?? logs/20261019_1852.md ?? logs/20261019_1930.md ?? logs/20261021_0839.md ?? logs/20261021_0912.md ?? logs/20261029_2026.md ?? logs/20261030_1415.md ?? logs/20261030_1750.md ?? logs/20261101_1100.md ?? logs/20261109_1250.md ?? logs/20261109_1325.md ?? logs/20261109_1600.md ?? logs/20261109_1800.md ?? logs/20261109_2120.md ?? logs/20261110_1740.md ?? logs/20261110_2105.md ?? logs/20261110_2155.md ?? logs/20261110_2240.md ?? logs/20261111_1140.md ?? logs/20261112_1219.md ?? logs/20261113_2200.md ?? logs/20261114_0446.md ?? logs/20261114_0743.md ?? logs/20261114_1916.md ?? logs/20261114_1928.md ?? logs/20261114_1940.md ?? logs/20261114_2052.md ?? logs/20261114_2240.md ?? logs/20261114_2245.md ?? logs/20261114_2250.md ?? logs/20261114_2300.md ?? logs/20261114_2308.md ?? logs/20261114_2313.md ?? logs/20261114_2315.md ?? logs/20261114_2320.md ?? logs/20261114_2324.md ?? logs/20261114_2329.md ?? logs/DAY153_approach_addition.md ?? logs/DAY153_camera_index_fix.md ?? logs/DAY153_detection_debug.md ?? logs/DAY153_detection_fix.md ?? logs/DAY153_implementation_summary.md ?? logs/DAY153_pre_summary.md ?? logs/DAY153_self_check.md ?? logs/DAY154_place_dynamic.md ?? logs/DAY154_scan_setup.md ?? logs/DAY154_scan_verify.md ?? logs/DAY158_rename_summary.md ?? logs/DAY169_tipbrep_reader_creation.log ?? logs/DAY169_verify_lookup.log ?? logs/calib_frames/ ?? logs/debug_frames/ ?? logs/debug_side_white_mask_20260519_194345.jpg ?? logs/debug_side_white_mask_20260519_194408.jpg ?? logs/debug_side_white_mask_20260519_194441.jpg ?? logs/debug_side_white_mask_20260519_194458.jpg ?? logs/debug_side_white_mask_20260519_194518.jpg ?? logs/debug_side_white_mask_20260519_194543.jpg ?? logs/debug_side_white_mask_20260519_194606.jpg ?? logs/debug_side_white_mask_20260519_194620.jpg ?? logs/debug_side_white_mask_20260519_194624.jpg ?? logs/debug_side_white_mask_20260519_194642.jpg ?? logs/debug_white_score_DAY209_20260519_190850.jpg ?? logs/debug_white_score_DAY209_20260519_190915.jpg ?? logs/debug_white_score_DAY209_20260519_190928.jpg ?? logs/debug_white_score_DAY209_20260519_190942.jpg ?? logs/debug_white_score_DAY209_20260519_190957.jpg ?? logs/debug_white_score_DAY209_20260519_191117.jpg ?? logs/debug_white_score_DAY209_20260519_191130.jpg ?? logs/debug_white_score_DAY209_20260519_191142.jpg ?? logs/debug_white_score_DAY209_20260519_191154.jpg ?? logs/debug_white_score_DAY209_20260519_191337.jpg ?? logs/debug_white_score_DAY209_20260519_191347.jpg ?? logs/debug_white_score_DAY209_20260519_191358.jpg ?? logs/debug_white_score_DAY209_20260519_191413.jpg ?? logs/debug_white_score_DAY209_20260519_191424.jpg ?? logs/debug_white_score_DAY209_20260519_191435.jpg ?? logs/debug_white_score_DAY209_20260519_192857.jpg ?? logs/debug_white_score_DAY209_20260519_193136.jpg ?? logs/debug_white_score_DAY209_20260519_193202.jpg ?? logs/debug_white_score_DAY209_20260519_193228.jpg ?? logs/debug_white_score_DAY209_20260519_193254.jpg ?? logs/debug_white_score_DAY209_20260519_193318.jpg ?? logs/debug_white_score_DAY209_20260519_193348.jpg ?? logs/descend_log_20260602_183303.csv ?? logs/descend_log_20260602_183726.csv ?? logs/descend_log_20260602_184021.csv ?? logs/descend_log_20260602_184121.csv ?? logs/descend_log_20260602_184405.csv ?? logs/descend_log_20260602_195623.csv ?? logs/descend_log_20260602_200931.csv ?? logs/descend_log_20260602_201627.csv ?? logs/descend_log_20260603_103022.csv ?? logs/descend_log_20260603_121403.csv ?? logs/descend_log_20260603_121543.csv ?? logs/descend_log_20260603_122414.csv ?? logs/descend_log_20260603_122519.csv ?? logs/descend_log_20260603_130502.csv ?? logs/descend_log_20260603_135148.csv ?? logs/descend_log_20260603_142211.csv ?? logs/descend_log_20260603_142550.csv ?? logs/descend_log_20260603_142711.csv ?? logs/descend_log_20260603_143427.csv ?? logs/descend_log_20260603_164819.csv ?? logs/descend_log_20260603_172047.csv ?? logs/descend_log_20260603_172141.csv ?? logs/descend_log_20260603_181621.csv ?? logs/descend_log_20260603_181833.csv ?? logs/descend_log_20260603_182100.csv ?? logs/descend_log_20260603_182254.csv ?? logs/descend_log_20260603_182424.csv ?? logs/descend_log_20260603_182542.csv ?? logs/descend_log_20260603_182700.csv ?? logs/descend_log_20260603_182816.csv ?? logs/descend_log_20260603_182939.csv ?? logs/descend_log_20260603_183131.csv ?? logs/descend_log_20260604_100440.csv ?? logs/descend_log_20260604_100604.csv ?? logs/descend_log_20260604_100753.csv ?? logs/descend_log_20260604_100924.csv ?? logs/descend_log_20260604_101105.csv ?? logs/descend_log_20260604_101232.csv ?? logs/descend_log_20260604_102108.csv ?? logs/descend_log_20260604_103759.csv ?? logs/descend_log_20260604_105959.csv ?? logs/descend_log_20260606_191135.csv ?? logs/descend_log_20260606_191454.csv ?? logs/descend_log_20260606_191620.csv ?? logs/descend_log_20260606_191746.csv ?? logs/descend_log_20260606_194001.csv ?? logs/descend_log_20260606_194546.csv ?? logs/descend_log_20260606_201548.csv ?? logs/descend_log_20260606_201857.csv ?? logs/descend_log_20260606_202158.csv ?? logs/descend_log_20260606_202542.csv ?? logs/descend_log_20260606_202803.csv ?? logs/descend_log_20260606_203035.csv ?? logs/descend_log_20260606_203358.csv ?? logs/detect_place_sample_01_box_right_far.jpg ?? logs/detect_place_sample_02_box_right_far_v2.jpg ?? logs/detect_place_sample_03_box_left_far.jpg ?? logs/detect_place_sample_04_box_left_close.jpg ?? logs/detect_place_sample_05_correct_position.jpg ?? logs/joint_debug.md ?? logs/link6_debug.md ?? logs/lookup_test_20260417_1834.txt ?? logs/place_align_log_20260603_122421.csv ?? logs/place_align_log_20260603_122531.csv ?? logs/place_align_log_20260603_142602.csv ?? logs/place_align_log_20260603_143441.csv ?? logs/place_release_trials.csv ?? logs/place_test_20260519_210457.csv ?? logs/place_test_20260519_210457.txt ?? logs/place_test_20260519_211301.csv ?? logs/place_test_20260519_211301.txt ?? logs/place_test_20260519_211511.csv ?? logs/place_test_20260519_211511.txt ?? logs/place_test_20260519_211550.csv ?? logs/place_test_20260519_211550.txt ?? logs/place_test_20260519_211633.csv ?? logs/place_test_20260519_211633.txt ?? logs/place_test_20260519_211639.csv ?? logs/place_test_20260519_211639.txt ?? logs/place_test_20260519_211905.csv ?? logs/place_test_20260519_211905.txt ?? logs/place_test_20260519_212654.csv ?? logs/place_test_20260519_212654.txt ?? logs/place_test_20260519_212812.csv ?? logs/place_test_20260519_212812.txt ?? logs/place_test_20260519_213204.csv ?? logs/place_test_20260519_213204.txt ?? logs/place_test_20260519_213323.csv ?? logs/place_test_20260519_213323.txt ?? logs/place_test_20260519_213543.csv ?? logs/place_test_20260519_213543.txt ?? logs/place_test_20260519_213619.csv ?? logs/place_test_20260519_213619.txt ?? logs/place_test_20260519_213703.csv ?? logs/place_test_20260519_213703.txt ?? logs/place_test_20260519_213923.csv ?? logs/place_test_20260519_213923.txt ?? logs/place_test_20260519_214020.csv ?? logs/place_test_20260519_214020.txt ?? logs/place_test_20260519_214200.csv ?? logs/place_test_20260519_214200.txt ?? logs/place_test_20260520_101000.csv ?? logs/place_test_20260520_101000.txt ?? logs/place_test_20260520_101102.csv ?? logs/place_test_20260520_101102.txt ?? logs/place_test_20260520_101215.csv ?? logs/place_test_20260520_101215.txt ?? logs/place_test_20260520_101247.csv ?? logs/place_test_20260520_101247.txt ?? logs/place_test_20260520_103914.csv ?? logs/place_test_20260520_103914.txt ?? logs/place_test_20260520_103928.csv ?? logs/place_test_20260520_103928.txt ?? logs/place_test_20260520_104457.csv ?? logs/place_test_20260520_104457.txt ?? logs/place_test_20260520_105102.csv ?? logs/place_test_20260520_105102.txt ?? logs/place_test_20260520_105417.csv ?? logs/place_test_20260520_105417.txt ?? logs/place_test_20260520_105427.csv ?? logs/place_test_20260520_105427.txt ?? logs/place_test_20260520_105514.csv ?? logs/place_test_20260520_105514.txt ?? logs/place_test_20260520_105530.csv ?? logs/place_test_20260520_105530.txt ?? logs/place_test_20260520_105825.csv ?? logs/place_test_20260520_105825.txt ?? logs/place_test_20260520_110424.csv ?? logs/place_test_20260520_110424.txt ?? logs/place_test_20260520_110439.csv ?? logs/place_test_20260520_110439.txt ?? logs/place_test_20260520_110731.csv ?? logs/place_test_20260520_110731.txt ?? logs/place_test_20260520_111024.csv ?? logs/place_test_20260520_111024.txt ?? logs/place_test_20260520_111106.csv ?? logs/place_test_20260520_111106.txt ?? logs/place_test_20260520_111905.csv ?? logs/place_test_20260520_111905.txt ?? logs/place_test_20260520_111923.csv ?? logs/place_test_20260520_111923.txt ?? logs/place_test_20260520_112204.csv ?? logs/place_test_20260520_112204.txt ?? logs/place_test_20260520_112249.csv ?? logs/place_test_20260520_112249.txt ?? logs/place_test_20260520_112305.csv ?? logs/place_test_20260520_112305.txt ?? logs/place_test_20260520_112320.csv ?? logs/place_test_20260520_112320.txt ?? logs/place_test_20260520_112610.csv ?? logs/place_test_20260520_112610.txt ?? logs/place_test_20260520_112626.csv ?? logs/place_test_20260520_112626.txt ?? logs/place_test_20260520_112709.csv ?? logs/place_test_20260520_112709.txt ?? logs/place_test_20260520_112751.csv ?? logs/place_test_20260520_112751.txt ?? logs/place_test_20260520_112835.csv ?? logs/place_test_20260520_112835.txt ?? logs/place_test_20260520_113311.csv ?? logs/place_test_20260520_113311.txt ?? logs/place_test_20260520_113311_cleanup_home_side.png ?? logs/place_test_20260520_113311_cleanup_home_top.png ?? logs/place_test_20260520_113330.csv ?? logs/place_test_20260520_113330.txt ?? logs/place_test_20260520_113330_cleanup_home_side.png ?? logs/place_test_20260520_113330_cleanup_home_top.png ?? logs/place_test_20260520_113330_phase0_home_side.png ?? logs/place_test_20260520_113330_phase0_home_top.png ?? logs/place_test_20260520_113330_phase2_approach_side.png ?? logs/place_test_20260520_113330_phase2_approach_top.png ?? logs/place_test_20260520_113716.csv ?? logs/place_test_20260520_113716.txt ?? logs/place_test_20260520_113716_cleanup_home_side.png ?? logs/place_test_20260520_113716_cleanup_home_top.png ?? logs/place_test_20260520_113716_phase0_home_side.png ?? logs/place_test_20260520_113716_phase0_home_top.png ?? logs/place_test_20260520_113716_phase2_approach_side.png ?? logs/place_test_20260520_113716_phase2_approach_top.png ?? logs/place_test_20260520_113835.csv ?? logs/place_test_20260520_113835.txt ?? logs/place_test_20260520_113835_cleanup_home_side.png ?? logs/place_test_20260520_113835_cleanup_home_top.png ?? logs/place_test_20260520_113835_phase0_home_side.png ?? logs/place_test_20260520_113835_phase0_home_top.png ?? logs/place_test_20260520_113835_phase2_approach_side.png ?? logs/place_test_20260520_113835_phase2_approach_top.png ?? logs/place_test_20260520_114124.csv ?? logs/place_test_20260520_114124.txt ?? logs/place_test_20260520_114124_cleanup_home_side.png ?? logs/place_test_20260520_114124_cleanup_home_top.png ?? logs/place_test_20260520_114141.csv ?? logs/place_test_20260520_114141.txt ?? logs/place_test_20260520_114141_cleanup_home_side.png ?? logs/place_test_20260520_114141_cleanup_home_top.png ?? logs/place_test_20260520_114141_phase0_home_side.png ?? logs/place_test_20260520_114141_phase0_home_top.png ?? logs/place_test_20260520_114141_phase2_approach_side.png ?? logs/place_test_20260520_114141_phase2_approach_top.png ?? logs/place_test_20260520_114449.csv ?? logs/place_test_20260520_114449.txt ?? logs/place_test_20260520_114449_cleanup_home_side.png ?? logs/place_test_20260520_114449_cleanup_home_top.png ?? logs/place_test_20260520_114507.csv ?? logs/place_test_20260520_114507.txt ?? logs/place_test_20260520_114507_cleanup_home_side.png ?? logs/place_test_20260520_114507_cleanup_home_top.png ?? logs/place_test_20260520_114507_phase0_home_side.png ?? logs/place_test_20260520_114507_phase0_home_top.png ?? logs/place_test_20260520_114507_phase2_approach_side.png ?? logs/place_test_20260520_114507_phase2_approach_top.png ?? logs/place_test_20260520_114634.csv ?? logs/place_test_20260520_114634.txt ?? logs/place_test_20260520_114634_cleanup_home_side.png ?? logs/place_test_20260520_114634_cleanup_home_top.png ?? logs/place_test_20260520_114650.csv ?? logs/place_test_20260520_114650.txt ?? logs/place_test_20260520_114650_cleanup_home_side.png ?? logs/place_test_20260520_114650_cleanup_home_top.png ?? logs/place_test_20260520_114650_phase0_home_side.png ?? logs/place_test_20260520_114650_phase0_home_top.png ?? logs/place_test_20260520_114650_phase2_approach_side.png ?? logs/place_test_20260520_114650_phase2_approach_top.png ?? logs/place_test_20260520_114947.csv ?? logs/place_test_20260520_114947.txt ?? logs/place_test_20260520_114947_cleanup_home_side.png ?? logs/place_test_20260520_114947_cleanup_home_top.png ?? logs/place_test_20260520_115003.csv ?? logs/place_test_20260520_115003.txt ?? logs/place_test_20260520_115003_cleanup_home_side.png ?? logs/place_test_20260520_115003_cleanup_home_top.png ?? logs/place_test_20260520_115003_phase0_home_side.png ?? logs/place_test_20260520_115003_phase0_home_top.png ?? logs/place_test_20260520_115003_phase2_approach_side.png ?? logs/place_test_20260520_115003_phase2_approach_top.png ?? logs/place_test_20260520_115124.csv ?? logs/place_test_20260520_115124.txt ?? logs/place_test_20260520_115124_cleanup_home_side.png ?? logs/place_test_20260520_115124_cleanup_home_top.png ?? logs/place_test_20260520_115140.csv ?? logs/place_test_20260520_115140.txt ?? logs/place_test_20260520_115140_cleanup_home_side.png ?? logs/place_test_20260520_115140_cleanup_home_top.png ?? logs/place_test_20260520_115214.csv ?? logs/place_test_20260520_115214.txt ?? logs/place_test_20260520_115214_cleanup_home_side.png ?? logs/place_test_20260520_115214_cleanup_home_top.png ?? logs/place_test_20260520_115308.csv ?? logs/place_test_20260520_115308.txt ?? logs/place_test_20260520_115308_cleanup_home_side.png ?? logs/place_test_20260520_115308_cleanup_home_top.png ?? logs/place_test_20260520_115325.csv ?? logs/place_test_20260520_115325.txt ?? logs/place_test_20260520_115325_cleanup_home_side.png ?? logs/place_test_20260520_115325_cleanup_home_top.png ?? logs/place_test_20260520_115325_phase0_home_side.png ?? logs/place_test_20260520_115325_phase0_home_top.png ?? logs/place_test_20260520_115325_phase2_approach_side.png ?? logs/place_test_20260520_115325_phase2_approach_top.png ?? logs/place_test_20260520_115413.csv ?? logs/place_test_20260520_115413.txt ?? logs/place_test_20260520_115413_cleanup_home_side.png ?? logs/place_test_20260520_115413_cleanup_home_top.png ?? logs/place_test_20260520_115429.csv ?? logs/place_test_20260520_115429.txt ?? logs/place_test_20260520_115429_cleanup_home_side.png ?? logs/place_test_20260520_115429_cleanup_home_top.png ?? logs/place_test_20260520_115429_phase0_home_side.png ?? logs/place_test_20260520_115429_phase0_home_top.png ?? logs/place_test_20260520_115429_phase2_approach_side.png ?? logs/place_test_20260520_115429_phase2_approach_top.png ?? logs/place_test_20260520_115823.csv ?? logs/place_test_20260520_115823.txt ?? logs/place_test_20260520_115823_cleanup_home_side.png ?? logs/place_test_20260520_115823_cleanup_home_top.png ?? logs/place_test_20260520_115840.csv ?? logs/place_test_20260520_115840.txt ?? logs/place_test_20260520_115840_cleanup_home_side.png ?? logs/place_test_20260520_115840_cleanup_home_top.png ?? logs/place_test_20260520_115840_phase0_home_side.png ?? logs/place_test_20260520_115840_phase0_home_top.png ?? logs/place_test_20260520_115840_phase2_approach_side.png ?? logs/place_test_20260520_115840_phase2_approach_top.png ?? logs/place_test_20260520_115929.csv ?? logs/place_test_20260520_115929.txt ?? logs/place_test_20260520_115929_cleanup_home_side.png ?? logs/place_test_20260520_115929_cleanup_home_top.png ?? logs/place_test_20260520_115929_phase0_home_side.png ?? logs/place_test_20260520_115929_phase0_home_top.png ?? logs/place_test_20260520_115929_phase2_approach_side.png ?? logs/place_test_20260520_115929_phase2_approach_top.png ?? logs/place_test_20260520_120021.csv ?? logs/place_test_20260520_120021.txt ?? logs/place_test_20260520_120021_cleanup_home_side.png ?? logs/place_test_20260520_120021_cleanup_home_top.png ?? logs/place_test_20260520_120021_phase0_home_side.png ?? logs/place_test_20260520_120021_phase0_home_top.png ?? logs/place_test_20260520_120021_phase2_approach_side.png ?? logs/place_test_20260520_120021_phase2_approach_top.png ?? logs/place_test_20260520_120319.csv ?? logs/place_test_20260520_120319.txt ?? logs/place_test_20260520_120319_cleanup_home_side.png ?? logs/place_test_20260520_120319_cleanup_home_top.png ?? logs/place_test_20260520_120319_phase0_home_side.png ?? logs/place_test_20260520_120319_phase0_home_top.png ?? logs/place_test_20260520_120319_phase2_approach_side.png ?? logs/place_test_20260520_120319_phase2_approach_top.png ?? logs/place_test_20260520_120939.csv ?? logs/place_test_20260520_120939.txt ?? logs/place_test_20260520_120939_cleanup_home_side.png ?? logs/place_test_20260520_120939_cleanup_home_top.png ?? logs/place_test_20260520_120939_phase0_home_side.png ?? logs/place_test_20260520_120939_phase0_home_top.png ?? logs/place_test_20260520_120939_phase2_approach_side.png ?? logs/place_test_20260520_120939_phase2_approach_top.png ?? logs/place_test_20260520_121820.csv ?? logs/place_test_20260520_121820.txt ?? logs/place_test_20260520_121820_cleanup_home_side.png ?? logs/place_test_20260520_121820_cleanup_home_top.png ?? logs/place_test_20260520_121820_phase0_home_side.png ?? logs/place_test_20260520_121820_phase0_home_top.png ?? logs/place_test_20260520_121820_phase2_approach_side.png ?? logs/place_test_20260520_121820_phase2_approach_top.png ?? logs/place_test_20260520_121906.csv ?? logs/place_test_20260520_121906.txt ?? logs/place_test_20260520_121906_cleanup_home_side.png ?? logs/place_test_20260520_121906_cleanup_home_top.png ?? logs/place_test_20260520_121906_phase0_home_side.png ?? logs/place_test_20260520_121906_phase0_home_top.png ?? logs/place_test_20260520_121906_phase2_approach_side.png ?? logs/place_test_20260520_121906_phase2_approach_top.png ?? logs/place_test_20260520_143701.csv ?? logs/place_test_20260520_143701.txt ?? logs/place_test_20260520_143701_phase0_home_side.png ?? logs/place_test_20260520_143701_phase0_home_top.png ?? logs/place_test_20260520_143747.csv ?? logs/place_test_20260520_143747.txt ?? logs/place_trials.csv ?? logs/req186/ ?? logs/shots_187/ ?? logs/template_learning.log ?? logs/variation_comparison.md ?? logs/verdict_seed_ai_20261114.txt ?? logs/verdict_viewer_194_panel.png ?? logs/verdict_viewer_server.log ?? logs/xyz_track_test_20260518_193810.csv ?? logs/xyz_track_test_20260518_195725.csv ?? logs/xyz_track_test_20260518_200435.csv ?? logs/xyz_track_test_20260518_201641.csv ?? logs/xyz_track_test_20260518_202130.csv ?? logs/xyz_track_test_20260518_202831.csv ?? logs/xyz_track_test_20260518_203221.csv ?? logs/xyz_track_test_20260518_203408.csv ?? logs/xyz_track_test_20260518_204420.csv ?? logs/xyz_track_test_20260518_204557.csv ?? logs/xyz_track_test_20260518_205032.csv ?? logs/xyz_track_test_20260518_205427.csv ?? logs/xyz_track_test_20260518_205616.csv ?? logs/xyz_track_test_20260518_210647.csv ?? logs/xyz_track_test_20260518_211232.csv ?? logs/xyz_track_test_20260518_211353.csv ?? logs/xyz_track_test_20260518_211544.csv ?? logs/xyz_track_test_20260518_211703.csv ?? logs/xyz_track_test_20260518_211939.csv ?? logs/xyz_track_test_20260518_212236.csv ?? logs/xyz_track_test_20260518_212335.csv ?? logs/xyz_track_test_20260518_212447.csv ?? logs/xyz_track_test_20260518_212744.csv ?? logs/xyz_track_test_20260518_213019.csv ?? logs/xyz_track_test_20260518_213513.csv ?? logs/xyz_track_test_20260518_213656.csv ?? logs/xyz_track_test_20260518_213811.csv ?? logs/xyz_track_test_20260518_214452.csv ?? logs/xyz_track_test_20260518_214651.csv ?? logs/xyz_track_test_20260518_214851.csv ?? logs/xyz_track_test_20260518_215212.csv ?? logs/xyz_track_test_20260518_215532.csv ?? logs/xyz_track_test_20260518_221313.csv ?? logs/y_calibration_20260516_200819.csv ?? logs/y_calibration_20260516_201220.csv ?? logs/y_calibration_20260516_201452.csv ?? logs/y_calibration_20260516_201634.csv ?? logs/y_calibration_20260516_202140.csv ?? logs/y_calibration_low_20260516_203456.csv ?? logs/y_calibration_mid_20260516_204525.csv ?? mat_corner_detection_result.png ?? mat_rectified.png ?? mat_rectify.py ?? match_features_log07.py ?? measure_baseline_log08.py ?? measure_contours_log06.py ?? measure_rectified_log08.py ?? mecharm_daemon.py.QUARANTINE_send_coords_DAY287 ?? mecharm_daemon.py.bak_pre_coords_20260711_213944 ?? mecharm_daemon.py.pi_candidate_20261019_LOG352 ?? mecharm_daemon.py.pi_candidate_v2_20261019_LOG352 ?? mecharm_daemon.py.pi_deployed_20261019_LOG352 ?? motion_completion_pi.py ?? move_to_home.py ?? move_to_pick.py ?? noise_test_20260502_125230.csv ?? noise_test_20260502_130537.csv ?? noise_test_20260502_130707.csv ?? noise_test_20260502_131309.csv ?? noise_test_20260502_131747.csv ?? noise_test_20260502_132515.csv ?? noise_test_20260502_132743.csv ?? observe/emit.py.bak_DAY239_pre_nonblocking ?? observe/emit.py.bak_DAY241_pre_block_place ?? observe/emit.py.bak_DAY241_pre_blockbox ?? observe/emit.py.bak_DAY241_pre_in_box ?? observe/emit.py.bak_DAY242_pre_caps ?? observe/emit.py.bak_DAY242_pre_tip_panel ?? observe/observe_server.py ?? observe/static/index.html.bak_DAY239_pre_glance_drilldown ?? observe/static/index.html.bak_DAY241_pre_arm_full_joints ?? observe/static/index.html.bak_DAY241_pre_dashboard_expand ?? observe/static/index.html.bak_DAY241_pre_gripper_coords ?? observe/static/index.html.bak_DAY241_pre_gripper_debounce ?? observe/static/index.html.bak_DAY241_pre_history ?? observe/static/index.html.bak_DAY241_pre_idle ?? observe/static/index.html.bak_DAY241_pre_inbox_latch ?? observe/static/index.html.bak_DAY241_pre_joints_glance ?? observe/static/index.html.bak_DAY241_pre_phase_latch ?? observe/static/index.html.bak_DAY241_pre_remove_arm ?? observe/static/index.html.bak_DAY241_pre_urdf_fk ?? observe/static/index.html.bak_DAY242_pre_caps ?? observe/static/index.html.bak_DAY242_pre_tip_panel ?? observe/static/index.html.bak_DAY247_pre_scrollfix ?? observe/static/index.html.bak_DAY247_pre_sidebarstretch ?? observe/static/index_pre_sidebar_20260620.html ?? observe/telemetry_probe.py ?? pi05/POWER_AB.md ?? pi05/build_deep_even10_v2.sh ?? pi05/build_demo_episodes.py.bak_pre_LOG352_20261019 ?? pi05/diag_fill_flags.py ?? pi05/pos5_lift_compare.py ?? pi05/power_ab_compare.py ?? pi05/test_build_deep_even10_v2.py ?? pi05/test_pos5_lift_compare.py ?? pi05/test_power_ab.py ?? pi05/test_state_source.py ?? "pi05/verdict_viewer/\345\210\244\345\256\232\343\201\256\347\224\273\351\235\242\343\202\222\351\226\213\343\201\217.command" ?? pick_and_place_fixed.py ?? pick_cover_corners_log07.py ?? pick_sheet_corners_log08.py ?? pipeline_timeline.html ?? place_test.py ?? place_test.py.bak ?? place_test.py.bak2 ?? place_test.py.bak3 ?? positions_clean.json ?? positions_now.json ?? probe_idle_send.py ?? probe_wb.py ?? r2r2r_dryrun.py ?? r2r2r_loop.py.bak_DAY159_pre_2point ?? r2r2r_loop.py.bak_DAY159_pre_dynamic ?? r2r2r_loop.py.bak_DAY159_pre_phaseC ?? r2r2r_loop.py.bak_DAY166_pre_homography ?? r2r2r_loop.py.bak_DAY166_pre_template_restore ?? r2r2r_loop.py.bak_DAY166_pre_whitehsv ?? r2r2r_loop.py.bak_DAY168_pre_camera_autodetect ?? r2r2r_loop_v2.py ?? ransac_only_log07.py ?? recalibrate_homography.py.bak_DAY168_pre_index_fix ?? recalibrate_homography.py.bak_DAY168_pre_unified ?? recalibrate_homography.py.sed_bak ?? rectify_sheet_log08.py ?? rectify_sheets_log06.py ?? results/ ?? run_pick_place.sh ?? sample_images/ ?? show_camera.py ?? test_blue_detect.py ?? test_day170_only_day171.py ?? test_day170_speed50_day171.py ?? test_ee_offset.py ?? test_gripper_only.py ?? test_j2_range_day173.py ?? test_joint_range_day173.py ?? test_joint_range_day173_v2.py ?? test_lookup_9points.py ?? test_pick_2points_day171.py ?? test_pick_2points_day171_sync.py ?? test_pick_day175.py ?? test_pick_new_csv_day171.py ?? test_place_day175.py ?? test_place_detection_offline.py ?? test_sequence_day175.py ?? test_side_camera_tip_detection.py ?? test_side_white_mask.py ?? test_white_box_score.py ?? tools/gamepad_check.py ?? tools/pi/servo_check_pi.py ?? tools/servo_check.sh ?? tools/test_servo_check.sh ?? tools/test_servo_check_pi.py ?? verify_dynamic_pick.py ?? verify_dynamic_pick_auto.py ?? verify_dynamic_pick_auto_correct.py ?? verify_fk_calibration.py ?? verify_homography.py.bak_DAY168_pre_unified ?? verify_lowerleft_scan.py ?? verify_y_direction.py ?? vision/ ?? visual_servo_20260502_084046.csv ?? visual_servo_20260502_181427.csv ?? visual_servo_20260502_183654.csv ?? visual_servo_20260502_205548.csv ?? visual_servo_20260502_211405.csv ?? visual_servo_20260503_071901.csv ?? visual_servo_20260503_073918.csv ?? visual_servo_20260503_083158.csv ?? visual_servo_20260506_082640.csv ?? visual_servo_20260506_082916.csv ?? visual_servo_20260506_194904.csv ?? visual_servo_20260514_223230.csv ?? visual_servo_20260514_224150.csv ?? visual_servo_20260514_224442.csv ?? visual_servo_20260514_225526.csv ?? visual_servo_20260514_233646.csv ?? visual_servo_20260515_212307.csv ?? visual_servo_pick.py.day180_backup ?? visual_servo_pick.py.day184_pre_debug_log ?? visual_servo_pick.py.day184_pre_descend_servo ?? visual_servo_pick.py.day184_pre_gripper_fix ?? visual_servo_pick.py.day184_pre_j1_gripper ?? visual_servo_pick.py.day184_pre_marker_fix ?? visual_servo_pick.py.day185_pre_2d_converge ?? visual_servo_pick.py.day185_pre_approach_height ?? visual_servo_pick.py.day185_pre_approach_redesign ?? visual_servo_pick.py.day185_pre_blue_fullscreen ?? visual_servo_pick.py.day185_pre_descend_fix ?? visual_servo_pick.py.day185_pre_dynamic ?? visual_servo_pick.py.day185_pre_fix_definitive ?? visual_servo_pick.py.day185_pre_j2_tune ?? visual_servo_pick.py.day185_pre_persist ?? visual_servo_pick.py.day185_pre_posture_unify ?? visual_servo_pick.py.day185_pre_revert ?? visual_servo_pick.py.day185_pre_sign_fix ?? visual_servo_pick.py.day185_pre_tight_threshold ?? visual_servo_pick.py.day185_pre_topmost ?? visual_servo_pick.py.day185_pre_visualize ?? visual_servo_pick.py.day185_pre_window_thread ?? visual_servo_pick.py.day186_pre_3joint_reach ?? visual_servo_pick.py.day186_pre_descend_j2_minus5 ?? visual_servo_pick.py.day186_pre_descend_obs ?? visual_servo_pick.py.day186_pre_imwrite_off ?? visual_servo_pick.py.day186_pre_limit_disable ?? visual_servo_pick.py.day186_pre_loop_speedup ?? visual_servo_pick.py.day186_pre_nonblock ?? visual_servo_pick.py.day186_pre_normal_limit_disable ?? visual_servo_pick.py.day186_pre_post_descend_refine ?? visual_servo_pick.py.day186_pre_refine_mode ?? visual_servo_pick.py.day186_pre_send_interval ?? visual_servo_pick.py.day186_pre_sleep_removal ?? visual_servo_pick.py.day186_pre_ssh_merge ?? visual_servo_pick.py.day186_pre_ssh_persist ?? visual_servo_pick.py.day186_pre_z_tracking ?? visual_servo_pick.py.day188_pre_z_sign_fix ?? visual_servo_pick.py.day189_pre_daemon ?? visual_servo_pick_architecture_2026-05-15.json ?? xyz_track_design.md ?? xyz_track_test.py ?? y_calibration.py codex - **P2** — [diag_fill_flags.py:98](/Users/shimazueiichi/r2r2r-scripts/pi05/diag_fill_flags.py:98):対象エピソードが0件だと `rows[0]` で異常終了します。先に出力ディレクトリが作られるため、再実行も「出力先がもうある」で拒否されます。空の場合も固定の列名でCSVを出力するか、ディレクトリ作成前に終了してください。 本体の変更には、指定条件に反する不具合は見つかりませんでした。印は補間と同じ区間条件を使い、選別後の `idx` に対応しています。 純粋計算の4テストは成功。実データ再生成によるバイト一致テストは未実施です。既存データセットは変更していません。 tokens used 22,414 - **P2** — [diag_fill_flags.py:98](/Users/shimazueiichi/r2r2r-scripts/pi05/diag_fill_flags.py:98):対象エピソードが0件だと `rows[0]` で異常終了します。先に出力ディレクトリが作られるため、再実行も「出力先がもうある」で拒否されます。空の場合も固定の列名でCSVを出力するか、ディレクトリ作成前に終了してください。 本体の変更には、指定条件に反する不具合は見つかりませんでした。印は補間と同じ区間条件を使い、選別後の `idx` に対応しています。 純粋計算の4テストは成功。実データ再生成によるバイト一致テストは未実施です。既存データセットは変更していません。