フィジカルAI研究室を作る Log#15 | mechArm 270 の失敗を巻き戻し、直して覚えさせる

この記事の素材(コード・ログ・データ 6ファイル・まとめてダウンロードあり)

Physical Intelligence の π0.5 で動かす小型ロボットアーム mechArm 270 の実機推論に、失敗した区間をアームの動きごと巻き戻すキーと、関節を1°ずつ直すキーを足し、直した動きだけを学習データとして取り出す仕組みを作りました。実機ではまだ動かしておらず、アームなしのテスト37件と、別の AI によるコードレビューを通ったところまでです。

π0.5(パイレイテンゴ)は、米国の Physical Intelligence 社が公開しているロボット用の AI のモデルです。上から見たカメラの画像と6つの関節の角度を受け取り、次の1秒ぶんの関節の角度を返します。人が手で教えた19回の動き(お手本)で学習させてあり、前の回(LOG401)では、3か所に5回ずつ置いた赤いブロックを、15回中9回白い箱に入れました。

残りの6回は失敗です。爪がブロックの奥に下りてつかみ損ねる、つかんで持ち上げた瞬間に落とす、といった失敗でした。今のやり方では、失敗した回は最初からやり直すしかなく、どこをどう直せばよかったかは AI に伝わりません。

そこで参考にしたのが、米国の MicroFactory という会社の、卓上のロボットセル(箱の中でアームが作業する装置)です。紹介動画では、ロボットがミスをしたら時間をさかのぼるように動きを巻き戻し、AI に動かさせたまま人が横から手を入れて直し、その直しを AI が覚えて次から同じミスをしなくなる、という流れを見せています。これを、リーダーアーム(人が手で動かす操作用のアーム)を持っていない mechArm 270 で、キーボードを使ってまねる形にしました。

考えていく途中で、はじめの思い込みが1つ外れました。記録に残った関節の角度の数字だけを直しても、学習データにはなりません。 学習データは写真と関節の角度の組で、写真には直す前の動きが写っているからです。直した動きは、カメラに手が写らない所から操作して、実機を動かしたまま撮る必要があります。MicroFactory の動画でも、人が握る操作用のアームは、ロボットが作業する場所の外に置かれていました。

やったことの全体は次のとおりです。

やったことなぜ結果
MicroFactory の動画と、前の回の失敗の記録を見比べ、mechArm 270 での直し方を決めた
失敗した回を最初からやり直すのではなく、失敗したところだけを直して AI に覚えさせるため
推論1回ぶんの区切りで巻き戻し、カメラの外のキーボードから関節を直す形に決めた
実機推論のプログラムに、巻き戻し(b キー)・関節の補正(c キー)・1秒10コマの記録を足した
失敗した区間に戻り、関節の一部だけを直して、その動きを写真と組で残すため
アームなしのテスト26件が通り、別の AI のレビューを3回通した
つかんだ区間も巻き戻せるようにし、人の手が写るコマを学習データから外した
失敗の中には、つかんだあとに落とす・箱にぶつかるものもあるため
テストは合わせて37件が通り、レビューの判定は「実機テストに進んでよい」
直した動きを学習用のエピソードにするスクリプトを作った
元のお手本19本に足して、π0.5 を学習し直すため
形はお手本とそろった。実機の記録がまだないので、データセットはまだ作っていない
LOG401 の位置E の5回目を上のカメラで撮ったコマ。左上が動き始め、右上が爪を閉じる直前(推論4回目)、左下が閉じたあと(推論5回目)、右下が推論6回目。爪はブロックの奥側で閉じ、ブロックは爪の手前に残っている

GPU を買うか借りるかの判断は、Runpod で実際に借りて学習させた費用をもとに、別のページにまとめています。

導入比較ガイドロボットAIの学習用GPU、買うか借りるか実際に借りて学習させた費用と、損益分岐の計算機で決められます

この回の作業は、Claude(設計と記録を一緒に組み立てた AI)と進めました。実機を動かすプログラムは Claude Code(プログラムを書く AI)に依頼箱を通して頼み、OpenAI の codex(別の会社のプログラムを書く AI)にコードを読んでもらってから受け取っています。アームはこの回は一度も動かしていません。ここから下は、依頼文・報告・レビュー・コードを全量で載せた作業ログです。効果の数字は、実機で試していないので、どれも見込みです。

作業ログ ― MicroFactory の巻き戻しを、mechArm 270 でどう作るかを決めた

MicroFactory は、卓上の箱の中でアームに手作業を覚えさせる会社

MicroFactory は、米国の卓上ロボットセルの会社です。箱の中に市販のアームと手先を入れ、人が操作用のアームで数回やって見せた動きを AI に覚えさせて、基板へのコネクタの差し込みや結束バンド締めのような手作業を任せます。この研究室では、LOG276 で仕組みを分解し、LOG329 で紹介動画を読みました。

この回で使う言葉は次のとおりです。

言葉意味
巻き戻し
ロボットがミスしたとき、今までの動きを逆にたどって、ミスの手前の姿勢へ戻すこと
クラッチ
AI に動かさせたまま、人が操作用のアームで横から手を入れて動きを直す仕組み。手を離すと、また AI だけで動く
介入
人が途中で手を入れて、ロボットの動きを直すこと
リーダーアーム
人が手で動かす操作用のアーム。本物のロボットがその動きをまねる

動画は YouTube にあり、巻き戻しとクラッチの話は 4:25 ごろからです。共有した2本の切り抜きから読み取れたのは、次の4つです。

  • 人は、ロボットの作業場所の外に置いた小さなリーダーアームを握り、クラッチを使ってリアルタイムに動きを直している。手を離すと、ロボットはまた AI だけで続ける(字幕は「あとは私抜きで仕事を進めてください」)
  • リーダーアームは作業場所の外にあるので、ロボットを撮るカメラに人の手が写らない
  • 失敗した動きを、時間をさかのぼるように戻してからやり直させている。題材の差し込み作業では、戻す動きがそのまま引き抜く動きになるので、部品の状態もほぼ元に戻る
  • 直した内容を覚えて、次からは同じ間違いを正す、と説明している。比べる相手として Physical Intelligence の論文の図が出ていて、字幕では、仕上げの学習だけで5〜10時間分のデータが要り、成功率は約85%と紹介されていた

クラッチの中身は、映像からの推測です。押している間だけ人の手の動きが AI の動きに上乗せされ、離すと AI の動きだけに戻る仕組みに見えます。これは、関節の一部だけを補正する、という使い方と同じ形です。

実機推論は、推論1回ぶんごとに止まる作りだった

mechArm 270 の実機推論は、pi05/run_policy_client.py が受け持っています。AI に1回問い合わせると、次の1秒分の関節の角度が10ステップぶん返ってきます。この1回分の答えを、この記事ではチャンクと呼びます。プログラムは、チャンクを1つ受け取るたびに止まって、Enter で実行するかどうかを聞きます。

チャンクごとに、その時の写真1枚・実測の関節の角度・AI が返した10ステップ分の関節の角度・実際に送った中継点が、log.jsonl と frames/ に残っていました。つまり、チャンクの区切りは、そのまま巻き戻せる区切りとして使えます。毎回 Enter で止まる作りなので、そこにキーを足せば、失敗したところで止めて巻き戻せます。

はじめの案と、動画を見て直した2点

最初に考えたのは、記録を後から直す方法でした。記録を読むビューアで失敗した区間を選び、その区間の関節の角度に補正を入れ、実機でもう一度再生して撮り直す、という順番です。ここで2つ、前提を置いていました。

  1. 記録の関節の角度だけを直しても、写真には直す前の動きが写っているので、学習データにならない。直した動きは、実機で動かして撮り直す必要がある
  2. アームは巻き戻せても、ブロックは巻き戻らない。押されたブロックは手で置き直す必要がある

動画を見て、この2つを直しました。

はじめの前提動画を見て直したこと
直した動きは、いつも撮り直しが要る
撮り直しが要るのは、手でアームを動かしたときと、後から数字だけ直したときだけ。カメラの外から操作して直せば、写真と関節の角度が最初から合っているので、直した区間をそのまま学習データに使える
巻き戻しても場面は戻らない
mechArm 270 の失敗の多くは、ブロックに触れる前、爪を閉じる所で起きている(LOG401 の位置E の2回・位置D の2回)。ここなら、アームを戻すだけで場面も戻る

ただし、2つ目には続きがありました。LOG401 の位置D では、ブロックをつかんで持ち上げた瞬間に落とす回が2回ありました。つかんだあとの失敗について聞くと、次の答えでした。

掴んだ後も問題あるよ。

つかんだ後の失敗(掴んだブロックを落とす、白箱に入れる際に先にアームが上がり切らないで白箱にぶつかる)

この2つに合わせて、つかんだ区間の巻き戻し方を足しています(依頼2の節)。

リーダーアームがない mechArm 270 では、キーボードをクラッチにする

mechArm 270 には、リーダーアームがありません。そこで、推論のあとの確認(Enter で止まるところ)に、次の2つのキーを足すことにしました。

  • b(巻き戻し):直前に実行したチャンクで送った中継点を逆の順にたどって送り、そのチャンクを始めたときの姿勢へ戻す。続けて押すと、1チャンクずつさかのぼる
  • c(補正):キーを押している間だけ、選んだ関節を1°ずつ動かす。Enter で、その姿勢から AI に戻す

キーボードはカメラの外にあるので、補正している間の写真に手は写りません。補正している間と再開したあとを1秒10コマで撮り、関節の角度と組にして残せば、直した区間をそのまま学習データに使えます。今は、チャンク1つにつき写真は1枚しか残っていないので、ここは足す必要がありました。

直した区間を、元のお手本19本に足して、π0.5 を学習し直します。お手本はうまくいった動きだけなので、AI は、外れかけたときにどう戻ればよいかを知りません。外れかけた姿勢から正しい動きへ戻るデータが入ることが、この仕組みのねらいです。

本物の形に近づけるなら、SO-101 のリーダーアームで、押している間だけ上乗せする形になります。ただ、それはキーボードの版で、直すのが間に合わないことを実機で測ってからにします。

実機の失敗の例:LOG401 の位置E の5回目は、爪がブロックの奥で閉じた

最初に試す題材にするのは、LOG401 の位置E の5回目(記録 pi05_20261029_150950)です。推論4回目で爪を閉じましたが、爪はブロックの奥側で閉じ、ブロックは爪の手前に残りました。推論6回目では、AI が j0(根元の回転)を 13° あまり振る答えを返したので、送らずに h で HOME に戻しています。

log.jsonl のチャンクごとの値です(state は推論を始めたときの関節の角度、target はそのチャンクで最後に向かった目標)。

推論推論の時間state(j0〜j5)グリッパーtarget(j0〜j5)爪の指令実行
0560ms
−0.17 +1.49 +1.84 +0.17 −0.26 −30.14
開
+3.75 +18.55 +13.03 −1.87 −23.47 −27.19
なしした
1688ms
+3.75 +18.55 +13.03 −1.87 −23.47 −27.19
開
+8.04 +36.70 +25.40 −2.69 −51.96 −26.45
なしした
21535ms
+8.04 +36.70 +25.40 −2.69 −51.96 −26.45
開
+9.41 +45.70 +30.28 −2.62 −62.92 −26.42
なしした
3613ms
+9.41 +45.70 +30.28 −2.62 −62.92 −26.42
開
+9.79 +56.04 +21.52 −2.52 −61.91 −26.58
なしした
4606ms
+9.79 +56.04 +21.52 −2.52 −61.91 −26.58
開
+9.80 +58.98 +19.37 −2.56 −61.62 −26.62
閉じるした
5554ms
+9.80 +58.98 +19.37 −2.56 −61.62 −26.62
閉
+9.85 +51.42 +26.97 −2.55 −64.26 −26.78
なしした
61542ms
+9.85 +51.42 +26.97 −2.55 −64.26 −26.78
閉
+23.11 +49.40 +18.11 +0.27 −60.64 −29.40
なしせずに HOME

新しいキーがあれば、推論6回目の確認で次のように直せます(実機ではまだ試していません)。

  1. b を押す → 推論5回目(爪を閉じたあと持ち上げた区間)を逆にたどり、推論5回目を始めた姿勢へ戻る
  2. もう一度 b を押す → 推論4回目はつかんだ区間なので、持っているか(y)落としたか(n)を聞かれる。この回は何もつかめていないので n → その場でグリッパーを開いてから、推論4回目を始めた姿勢へ戻る
  3. c を押し、j1・j2(肩とひじ)を少しずつ動かして、爪がブロックの手前に下りる向きへ直す → Enter で AI に戻す
  4. 箱に入ったら h で終え、結果を聞かれたら y

この流れで記録した回からは、推論4〜5回目の失敗した区間と巻き戻しの動きが除かれ、補正の区間と、そこから AI が続けた動きが学習データに残ります。

依頼1:巻き戻し(b)・関節の補正(c)・1秒10コマの記録を足した

この記事のコード・ログ・データは、1ファイルずつ下に置いています。全文はリンク先にあります。

ファイルの一覧(6本)

01_codex_1_5_review_result_20261029_rewind_correct_codex.md ― codex のレビューは、1回目に必須の指摘が5件あった / codex の答え review_result_20261029_rewind_correct_codex.md(1回目)・3,122字

02_pi05_run_policy_client.py.txt ― pi05/run_policy_client.py・66,108字

03_pi05_policy_recorder.py.txt ― pi05/policy_recorder.py・9,877字

04_pi05_rewind_correct.py.txt ― pi05/rewind_correct.py・5,241字

05_pi05_build_correction_episodes.py.txt ― pi05/build_correction_episodes.py・18,008字

06_pi05_test_rewind_correct.py.txt ― pi05/test_rewind_correct.py・41,635字

実機を動かすプログラムは、Claude Code(Anthropic のプログラムを書く AI)に頼みました。頼み方は、依頼箱という仕組みです。iCloud の「依頼箱」フォルダの「新規」に依頼文の Markdown を置くと、Mac で動いている見張り係のプログラムが Claude Code に渡し、終わると報告を「結果」に書き戻して、Mac に通知を出します。関節を動かす変更なので、Claude Code が codex にコードを読ませてから報告する決まりにしています。実機には流さない、というのも依頼の決まりです。

ねらい・変わったこと・見込める効果は次のとおりです。

  • ねらい:失敗した回を最初からやり直すのではなく、失敗したチャンクまで戻って、関節の一部だけを直してから AI に続けさせる
  • 変わったこと:推論のあとの確認が「Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了」から、b(巻き戻し)と c(補正)を加えた形になった。実行している間は、上のカメラの写真と関節の角度が1秒10コマで残り、1コマごとに、AI の動き・巻き戻し中・補正中・HOME へ戻る間のどれかの印が付く
  • 見込める効果:失敗1回ごとに、外れかけた姿勢から戻る動きのデータが1本できる見込み。何本で成功率が変わるかは、学習し直したあとに同じ配置で数えて確かめる

依頼文 20261029_25_実機推論に巻き戻しと補正を足す.md

---
作業フォルダ: /Users/shimazueiichi/r2r2r-scripts
上限時間: 180
---
# 依頼:実機推論(pi05/run_policy_client.py)に「巻き戻し」と「関節の補正」を足し、直した動きを学習データにする(2026-10-29)

## ねらい

MicroFactory の「失敗したら巻き戻し、モデルに動かさせながら人が直し、その直しを覚えさせる」を mechArm で試す。
リーダーアームはないので、カメラの外(キーボード)から関節の一部だけを直す。手はカメラに映らないので、直した区間はそのまま学習データに使える。
今の困りごとは「ブロックの位置にアームが行かない」で、ブロックに触れる前の失敗なので、アームを巻き戻せば場面もそのまま戻る。

今日の LOG14 の記録(`/Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261029_150950/`)が実例。推論6回目で j0 が +13.5° 跳ぶ予測が出て h で戻した。

## 今の作り(前提)

- 実行コマンド:`python3 pi05/run_policy_client.py --raw-dir $RAW --steps-per-chunk 10 --via-stride 3 --settle-retries 0 --state-from-target --execute --ignore-framing`
- 推論1回ごとに `Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了` で止まる
- `log.jsonl` に推論1回ごとの state・measured_state・actions・vias・arrived が残り、`frames/` に推論1回につき写真1枚が残る

## A. 記録を足す(1秒10コマ)

- `--execute` の間、上カメラの写真と実測の関節角・グリッパーを 1秒10コマで記録し続ける。お手本データ(`datasets/mecharm_redblock_box_teach_v1_trim2/` の元になった run)と同じ形で残し、`pi05/build_demo_episodes.py` がそのまま読めるようにする。同じ形にできない場合は、変換を build_demo_episodes.py 側に足す
- 1コマごとに「その時の状態」を付ける:`model`(モデルの動き)/`rewind`(巻き戻し中)/`correct`(補正中)/`home`
- 記録の置き場所は今と同じ `runs/pi05_policy/{run_stem}/` の中。新しい置き場所は作らない
- 終わるとき(h・q のとき)に `結果: y=成功 / n=失敗 / Enter=記録しない >` を聞き、meta に残す

## B. 巻き戻し(b キー)

- 推論のあとの確認で `b` を押すと、直前に実行した推論1回分の中継点を逆順にたどって送り、その推論を始めたときの姿勢(measured_state)へ戻す
- 続けて `b` を押すと、さらに1回分ずつさかのぼる
- 戻ったあとは、その姿勢からもう一度推論する
- 巻き戻した推論の区間は log.jsonl に `rewound: true` を付けて残す(消さない)

## C. 関節の補正(c キー)

- 推論のあとの確認で `c` を押すと補正モードに入る。補正モードでは Enter を待たずに1文字ずつキーを読む(termios など)。キーを押し続けると、Mac のキーリピートで繰り返し効く
- キーの割り当て(案。使いやすい割り当てがあれば変えてよい。画面に一覧を出す)
  - `1`〜`6`:直す関節を選ぶ(j0〜j5)
  - `+`/`-`(または `.`/`,`):選んだ関節を1刻み動かす。刻みの既定は 1°
  - `[`/`]`:刻みを 0.5° / 1° / 2° で切り替える
  - `g`:グリッパーの開閉
  - `Enter`:補正を終えて、その姿勢からモデルの推論に戻る
  - `b`:補正を取り消して、補正を始めた姿勢へ戻る
- 送り方は今と同じ send_angles(speed 20)と到着確認。今の範囲チェック(apply_limits・check_send_safe)をそのまま通す。**新しい確認や停止条件は足さない**
- 補正した内容(関節・量・前後の角度・時刻)を log.jsonl に `type: "correction"` として残す

## D. 直した動きを学習データにする

- 新しいスクリプト(例 `pi05/build_correction_episodes.py`):A の記録から学習用のエピソードを作る
  - 使うのは、結果が「成功」の run だけ
  - `rewind` のコマと、巻き戻しで取り消した区間のコマは除く(その手前と、巻き戻したあとの続きだけをつなぐ)
  - `model` と `correct` のコマを使う。actions は「0.1秒後の state」(trim2 と同じ作り方)
  - 止まっている区間は `--trim-mid-idle` と同じ決まりで詰める
- 出力:`datasets/mecharm_redblock_box_corr_v1/raw_episodes/`(お手本と同じ形・README.md に作り方と数を書く)。元のデータは読むだけ(上書き・移動・削除しない)
- 補正の入ったエピソードが、元のお手本19本と一緒に学習に使えるか(形・キー・FPS・画像の大きさ)を確かめる

## E. 確かめ(実機なし)

- `--execute` なし(ドライラン)でも b・c が動くようにし、アームなしで流れを試せるようにする
- テストを足す:巻き戻しの中継点の並び(逆順・始めの姿勢で終わる)、補正の刻みと範囲チェック、D の区間の除き方(rewind と取り消した区間が入らない)
- `b`・`c` を押さなければ、今までと同じ動き・同じログになることを確かめる(ログは項目が増えるだけ)

## 変えないもの

- モデルのサーバー・送り方(speed 20・中継点の作り方)・今の範囲チェックの値
- 既存のデータセット・記録

## 終わったら

- 関節を動かす変更なので、codex のレビューを通してから報告する(code_review_request_template.md の形)。指摘は直すか、直さない理由を書く
- 実機には流さない。報告に、エイイチが実機で最初に試す手順(LOG14 と同じ配置で、推論1回目のあとに b → c で j0 を数度動かす → Enter で再開 → 成功なら y)を書く
- 個別のファイルを指定して add・commit する(`git add .` は使わない)

依頼箱の見張り係に、r2r2r-scripts を足した

見張り係が自動で回すのは、設定ファイル config.json の allowed_dirs に書いた作業フォルダだけです。それまではサービスロボット導入シミュレーションの ServiceSim だけだったので、実機のプログラムがある r2r2r-scripts を足しました。

{
  "inbox": "~/Library/Mobile Documents/com~apple~CloudDocs/デスクトップ/ADAPT DESIGN/じぶんの/PixelstoMotors/依頼箱",
  "allowed_dirs": [
    "/Users/shimazueiichi/Robotics_UX/ServiceSim",
    "/Users/shimazueiichi/r2r2r-scripts"
  ],
  "claude": "/Users/shimazueiichi/.npm-global/bin/claude",
  "permission_mode": "auto",
  "default_limit_minutes": 180,
  "poll_seconds": 30,
  "settle_seconds": 15,
  "extra_args": [],
  "drop_env": [
    "ANTHROPIC_API_KEY",
    "ANTHROPIC_AUTH_TOKEN"
  ],
  "set_env": {
    "ENABLE_CLAUDEAI_MCP_SERVERS": "false"
  }
}

見張り係は、起動したときに一度だけ設定を読みます。設定を変えても、動いている見張り係には効きません。1回目は、見張り係が動いている窓とは別の窓で入れ替えのスクリプト(update.sh)を打ったので、新しい見張り係は「もう動いています」で起動せず、古い設定のままの見張り係が依頼を拾って「失敗」に回しました。何も実行されていないので、コードは変わっていません。見張り係の窓を Ctrl+C で止めてから打ち直して、動き出しました。記録 記録.log の該当する行です。

2026-10-29T19:33:20 「止める」があるので一時停止中
2026-10-29T19:35:20 開始 20261029_25_実機推論に巻き戻しと補正を足す.md
2026-10-29T19:35:20 失敗 20261029_25_実機推論に巻き戻しと補正を足す.md → 結果/20261029_25_実機推論に巻き戻しと補正を足す_20261029_1935.md
2026-10-29T19:36:20 「止める」があるので一時停止中
2026-10-29T19:37:21 見張り係を止めました
2026-10-29T19:37:29 見張り係を起動
2026-10-29T19:37:29 開始 20261029_25_実機推論に巻き戻しと補正を足す.md
2026-10-29T20:27:13 完了 20261029_25_実機推論に巻き戻しと補正を足す.md → 結果/20261029_25_実機推論に巻き戻しと補正を足す_20261029_1937.md

打ち直したときの Mac のターミナルの出力です。

(base) shimazueiichi@shimadzueiichinoMacBook-Pro ~ %    bash ~/r2r2r-scripts/inbox/update.sh
 
自動起動:登録済み(/Users/shimazueiichi/Library/LaunchAgents/com.pixelstomotors.inbox.plist)
commit: c071dc6 依頼箱の見張り係を更新
依頼箱: /Users/shimazueiichi/Library/Mobile Documents/com~apple~CloudDocs/デスクトップ/ADAPT DESIGN/じぶんの/PixelstoMotors/依頼箱 あり
自動で回してよい場所: /Users/shimazueiichi/Robotics_UX/ServiceSim あり
自動で回してよい場所: /Users/shimazueiichi/r2r2r-scripts あり
claude: /Users/shimazueiichi/.npm-global/bin/claude
claude の版: 2.1.311 (Claude Code)
承認の扱い: auto / 拒否の決まり: /Users/shimazueiichi/r2r2r-scripts/inbox/settings.json
外す環境変数: ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN / うち今この窓で設定されているもの: ANTHROPIC_API_KEY
2026-10-29T19:37:29 見張り係を起動
2026-10-29T19:37:29 開始 20261029_25_実機推論に巻き戻しと補正を足す.md

Claude Code の報告(50分・テスト26件・codex のレビュー3回)

# 結果:20261029_25_実機推論に巻き戻しと補正を足す

- 状態:完了
- 始めた時刻:2026-10-29 19:37
- 終わった時刻:2026-10-29 20:27(50分)
- 作業フォルダ:/Users/shimazueiichi/r2r2r-scripts
- この続きを Claude Code で話すとき:作業フォルダで `claude --resume 644ac1ac-9284-49d4-a08b-328fa8add63b`

## Claude Code の報告

やったこと
- `pi05/run_policy_client.py` の推論のあとの確認に、b(巻き戻し)と c(関節の補正)を足しました。b は直前の1回分(推論1回、または受け入れた補正1回)で実際に送った目標を逆の順にたどり、始めの姿勢へ戻してからもう一度推論します。続けて b を押すと1回分ずつさかのぼります。巻き戻した区間は log.jsonl に `type: "rewind"`、`rewound: true` の行を書き足して残します。もとの推論の行は消さず、書き換えもしません。
- c では Enter を待たずに1文字ずつ読みます。キーは 1〜6 で関節、+ と - で1刻み、[ と ] で刻みを 0.5° / 1° / 2° に切り替え、g でグリッパー、Enter で推論に戻る、b で取り消しです。送り方は推論と同じ(send_angles 速度20と到着確認)で、apply_limits と check_send_safe をそのまま通します。キーを押し続けても、1回送るたびに溜まったキーを捨てるので、送りすぎることはありません。補正の1刻みごとに `type: "correction"` を記録します。
- `--execute` の間は、上カメラと実測の関節角を1秒10コマで `recording/` に残します。形はお手本と同じで、1コマごとに状態(model / rewind / correct / home)が付きます。h か q で終えるときに結果を聞き、`{run_stem}.json` に残します。
- `--dry-keys` を足しました。アームにも daemon にも触らず、b と c の流れを試せます。
- 新しく作ったファイル:`policy_recorder.py`(記録)、`rewind_correct.py`(計算だけ)、`build_correction_episodes.py`(学習用エピソードを作る)、`test_rewind_correct.py`(テスト)。
- codex のレビューを3回通しました。1回目の必須指摘5件、2回目の必須指摘2件、3回目の軽い指摘1件を、すべて直しました。3回目の判定は「段階的な実機テストに進んでよい」です。記録の頻度と通信の遅れは実機で測るよう求められています。
- 実機には流していません。

結果
- アームなしのテストは26件すべて通りました。b と c を押さなければ、変更前の版と比べて送信・グリッパー・ログが同じになることも、3通りの動かし方で確かめました(ログは項目が増えるだけです)。
- 合成の記録から作った補正エピソードは、お手本 trim2(19本)と形がそろっています(npz のキー・型、FPS 10、画像 384×216)。お手本の作り方(build_demo_episodes)でも、この記録はそのまま読めました。
- `datasets/mecharm_redblock_box_corr_v1` はまだ作っていません。記録付きで成功した run がまだないためです。成功 run ができたら `python3 pi05/build_correction_episodes.py --check-with <trim2 の raw_episodes>` で作成と確認をします。

エイイチが実機で最初に試す手順(LOG14 と同じ配置)
1. `python3 pi05/run_policy_client.py --raw-dir $RAW --steps-per-chunk 10 --via-stride 3 --settle-retries 0 --state-from-target --execute --ignore-framing`
2. 推論1回目は Enter で実行する
3. 次の確認で b を押す。始めの姿勢(HOME 付近)へ戻り、もう一度推論が出ることを確かめる
4. 次の確認で c を押し、1 で j0 を選んで + か - を数回押す(1回で1°)。Enter で推論に戻る
5. そのまま Enter で進め、ブロックが箱に入ったら h を押し、結果を聞かれたら y
6. 終わったら `recording/top_meta.json` の actual_hz と effective_fps(どちらも10前後が目安)を見る。送信と到着確認が前より遅くなっていないかも確かめる

変えたファイル
- pi05/run_policy_client.py(変更)
- pi05/policy_recorder.py、pi05/rewind_correct.py、pi05/build_correction_episodes.py、pi05/test_rewind_correct.py(新規)
- docs/review_request_20261029_rewind_correct.md(r2・r3 も)、docs/review_result_20261029_rewind_correct_codex.md(r2・r3 も)(レビュー記録)
- コミット 2c860e5(ファイルを個別に指定して add)。作業記録は logs/20261029_2026.md

決めてほしいこと
- グリッパーを動かした推論や補正は、b で巻き戻さず、断って聞き直すようにしました。ブロックを持ったまま開くと落とすためです。この方針でよいか。
- 補正を b で取り消すときは、グリッパーも始めの状態に戻します。ただし姿勢が戻りきれなかったときは、グリッパーは今のままにします。この方針でよいか。
- 依頼どおり、学習データには model と correct のコマだけを使い、HOME へ戻る区間は除いています。お手本には HOME へ戻る動きが入っていますが、この違いのままでよいか。
- 記録スレッドが関節角を1秒10回読むため、本体の送信や到着確認がそのぶん待たされることがあります。実機で測った結果、遅れが大きければ読む回数を減らすかどうか。

codex のレビューは、1回目に必須の指摘が5件あった

codex のレビューは3回でした。1回目の判定は「現状のまま実機テストへ進むのは見送り」で、必須の指摘が5件ありました。巻き戻しが途中で止まっても終わったことになる、グリッパーを2回押して元に戻すと動かしたことにならない、巻き戻しで除いた区間の写真が境目で混ざる、などです。2回目に必須2件、3回目に軽い指摘1件が出て、3回目の判定が「段階的な実機テストに進んでよい」でした。Claude Code が書いたレビューの依頼文と、codex の答えを全量で載せます。

レビューの依頼文 review_request_20261029_rewind_correct.md

# コードレビュー依頼:実機推論に巻き戻し (b) と関節の補正 (c) と 1 秒 10 コマの記録を足す

対象ファイル:
- `pi05/run_policy_client.py`(変更。`git diff HEAD -- pi05/run_policy_client.py` で差分)
- `pi05/rewind_correct.py`(新規。計算だけ)
- `pi05/policy_recorder.py`(新規。上カメラ + 実測角の記録スレッド)
- `pi05/build_correction_episodes.py`(新規。記録 → 学習用エピソード)
- `pi05/test_rewind_correct.py`(新規。アームなしのテスト 16 件)

---

## このコードがやろうとしていること

mechArm 270 Pi を π0.5 (Runpod) の出力で動かす Mac 側クライアント。推論 1 回ごとに Enter 確認で止まる。
今回、確認のところで b(直前の 1 回分を巻き戻す)と c(キーボードで関節を 1 刻みずつ直す)を足し、
`--execute` の間は上カメラと実測角を 1 秒 10 コマで残して、直した動きを学習データにする。

## 設計仕様

1. b: 直前に実行した 1 回分(推論 1 回 / 受け入れた補正 1 回)で**実際に送った目標**を逆順にたどり、始めの姿勢(推論なら measured_state)で終わる。続けて b で 1 回分ずつさかのぼる。戻ったらその姿勢から再推論。グリッパーを動かした回は巻き戻さない(断って聞き直す)。各点は送る直前に実測から apply_limits と check_send_safe をかけ直し、通らない点が出たらそこで止める(送らない)。移動量の上限を超える区間は等分する。log.jsonl に `type: rewind, rewound: true` を追記(推論の行は消さない)
2. c: termios cbreak で 1 文字ずつ。1〜6 関節 / +- 1 刻み / [ ] 刻み 0.5・1・2° / g グリッパー / Enter 受け入れ / b 取り消し(始めの姿勢へ戻りグリッパーも戻す)。送り方は推論と同じ `_send_and_wait_arrival`(send_angles speed 20 + 到着確認)。apply_limits と check_send_safe を通し、通らない刻みは送らない。**新しい確認や停止条件は足さない**。1 刻み送ったあとに溜まったキーは tcflush で捨てる(キーリピートで送りすぎない)
3. 記録: 別スレッド 2 本(カメラ / get_angles 10Hz)。daemon のソケットは本体と共用なので `visual_servo_pick._daemon_request` を RLock で包む(install_daemon_lock)。上カメラは記録スレッドだけが読み、本体は「求めた時刻より後に撮れたコマ」を受け取る。states.csv の stage 列 / top_frame_log.csv の mode 列に model / rewind / correct / home
4. h / q で終えるとき結果 y/n/Enter を聞き `{run_stem}.json` に outcome と judgments を残す
5. `--dry-keys`: daemon に触らず仮の姿勢で b / c の流れを試す。b / c を押さなければ従来と同じ送信・同じログ(項目が増えるだけ。テストで git HEAD と比較済み)
6. build_correction_episodes: 成功の run だけ。model / correct のステップのみ。巻き戻した区間(区間開始〜巻き戻し終了)と取り消した補正を除いてつなぐ。actions は次の state。停止は build_demo_episodes と同じ決まりで詰める。戻りきれなかった巻き戻しがある run は使わない

## レビューしてほしいチェック項目

### A. ロジックの正しさ
A1. 巻き戻しの中継点(逆順・始めの姿勢で終わる・等分)と、送る前のかけ直しは正しいか
A2. history に積む条件(送った目標が 1 つ以上 / グリッパーを動かした)と、b を断る条件は妥当か
A3. 補正の目標の積み上げ(cur)と apply_limits の基準(実測)の組み合わせで、意図しない大きな動きが出ないか
A4. 除く時間の窓(segment_t[0]〜t_end)で、巻き戻した区間の画像・姿勢が学習データに残らないか
A5. 記録スレッドと本体の競合(ソケット・カメラ・CSV)、stop() の後始末

### B. 副作用・破壊チェック
B1. b / c を押さないとき、従来の送信・グリッパー・ログが変わっていないか
B2. 記録スレッドの get_angles(10Hz)が、本体の到着確認や送信の時間を大きく変えないか
B3. 既存のデータセット・記録を書き換えないか

### C. 暴走・安全リスク
C1. キーリピートで送りすぎないか(tcflush / os.read)
C2. 各関節の安全範囲(j4: -90〜+60、j1 上限 88)を補正・巻き戻しでも通っているか
C3. 関節角が読めない (None) ときに送らずに済むか
C4. Ctrl-C で端末の設定が戻るか・finally でアームを動かさないか

### D. 制約ルールの遵守
D1. send_coords() 不使用 / D2. 定数(SPEED 20・SEND_WAIT 1.0・HOME・J4_SAFE・J1_SAFE_MAX・max_move)不変 / D3. release_all_servos 不使用 / D6. KIOXIA マウントガード

## レビュー結果のフォーマット
各項目 ✅ OK / ⚠️ 要注意 / ❌ NG(行番号と修正案)。最後に実機テストに進んで良いか・直すべき項目。

## 固定事項
HOME=[0,0,0,0,0,-30] / SPEED=20 / SEND_WAIT=1.0 / J4_SAFE=-90〜+60 / send_coords 禁止 / 失敗時の自動 HOME リトライ禁止

codex の答え review_result_20261029_rewind_correct_codex.md(1回目)

**判定:❌ 現状のまま実機テストへ進むのは見送りです。** 対象5ファイルと `run_policy_client.py` の `git diff HEAD` を確認しました。ファイルは変更していません。

特に修正が必要な点は次のとおりです。行番号は現在のファイル基準です。

1. **❌ 巻き戻し未完了でも `finished=True` になる(A1・A4)**  
   `run_policy_client.py:531–554, 575–579`  
   `traverse()` は送信が未到達でも最後に `True` を返します。また、実測からの `apply_limits` で目標が変更されても、元の中継点や開始姿勢へ到達したか確認しません。結果として、戻りきれない run が `build_correction_episodes.py:163–168` の除外を通過します。  
   **修正案:** 送信処理を完走したかと、開始姿勢へ戻れたかを分け、最終実測と開始姿勢の差から `finished` を判定する。追加の自動HOMEやリトライは不要です。
別のタブで開く保存

レビューの依頼文 review_request_20261029_rewind_correct_r2.md

# コードレビュー依頼 R2:実機推論の巻き戻し・補正・記録(R1 指摘の反映確認)

前回: docs/review_request_20261029_rewind_correct.md / 結果 docs/review_result_20261029_rewind_correct_codex.md

## R1 指摘への対応
| # | 対応 |
|---|---|
| 1 | `reached_pose()` を追加。巻き戻し・補正の取り消しとも、送り切った (traverse_completed) かつ最後の実測が始めの姿勢から 3° 以内 (reached_start) のときだけ finished=True。build_correction_episodes は finished でない巻き戻し/取り消しがある run を使わない |
| 2 | 補正中に一度でも g を押したら grip_used=True(往復でも)。history 登録条件と b を断る条件に grip_used を使う |
| 3 | 1 点でも送った推論は、途中で止まっても (broke) history に積む(partial=True)。グリッパーは broke では動かしていないので grip_changed=False |
| 4 | 画像の候補 (top_frame_log の各コマ) にも、状態 (model/correct) と除く窓を同じ決まりで当ててから最近傍を選ぶ |
| 5 | stop(): join のあと生きているスレッドがあれば mp4 を閉じず、カメラも本体で閉じない。top_meta.json の status=thread_not_stopped、{run_stem}.json の recording_enabled=false。build_correction_episodes は status!=ok の run を使わない。カメラスレッドは read 直後に stop_flag を見る |
| A3 | 補正の 1 刻みが未到達なら、次の刻みは実測から数える(cur を実測に戻す) |
| C3 | 取り消しで始めの姿勢に戻れなかったときはグリッパーを戻さない |
| B3 | 出力先に pi05_policy 以外から作ったエピソードがあれば ABORT |
| B1 | test_unchanged_without_b_c で git HEAD 版と送信・グリッパー・ログを比較(3 通り。一致) |
| D6 | run_policy_client の既存ガードは今回の範囲外のため変更しない。builder は既定で bde.ensure_ssd() (is_mount) を通る。--data-root はテスト用の隠しオプション |
| B2 | 記録スレッドの get_angles と本体のロック待ちは実機でしか測れない。top_meta.json に actual_hz を残す |

異常系テストを追加(計 22 件, すべて OK): 戻りきれない巻き戻し / グリッパー往復 / 未到達の補正 / 戻れない取り消し / 記録スレッドが止まらない / 途中で止まった推論の巻き戻し / 除いた区間の画像が境界で入らない。

## お願い
R1 の 1〜5 が直っているか、直し方で新しい問題が出ていないかを、前回と同じ形式(✅/⚠️/❌・行番号・修正案)で。最後に実機テストに進んで良いか。

codex の答え review_result_20261029_rewind_correct_codex_r2.md(2回目)

**判定:❌ 実機テストは、下記2点の修正後に進めるのが妥当です。**

依頼書、対象5ファイル、`run_policy_client.py` の `git diff HEAD` を確認しました。ファイルは変更していません。行番号は現在のファイル基準です。

1. **❌ 初回推論前の補正で閉じたグリッパーが、推論開始時に勝手に開く(A2・B1)**

   対象:[run_policy_client.py:675](/Users/shimazueiichi/r2r2r-scripts/pi05/run_policy_client.py:675)、同1042–1053、1071–1079、1171–1175。

   起動直後に `c → g → Enter` で閉じても、`grip_opened` は `False` のままです。その後の初回推論実行で、開始時の開放処理が走ります。補正で物を保持した場合、ここで落とす可能性があります。

   また、この開放後も内部の `grip` は閉状態のままで、初期開放はhistoryの `grip_changed` にも含まれません。モデルへ渡す状態と実機が食い違い、グリッパーを動かした推論を巻き戻せる場合があります。

   **修正案:** 補正でグリッパーを操作した場合は初期開放を処理済みとして扱う。実際の開閉指令、内部状態、historyの操作履歴を一致させる。初回実行前に `c/g` を使う回帰テストを追加する。

2. **❌ 戻れなかった操作をhistoryから失い、次の `b` が古い区間を巻き戻す(A1・A2)**

   対象:[run_policy_client.py:1031](/Users/shimazueiichi/r2r2r-scripts/pi05/run_policy_client.py:1031)、同1044–1054。

   巻き戻しは実行前に `history.pop()` し、`finished=False` でも削除されたままです。また、補正取消が失敗しても、その残存移動はhistoryに登録されません。

   例えば、推論A→推論B→Bの巻き戻し失敗→再度 `b` と操作すると、Bの途中姿勢からAの経路へ進みます。補正取消失敗でグリッパーを閉じたままの場合も、以前の区間の判定だけで巻き戻せます。builderのrun除外では、実行中の経路の不整合は防げません。

   **修正案:** 成功した巻き戻しだけhistoryから確定削除する。未完了の巻き戻し・補正取消は残存区間または巻き戻し不可の境界として保持し、古い区間へ飛ばないようにする。自動HOMEや自動リトライは不要です。

R1指摘の反映状況です。

| R1 | 判定 | 確認結果 |
|---|---|---|
| 1:巻き戻し完了判定 | ✅ | `run_policy_client.py:588–590, 717–718`。完走と開始姿勢への到達を併用。builderの163–168行で未完了runを除外。操作後のhistoryには上記指摘2が残る。 |
| 2:グリッパー往復 | ✅ | 同680、1046–1052行。`grip_used` をhistory登録・巻き戻し禁止に使用。 |
| 3:部分実行の保持 | ✅ | 同1168–1176行。中断した推論も送信済み目標があればhistoryに残す。 |
| 4:除外画像の再混入 | ✅ | `build_correction_episodes.py:203–211`。画像候補にも時間窓とmode判定を適用してから最近傍を選ぶ。 |
| 5:停止時の資源競合 | ✅ | `policy_recorder.py:129–157, 194–195`、本体1229行。生存スレッドがあればVideoWriter・カメラを閉じず、異常記録をbuilderから除外。 |

その他のチェック結果です。

| 項目 | 判定 | 結果・修正案 |
|---|---|---|
| A1・A2 | ❌ | 上記指摘1・2を修正。逆順・等分・送信前の制限適用自体は維持。 |
| A3 | ⚠️ | 本体664–669行。未到達後の再読取が成功すれば実測に戻るが、失敗すると古い目標が残る。次のmoveで読めた実測を基準に復帰できるよう、未到達状態を保持する。 |
| A4 | ✅ | 除外窓・画像候補のフィルターは改善済み。 |
| A5 | ⚠️ | 停止競合は改善。記録の健全性判定には追加余地あり。`policy_recorder.py:209–218` はVideoWriterの `isOpened()` を確認せず、書込例外も最終statusに反映しない。記録失敗フラグを残すとよい。 |
| B1 | ✅ | b/cなしのHEAD比較テストを3通り実装済み。今回のレビューでは未実行。 |
| B2 | ⚠️ | `policy_recorder.py:53–55`。通信中のロック待ちは残る。`actual_hz` に加え、本体の送信・到着確認の遅延を実機で確認する。 |
| B3 | ✅ | builder361–366行で、既存の非pi05_policyエピソードを含む出力先を拒否。元記録は読み取りのみ。 |
| C1 | ✅ | `os.read`・`tcflush` によるキー読み取りを維持。 |
| C2 | ✅ | 補正・巻き戻しとも `apply_limits` と `check_send_safe` を通る。 |
| C3 | ✅ | 実測取得失敗時は関節送信を行わず、取消未到達時はグリッパー復元もしない。 |
| C4 | ✅ | 端末設定を復元し、finallyでアームを動かさない。 |
| D1・D2・D3 | ✅ | 追加処理に `send_coords()`・サーボ解放なし。指定定数・既存待機時間の変更なし。 |
| D6 | ⚠️ | 本体の既存存在確認は据え置き。builderは既定で `ensure_ssd()` を通る。今回の対象範囲内では説明どおり。 |

`test_rewind_correct.py` の追加異常系とHEAD比較処理は読みました。一時ファイル・動画を書き出すため、読み取り専用環境ではテストを実行しておらず、「22件成功」は独立に再確認していません。

**実機テスト前に指摘1・2を修正し、「初回推論前のc/g」「巻き戻し失敗後のb」「補正取消失敗後のb」をアームなしで確認してください。**

レビューの依頼文 review_request_20261029_rewind_correct_r3.md

# コードレビュー依頼 R3:実機推論の巻き戻し・補正・記録(R2 指摘の反映確認)

前回: docs/review_result_20261029_rewind_correct_codex_r2.md

## R2 指摘への対応
| # | 対応 |
|---|---|
| 1 | 補正で一度でも g を押したら(受け入れ・取り消しとも)grip_opened=True にし、最初の推論の実行で開始時の開放をしない。内部の grip は補正後の状態のまま(モデルにもそれを渡す)。テスト test_grip_in_correction_before_first_chunk |
| 2 | 巻き戻し / 補正の取り消しが finished=False なら、history に {"kind":"blocked","blocked":true} を積む。b は直前が blocked なら断って聞き直す(「これより前へは巻き戻しません」)。テスト test_b_after_failed_rewind_is_refused / test_b_after_failed_cancel_is_refused |
| A3 | 未到達のあとは resync フラグを立て、次の move で読めた実測を基準にする(読み直し失敗でも古い目標を使わない) |
| A5 | VideoWriter の isOpened() を確認し、開けない / 書けないときは write_errors を数える。top_meta.json の status=write_error、{run_stem}.json の recording_enabled=false → builder は使わない |
| B2 / D6 | 前回の説明どおり(実機で actual_hz と送信の遅れを確認する。本体の既存ガードは範囲外) |

テスト計 25 件すべて OK(`python3 pi05/test_rewind_correct.py`)。

## お願い
R2 の 1・2 が直っているか、新しい問題がないかを同じ形式で。最後に実機テストに進んで良いか。

codex の答え review_result_20261029_rewind_correct_codex_r3.md(3回目)

**判定:✅ R2の主要2点は修正されています。段階的な実機テストに進んでよいと判断します。**  
学習データ生成には、下記の非ブロッキング指摘が1点あります。

依頼書、前回レビュー、対象5ファイル、および `run_policy_client.py` の `git diff HEAD` を確認しました。ファイルは変更していません。行番号は現在のファイル基準です。

1. **⚠️[P2]JPEG保存失敗でも、正常なエピソードとして採用される**

   対象:[build_correction_episodes.py:234](/Users/shimazueiichi/r2r2r-scripts/pi05/build_correction_episodes.py:234)

   `cv2.imwrite()` の戻り値を確認せず、直後に `written` を増やしています。容量不足などで保存が `False` を返した場合も抽出件数の検査を通過し、画像が欠けたエピソードに `episode.npz`・`meta.json` を生成して `used=True` を返します。

   **修正案:** 保存成功時だけ件数を増やし、失敗時は生成途中のエピソードを不採用にする。`imwrite=False` の異常系テストを追加する。実機の動作確認は妨げませんが、学習データとして採用する前に対応してください。

R2指摘の反映状況です。

| R2 | 判定 | 確認結果 |
|---|---|---|
| 1:初回推論前の補正によるグリッパー操作 | ✅ | [本体1058行](/Users/shimazueiichi/r2r2r-scripts/pi05/run_policy_client.py:1058)で、受け入れ・取消とも `grip_used` により `grip_opened=True`。補正後の `grip` を保持し、次のモデル入力にも反映。 |
| 2:巻き戻し・補正取消の失敗後に古い区間へ進む | ✅ | [本体1041行](/Users/shimazueiichi/r2r2r-scripts/pi05/run_policy_client.py:1041)・1062行で `blocked` 境界を登録。999行で次の `b` を拒否。後続操作を積んでも、その境界を越える巻き戻しはできません。 |
| A3:未到達後の補正基準 | ✅ | `resync` を保持し、次のmoveで実測を取得できたときに補正基準を更新。読み取り失敗時は送信せず、フラグも保持。 |
| A5:動画書き込み失敗 | ✅ | VideoWriterの開放状態・書込例外を `write_errors` に反映。終了時の `status` と `recording_enabled` を通じてbuilderが除外。 |

その他の確認結果です。

| 項目 | 判定 | 結果 |
|---|---|---|
| 巻き戻し・補正の送信制限 | ✅ | 実測から `apply_limits`・`check_send_safe` を適用する構造を維持。 |
| 未完了操作の学習除外 | ✅ | 未完了の巻き戻し・補正取消を含むrunは除外。画像候補にも除外窓を適用。 |
| 追加回帰テスト | ✅ | R2の3ケースを確認。ただし初回c/gテストは受け入れ経路のみで、取消経路の結合テストは未追加。 |
| B2:記録による通信待ち | ⚠️ | ロック待ちは残るため、`actual_hz` と送信・到着確認の遅延は実機で確認が必要。 |
| 禁止事項 | ✅ | 追加処理に `send_coords()`・サーボ解放なし。指定の校正値や既存待機時間の変更なし。 |

5ファイルの構文解析は成功しました。テスト一式は一時ファイル・動画を生成するため、読み取り専用環境では実行しておらず、依頼書の「25件すべてOK」は独立に再確認していません。

**実機では、初回推論前のc/g、通常の巻き戻し、未到達後のb拒否を順に確認し、記録頻度と通信遅延を測定する段階へ進んでよいと判断します。**

作業記録 logs/20261029_2026.md

# 2026-10-29 実機推論に巻き戻し (b) と関節の補正 (c) を追加

依頼: 20261029_25_実機推論に巻き戻しと補正を足す.md / コミット 2c860e5

## やったこと
- run_policy_client.py に b (巻き戻し) / c (補正) / --dry-keys / 1 秒 10 コマの記録 / 終了時の結果 y/n
- 新規: policy_recorder.py / rewind_correct.py / build_correction_episodes.py / test_rewind_correct.py
- テスト 26 件 OK (git HEAD 版との比較で, b/c を押さなければ送信・ログが同じことを確認)
- codex レビュー 3 回 (R1 必須5 / R2 必須2 / R3 P2 1 をすべて反映)
- 実機には流していない. datasets/mecharm_redblock_box_corr_v1 はまだ作っていない (成功 run がないため)

## 未決 (エイイチ)
- グリッパーを動かした回は巻き戻さない方針でよいか
- 補正の取り消しでグリッパーも始めの状態に戻す方針でよいか
- 学習データから home 区間を除く (依頼どおり) でよいか
- 記録の get_angles 10Hz が送信・到着確認を遅らせないか, 実機で actual_hz と合わせて確認

報告の「決めてほしいこと」4点への答え

聞かれたこと答え
グリッパーを動かしたチャンクは、b で巻き戻さず聞き直す
つかんだ区間は巻き戻せるようにする(依頼2)。離した区間は今のまま断る
補正を取り消すときは、グリッパーも始めの状態に戻す。戻りきれなければ今のまま
このままでよい
学習データに、HOME へ戻る区間は入れない
このままでよい。エピソードが箱に入れたところで終わるだけなので、学習の邪魔にはならない
記録が関節の角度を1秒10回読むので、送信と到着確認が待たされることがある。遅れが大きければ読む回数を減らすか
実機で測ってから決める

依頼2:つかんだ区間も巻き戻し、人の手が写るコマを学習データから外した

依頼1の作りでは、グリッパーを動かしたチャンクは巻き戻しを断っていました。つかんだまま戻るとブロックを落とすからです。ただ、それでは、つかみ方が悪かった回(端をつかんだ・奥でつかんだ)をやり直せません。

そこで、つかんだチャンクを b で戻すときは、1文字で聞くようにしました。

答え動き使う場面
y(持っている)
送った目標を逆にたどって、つかんだ位置まで下ろす → グリッパーを開いてブロックを置く → 推論を始めた姿勢へ戻る
つかみ方が悪かった。ブロックはほぼ元の場所に戻る
n(落とした)
その場ですぐグリッパーを開く → 推論を始めた姿勢へ戻る → ブロックを手で元の位置へ置き直してから Enter
運ぶ途中で落とした・何もつかめていなかった。閉じた指が、置き直したブロックに当たらないように先に開く

箱の上で離したチャンクは、今のまま巻き戻しを断ります。離したブロックをもう一度つかむことはできないからです。白箱にぶつかる失敗は、運ぶ途中のチャンク(グリッパーを動かしていないチャンク)なので、グリッパーを閉じたまま b で戻し、c で j1・j2 を上げる向きへ直せます。

もう1つ、依頼1では抜けていた点がありました。Enter や b を待っている間も記録は続いているので、ブロックや箱を手で置き直すと、手が写ったコマが残ります。入力を待っている間のコマに「待ち」の印を付け、学習データに入らないようにしました。

ねらい・変わったこと・見込める効果は次のとおりです。

  • ねらい:つかんだあとの失敗(持ち上げた瞬間に落とす・つかみ方が悪い)も、その手前まで戻って直せるようにする
  • 変わったこと:巻き戻しを断るのは、箱の上で離したチャンクだけになった。入力を待っている間のコマは学習データから外れる
  • 見込める効果:LOG401 の失敗6回は、どれもつかむ所か持ち上げた所で起きていて、箱の上で離したあとの失敗はなかった。その6回の形なら、どれも巻き戻して直せる見込み

依頼文 20261029_27_つかんだ区間の巻き戻しと落としたときの戻し方.md

---
作業フォルダ: /Users/shimazueiichi/r2r2r-scripts
上限時間: 180
---
# 依頼:つかんだ区間も巻き戻せるようにし、落としたとき・人がブロックを置き直す間の扱いを足す(2026-10-29)

依頼 25(コミット 2c860e5・報告は依頼箱の 結果/20261029_25_実機推論に巻き戻しと補正を足す_20261029_1937.md)の続き。
まず logs/20261029_2026.md と docs/review_result_20261029_rewind_correct_codex*.md を読んでから始める。

## 依頼 25 の「決めてほしいこと」への答え(エイイチと決めた)

1. グリッパーを動かした区間を b で断る → **つかんだ区間は下の A で巻き戻せるようにする。離した区間は今のまま断る**
2. 補正を取り消すときはグリッパーも元に戻す・戻りきれなければ今のまま → このままでよい
3. 学習データに HOME へ戻る区間は入れない → このままでよい
4. 記録のせいで送信が遅れたら読む回数を減らすか → 実機で測ってから決める(今は変えない)

## 実機で起きている、つかんだ後の失敗(エイイチより)

- つかんだブロックを運ぶ途中で落とす
- 白箱に入れるとき、アームが上がりきらないうちに箱の方へ動き、白箱にぶつかる

2つ目は運ぶ途中の区間(グリッパーを動かしていない区間)なので、今の b と c で戻して直せるはず。B の 3 で確かめる。

## A. つかんだ区間(グリッパーを閉じた推論1回分)の巻き戻し

b でその区間を戻すとき、1文字で聞く:`y=持っている(下ろして置いてから戻る) / n=落とした(先に開いてから戻る) / その他=やめる`

- **y(持っている)**:その区間で送った目標を逆の順にたどり、グリッパーを閉じた時点の姿勢(つかんだ位置)まで下ろす → グリッパーを開いてブロックを置く → 残りを逆の順にたどって、その推論を始めた姿勢へ戻る。ブロックはほぼ元の場所に戻る
- **n(落とした)**:今の位置ですぐグリッパーを開く → 逆の順にたどって、その推論を始めた姿勢へ戻る(下ろすときに、閉じた指が置き直したブロックに当たらないよう、先に開く)。戻ったあと、ブロックを人が元の位置へ置き直してから Enter で続ける。元の位置の目安として、戻った推論の始めの写真(frames/)のパスを画面に出す
- つかんだ区間より前(運ぶ途中の区間がいくつか続いたあと)にさかのぼる場合も、つかんだ区間に来た所で同じように聞く
- 送り方・範囲チェックは今の b と同じ。新しい確認や停止条件は、この y/n 以外は足さない
- log.jsonl の rewind 行に `grasp_undo: "placed"` か `"dropped"` を残す

離した区間(グリッパーを開いた推論1回分)は今のまま断る。断るときの文言に「ブロックを置き直すなら h で終えてやり直す」と出す。

## B. 人の手が映るコマを学習データから外す

推論のあとの確認(Enter・b・c・y/n を待っている間)も記録は続いているので、ブロックや箱を手で置き直すと、手が写ったコマが残る。

1. 入力を待っている間のコマには状態 `wait` を付ける(今の作りで既に付いているなら、そのことを報告に書く)
2. build_correction_episodes.py は `wait` のコマを使わない。止まっている区間の詰め方(先頭2コマを残す)で wait のコマが残らないことも確かめる
3. 確かめ(実機なし・--dry-keys と合成の記録):
   - 運ぶ途中の区間の b → グリッパーは閉じたままで、送る目標が逆の順になる(白箱にぶつかったときの戻し方)
   - つかんだ区間の b で y → 「つかんだ位置まで下ろす → 開く → 始めの姿勢へ」の順になる
   - つかんだ区間の b で n → 「開く → 始めの姿勢へ」の順になる
   - wait のコマ・rewind のコマ・巻き戻しで取り消した区間が、学習用エピソードに入らない

## 変えないもの

- b・c を押さないときの動きとログ(今と同じであることを、依頼 25 と同じ比べ方で確かめる)
- 送り方(speed 20・中継点の作り方)・範囲チェックの値・記録の頻度

## 終わったら

- 関節とグリッパーを動かす変更なので、codex のレビューを通してから報告する。指摘は直すか、直さない理由を書く
- 実機には流さない。報告に、エイイチが実機で試す手順を書く(つかんで持ち上げたあと b → y/運ぶ途中で b → c で j1・j2 を上げる方へ直す → Enter)
- 個別のファイルを指定して add・commit する

Claude Code の報告(49分・テスト37件・codex のレビュー1回)

Claude Code の最後の報告は、レビューの指摘を直したことと、決めてほしいこと2点だけの短いものでした。何を変えたかの詳しい中身は、下の作業記録 logs/20261029_2142.md にあります。

# 結果:20261029_27_つかんだ区間の巻き戻しと落としたときの戻し方

- 状態:完了
- 始めた時刻:2026-10-29 21:13
- 終わった時刻:2026-10-29 22:02(49分)
- 作業フォルダ:/Users/shimazueiichi/r2r2r-scripts
- この続きを Claude Code で話すとき:作業フォルダで `claude --resume 4af1baaa-b12e-4a51-a5b4-52e9dd68238c`

## Claude Code の報告

codex のレビュー結果は、もう確認と反映を済ませています。この依頼でほかにやることはありません。

## やったこと
- codex のレビュー結果を読みました。判定は「実機テストに進んでよい」です。
- 指摘は 1 件(P3)でした。安全停止のあとの「h=HOMEに戻して終了」の入力待ちが、`model` のまま記録されていました。ここも `wait` にしました。
- レビューの結果を docs/review_result_20261029_grasp_rewind_codex.md に残しました。

## 結果
- 直したあとにテストを流し、37 件すべて通りました。
- コミット 4387d69 に入れました。
- 実機には流していません。

## 変えたファイル
前の報告から増えたものはありません(P3 の修正はコミット 4387d69 に入っています)。

## 決めてほしいこと
前の報告の 2 点のままです。
1. y で、つかんだ位置まで下ろしきれなかったときは、グリッパーを開かずに止める扱いにしています。これでよいかを決めてください。
2. ブロックを持っていて肩が上がりきらず、始めの姿勢から 3° 以内に戻れないと、「戻りきれなかった」扱いになり、そこから前へは巻き戻しません。実機で起きるかを見てから、どうするかを決めてください。

決めてほしいことの2点は、まだ決めていません。1つ目(つかんだ位置まで下ろしきれなければ開かない)は、宙でブロックを離さないための扱いで、依頼1の「補正を取り消すときに戻りきれなければ、グリッパーは今のまま」と同じ考えです。2つ目(ブロックを持っていて肩が上がりきらず、始めの姿勢から 3° 以内に戻れなければ、そこから前へは巻き戻さない)は、実機で起きるかを見てから決めます。

codex のレビューは1回で、判定は「実機テストに進んでよい」でした。指摘は軽いもの1件(安全停止のあとの入力待ちが、待ちの印になっていない)で、直してあります。

レビューの依頼文 review_request_20261029_grasp_rewind.md

# コードレビュー依頼:つかんだ区間の巻き戻し (y/n) と 入力待ちのコマ (wait) を学習データから外す

前提: 依頼 25 (コミット 2c860e5. 巻き戻し b / 補正 c / 1 秒 10 コマの記録) の続き。
過去のレビュー: docs/review_result_20261029_rewind_correct_codex*.md

対象 (`git diff HEAD -- pi05/` で差分):
- `pi05/run_policy_client.py`(run_rewind に grasp 引数 / 確認の入力ループ / history に grip_cmd)
- `pi05/rewind_correct.py`(MODE_WAIT / GRASP_PLACED / GRASP_DROPPED を追加)
- `pi05/build_correction_episodes.py`・`pi05/policy_recorder.py`(説明文のみ)
- `pi05/test_rewind_correct.py`(テスト 11 件追加。計 37 件)

## 仕様(エイイチと決めたこと)

A. つかんだ区間(グリッパーを閉じた推論 1 回分)を b で戻すとき 1 文字で聞く:
   `y=持っている(下ろして置いてから戻る) / n=落とした(先に開いてから戻る) / その他=やめる`
  - y: 送った目標を逆にたどり、グリッパーを閉じた時点の姿勢(閉じる前に最後に送った目標)まで下ろす → 開く → 残りを逆にたどって推論を始めた姿勢へ
  - n: 今の位置ですぐ開く → 逆にたどって推論を始めた姿勢へ → 始めの写真 (frames/NNNN.jpg) のパスを出し、人がブロックを置き直して Enter で続ける
  - 運ぶ区間をいくつか戻したあと、つかんだ区間に来た所で同じように聞く(b は 1 回分ずつさかのぼる)
  - 送り方・範囲チェックは今の b と同じ (traverse)。y/n 以外の新しい確認・停止条件は足さない
  - rewind 行に grasp_undo: "placed" / "dropped"
  - 離した区間(開いた推論)は今のまま断る。文言に「ブロックを置き直すなら h で終えてやり直す」
  - グリッパーを動かした補正は今のまま断る(依頼の範囲外)
  - 実装上の判断: y で「つかんだ位置まで下ろせなかった」(traverse が止まる / 3° 以内に着かない) ときは開かない(宙で落とさない)。finished=False → 次の b は blocked で断る。依頼 25 で決めた「補正の取り消しで姿勢が戻りきれなければグリッパーは今のまま」と同じ考え
B. 入力を待っている間(Enter/b/c/y/n、n のあとの置き直しの Enter)は記録の状態を `wait` にする。build_correction_episodes は TRAIN_MODES=(model, correct) なので wait を使わない(止まっている区間の詰め方より前に外れる)

変えないもの: b/c を押さないときの送信・グリッパー・log.jsonl(git HEAD 版との比較テスト test_unchanged_without_b_c で一致)/ SPEED 20 / 中継点の作り方 / 範囲チェックの値 / 記録の頻度。変わるのは states.csv に wait の stage 行が増えること。

## チェック項目
A1. y / n の送る順番(下ろす → 開く → 戻る / 開く → 戻る)と、つかんだ位置の決め方は正しいか
A2. 失敗時(読めない・範囲外・未到達)にグリッパーと history・grip 変数が食い違わないか。開いたのに grip=1 のまま、などがないか
A3. b を断る / 聞く条件(grip_cmd が 1 の推論だけ聞く。0 の推論・グリッパーを動かした補正・blocked は断る)は正しいか
A4. wait の付け外しで、学習に使うべき model のコマ(実行中の動き)が wait になったり、wait が model に残ったりしないか
B1. b/c を押さないときの送信・ログが変わっていないか
C. 安全: 開くタイミングで物を宙で落とす経路がないか(n は仕様で今すぐ開く)。send_coords 不使用・release_all_servos 不使用・定数不変

## レビュー結果のフォーマット
各項目 ✅ OK / ⚠️ 要注意 / ❌ NG(行番号と修正案)。最後に実機テストに進んで良いか・直すべき項目。

codex の答え review_result_20261029_grasp_rewind_codex.md

**判定:実機テストに進んでよいと判断します。動作を妨げる問題は見つかりませんでした。入力待ちの記録に軽微な漏れが1点あります。**

依頼書と `git diff HEAD -- pi05/`、関連処理を確認しました。ファイルは変更していません。

| 項目 | 判定 | 確認結果 |
|---|---|---|
| A1:y/n の順序・つかんだ位置 | ✅ OK | y は閉じる前の最後の送信目標へ移動→到達確認→開放→開始姿勢へ。送信なしなら開始姿勢を使用。n は開放→巻き戻し→開始写真の表示→置き直し待ち。 |
| A2:失敗時の整合性 | ✅ OK | y の下降失敗・読取失敗・未到達では開かない。開放後は、戻りが失敗しても `grip=0` に更新。未完了なら `blocked` を積み、古い履歴への巻き戻しを拒否。 |
| A3:拒否・確認条件 | ✅ OK | `blocked` を先に拒否し、`grip_changed` かつ推論の `grip_cmd==1` の場合だけ質問。開いた推論・グリッパー操作を含む補正は拒否。指定の案内文もあり。 |
| A4:wait の付け外し | ⚠️ 要注意 | 通常確認・y/n・置き直し待ちは適切。安全停止後の確認だけ切替漏れあり。下記参照。 |
| B1:b/c を押さない場合 | ✅ OK | 差分上、既存の送信・グリッパー・`log.jsonl` の処理を維持。HEADとの比較テストもありますが、今回未実行。 |
| C:安全・禁止事項 | ✅ OK | y の開放は `traverse` 完了かつ把持姿勢から3°以内の場合のみ。追加処理に `send_coords()`・`release_all_servos()` なし。速度・範囲チェック値・既存sleepの変更なし。 |

**⚠️[P3]安全停止後の入力待ちが `model` のまま記録される**

対象:[run_policy_client.py:1305](/Users/shimazueiichi/r2r2r-scripts/pi05/run_policy_client.py:1305)

安全範囲チェックで停止した後の `h=HOMEに戻して終了 / 他=そのまま終了` は、`MODE_WAIT` に切り替えず入力を待ちます。この間のコマは `model` として残ります。

この終了経路では成功結果を取得しないため、通常のbuilderでは学習対象にならず、直ちに学習データが混入する問題ではありません。ただし「入力待ちはwait」という記録方針には不整合です。

修正案は、この `input()` の直前にも `recorder.set_mode(MODE_WAIT)` を追加することです。h 選択後は既存の `MODE_HOME` 切替を使えます。

5ファイルの構文解析は成功しました。テスト一式は一時ファイル・動画を生成するため、読み取り専用環境では実行しておらず、37件の成功は独立に再確認していません。

**必須修正はありません。上記の記録漏れは修正を推奨します。実機では y/n の順序、y の未到達時に開かないこと、開放後に戻りが失敗しても次のモデル入力が開状態になることを確認してください。**
tokens used

作業記録 logs/20261029_2142.md

# 2026-10-29 つかんだ区間の巻き戻し (y/n) と 入力待ちのコマ (wait) を学習データから外す

依頼: 20261029_27_つかんだ区間の巻き戻しと落としたときの戻し方.md (依頼 25 / 2c860e5 の続き)

## やったこと
- run_policy_client.py
  - つかんだ区間 (グリッパーを閉じた推論) の b で y/n を聞く
    - y: つかんだ位置 (閉じる前に最後に送った目標) まで下ろす → 開く → 逆にたどって始めの姿勢へ.
      下ろしきれない (traverse が止まる / 3° 以内に着かない) ときは開かない → finished=False → 次の b は断る
    - n: すぐ開く → 逆にたどって始めの姿勢へ → frames/NNNN.jpg のパスを出して Enter 待ち
    - その他: やめる. rewind 行に grasp_undo / gripper_opened / grasp_pose など
  - 離した区間の b は断る (文言に「ブロックを置き直すなら h で終えてやり直してください」)
  - 入力待ち (Enter/b/c/y/n・置き直しの Enter・安全停止後の h 確認) の間は記録の状態を wait に
    (依頼 25 の時点では wait はなく model だった)
- rewind_correct.py: MODE_WAIT / GRASP_PLACED / GRASP_DROPPED
- build_correction_episodes.py: 処理は変えず (TRAIN_MODES=model/correct なので wait は使わない). 説明文だけ
- test_rewind_correct.py: 11 件追加 (計 37 件 OK). HEAD 比較テストは HEAD が依頼 25 版になったので項目の外し方を両側に

## codex レビュー
- docs/review_request_20261029_grasp_rewind.md → docs/review_result_20261029_grasp_rewind_codex.md
- 判定: 実機テストに進んでよい. P3 1 件 (安全停止後の入力待ちが model のまま) → 反映

## 未決 (エイイチ)
- y で下ろしきれないときは開かない (依頼 25 の「戻りきれなければグリッパーは今のまま」と同じ考え) でよいか
- 実機での確認 (手順は依頼箱の報告に記載)

実機で最初に試す手順

実機での確かめは次の回にします。LOG401 と同じ配置で、次の順に試します。

  1. いつものコマンドで起動し、推論1回目は Enter
python3 pi05/run_policy_client.py --raw-dir $RAW --steps-per-chunk 10 --via-stride 3 --settle-retries 0 --state-from-target --execute --ignore-framing
  1. 次の確認で b → HOME 付近に戻り、もう一度推論が出るか
  2. 次の確認で c → 1 で j0 を選び、+ か - を数回 → Enter で推論に戻る
  3. つかんで持ち上げたところで b → y → つかんだ位置に下ろして置き、推論を始めた姿勢へ戻るか
  4. 運ぶ途中で b → c で j1・j2 を上げる向きへ直す → Enter
  5. ブロックが箱に入ったら h を押し、結果を聞かれたら y
  6. 終わったら、記録の recording/top_meta.json の actual_hz と effective_fps(どちらも10前後が目安)を見る。送信と到着確認が前より遅くなっていないかも見る

変えたコード(全量・r2r2r-scripts のコミット 2c860e5 と 4387d69)

ファイル中身
pi05/run_policy_client.py
実機推論の本体。b・c・y/n・記録・結果の聞き取りを足した
pi05/policy_recorder.py
上のカメラと関節の角度を1秒10コマで残す記録係(新規)
pi05/rewind_correct.py
巻き戻しの中継点・補正のキー・学習から外す区間の計算だけ(新規)
pi05/build_correction_episodes.py
記録から学習用のエピソードを作る(新規)
pi05/test_rewind_correct.py
アームなしのテスト37件(新規)

pi05/run_policy_client.py

02_pi05_run_policy_client.py.txt66,108字・1,359行・python
#!/usr/bin/env python3
"""run_policy_client.py — π0.5 (Runpod の serve_policy) の出力で mechArm 270 を動かす Mac 側クライアント.

流れ (1 チャンクごと):
  上カメラ画像 + 実測 6 軸 + グリッパー状態 → π0.5 → 行動チャンク (10 x 7, 0.1 秒刻みの絶対角)
  → 先頭 N ステップ先 (既定 5 = 0.5 秒先) の姿勢へ単発 send_angles (学習データと同じ速度 20)
  → --via-stride N を付けると, 途中の姿勢 (N-1, 2N-1, ... ステップ) も中継点として
     順に送る (チャンクの中の順番を残すため. 既定 0 = 1 点だけ送る従来どおり)
別のタブで開く保存

pi05/policy_recorder.py

03_pi05_policy_recorder.py.txt9,877字・246行・python
#!/usr/bin/env python3
"""policy_recorder.py — 実機推論 (run_policy_client.py --execute) の間, 上カメラと実測角を 1 秒 10 コマで残す (2026-10-29).

お手本 (record_teach_demo.py + recorder.py --top) と同じ形で書くので,
build_demo_episodes.build_one() がそのまま読める:
  {run_dir}/recording/states.csv          recorder.py と同じ列. actual / gripper_cmd / stage 行.
                                          stage 列 = その時の状態 (model / rewind / correct / home / wait)
  {run_dir}/recording/top.mp4             上カメラ (元の大きさ. 10 コマ/秒)
別のタブで開く保存

pi05/rewind_correct.py

04_pi05_rewind_correct.py.txt5,241字・146行・python
#!/usr/bin/env python3
"""rewind_correct.py — 実機推論の「巻き戻し (b)」と「関節の補正 (c)」の計算部分 (2026-10-29).

アームにも daemon にも触らない (計算だけ). run_policy_client.py と
build_correction_episodes.py の両方から使い, test_rewind_correct.py で確かめる.

  - rewind_waypoints: 実行した区間 (推論1回分 / 補正1回分) で送った目標を逆順にたどり,
    始めの姿勢で終わる中継点の並びを作る
別のタブで開く保存

pi05/build_correction_episodes.py

05_pi05_build_correction_episodes.py.txt18,008字・400行・python
#!/usr/bin/env python3
"""build_correction_episodes.py — 実機推論 (巻き戻し・補正つき) の記録から π0.5 学習用エピソードを作る (2026-10-29).

入力 (1 試行 = 1 run_stem. run_policy_client.py --execute が残したもの):
  runs/pi05_policy/{run_stem}/{run_stem}.json            結果 (outcome / judgments)
  runs/pi05_policy/{run_stem}/log.jsonl                  推論・巻き戻し・補正の記録
  runs/pi05_policy/{run_stem}/recording/states.csv       actual (実測6軸) / gripper_cmd / stage (= 状態)
  runs/pi05_policy/{run_stem}/recording/top.mp4 + top_frame_log.csv
別のタブで開く保存

pi05/test_rewind_correct.py

06_pi05_test_rewind_correct.py.txt41,635字・820行・python
#!/usr/bin/env python3
"""test_rewind_correct.py — 巻き戻し・補正・補正エピソード作りの確かめ (アームなし. 2026-10-29).

  python3 pi05/test_rewind_correct.py          # 全部
  python3 pi05/test_rewind_correct.py -v

中身:
  - 巻き戻しの中継点の並び (逆順・始めの姿勢で終わる・移動量の上限で等分)
別のタブで開く保存

次は実機で巻き戻しと補正を試し、直したお手本で π0.5 を学習し直す

次の回でやることは3つです。

  • 上の手順で、巻き戻し・補正・つかんだ区間の y と n を実機で試し、記録の頻度と送信の遅れを測る
  • 位置D と位置E で失敗した所を巻き戻して直し、成功した回を集める。集まったら build_correction_episodes.py で datasets/mecharm_redblock_box_corr_v1 を作る
  • 元のお手本19本と直した区間を合わせて、Runpod で π0.5 を学習し直し、LOG401 と同じ3か所に5回ずつ置いて、入る割合が変わるかを数える