---
title: "フィジカルAI研究室を作る Log#12 | Physical Intelligence の π0.5 が初めてブロックを箱に入れた"
slug: pi05-first-block-in-box
date: 2026-10-22
day: 361
meta_description: "Physical Intelligenceのπ0.5で動かすmechArm 270は、つかんだブロックを持ち上げきれず箱に当てていた。肩が毎回約2°届かず、不足が積み重なっていた。AIに渡す角度を直前の目標に変えると、初めて箱に入った。"
tags: [フィジカルAI研究室, π0.5, openpi, Physical Intelligence, mechArm 270, 模倣学習, 実機テスト, Runpod, codex, 再現手順]
series: "フィジカルAI研究室"
---

机の上の小さなロボットアームが、AI の指示だけで赤いブロックをつかみ、持ち上げて、白い箱の中に落としました。人がお手本を見せて学ばせた AI でこのアームを動かし始めてから、ブロックが箱に入ったのはこれが初めてです。同じ日の朝、同じ AI は、つかんだブロックをマットに付けたまま引きずり、箱の壁にぶつけて箱ごと押していました。

朝と夕方で、AI そのものは何も変えていません。学習し直してもいません。変えたのは、AI の答えをアームに届ける側の2か所だけです。

原因は、アームの肩の小さな「届かなさ」でした。ブロックを持って腕を上げる指令を出すと、肩の関節は毎回、目標より約2°低いところで止まります。この日の記録を全部数えると、ブロックを持って肩を上げた指令43回のうち、43回とも目標に届いていませんでした（0.77〜2.80°、真ん中の値は 2.20°）。2°は目で見ても分からないほどの差です。ところが AI は、「いま腕が何度にあるか」を測った値を見て、次の1秒の動きを決めます。低いまま止まった角度を見て、そこからまた「これだけ上げる」と答えるので、足りなかった分は取り戻されず、毎回積み重なっていきます。0.5秒ずつ動かした回では、合計 41.2° 上げる指令に対して、実際に上がったのは 11.1° でした。

使った AI は、米国の [Physical Intelligence](https://www.pi.website/) 社が公開しているロボット用のモデル [π0.5](https://www.pi.website/blog/pi05)（パイレイテンゴ）です。上から見たカメラの画像と、6つの関節の角度を受け取り、次の1秒（10ステップ）の関節の角度を返します。人が手でアームを動かして教えた動きを19回録り、それを見せて学習させました（模倣学習）。

AI が悪いのか、アームが悪いのかを分けるために、お手本そのものをアームでもう一度再生して、横から撮りました。再生ではブロックは毎回箱に入り、ブロックは箱のふちより十分に高いところを通っていました。お手本の再生は、毎回「この角度へ行け」と決まった角度を送るので、2°の不足はその場かぎりで、次へ持ち越されません。AI で動かすときだけ、不足が持ち越されていたことになります。

そこで、AI に渡す「いまの角度」を、測った値ではなく、直前にアームへ送った目標の角度に変えました。**AI に渡す角度を、測った値から直前に送った目標に変えると、肩の不足が積み重ならなくなり、ブロックが初めて箱に入りました。** あわせて、1秒分の答えのうち最後の姿勢だけを送っていたのを、途中の姿勢も順に送るように変え、「持ち上げてから回る」という順番を保つようにしています。

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

| やったこと | なぜ | 結果 |
|---|---|---|
| お手本と同じ位置にブロックを置く道具を作った | AI が学習した場面と同じ条件で試すため | 位置C・D・E のどれでも、お手本の最初のコマを重ねて置けるようになった |
| 位置C で AI に動かさせた（朝） | 前の回の「持ち上げずに引きずる」が、置き場所のせいかを確かめるため | お手本どおりの位置でも、引きずって箱の壁に当てた |
| 肩を上げる指令と、実際に上がった角度を全部数えた | どこで高さを失っているかを知るため | 43回とも目標より低く止まった。下げる向きは約1°行き過ぎる |
| 同じ目標を送り直して詰める処理を足した | 2°の不足を、その場で取り戻せるかを見るため | 送り直しても縮まらなかった |
| 1秒分の途中の姿勢も送るようにした | お手本は、つかんだあと1.5秒その場で持ち上げてから回っていたため | 順番は保てたが、高さはまだ足りなかった |
| お手本の動きをそのまま実機で再生し、横から撮った | AI とアームのどちらに原因があるかを分けるため | 4回とも箱に入った。ブロックは箱のふちより上を通った |
| AI に渡す角度を、直前に送った目標にした | 不足が積み重なる仕組みを断つため | 18:16 の回で、つかんで持ち上げ、箱に入れた |

【画像】LOG361_01_success_181602.jpg 18:16 の回を横から撮った動画のコマ。ブロックの上で深くつかみ、持ち上げてから右へ回り、箱の上で離して、ブロックが箱の中に残っている

【動画】LOG361_v3_success_181602.mp4 18:16 の回を横から撮った動画（約3分20秒）。π0.5 がブロックを箱に入れた最初の回

ただ、続けて試した回は安定していません。18:26 の回は箱の位置で爪を開きましたが、動画がなく、箱に入ったかは確かめられていません。18:30 と 18:32 の回はブロックをつかみ損ねました。そのあと、手首の関節 j4 が +45.87° のまま動かなくなり、この日の実機はここで終えています。お手本の他の置き場所（位置D・E）はまだ試せていません。

この回の作業も、Claude（この記事の手順とプログラムを一緒に組み立てた AI）と進めました。手順・分析・記録の集計は Claude、アームを動かすプログラムの変更は Claude Code、その確認は [codex](https://github.com/openai/codex)（別の AI）が行い、アームの操作と、目で見た判断・止める判断はこちらで行っています。ここから下は、使ったコマンド・コード・出力を全量で載せた作業ログです。ログの中の Pod（借りた GPU マシン）の IP アドレスとポート番号は、`<POD_IP>` と `<SSH_PORT>` に置き換えています。コミットの説明文や Claude Code の報告に出てくる「LOG359」は、記事の番号が決まる前に仮に付けた番号で、この記事（LOG361）のことです。


## 作業ログ ― 推論用の Pod を借り直し、学習済みのモデルを送ってサーバーを起動した

前の回（[LOG358](/record/pi05-learned-the-pauses)）で学習し直したモデル（`pi05_mecharm_trim_lora`・お手本 `teach_v1_trim2`・4,000 ステップ）は、Mac につないだ外付け SSD（KIOXIA）の `checkpoints/pi05_mecharm_trim_lora_v1/3999/` に持ち帰ってあります。推論だけなら学習ほど GPU のメモリは要らないので、Runpod で推論用の Pod を借り直しました。朝の Pod は GPU の型番と料金を記録していません。夕方に借り直した Pod は A40（46GB）で、料金は記録していません。

Mac から、mechArm 用のスクリプト一式と学習設定の追加スクリプト、モデルを送りました。モデルは大きいファイルから順に4本同時に送り、送り終えたあとファイルの大きさを Pod 側と1つずつ照らし合わせています。

```
(base) shimazueiichi@shimadzueiichinoMacBook-Pro 3999 % P=<SSH_PORT>; IP=<POD_IP>; K=~/.ssh/id_ed25519
ssh -p $P -i $K root@$IP "mkdir -p /workspace/r2r2r /workspace/logs"
scp -P $P -i $K -r ~/r2r2r-scripts/pi05 root@$IP:/workspace/r2r2r/
scp -P $P -i $K /Volumes/KIOXIA/r2r2r-data/lab/Log11/pod/add_trim_config.py root@$IP:/workspace/r2r2r/
cd /Volumes/KIOXIA/r2r2r-data/checkpoints/pi05_mecharm_trim_lora_v1/3999
find . -type d | ssh -p $P -i $K root@$IP "mkdir -p /workspace/ckpt/3999 && cd /workspace/ckpt/3999 && xargs mkdir -p"
find . -type f -exec stat -f '%z %N' {} + | sort -rn | cut -d' ' -f2- | xargs -P 4 -I{} scp -q -P $P -i $K {} root@$IP:/workspace/ckpt/3999/{}
ssh -p $P -i $K root@$IP "cd /workspace/ckpt/3999 && find . -type f -printf '%s %p\n'" > /tmp/remote_ck.txt
find . -type f | while read f; do s=$(stat -f %z "$f"); grep -qx "$s $f" /tmp/remote_ck.txt || echo "不一致: $f"; done; echo "確認おわり"
eval_policy_offline.py                        100% 9921    35.6KB/s   00:00    
convert_to_lerobot.py                         100% 2873    10.5KB/s   00:00    
run_policy_client.py                          100%   24KB  88.5KB/s   00:00    
check_dataset.py                              100%   14KB  52.2KB/s   00:00    
build_demo_episodes.py.bak_pre_LOG352_2026101 100%   11KB  40.6KB/s   00:00    
RUNPOD_TRAIN.md                               100%   15KB  54.0KB/s   00:00    
install_addon.py                              100% 4786    17.4KB/s   00:00    
mecharm_policy.py                             100% 2321     8.5KB/s   00:00    
eval_policy_offline.cpython-312.pyc           100%   15KB  55.2KB/s   00:00    
build_demo_episodes.cpython-310.pyc           100%   11KB  39.5KB/s   00:00    
build_demo_episodes.cpython-312.pyc           100%   29KB 107.9KB/s   00:00    
check_dataset.cpython-312.pyc                 100%   25KB  93.5KB/s   00:00    
policy_ws.cpython-312.pyc                     100% 4580    16.4KB/s   00:00    
camera_align.cpython-312.pyc                  100%   18KB  68.5KB/s   00:00    
run_policy_client.cpython-312.pyc             100%   30KB 110.6KB/s   00:00    
build_demo_episodes.py                        100%   24KB  90.5KB/s   00:00    
policy_ws.py                                  100% 2778    10.1KB/s   00:00    
camera_align.py                               100%   13KB  49.1KB/s   00:00    
add_trim_config.py                            100% 1966     7.0KB/s   00:00    
```

Pod 側では、tmux（接続が切れても作業が続く画面）を先に1行だけで開き、その中で openpi（π0.5 を動かすための公開コード、コミット 215abfb）を取り直して `uv sync` し、mechArm 用の追加（`install_addon.py`）と学習設定の登録（`add_trim_config.py`）を入れてから、推論サーバーを起動しました。手順は前の回と同じで、設定名とお手本の名前だけが `pi05_mecharm_trim_lora`・`mecharm_redblock_box_teach_v1_trim2` に変わります。Pod の画面の出力は残していないので、使ったコマンドだけを載せます。

```
tmux new -s p
```

```
python3 /workspace/r2r2r/pi05/openpi_addon/install_addon.py /workspace/openpi
python3 /workspace/r2r2r/add_trim_config.py /workspace/openpi
cd /workspace/openpi
mkdir -p assets/pi05_mecharm_trim_lora/local && cp -r /workspace/ckpt/3999/assets/local/mecharm_redblock_box_teach_v1_trim2 assets/pi05_mecharm_trim_lora/local/
uv run scripts/serve_policy.py policy:checkpoint --policy.config=pi05_mecharm_trim_lora --policy.dir=/workspace/ckpt/3999 2>&1 | tee /workspace/logs/serve.log
```

Mac 側からは、Pod の 8000 番を手元の 8000 番へつなぐ SSH のトンネルを張り、アームを動かすクライアントは `ws://localhost:8000` に問い合わせます。

```
ssh -N -L 8000:localhost:8000 -p <SSH_PORT> -i ~/.ssh/id_ed25519 root@<POD_IP>
```

KIOXIA の `lab/Log12/serve.log` に持ち帰った、朝のサーバーのログです（10時28分に持ち帰った時点のもの）。時刻は Pod の時計（世界標準時）です。

```
INFO:root:Loading model...
INFO:2026-10-22 00:52:10,003:jax._src.xla_bridge:925: Unable to initialize backend 'rocm': module 'jaxlib.xla_extension' has no attribute 'GpuAllocatorConfig'
INFO:jax._src.xla_bridge:Unable to initialize backend 'rocm': module 'jaxlib.xla_extension' has no attribute 'GpuAllocatorConfig'
INFO:2026-10-22 00:52:10,005:jax._src.xla_bridge:925: Unable to initialize backend 'tpu': INTERNAL: Failed to open libtpu.so: libtpu.so: cannot open shared object file: No such file or directory
INFO:jax._src.xla_bridge:Unable to initialize backend 'tpu': INTERNAL: Failed to open libtpu.so: libtpu.so: cannot open shared object file: No such file or directory
INFO:absl:orbax-checkpoint version: 0.11.13
INFO:absl:Created BasePyTreeCheckpointHandler: use_ocdbt=True, use_zarr3=False, pytree_metadata_options=PyTreeMetadataOptions(support_rich_types=False), array_metadata_store=<orbax.checkpoint._src.metadata.array_metadata_store.Store object at 0x706101a9bb10>
INFO:absl:Restoring checkpoint from /workspace/ckpt/3999/params.
INFO:absl:[thread=MainThread] Failed to get flag value for EXPERIMENTAL_ORBAX_USE_DISTRIBUTED_PROCESS_ID.
INFO:absl:[process=0] /jax/checkpoint/read/bytes_per_sec: 1.3 GiB/s (total bytes: 6.3 GiB) (time elapsed: 5 seconds) (per-host)
INFO:absl:Finished restoring checkpoint in 5.07 seconds from /workspace/ckpt/3999/params.
INFO:openpi.shared.download:Downloading gs://big_vision/paligemma_tokenizer.model to /root/.cache/openpi/big_vision/paligemma_tokenizer.model
INFO:tqdm_loggable.tqdm_logging:Progress on: -/4264023 rate:- remaining:? elapsed:00:00 postfix:-
INFO:tqdm_loggable.tqdm_logging:Progress on: 4.07MiB/4.07MiB rate:4,259,565.7iB/s remaining:00:00 elapsed:00:01 postfix:-
INFO:root:Loaded norm stats from /workspace/openpi/assets/pi05_mecharm_trim_lora/local/mecharm_redblock_box_teach_v1_trim2
INFO:root:Loaded norm stats from /workspace/ckpt/3999/assets/local/mecharm_redblock_box_teach_v1_trim2
INFO:root:Creating server (host: 05c03cfb11fc, ip: 172.16.80.2)
INFO:websockets.server:server listening on 0.0.0.0:8000
INFO:websockets.server:connection open
INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 37440) opened
INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 37440) closed
INFO:websockets.server:connection open
INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 40204) opened
INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 40204) closed
INFO:websockets.server:connection open
INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 52988) opened
INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 52988) closed
INFO:websockets.server:connection open
INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 55516) opened
INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 55516) closed
```

`Loaded norm stats from …/mecharm_redblock_box_teach_v1_trim2` の2行で、学習に使ったお手本（trim2）から計算した正規化の値を読んだことが分かります。`connection open` と `closed` の組は、Mac のクライアントが1回つなぐたびに出る行です。


## お手本と同じ位置にブロックを置くため、camera_align.py に --episode を足した

前の回の夕方は、ブロックをお手本の置き場所と置き場所の間に置いていました。今回は、AI が学習した場面と同じ条件で試すため、お手本とまったく同じ位置に置くことにしました。お手本は5か所（A〜E）で録っていて、今回は位置C から試します。

上のカメラの写り方を確かめる `camera_align.py` は、ライブの映像にお手本の最初のコマを半透明で重ねて表示します。これまでは重ねるお手本が位置A の1本に決まっていたので、どのお手本を重ねるかを選べるようにしました（Claude Code の実装）。重なって見えるお手本のブロックに、実物のブロックを合わせれば、同じ位置に置けます。Claude Code の報告です。

```
 --episode を足しました。変更は pi05/camera_align.py の 1
  ファイルだけ（未コミット）、run_policy_client.py は 1 行も触っていません。

  変えた行
     
  ┌─────────┬────────────────────────────────────────────────────────────────┐
  │   行    │                              変更                              │
  ├─────────┼────────────────────────────────────────────────────────────────┤
  │ 9-12,   │ docstring: 使い方 2                                            │
  │ 15-16,  │ つ（写り方合わせ／ブロックの位置合わせ）、--episode            │
  │ 32-33   │ の説明と実行例                                                 │
  ├─────────┼────────────────────────────────────────────────────────────────┤
  │         │ pick_episode(raw_dir, episode=None) を新設。None               │
  │ 70-89   │ なら最初のエピソード（従来どおり）。完全一致 → 1               │
  │         │ 本だけに当たる部分一致 →                                       │
  │         │ 見つからない／複数当たるときはエピソード一覧を出して ABORT     │
  ├─────────┼────────────────────────────────────────────────────────────────┤
  │         │ grasp_j0(ep_dir)                                               │
  │ 92-102  │ を新設。つかんだ瞬間（グリッパーが閉に変わるステップ）の j0    │
  │         │ を返す。どの位置のお手本かを表示するためだけに使う             │
  ├─────────┼────────────────────────────────────────────────────────────────┤
  │ 105-118 │ load_reference(raw_dir) → load_reference(raw_dir,              │
  │         │ episode=None)。中身は pick_episode に委譲。既定の挙動は不変    │
  ├─────────┼────────────────────────────────────────────────────────────────┤
  │ 179-183 │ _put() を新設（黒で縁取ってから描く）                          │
  ├─────────┼────────────────────────────────────────────────────────────────┤
  │ 186,    │ draw_overlay(..., ref_label="") に引数追加。文字を _put        │
  │ 195-200 │ に変更し、左下に ref: <エピソード名> j0=±NN.N を表示           │
  ├─────────┼────────────────────────────────────────────────────────────────┤
  │ 207-211 │ --episode オプション追加                                       │
  ├─────────┼────────────────────────────────────────────────────────────────┤
  │ 216-225 │ load_reference(..., args.episode) に変更し、[REF ]             │
  │         │ 行でお手本名・つかんだ瞬間の j0・使い方を表示                  │
  ├─────────┼────────────────────────────────────────────────────────────────┤
  │ 240-241 │ draw_overlay に ref_label を渡す                               │
  └─────────┴────────────────────────────────────────────────────────────────┘

  load_reference の第 2 引数は既定 None なので、run_policy_client.py の
  load_reference(Path(args.raw_dir)) 
  は今までどおり最初のエピソードを基準にします（写り方の検査の基準は固定のまま）
  。判定（dy・dx・response）のしきい値も変えていません。

  位置 C・D・E の確認

  カメラを開く部分（cv2.VideoCapture / cv2.imshow）は iPhone
  が要るのでここでは実行できません。基準の選択 → 画像の読み込み → 
  重ね画像の生成まで（open_top_camera() の直前まで）を実データで確かめました。

  ┌────────────────────────┬──────────────────┬────────┬───────────┬───────┐
  │          指定          │  選ばれたお手本  │ 基準コ │ つかんだ  │ 重ね  │
  │                        │                  │   マ   │ 瞬間の j0 │ 画像  │
  ├────────────────────────┼──────────────────┼────────┼───────────┼───────┤
  │ --episode              │ run_0001_2026101 │ 000000 │           │ 1152x │
  │ なし（位置A）          │ 9_183454         │ .jpg 3 │ -36.4°    │ 648   │
  │                        │                  │ 84x216 │           │ 生成  │
  ├────────────────────────┼──────────────────┼────────┼───────────┼───────┤
  │ --episode run_0001_202 │ run_0001_2026101 │ 000000 │           │       │
  │ 61019_192343（位置C）  │ 9_192343         │ .jpg 3 │ -27.7°    │ 生成  │
  │                        │                  │ 84x216 │           │       │
  ├────────────────────────┼──────────────────┼────────┼───────────┼───────┤
  │ --episode run_0001_202 │ run_0001_2026101 │ 000000 │           │       │
  │ 61019_193404（位置D）  │ 9_193404         │ .jpg 3 │ -61.6°    │ 生成  │
  │                        │                  │ 84x216 │           │       │
  ├────────────────────────┼──────────────────┼────────┼───────────┼───────┤
  │ --episode run_0001_202 │ run_0001_2026101 │ 000000 │           │       │
  │ 61019_194818（位置E）  │ 9_194818         │ .jpg 3 │ +13.2°    │ 生成  │
  │                        │                  │ 84x216 │           │       │
  ├────────────────────────┼──────────────────┼────────┼───────────┼───────┤
  │ --episode              │ run_0001_2026101 │ 同上   │ -27.7°    │ 生成  │
  │ 192343（部分一致）     │ 9_192343         │        │           │       │
  └────────────────────────┴──────────────────┴────────┴───────────┴───────┘

  j0 が 4 つとも違うので、狙いどおり別のブロック位置のお手本が選べています。異常
  系も確認しました: 存在しない名前 → 19 本の一覧を出して終了、run_0001（19
  本に該当）→ 「19 本に当てはまります」で終了。

  途中で見つけて直した不具合

  重ね画像を実際に描いて確認したところ、resp=... と ref: の行が机の白い背景の上で
  ほぼ読めませんでした（薄いグレーの文字で縁取りなし）。_put()
  で黒の縁取りを入れて直しています。下は位置E の重ね画像（左の赤ブロック =
  ライブ、グリッパーの右脇にうっすら見える赤 = お手本E のブロック）:

  - 文字はマットの黒でも机の白でも読めます
  - 左下に ref: run_0001_20261019_194818  j0=+13.2 が出ます

  実用上の注意が 1 つ: 位置E のようにブロックが HOME
  のアームの陰に入る位置だと、お手本のブロックが見えにくいです。その場合は
  --alpha 0.7 でお手本を濃くすると合わせやすくなります。

  commit は指示がなかったので止めてあります（pi05/camera_align.py
  のみ変更）。入れてよければ個別指定で commit します。
```

コミットの説明文です。

```
commit b5b093c700893257a9c65ac87093299debb0d715
Date:   Wed Oct 21 20:12:38 2026 +0900

camera_align.py: --episode で重ねるお手本を選べるようにする (LOG359)

LOG359 の実機テストで, ブロックをお手本と同じ位置 (C / D / E) に置くため.
これまで重ねる基準は --raw-dir の最初のエピソード (20261019_183454・位置A) に
固定だったので, 位置A のブロックにしか合わせられなかった.
重なった画像のブロックに実物のブロックを合わせれば, そのお手本と同じ位置に置ける.

- pick_episode(raw_dir, episode=None) を新設. episode=None なら最初のエピソード
  (従来どおり). 完全一致 -> 1 本だけに当たる部分一致 (192343 など) の順で探し,
  見つからない / 複数当たるときはエピソード一覧を出して ABORT する.
- load_reference(raw_dir, episode=None) に第 2 引数を追加. 既定は None なので
  run_policy_client.py の呼び出し (写り方の検査) は最初のエピソードのまま変わらない.
- grasp_j0() を新設し, [REF] 行と画面左下に お手本名 と つかんだ瞬間の j0 を出す.
  どの位置のお手本を重ねているかが分かるように (check_dataset.py の項目 5 と同じ見方).
- 画面の文字を黒で縁取る (_put). 薄いグレーのままだと机の白に重なった行が読めなかった.

判定 (dy / dx / response) としきい値は変更なし. アームに送る処理は触っていない.

確認 (カメラを開く手前まで・実データ):
  --episode なし                     -> 183454 (位置A) つかんだ j0=-36.4°
  --episode run_0001_20261019_192343 -> 192343 (位置C) つかんだ j0=-27.7°
  --episode run_0001_20261019_193404 -> 193404 (位置D) つかんだ j0=-61.6°
  --episode run_0001_20261019_194818 -> 194818 (位置E) つかんだ j0=+13.2°
  --episode 192343 (部分一致)        -> 192343
  存在しない名前 -> 19 本の一覧を出して終了 / run_0001 (19 本該当) -> 複数一致で終了

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
```

位置C・D・E のお手本の最初のコマです。位置E は、たたんだ姿勢のアームの右の爪の下にブロックが隠れます。

【画像】LOG361_02_positions_CDE.jpg 上カメラで見たお手本の最初のコマ。左から位置C（192343）・位置D（193404）・位置E（194818）。位置E のブロックは右の爪の陰にある

お手本の上カメラの画像から、ブロックがマットのどこにあるかを mm で出しました。マットの四隅を画像で見つけ、赤い部分の中心と向きを測るスクリプトです。

```python
# お手本の最初のコマで、赤いブロックの中心をマットの端からの距離 (mm) にする (LOG361)
#  マットの横幅 620mm を画像の左右の端の間の画素数で割って 1 画素の大きさを出す
import os
import cv2, numpy as np
ROOT = os.environ.get("R2R2R_DATA", "/Volumes/KIOXIA/r2r2r-data"); os.chdir(ROOT)
R = "datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes"
def mat_edges(im):
    g = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY); dark = g < 90
    L, Rr = [], []
    for y in range(120, 180):
        xs = np.where(dark[y])[0]; L.append(xs.min()); Rr.append(xs.max())
    yb = np.median([np.where(dark[:, x])[0].max() for x in range(70, 110)])
    return np.median(L), np.median(Rr), yb
def block(im, s_min, v_min):
    hsv = cv2.cvtColor(im, cv2.COLOR_BGR2HSV)
    m = (((hsv[..., 0] < 10) | (hsv[..., 0] > 165)) & (hsv[..., 1] > s_min) & (hsv[..., 2] > v_min)).astype(np.uint8)
    m[:60] = 0
    n, lab, st, cen = cv2.connectedComponentsWithStats(m); k = 1 + np.argmax(st[1:, 4])
    pts = np.column_stack(np.where(lab == k))[:, ::-1].astype(np.float32)
    (_, _), (bw, bh), ang = cv2.minAreaRect(pts)
    return cen[k], st[k, 4], ang, bw, bh
for name, e, s_min, v_min in [("C", "192343", 70, 50), ("C", "192438", 70, 50), ("C", "192539", 70, 50), ("C", "192633", 70, 50),
                               ("D", "193404", 70, 50), ("D", "193459", 70, 50), ("D", "193617", 70, 50), ("D", "193825", 70, 50), ("D", "193932", 70, 50),
                               ("E", "194818", 120, 80), ("E", "194913", 120, 80), ("E", "195023", 120, 80), ("E", "195120", 120, 80)]:
    im = cv2.imread(f"{R}/run_0001_20261019_{e}/frames/000000.jpg")
    xl, xr, yb = mat_edges(im); mm = 620 / (xr - xl)
    (cx, cy), area, ang, bw, bh = block(im, s_min, v_min)
    print(f"{name} {e}  1画素 {mm:.2f}mm  画素数 {area:3d}  左の端から {(cx-xl)*mm:4.0f}mm  下の端から {(yb-cy)*mm:4.0f}mm  向き {ang:5.0f}°  {bw*mm:.0f}x{bh*mm:.0f}mm")
```

出力です。位置C は、マットの左の端から約 185mm、下の端から約 122mm、45〜53° 回した向きです。位置E は爪の陰で赤い部分が数画素しか見えないので、位置の数字は当てになりません。

```
C 192343  1画素 2.24mm  画素数 191  左の端から  180mm  下の端から  120mm  向き   -45°  32x33mm
C 192438  1画素 2.24mm  画素数 188  左の端から  184mm  下の端から  121mm  向き   -53°  31x32mm
C 192539  1画素 2.24mm  画素数 180  左の端から  186mm  下の端から  122mm  向き   -53°  33x32mm
C 192633  1画素 2.24mm  画素数 191  左の端から  187mm  下の端から  120mm  向き   -51°  33x32mm
D 193404  1画素 2.23mm  画素数 253  左の端から   63mm  下の端から  244mm  向き   -22°  37x38mm
D 193459  1画素 2.24mm  画素数 252  左の端から   66mm  下の端から  239mm  向き   -20°  38x38mm
D 193617  1画素 2.24mm  画素数 249  左の端から   68mm  下の端から  240mm  向き   -27°  35x37mm
D 193825  1画素 2.24mm  画素数 256  左の端から   68mm  下の端から  239mm  向き   -22°  38x39mm
D 193932  1画素 2.24mm  画素数 253  左の端から   62mm  下の端から  243mm  向き   -31°  37x39mm
E 194818  1画素 2.23mm  画素数  18  左の端から  378mm  下の端から  103mm  向き   -90°  11x7mm
E 194913  1画素 2.24mm  画素数   7  左の端から  356mm  下の端から  120mm  向き   -90°  4x4mm
E 195023  1画素 2.23mm  画素数  12  左の端から  373mm  下の端から  100mm  向き   -90°  11x4mm
E 195120  1画素 2.24mm  画素数  14  左の端から  373mm  下の端から   99mm  向き   -76°  11x7mm
```

位置C に合わせたときの `camera_align.py` の画面です。左上に OK と、写り方のずれ（dy・dx）が出ます。

【画像】LOG361_05_camera_align_C.jpg camera_align.py の画面。上カメラのライブ映像にお手本 192343（位置C）の最初のコマを重ね、左上に OK と dy −1.1・dx +0.1 が出ている。ブロックは重なった位置に置いてある


## 位置C の朝の回は、つかんで運んだが、引きずって箱の壁に当てた

アームを動かす常駐プログラム（daemon。Raspberry Pi の上で動き、Mac からの角度の指令を受けてアームへ送る）が動いているかを確かめ、アームをたたんだ姿勢（HOME）に戻して爪を開いてから、π0.5 で動かしました。1回目（9:52）です。1回の問い合わせで返ってくる10ステップ（1秒分）のうち、最後の姿勢だけを送る、これまでのやり方です。最初の問い合わせは、サーバー側のコンパイルで 52 秒かかっています。

```
Last login: Thu Oct 22 09:07:18 on ttys006
(base) shimazueiichi@shimadzueiichinoMacBook-Pro ~ % ssh -i ~/.ssh/id_rsa_pi ubuntu@192.168.2.1 'ss -ltn | grep 5555' || { ssh -i ~/.ssh/id_rsa_pi ubuntu@192.168.2.1 "setsid nohup python3 /home/ubuntu/mecharm_daemon.py </dev/null >>/home/ubuntu/daemon.log 2>&1 &"; sleep 5; ssh -i ~/.ssh/id_rsa_pi ubuntu@192.168.2.1 'tail -3 ~/daemon.log; ss -ltn | grep 5555'; }
[DAEMON 14:50:28] ✓ MyCobot 初期化完了
[DAEMON 14:50:28] startup_warmup angles=[-0.35, 93.25, -7.99, 1.84, -86.83, -29.7]
[DAEMON 14:50:28] ポート 5555 で待ち受け中...
LISTEN   0         1                   0.0.0.0:5555             0.0.0.0:*       
(base) shimazueiichi@shimadzueiichinoMacBook-Pro ~ % cd ~/r2r2r-scripts
python3 dynamic_tracking_limits/place/place_modules/08_home_from_anywhere.py
python3 -c "from visual_servo_pick import get_daemon_socket, daemon_set_gripper, close_daemon_socket; get_daemon_socket(); daemon_set_gripper(0); close_daemon_socket()"
[INIT] daemon 接続中...
  [WARN] fresh_mode切替不可: daemon error: set_fresh_mode is not available in this pymycobot environment
[INIT] fresh_mode=1
[PRE]  現在姿勢: [-0.35, 93.25, -7.99, 1.84, -86.83, -29.70]
[SEND] HOME へ移動指令
[WAIT] t=2.1s  max_err=8.78°
[WAIT] t=2.6s  max_err=1.31°
[DONE] HOME 到達 max_err=1.31°
[POST] 最終姿勢: [-0.26, 1.23, 0.61, 0.52, 1.31, -29.79]
  [WARN] fresh_mode切替不可: daemon error: set_fresh_mode is not available in this pymycobot environment
[EXIT] fresh_mode=0, socket close
  [Pi] GRIPPER: OPEN result= -1
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % cd ~/r2r2r-scripts
RAW=/Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
python3 pi05/run_policy_client.py --raw-dir $RAW --steps-per-chunk 10 --execute
[SAFE  ] 安全範囲 (学習 19 本 ±10°): j0[-72,+55]  j1[-9,+88]  j2[-46,+41]  j3[-18,+27]  j4[-90,+10]  j5[-51,-14]
[SAFE  ] 肩 j1 の上限は J1_SAFE_MAX=88° で切った (これを超える指令はアームが黙って捨てる / LOG352)  元データ: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
[MODE  ] EXECUTE  steps/chunk=10  max_move=20.0°  log=/Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_095251
[CAMERA] 写り方 dy=-0.5 dx=+0.6 response=0.524 → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[CAMERA] 基準: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes/run_0001_20261019_183454/frames/000000.jpg
[POLICY] 接続 ws://localhost:8000  metadata={}
[GRIP  ] 開始時のグリッパー開放は, 最初の目標が検査を通ってから行います (爪が閉じていたら手で開けておく)
[000] 推論 52684ms  10ステップ先  Δ=-10.5 +20.0  +5.0  -3.0 -20.0  +2.1
       [LIMIT] j1 移動量 +21.2° を ±20° に制限
       [LIMIT] j4 移動量 -27.0° を ±20° に制限
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[GRIP  ] 開始時にグリッパーを開く
  [Pi] GRIPPER: OPEN result= -1
[SEND] pi05_chunk000: send_angles (single) [ -10.74,  +21.23,   +5.75,   -2.77,  -20.26,  -27.74]  speed=20 wait=1.0s  (pre max|Δ|=20.00°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.02° (tol 3.0°)
[001] 推論 861ms  10ステップ先  Δ=-12.5 +20.0  +6.3  +0.1 -20.0  +0.5
       [LIMIT] j1 移動量 +23.7° を ±20° に制限
       [LIMIT] j4 移動量 -28.5° を ±20° に制限
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk001: send_angles (single) [ -23.21,  +42.23,  +12.68,   -2.94,  -39.24,  -27.79]  speed=20 wait=1.0s  (pre max|Δ|=20.00°, post-send timeout 8.0s)

[SEND] arrival OK: max|Δ|=0.92° (tol 3.0°)
[002] 推論 804ms  10ステップ先  Δ= -9.5 +16.5  +5.5  -0.0 -20.0  +0.1
       [LIMIT] j4 移動量 -20.5° を ±20° に制限
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > [SEND] pi05_chunk002: send_angles (single) [ -32.98,  +59.66,  +18.79,   -2.23,  -59.02,  -27.81]  speed=20 wait=1.0s  (pre max|Δ|=19.91°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.44° (tol 3.0°)
[003] 推論 2310ms  7ステップ先  Δ= +0.1  +1.8  -1.6  -1.0  +1.0  +0.1  グリッパー→閉
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk003: send_angles (single) [ -32.81,  +62.17,  +16.77,   -3.07,  -59.50,  -27.87]  speed=20 wait=1.0s  (pre max|Δ|=1.79°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.93° (tol 3.0°)
  [Pi] GRIPPER: VALUE=20 speed=100 result= -1
[004] 推論 804ms  10ステップ先  Δ=+13.5  -5.2  -1.2  +2.7  +0.2  -1.7
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk004: send_angles (single) [ -19.49,  +57.40,  +15.34,   +0.14,  -61.43,  -30.00]  speed=20 wait=1.0s  (pre max|Δ|=13.46°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.99° (tol 3.0°)
[005] 推論 806ms  10ステップ先  Δ=+20.0  -5.7  -4.9  +3.5  +3.6  -2.0
       [LIMIT] j0 移動量 +25.9° を ±20° に制限
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk005: send_angles (single) [  +0.41,  +53.59,  +11.16,   +3.68,  -54.86,  -31.23]  speed=20 wait=1.0s  (pre max|Δ|=20.00°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.39° (tol 3.0°)
[006] 推論 2172ms  10ステップ先  Δ=+20.0  -7.9  -4.5  +0.9  +7.2  -0.2
       [LIMIT] j0 移動量 +24.4° を ±20° に制限
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk006: send_angles (single) [ +20.08,  +48.06,   +8.16,   +3.66,  -48.66,  -30.77]  speed=20 wait=1.0s  (pre max|Δ|=20.00°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.65° (tol 3.0°)
[007] 推論 1081ms  10ステップ先  Δ=+19.7  +1.4  -6.4  +1.5  +2.7  -0.9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk007: send_angles (single) [ +39.41,  +52.10,   +3.37,   +5.31,  -46.20,  -31.73]  speed=20 wait=1.0s  (pre max|Δ|=19.73°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.37° (tol 3.0°)
[008] 推論 2683ms  10ステップ先  Δ= +0.7 +10.9  -2.4  +0.9  -9.2  -0.1  グリッパー→開
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > h
[SEND] pi05_home: send_angles (single) [  +0.00,   +0.00,   +0.00,   +0.00,   +0.00,  -30.00]  speed=20 wait=1.0s  (pre max|Δ|=53.08°, post-send timeout 10.0s)
[SEND] arrival OK: max|Δ|=1.93° (tol 2.5°)
[DONE  ] 記録: /Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_095251
```

チャンク03（問い合わせの番号）でつかみ、04〜07 で箱の方へ回り、08 で「爪を開く」と返ってきたところで、送らずに h（HOME に戻して終了）で止めました。

続けて動かそうとすると、上カメラの写り方の確認で3回止まりました。`response`（お手本の画像との似かたの強さ）が 0.2 を下回り、「測れない」になっています。カメラを開き直してから `camera_align.py` で確かめ、写り方が OK に戻ってから動かしました。

```
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % cd ~/r2r2r-scripts
RAW=/Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
python3 pi05/run_policy_client.py --raw-dir $RAW --steps-per-chunk 10 --execute
[SAFE  ] 安全範囲 (学習 19 本 ±10°): j0[-72,+55]  j1[-9,+88]  j2[-46,+41]  j3[-18,+27]  j4[-90,+10]  j5[-51,-14]
[SAFE  ] 肩 j1 の上限は J1_SAFE_MAX=88° で切った (これを超える指令はアームが黙って捨てる / LOG352)  元データ: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
[MODE  ] EXECUTE  steps/chunk=10  max_move=20.0°  log=/Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_095832
[CAMERA] 写り方 dy=-6.7 dx=+7.2 response=-0.059 → 測れない (相関が弱く dx/dy が当てにならない (response=-0.059 < 0.20))
[CAMERA] 基準: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes/run_0001_20261019_183454/frames/000000.jpg
[DONE  ] 記録: /Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_095832
[ABORT ] 上カメラの写り方が『測れない』. アームには何も送らずに終了しました.
         相関が弱く dx/dy が当てにならない (response=-0.059 < 0.20)
         pi05/camera_align.py で合わせ直す (iPhone を付け直す / 連係カメラを開き直す).
         この写り方のまま続けるなら --ignore-framing
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % python3 pi05/camera_align.py --raw-dir $RAW --episode run_0001_20261019_192343 --scale 5
[REF   ] 基準画像: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes/run_0001_20261019_192343/frames/000000.jpg
[REF   ] お手本 run_0001_20261019_192343 (つかんだ瞬間の j0 = -27.7°)
[REF   ] 重なった画像のブロックに実物のブロックを合わせると, お手本と同じ位置に置ける
[ALIGN ] |dy| <= 20 なら OK. アームは HOME に置いた状態で合わせる. q または Esc で終了 (ファイルには何も書かない)
[ALIGN ] dy=  +4.8  dx=  -2.9  response=0.428  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +5.8  dx=  -3.1  response=0.436  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +7.8  dx=  -4.2  response=0.423  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +8.8  dx=  -4.6  response=0.428  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +9.9  dx=  -7.4  response=0.396  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +8.8  dx=  -7.2  response=0.385  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +5.8  dx=  -9.0  response=0.423  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +3.2  dx= -11.9  response=0.506  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +2.0  dx= -30.0  response=0.297  → ずれ (|dx|=30.0 > 20)
[ALIGN ] dy=  +0.4  dx= -33.0  response=0.295  → ずれ (|dx|=33.0 > 20)
[ALIGN ] dy=  -0.8  dx= -32.7  response=0.370  → ずれ (|dx|=32.7 > 20)
[ALIGN ] dy=  +0.4  dx= -29.7  response=0.368  → ずれ (|dx|=29.7 > 20)
[ALIGN ] dy=  +1.9  dx= -25.8  response=0.254  → ずれ (|dx|=25.8 > 20)
[ALIGN ] dy=  +3.2  dx= -22.5  response=0.299  → ずれ (|dx|=22.5 > 20)
[ALIGN ] dy=  +4.5  dx= -19.0  response=0.357  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +6.0  dx=  -9.1  response=0.395  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +7.5  dx=  -5.1  response=0.407  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +9.1  dx=  -1.6  response=0.392  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy= +10.6  dx=  +1.8  response=0.379  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy= +12.2  dx=  -1.0  response=0.391  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy= +14.9  dx=  -0.4  response=0.396  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy= +17.8  dx=  -0.0  response=0.345  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy= +11.9  dx=  -1.0  response=0.385  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +6.9  dx=  +0.9  response=0.451  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +3.8  dx=  -1.3  response=0.445  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +1.5  dx=  -4.0  response=0.430  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -1.1  dx=  -4.4  response=0.392  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -2.2  dx=  -5.5  response=0.402  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -3.6  dx=  -4.2  response=0.400  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -1.8  dx=  -1.2  response=0.404  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +0.6  dx=  -0.1  response=0.372  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -0.8  dx=  +0.2  response=0.434  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -1.9  dx=  +3.3  response=0.369  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
^C
[STOP  ] Ctrl-C
[DONE  ] 終了 (何も書いていません)
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % cd ~/r2r2r-scripts
RAW=/Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
python3 pi05/run_policy_client.py --raw-dir $RAW --steps-per-chunk 10 --execute
[SAFE  ] 安全範囲 (学習 19 本 ±10°): j0[-72,+55]  j1[-9,+88]  j2[-46,+41]  j3[-18,+27]  j4[-90,+10]  j5[-51,-14]
[SAFE  ] 肩 j1 の上限は J1_SAFE_MAX=88° で切った (これを超える指令はアームが黙って捨てる / LOG352)  元データ: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
[MODE  ] EXECUTE  steps/chunk=10  max_move=20.0°  log=/Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_100108
[CAMERA] 写り方 dy=-28.1 dx=+5.9 response=0.015 → 測れない (相関が弱く dx/dy が当てにならない (response=0.015 < 0.20))
[CAMERA] 基準: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes/run_0001_20261019_183454/frames/000000.jpg
[DONE  ] 記録: /Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_100108
[ABORT ] 上カメラの写り方が『測れない』. アームには何も送らずに終了しました.
         相関が弱く dx/dy が当てにならない (response=0.015 < 0.20)
         pi05/camera_align.py で合わせ直す (iPhone を付け直す / 連係カメラを開き直す).
         この写り方のまま続けるなら --ignore-framing
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % 
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % --ignore-framing
zsh: command not found: --ignore-framing
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % python3 pi05/run_policy_client.py --raw-dir $RAW --steps-per-chunk 10 --execute
[SAFE  ] 安全範囲 (学習 19 本 ±10°): j0[-72,+55]  j1[-9,+88]  j2[-46,+41]  j3[-18,+27]  j4[-90,+10]  j5[-51,-14]
[SAFE  ] 肩 j1 の上限は J1_SAFE_MAX=88° で切った (これを超える指令はアームが黙って捨てる / LOG352)  元データ: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
[MODE  ] EXECUTE  steps/chunk=10  max_move=20.0°  log=/Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_100202
[CAMERA] 写り方 dy=-26.8 dx=+6.3 response=0.015 → 測れない (相関が弱く dx/dy が当てにならない (response=0.015 < 0.20))
[CAMERA] 基準: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes/run_0001_20261019_183454/frames/000000.jpg
[DONE  ] 記録: /Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_100202
[ABORT ] 上カメラの写り方が『測れない』. アームには何も送らずに終了しました.
         相関が弱く dx/dy が当てにならない (response=0.015 < 0.20)
         pi05/camera_align.py で合わせ直す (iPhone を付け直す / 連係カメラを開き直す).
         この写り方のまま続けるなら --ignore-framing
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % python3 -c "from visual_servo_pick import get_daemon_socket, daemon_set_gripper, close_daemon_socket; get_daemon_socket(); daemon_set_gripper(0); close_daemon_socket()"
  [Pi] GRIPPER: OPEN result= -1
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % python3 pi05/camera_align.py --raw-dir $RAW --episode run_0001_20261019_192343 --scale 5
[REF   ] 基準画像: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes/run_0001_20261019_192343/frames/000000.jpg
[REF   ] お手本 run_0001_20261019_192343 (つかんだ瞬間の j0 = -27.7°)
[REF   ] 重なった画像のブロックに実物のブロックを合わせると, お手本と同じ位置に置ける
[ALIGN ] |dy| <= 20 なら OK. アームは HOME に置いた状態で合わせる. q または Esc で終了 (ファイルには何も書かない)
[ALIGN ] dy=  -1.0  dx=  +0.1  response=0.668  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
q

q
^C
[STOP  ] Ctrl-C
[DONE  ] 終了 (何も書いていません)
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % python3 pi05/run_policy_client.py --raw-dir $RAW --steps-per-chunk 10 --execute
[SAFE  ] 安全範囲 (学習 19 本 ±10°): j0[-72,+55]  j1[-9,+88]  j2[-46,+41]  j3[-18,+27]  j4[-90,+10]  j5[-51,-14]
[SAFE  ] 肩 j1 の上限は J1_SAFE_MAX=88° で切った (これを超える指令はアームが黙って捨てる / LOG352)  元データ: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
[MODE  ] EXECUTE  steps/chunk=10  max_move=20.0°  log=/Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_100648
[CAMERA] 写り方 dy=-6.7 dx=+2.8 response=0.585 → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[CAMERA] 基準: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes/run_0001_20261019_183454/frames/000000.jpg
[POLICY] 接続 ws://localhost:8000  metadata={}
[GRIP  ] 開始時のグリッパー開放は, 最初の目標が検査を通ってから行います (爪が閉じていたら手で開けておく)
[000] 推論 1306ms  10ステップ先  Δ= -9.5 +20.0  +5.4  -2.4 -20.0  +1.3
       [LIMIT] j1 移動量 +20.2° を ±20° に制限
       [LIMIT] j4 移動量 -25.7° を ±20° に制限
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[GRIP  ] 開始時にグリッパーを開く
  [Pi] GRIPPER: OPEN result= -1
[SEND] pi05_chunk000: send_angles (single) [  -9.70,  +21.49,   +7.35,   -2.70,  -20.26,  -28.38]  speed=20 wait=1.0s  (pre max|Δ|=20.00°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.19° (tol 3.0°)
[001] 推論 1350ms  10ステップ先  Δ=-13.6 +20.0  +6.6  +0.1 -20.0  +0.4
       [LIMIT] j1 移動量 +23.6° を ±20° に制限
       [LIMIT] j4 移動量 -30.4° を ±20° に制限
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > h
[SEND] pi05_home: send_angles (single) [  +0.00,   +0.00,   +0.00,   +0.00,   +0.00,  -30.00]  speed=20 wait=1.0s  (pre max|Δ|=22.58°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.75° (tol 2.5°)
[DONE  ] 記録: /Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_100648
```

10:06 の回は、動き出しのあとで h で止めています。10:07 の回が、この朝いちばん先まで進んだ回です。

```
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % python3 pi05/run_policy_client.py --raw-dir $RAW --steps-per-chunk 10 --execute
[SAFE  ] 安全範囲 (学習 19 本 ±10°): j0[-72,+55]  j1[-9,+88]  j2[-46,+41]  j3[-18,+27]  j4[-90,+10]  j5[-51,-14]
[SAFE  ] 肩 j1 の上限は J1_SAFE_MAX=88° で切った (これを超える指令はアームが黙って捨てる / LOG352)  元データ: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
[MODE  ] EXECUTE  steps/chunk=10  max_move=20.0°  log=/Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_100713
[CAMERA] 写り方 dy=-6.9 dx=+2.7 response=0.542 → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[CAMERA] 基準: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes/run_0001_20261019_183454/frames/000000.jpg
[POLICY] 接続 ws://localhost:8000  metadata={}
[GRIP  ] 開始時のグリッパー開放は, 最初の目標が検査を通ってから行います (爪が閉じていたら手で開けておく)
[000] 推論 1998ms  10ステップ先  Δ= -9.4 +20.0  +5.1  -2.2 -20.0  +0.5
       [LIMIT] j1 移動量 +20.4° を ±20° に制限
       [LIMIT] j4 移動量 -25.4° を ±20° に制限
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[GRIP  ] 開始時にグリッパーを開く
  [Pi] GRIPPER: OPEN result= -1
[SEND] pi05_chunk000: send_angles (single) [  -9.65,  +21.31,   +6.89,   -2.51,  -20.52,  -28.96]  speed=20 wait=1.0s  (pre max|Δ|=20.26°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.36° (tol 3.0°)
[001] 推論 1084ms  10ステップ先  Δ=-14.6 +20.0  +6.5  -0.1 -20.0  +0.4
       [LIMIT] j1 移動量 +23.9° を ±20° に制限
       [LIMIT] j4 移動量 -31.3° を ±20° に制限
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk001: send_angles (single) [ -24.38,  +42.41,  +14.24,   -1.75,  -39.16,  -29.20]  speed=20 wait=1.0s  (pre max|Δ|=20.00°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.09° (tol 3.0°)
[002] 推論 983ms  10ステップ先  Δ=-13.0 +17.1  +5.8  +0.5 -20.0  -0.1
       [LIMIT] j4 移動量 -24.5° を ±20° に制限
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk002: send_angles (single) [ -37.64,  +60.64,  +20.58,   -1.27,  -58.49,  -29.80]  speed=20 wait=1.0s  (pre max|Δ|=20.00°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.59° (tol 3.0°)
[003] 推論 812ms  7ステップ先  Δ= +0.1  +2.5  -1.5  -0.3  +0.9  -0.3  グリッパー→閉
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk003: send_angles (single) [ -36.97,  +63.55,  +18.46,   -1.84,  -60.20,  -30.40]  speed=20 wait=1.0s  (pre max|Δ|=2.47°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.88° (tol 3.0°)
  [Pi] GRIPPER: VALUE=20 speed=100 result= -1
[004] 推論 806ms  10ステップ先  Δ=+13.2  -5.8  +0.2  +2.7  -0.3  -1.3
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk004: send_angles (single) [ -23.82,  +56.95,  +18.16,   +0.87,  -61.43,  -31.28]  speed=20 wait=1.0s  (pre max|Δ|=13.18°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.90° (tol 3.0°)
[005] 推論 2176ms  10ステップ先  Δ=+20.0  -6.4  -2.7  +2.0  +6.0  -0.6
       [LIMIT] j0 移動量 +26.1° を ±20° に制限
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk005: send_angles (single) [  -3.90,  +52.08,  +15.35,   +3.35,  -52.51,  -31.23]  speed=20 wait=1.0s  (pre max|Δ|=20.00°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.50° (tol 3.0°)
[006] 推論 1006ms  10ステップ先  Δ=+20.0  -6.7  -4.1  +0.9  +6.2  -0.3
       [LIMIT] j0 移動量 +25.7° を ±20° に制限
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk006: send_angles (single) [ +15.79,  +47.91,  +12.73,   +3.40,  -47.09,  -31.10]  speed=20 wait=1.0s  (pre max|Δ|=20.00°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.80° (tol 3.0°)
[007] 推論 2526ms  10ステップ先  Δ=+20.0  -1.5  -6.6  +1.1  +3.6  -0.5
       [LIMIT] j0 移動量 +23.0° を ±20° に制限
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk007: send_angles (single) [ +35.55,  +49.23,   +7.64,   +4.44,  -43.85,  -31.35]  speed=20 wait=1.0s  (pre max|Δ|=20.00°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.58° (tol 3.0°)
[008] 推論 994ms  10ステップ先  Δ= +4.5 +13.6  -6.6  +1.4  -5.7  -0.9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk008: send_angles (single) [ +40.43,  +64.32,   +2.65,   +6.07,  -49.84,  -31.95]  speed=20 wait=1.0s  (pre max|Δ|=13.61°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.10° (tol 3.0°)
[009] 推論 876ms  4ステップ先  Δ= -0.1  +0.5  -0.0  +0.2  -1.0  -0.1  グリッパー→開
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk009: send_angles (single) [ +39.75,  +65.45,   +3.38,   +7.04,  -52.98,  -32.52]  speed=20 wait=1.0s  (pre max|Δ|=1.39°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.38° (tol 3.0°)
  [Pi] GRIPPER: OPEN result= -1
[010] 推論 801ms  4ステップ先  Δ= -0.0  -0.1  +0.2  +0.2  -0.6  -0.1  グリッパー→閉
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk010: send_angles (single) [ +39.89,  +65.93,   +3.49,   +6.99,  -52.26,  -32.55]  speed=20 wait=1.0s  (pre max|Δ|=0.23°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.69° (tol 3.0°)
  [Pi] GRIPPER: VALUE=20 speed=100 result= -1
[011] 推論 842ms  3ステップ先  Δ= -0.2  +0.1  +0.1  +0.1  -0.4  -0.1  グリッパー→開
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
  [Pi] GRIPPER: OPEN result= -1
[012] 推論 2247ms  4ステップ先  Δ= +0.0  +0.4  +0.1  +0.2  -1.0  -0.1  グリッパー→閉
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk012: send_angles (single) [ +40.45,  +67.00,   +3.12,   +7.26,  -52.21,  -32.61]  speed=20 wait=1.0s  (pre max|Δ|=0.89°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.32° (tol 3.0°)
  [Pi] GRIPPER: VALUE=20 speed=100 result= -1
[013] 推論 811ms  5ステップ先  Δ= -0.1  +0.2  -0.1  +0.2  -1.1  -0.2  グリッパー→開
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > h
[SEND] pi05_home: send_angles (single) [  +0.00,   +0.00,   +0.00,   +0.00,   +0.00,  -30.00]  speed=20 wait=1.0s  (pre max|Δ|=67.32°, post-send timeout 12.1s)
[SEND] [TIMEOUT] 12.1s 内に未到達: max|Δ|=2.54° actual=[  -0.26,   +1.49,   +2.54,   +0.26,   +0.17,  -30.23]
[SEND] リトライしません: pre→last max|Δ| 65.83° >= 1.0° (部分移動/ストール疑い)
[DONE  ] 記録: /Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_100713
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % 
```

チャンク03 でつかみ、08 で箱の位置まで回り、09〜13 で爪の「開く・閉じる」を繰り返しました。横から撮った動画では、ブロックはマットに付いたまま引きずられ、箱の壁に当たって箱を押しています。最後に h で HOME へ戻すと、ブロックを持ったまま戻りました。

【画像】LOG361_03_drag_100713.jpg 10:07 の回を斜め上から撮った動画のコマ。0:29 でつかみ、0:54 でブロックを箱の壁に当てて箱を押し、1:44 でブロックを持ったまま HOME に戻っている

【動画】LOG361_v1_drag_100713.mp4 10:07 の回を斜め上から撮った動画（約1分46秒）


## 0.5 秒ずつ動かした 10:20 の回は、深くつかみ、持ち上がらないまま31回問い合わせた

1回に動かす長さを 0.5 秒（5ステップ）にして、細かく問い合わせる回も試しました（`--steps-per-chunk 5`）。この回の画面の出力は残っていないので、記録（`log.jsonl`）から作った表を「実機の回すべてのチャンクの記録」の節に載せています。

この回は、閉じる前に肩を少しずつ下げ続け、お手本より約5°深いところ（肩 j1 = 69°、お手本は 64°）でつかみました。そのあと、肩を上げる指令が17回続きましたが、指令の合計 41.2° に対して、実際に上がったのは 11.1° です。上のカメラの画像を、お手本（位置C）の同じ場面と並べました。

【画像】LOG361_04_run102053_vs_demo_C.jpg 上カメラの画像。左が 10:20 の回のチャンク08・11・13・18・22・27、右がお手本 192343 の同じ場面。左は肩 j1 が 68〜58° のまま、右は 64° から 49° へ上がっている

この回までの記録をまとめ、学習と実機で、モデルへの入力や答えの使い方が食い違っていないかの点検を codex に頼みました。依頼文です。

```
# 確認依頼：π0.5 が実機でブロックを持ち上げない原因（学習と実機の食い違いの点検）

対象（読むだけ。コードの変更はしないでください）
- `~/r2r2r-scripts/pi05/run_policy_client.py`（実機クライアント。とくに grab_rgb / 状態の作り方 / plan_chunk / apply_limits / グリッパーの扱い）
- `~/r2r2r-scripts/pi05/build_demo_episodes.py`（お手本 → raw_episodes。--trim-mid-idle を含む版で teach_v1_trim2 を作った）
- `~/r2r2r-scripts/pi05/convert_to_lerobot.py`（raw_episodes → LeRobot 形式）
- `~/r2r2r-scripts/pi05/openpi_addon/`（mecharm_policy.py と config の追加。入力・出力の変換、正規化、delta かどうか）
- `~/r2r2r-scripts/pi05/eval_policy_offline.py`（お手本の画像と角度でサーバーに問い合わせる答え合わせ）
- 学習設定：`/Volumes/KIOXIA/r2r2r-data/lab/Log11/pod/add_trim_config.py`（pi05_mecharm_lora を写して repo_id・名前・ステップ数だけ変えたもの）

---

## 何が起きているか

mechArm 270 で、Physical Intelligence の π0.5 を LoRA で学習した（お手本19本・5か所・teach_v1_trim2・4,000ステップ）。
タスクは「赤いブロックをつかんで白い箱に入れる」。

実機では、ブロックはつかめる。しかし**つかんだあと持ち上げず、マットの上を引きずったまま箱へ運び、爪が箱の壁に当たって箱を押す**（横からの動画で確認済み）。お手本は、つかんだあと肩 j1 を 64° → 45° と約19°上げてから箱の上で下ろしている。お手本の持ち上げは十分に大きい。

## 分かっている事実（数値）

1. **答え合わせ（オフライン）では合っている**：お手本の画像と角度を渡すと、つかむ前後・持ち上げ・運ぶ間のすべてで、予測とお手本のずれは平均 0.1〜0.5°（記録：`/Volumes/KIOXIA/r2r2r-data/lab/Log11/offline_eval/20261021_180539/rows.csv`。位置C = run_0001_20261019_192343 の t=36〜108 を参照）
2. **実機では持ち上げが足りない**。ブロックはお手本の位置C ちょうどに置いた（上カメラの写り方は OK を確認）
   | 記録 | 1回に動かす長さ | 上限に当たった関節 | つかんだ姿勢 j0 / j1 | 運ぶ途中の j1 / j4 |
   |---|---|---|---|---|
   | お手本 位置C（4本） | — | — | −28 / 64 | 45〜51 / −54〜−66 |
   | pi05_20261022_095251 | 1秒（10ステップ） | 手を伸ばす間 j1・j4、運ぶ間 j0 | −33 / 63 | 51 / −46〜−49 |
   | pi05_20261022_100713 | 1秒（10ステップ） | 同上 | −37 / 63 | 51 / −44〜−47 |
   | pi05_20261022_102053 | 0.5秒（5ステップ） | なし | −31 / **69** | **56〜58** / −62〜−67 |
   （j4 は + が爪先を下げる向き。記録は `/Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/{記録名}/log.jsonl` と `frames/`。各チャンクの state・予測 actions・送った target がある）
3. 0.5秒ずつの回は、閉じる前に肩を少しずつ下げ続け、お手本より5°深くつかんだ。つかんだ後の予測は、5ステップあたり j1 −2〜−3.6° と小さく、1ステップあたりの持ち上げはお手本の4分の1ほど。回転もお手本の半分ほどの速さ
4. 昨日（10/21）の夕方の8回も、同じく「持ち上げが足りず引きずる」だった（そのときはブロックをお手本の位置の間に置いていた）

## 点検してほしいこと

**オフラインでは合い、実機ではずれる**ので、学習時と実機の推論時で、モデルに渡す入力や予測の使い方が食い違っていないかを見てほしい。

A1. **画像**：学習の画像（recorder が保存した jpg → raw_episodes → LeRobot）と、実機の grab_rgb（1920×1080 を 384×216 に INTER_AREA で縮め、RGB）の作り方は同じか。色の順、縮め方、JPEG を通すかどうか、大きさ、パディングの違い
A2. **状態 state**：7次元（6関節＋グリッパー）。実機のグリッパーの値（0/1）を切り替えるタイミングと、お手本でグリッパーの値が変わるタイミングは同じか。関節角の読み方（daemon_get_angles と、お手本の記録の読み方）に違いはないか
A3. **行動 actions**：お手本の action は「0.1秒後の state（絶対角）」。openpi 側で delta に変換しているか。している場合、推論時に絶対角へ戻す処理と、クライアントの扱いが合っているか。グリッパーの次元の扱い（delta の対象から外れているか）
A4. **正規化**：学習で使った norm_stats（teach_v1_trim2）と、推論サーバーが読む norm_stats は同じか（サーバーの起動ログ：`/Volumes/KIOXIA/r2r2r-data/lab/Log12/serve.log`）
A5. **実行の仕方**：クライアントはチャンクの最後の1つ（5番目または10番目）だけを send_angles で送り、着くまで待ってから次を問い合わせる。お手本では腕が動き続けているが、実機では毎回止まった状態で問い合わせる。この違いで、予測が「動き出し」の小さな動きを繰り返す形になり得るか
A6. そのほか、オフラインの答え合わせと実機の推論で、入力の作り方が違う箇所

## 返してほしいもの

- A1〜A6 それぞれについて、✅ 同じ／⚠️ 気になる／❌ 食い違っている（該当ファイルと行番号）
- 持ち上げが足りない原因として、いちばん疑わしいもの
- 原因を切り分けるための、**アームを動かさない**確かめ方の提案（たとえば、実機の記録の画像とお手本の画像を入れ替えてサーバーに問い合わせる、など）

固定事項（変えない）：HOME = [0,0,0,0,0,−30]、SPEED = 20、J4_SAFE −90〜+60、send_coords() は使わない。
```

codex の点検結果です。画像の作り方や正規化の値に、持ち上げ不足を説明する食い違いは見つからず、いちばん疑わしいのは「チャンクの最後の姿勢だけを送り、3°以内なら着いたとみなして次へ進む」実行のしかただ、という結論でした。

```
# π0.5 持ち上げ不足：学習・実機の食い違い点検

2026-10-22。コード・19本のraw_episodes・指定のオフラインCSV・実機3回のlog.jsonl・serve.log・FK比較表を読み取り専用で確認した。アーム、グリッパー、カメラ、推論サーバーへの操作・接続は行っていない。対象コード、HOME、SPEED、J4_SAFEは変更していない。以下の数値集計は保存済みデータだけを使った。

## 結論

**最有力は、チャンク末尾の姿勢だけを送る再計画方式と、3°の到達許容が、小さい持ち上げ指令を十分に実現できないまま次の予測へ進めていること。** それに、つかむ時点で学習軌道より深い姿勢へ外れる問題が重なっている。

「モデルが肩をお手本の4分の1しか上げる予測をしていない」とする根拠は、今回の数値からは支持できない。位置Cのrawでも5ステップ先のj1変化は約−2〜−3.8°で、実機ログの−2〜−3.6°と同程度の区間がある。**予測変位と実現変位を分ける必要がある。** またj1だけでは高さは決まらず、j2/j3/j4との組合せも関係する。

ただし、3°判定だけを唯一の原因と断定はしない。到達フラグは速度ゼロ・最終収束を保証しないし、次の実測までの間に追加移動する可能性もある。以下のログは、結果として小さい肩指令が十分実現していないことを示す。機械の追従特性・画像による分布ずれとの因果分離は追加の非駆動試験が必要。

## A1〜A6

### A1 ⚠️ 気になる：RGBと縮小は同じ、画像生成経路は同一ではない

- 学習raw生成：`build_demo_episodes.py:381–392`。recorderのtop.mp4をデコードし、長辺384へINTER_AREAで縮小、JPEG品質95で保存。
- LeRobot変換：`convert_to_lerobot.py:58–64`。JPEGをPillowでRGBにしてadd_frame。サイズをメタデータと照合。
- オフライン評価：`eval_policy_offline.py:68–72,117–126`。raw JPEGをOpenCVで読み、BGR→RGB。再縮小しない。
- 実機：`run_policy_client.py:134–143,315–330`。カメラから取得したフレームを長辺384へ同じINTER_AREAで縮小、BGR→RGBし、JPEGを通さず送る。

**色順の逆転、縮小サイズの不一致はコード上見つからない。** 位置Cのmetaは384×216。共通addonの `_parse_image` は配列のdtype/軸を扱うだけで、別の色変換はない（`mecharm_policy.py:28–34,41–61`）。ローカルopenpiのModelTransformFactoryはResizeImages(224,224)を持ち、実機も評価も同じサーバーなら同じパディング処理を受ける。

一方、学習は「カメラ→avc1動画→デコード→縮小→JPEG→デコード」、実機は「カメラ→縮小→直接送信」。recorderは `recorder.py:80,478–480` でavc1保存。圧縮・デコード差は実在するが、それが高さ不足の主因とする証拠はまだない。Pillow/OpenCVのデコード差やLeRobot側の再保存もピクセル同一を保証しない。

実機クライアントはカメラ解像度1920×1080を明示設定していない（245–256行）。実際の取得サイズに合わせて縮小する。1920×1080であることは保存画像だけでは逆算できない。フレーミングOKは画素全体・照明・箱・爪・ブロック位置の学習分布一致の証明ではない。

重要：実機のframes/*.jpgは、**推論へ送った後**にJPEG化して保存される（336行）。このJPEGを再送しても当時のRGB配列を完全再現したことにはならない。

### A2 ⚠️ 気になる：7次元・度数法は同じ、状態の時間的意味が違う

関節の元の取得関数は共通のdaemon_get_angles。お手本側はrun_pick_placeのtapが実測6軸をrecorderへ送る（`run_pick_place.py:593–608`）、rawではactualを線形補間する（`build_demo_episodes.py:102–125,303–324`）。実機はdaemonの単発実測をそのまま使う（`run_policy_client.py:122–131,315–328`）。角度の順番やrad/degの入替は見つからないが、**動作中の補間状態と、到達後に読み直す状態**の差がある。画像と関節の同時刻取得も保証されない。

グリッパーはどちらも0=open/1=closeの指令状態で、把持センサー値ではない。

- お手本：指令直前にgripper_cmdを通知（`run_pick_place.py:2273–2275`）、その時刻でrawのstateを切替（`build_demo_episodes.py:318–324`）。
- 実機：指令を送り2秒待ってからソフト上のgripを更新（`run_policy_client.py:401–407`）。次の問い合わせはその後なので、通常は閉じた後にgrip=1となり整合する。途中2秒間を問い合わせていないため、この差だけで主因とは言えない。
- plan_chunkは最初に開閉が変わる予測位置fを見つけ、**その直前の関節姿勢**を選ぶ。f=0なら現在姿勢で開閉する（146–154行）。開閉予定ステップまでの関節変位を1ステップ分省く設計で、把持姿勢のずれに寄与し得る。

初回はgrip=0と仮定して撮像・推論し、実際に開くのは最初の送信直前（242–243,386–392行）。開始時に爪が閉じていれば、最初の画像とstate[6]は食い違う。これは初回の潜在的不整合で、今回の持ち上げ不足の直接原因とまでは未確認。

### A3 ✅ 同じ：関節6軸はdelta学習→絶対角復元、爪はdelta対象外

`openpi_addon/install_addon.py:51–57`：mask=make_bool_mask(6,-1)。先頭6次元True、7番目False。

ローカルopenpiの `transforms.py:204–242` ではDeltaActionsが**チャンク先頭stateからの差分**を引き、AbsoluteActionsで同じstateを加算する。隣接actions間の差分を累積する方式ではない。クライアントが追加でdeltaを積算しないのは正しい。

`policy_config.py:77–87` の出力はmodel transforms→Unnormalize→data transformsで、最後に絶対角へ戻す。MecharmOutputsは先頭7次元を返す（`mecharm_policy.py:65–68`）。実機ログのactionsも絶対角の値域で、deltaをそのまま角度として送るような明らかな不一致はない。

19本すべてで `actions[:-1,:6] == state[1:,:6]` の最大差は **0**。爪も `actions[:-1,6] != state[1:,6]` は **0件**。

注意：trim後は残った次のstateをactionに再設定し、tを等間隔に振り直す（build:352–361,401–407）。したがって「0.1秒後」は**圧縮後の学習時間**であり、元動画の実時間0.1秒後とは限らない。19本のt_orig隣接間隔の最大は約11.70秒。削除境界の動作は別途確認が必要だが、これだけで持ち上げ不足と断定しない。

この判定はローカルaddon/openpiと保存ログに基づく。稼働中コンテナのソースのハッシュ照合は未実施。

### A4 ⚠️ 気になる：trim2のcheckpoint assetsを読む証拠はあるが、バイト一致は未確認

`add_trim_config.py`は元configをコピーし、name/repo_id/num_train_stepsのみ変更する。action_horizon=10、6軸deltaの設定は維持される。

`serve.log:8,15–16`：3999/paramsを復元し、config側のtrim2 assetsに続いて **checkpoint/3999/assets/local/mecharm_redblock_box_teach_v1_trim2** を読んでいる。ローカル `policy_config.py:59–64` もnorm_stats未指定ならcheckpoint assetsを優先する。旧teach_v1やv1のnormを使っている証拠はない。

SSDには `checkpoints/pi05_mecharm_trim_lora_v1/3999/assets/local/mecharm_redblock_box_teach_v1_trim2/norm_stats.json` がある。ただしサーバー側ファイル、学習時assetsのSHA256、10/21オフライン評価時のcheckpoint識別子は記録から照合できていない。**「同じrepo_id」から「同じnormの中身」とは断定しない。** ログからは低優先の原因候補。

### A5 ❌ 食い違っている：10Hz軌道の評価と末尾1姿勢の実行＋3°到達判定

`run_policy_client.py:333–334,393–395`はチャンクの選択姿勢1つだけを送り、 `_send_and_wait_arrival(...,3.0)` を呼ぶ。呼出先 `j0_sweep_scan.py:259–270` は全軸の最大角度誤差≤3°で成功し、速度ゼロや一定時間の収束を要求しない。

小さな持ち上げ指令が2°程度なら、開始姿勢自体が到達判定内にある。send自体は行われるため「必ず動かない」わけではないが、十分な移動を確認する前に成功して次の計画へ進める設計になっている。別軸の大きな変位も末尾姿勢への1回の補間となり、学習の軌跡と同じ経路を通る保証がない。途中で十分に上がってから旋回する軌跡を、浅く上げつつ旋回する直行補間に変え得る。

保存ログで確認できる例（102053）：

|chunk|現在j1|送信target j1|次の実測j1|指令上昇量|実現上昇量|
|---|---:|---:|---:|---:|---:|
|11|69.34|67.03|68.73|2.31|0.61|
|12|68.73|66.70|68.20|2.03|0.53|
|16|65.47|62.03|63.98|3.44|1.49|
|21|59.32|57.40|59.32|1.92|0.00|
|24|58.97|57.92|58.97|1.05|0.00|
|26|58.35|56.10|58.35|2.25|0.00|

いずれもnotes=[]。apply_limitsによるj1切詰めが原因の例ではない。

閉状態・開閉指令なし・target j1が現在より小さい行を集計し、その次のstateを実現値とした：

|記録|該当指令数|指令上昇量の合計°|実現上昇量の合計°|残差中央値°|
|---|---:|---:|---:|---:|
|095251|3|18.81|11.86|2.39|
|100713|4|20.30|12.04|1.99|
|102053|17|41.22|11.07|1.93|

合計は各行の現在→targetと現在→次stateを足した**指令追従の診断値**で、正味高さや同一出発点からの総角度ではない。未実現分を次回再び指令するので指令合計には重複がある。それでも「予測した上昇が実測に残らない」ことを示す。

102053の該当区間の問い合わせ記録間隔の中央値は約4.43秒。**5ステップ=学習上0.5秒先であり、実時間0.5秒周期ではない。** 095251/100713も対応区間は中央値約7.06/5.33秒。推論・通信・送信・読角・待機が加わっている。

「動き出し部分を繰り返す」はあり得るが、モデルに停止状態を示す速度入力があるわけではない。静止を直接識別していると断定せず、実測が軌道に追いつかず、チャンク後半を捨てて同じような局所予測を繰り返す閉ループ問題として捉える。

### A6 ⚠️ 気になる：オフライン評価は実行器を通らず、学習データ上の点評価

`eval_policy_offline.py:123–145`はお手本の画像/stateを直接渡して、予測チャンクと教師actionsを比較する。plan_chunk・apply_limits・到達許容・グリッパー待機・次の実測を通さない。よって「オフラインで合う」は、実機でその姿勢遷移を実現できることを検証していない。

位置C t=36〜108の25問い合わせはerr_meanの平均0.3564°だが、その範囲でerr_maxの最大は9.91°。全軸×全時点の平均だけでは局所誤差を隠す。stuckも最大変位軸で判定する（130–137行）ため、j0が回ればj1の持ち上げ不足は検出しにくい。

お手本Cの5ステップ先j1変位：t60=−2.00°、t66=−2.02°、t72=−3.36°、t78=−3.46°、t84=−3.78°。実機の−2〜−3.6°が常に教師の4分の1とは言えない。実時間あたりの速度低下、到達残差、違う状態に対する予測を混同しないこと。

実機102053では閉じた次のstate j1=69.34°に対し、教師Cは約63.7°。j0や他軸も異なる。ブロック位置を合わせても、画像内の腕姿勢・state・進行段階まで同じにはならない。最初のずれが把持前から出る理由は、画像とstateの入替試験で分離する必要がある。

## FK補足との対応

指定の `out_ee_height_compare.txt` を読んだ。教師4本は把持時41.3〜41.7mm、最高124.9〜135.2mm。実機は把持直後28.6/25.7/9.8mm、最高71.6/50.8/36.5mmで、把持前の下がり過ぎと把持後の上昇不足の両方があるという説明と整合する。

ただしFK表の生成コード・キャリブレーション精度を独立検証した結果ではない。今回の確定事実は関節ログの追従残差であり、mm換算値は提供されたFK表として扱う。

## アームを動かさない切り分け（優先順）

### 1. 保存actionsを実行器へ再生する、純粋な数値検査

ハードウェアをimportせず、plan_chunk/apply_limitsの純粋部分だけで、各行の「生actions→開閉で選んだ姿勢→制限後target→次state」を比較する。教師actionsにも同じ選択処理をかける。3°判定内の小移動割合、j1/j2/j4残差、開閉直前の省略量を出す。

今回のログ集計でこの第一段階は実施済み。さらに既存FKの純粋計算だけを使えば、予測5/10ステップ先・選択target・次の実測それぞれの高さを比較できる。予測時点で低いのか、targetで低くなるのか、実現時に低くなるのかを直接分離できる。実機用クライアントの--executeなし起動でもカメラ・daemonアクセスがあるため、この検査には使わない。

### 2. 保存画像×保存stateの2×2再問い合わせ

把持前・把持直後・上昇中の代表点をそれぞれ選び、同じcheckpoint・prompt・normを固定して、次をサーバー**だけ**に問い合わせる。

|画像|state|狙い|
|---|---|---|
|教師|教師|現在のサーバーで教師再現の基準を作る|
|実機|教師|画像差への感度|
|教師|実機|state差への感度|
|実機|実機|当時の挙動に近い再現|

各条件を複数回、可能なら同一ノイズ条件でも比較し、j1だけでなく6軸の5/10ステップ先変位・爪・FK高さを保存する。混合入力は物理的に不整合なので、実行用の良い指令を探す試験ではなく、入力感度の診断として扱う。

教師の画像・stateでも現在は再現しなければ、入力差を論じる前にcheckpoint/norm/サーバー版の違いを調べる。実機JPEGは当時の入力と完全同一でないため、再現誤差をすべてサーバーの変化と断定しない。

### 3. 圧縮・デコードだけを変える試験

同じ保存画像からPillow/OpenCV読込、JPEG再圧縮の有無を変え、stateと推論ノイズを固定して比較する。保存画像だけでは元の非圧縮実機RGBや動画圧縮前画像を復元できないので、これは圧縮への感度試験に限る。推論へ渡す直前とモデル変換後のshape/dtype/RGB統計・パディングを保存して、色順や形状の違いを直接確かめる。

### 4. 正規化と実行版の同一性を証明する

サーバーのcheckpoint assetsのnorm_stats.json、学習時のnorm、SSD上3999のnormのSHA256と7次元の内容を比較する。checkpoint・config・addon・transforms/policy_configの版も記録する。モデル出力のUnnormalize前後、AbsoluteActions前後を同一入力で検査し、関節6軸だけstateが加算され爪は加算されないことを確かめる。

現時点ではこれらのサーバー再問い合わせ・サーバー側ハッシュ照合は未実施。アーム操作なしで可能な次段階の提案である。

## 現段階の優先順位

1. **確認済み：小さい持ち上げ指令に比べて大きい到達許容と追従残差。** 実測が約2°届かない状態で再計画する。最優先の原因候補。
2. **確認済み：把持時点で教師より深い姿勢、末尾姿勢への直行、学習時間と実時間の違い。** その状態での分布ずれ・軌道の同期崩れが連鎖する可能性。
3. **未分離：画像の撮像・圧縮・シーン差、教師上でのみ良いモデルの汎化。** 2×2試験で調べる。
4. **低優先：deltaの誤解釈や旧normの使用。** 現コードとログにはそれを支持する証拠がないが、稼働サーバーの同一性までは未証明。

この点検から直ちに制約を緩めたり、速度を変えたり、送信を増やす結論にはしない。まず保存記録とサーバーだけの試験で、予測・実行・観測のどこが高さを失わせているかを確定する。
```


## 肩を上げる指令43回は、すべて目標より 0.77〜2.80° 低いところで止まっていた

codex が数えた3回分を、この日の実機の回すべてに広げて数え直しました。夕方の回まで含めて、あとから同じスクリプトで出したものです。ブロックを持っている（爪が閉じている）ときに、肩 j1 を上げる向き（角度を小さくする向き）の指令を送り、次に測った角度が指令からどれだけずれていたかを数えます。

```python
# 肩 j1 の「送った目標」と「次のチャンクの実測」の差を数える (LOG361)
#  + は腕が目標より低いまま止まった (j1 が大きい = 下向き)
#  中継点 (--via-stride) の回は、チャンクの最後に送った目標で比べる
import os, json
import numpy as np
ROOT = os.environ.get("R2R2R_DATA", "/Volumes/KIOXIA/r2r2r-data"); os.chdir(ROOT)
RUNS = ["20261021_183245", "20261022_095251", "20261022_100713", "20261022_102053",
        "20261022_114643", "20261022_131036", "20261022_181602", "20261022_182650"]
allup = []
for r in RUNS:
    L = [json.loads(l) for l in open(f"runs/pi05_policy/pi05_{r}/log.jsonl")]
    L = [x for x in L if "chunk" in x]
    up, dn = [], []
    for a, b in zip(L, L[1:]):
        if not a.get("executed"):
            continue
        s = np.array(a.get("measured_state", a["state"])[:6]); t = np.array(a["target"])
        n = np.array(b.get("measured_state", b["state"])[:6])
        cmd = t[1] - s[1]; res = n[1] - t[1]
        (up if cmd < 0 else dn).append((cmd, res, int(a["state"][6])))
    allup += [u for u in up if u[2] == 1]
    print(f"== {r}")
    print("  肩を上げる指令 (指令°, 指令からのずれ°, 爪):", " ".join(f"({c:+.1f},{e:+.2f},{g})" for c, e, g in up))
    print("  肩を下げる指令 (指令°, 指令からのずれ°, 爪):", " ".join(f"({c:+.1f},{e:+.2f},{g})" for c, e, g in dn))
    held = [(c, e) for c, e, g in up if g == 1]
    if held:
        print(f"  ブロックを持って上げた指令の合計 {sum(c for c,_ in held):+.1f}° / 実際に上がった量 {sum(c + e for c, e in held):+.1f}°")
e = np.array([u[1] for u in allup])
print(f"\n全体: ブロックを持って肩を上げる指令 {len(e)} 回  ずれ 最小 {e.min():+.2f}° 中央 {np.median(e):+.2f}° 最大 {e.max():+.2f}°  低いまま止まった回 {int((e > 0).sum())}")
```

```
== 20261021_183245
  肩を上げる指令 (指令°, 指令からのずれ°, 爪): (-5.8,+2.58,1) (-9.6,+2.52,1) (-9.8,+2.47,1) (-4.6,+2.64,1)
  肩を下げる指令 (指令°, 指令からのずれ°, 爪): (+20.0,+1.01,0) (+20.0,+1.00,0) (+20.0,+1.10,0) (+1.2,+1.05,0) (+10.1,+1.21,1) (+7.3,+0.53,1) (+4.4,-0.41,0) (+1.0,+0.21,1)
  ブロックを持って上げた指令の合計 -29.9° / 実際に上がった量 -19.7°
== 20261022_095251
  肩を上げる指令 (指令°, 指令からのずれ°, 爪): (-5.2,+1.92,1) (-5.7,+2.39,1) (-7.9,+2.65,1)
  肩を下げる指令 (指令°, 指令からのずれ°, 爪): (+20.0,+1.00,0) (+20.0,+0.92,0) (+16.5,+0.72,0) (+1.8,+0.40,0) (+1.4,+0.98,1)
  ブロックを持って上げた指令の合計 -18.8° / 実際に上がった量 -11.9°
== 20261022_100713
  肩を上げる指令 (指令°, 指令からのずれ°, 爪): (-5.8,+1.49,1) (-6.4,+2.50,1) (-6.7,+2.80,1) (-1.5,+1.48,1) (-0.1,+0.69,0)
  肩を下げる指令 (指令°, 指令からのずれ°, 爪): (+20.0,+1.10,0) (+20.0,+1.09,0) (+17.1,+0.44,0) (+2.5,-0.80,0) (+13.6,+0.63,1) (+0.5,+0.55,1) (+0.1,-0.07,1) (+0.4,+0.32,0)
  ブロックを持って上げた指令の合計 -20.3° / 実際に上がった量 -12.0°
== 20261022_102053
  肩を上げる指令 (指令°, 指令からのずれ°, 爪): (-2.3,+1.70,1) (-2.0,+1.50,1) (-1.9,+0.77,1) (-2.1,+1.43,1) (-2.6,+1.62,1) (-3.4,+1.95,1) (-3.6,+1.93,1) (-3.3,+2.20,1) (-2.9,+1.94,1) (-3.1,+2.12,1) (-1.9,+1.92,1) (-1.1,+1.09,1) (-2.4,+2.05,1) (-1.1,+1.05,1) (-2.9,+2.24,1) (-2.3,+2.25,1) (-2.5,+2.37,1)
  肩を下げる指令 (指令°, 指令からのずれ°, 爪): (+8.2,+0.99,0) (+11.5,+0.97,0) (+12.4,+1.08,0) (+11.3,+0.94,0) (+8.8,+0.83,0) (+2.1,+1.02,0) (+1.7,+0.45,0) (+2.5,-0.34,0) (+1.9,-0.52,0) (+2.0,-0.88,0) (+0.5,+0.38,0) (+3.2,+0.58,1) (+0.2,-0.19,1)
  ブロックを持って上げた指令の合計 -41.2° / 実際に上がった量 -11.1°
== 20261022_114643
  肩を上げる指令 (指令°, 指令からのずれ°, 爪): (-5.6,+1.94,1) (-6.3,+2.32,1) (-6.1,+2.65,1)
  肩を下げる指令 (指令°, 指令からのずれ°, 爪): (+20.0,+1.10,0) (+20.0,+1.09,0) (+17.4,+0.58,0) (+1.5,-0.48,0) (+2.7,+1.00,1)
  ブロックを持って上げた指令の合計 -18.0° / 実際に上がった量 -11.1°
== 20261022_131036
  肩を上げる指令 (指令°, 指令からのずれ°, 爪): (-4.2,+2.37,1) (-7.3,+2.61,1) (-8.1,+2.63,1)
  肩を下げる指令 (指令°, 指令からのずれ°, 爪): (+19.3,+0.97,0) (+24.2,+1.11,0) (+13.2,+0.87,0) (+3.7,+0.94,0) (+0.3,+1.16,1)
  ブロックを持って上げた指令の合計 -19.6° / 実際に上がった量 -11.9°
== 20261022_181602
  肩を上げる指令 (指令°, 指令からのずれ°, 爪): (-13.6,+2.54,1) (-14.3,+2.44,1) (-14.4,+2.42,1) (-8.5,+1.22,1) (-21.1,+2.33,0) (-22.6,+1.98,0) (-19.0,+1.73,0) (-3.1,+1.43,0) (-1.9,+1.60,0) (-1.6,+1.60,0)
  肩を下げる指令 (指令°, 指令からのずれ°, 爪): (+21.0,+0.96,0) (+21.0,+1.01,0) (+17.2,+0.99,0) (+5.3,+0.42,0) (+9.5,+0.93,0) (+0.7,+1.01,0) (+20.4,+1.06,1) (+1.2,+1.17,1)
  ブロックを持って上げた指令の合計 -50.8° / 実際に上がった量 -42.2°
== 20261022_182650
  肩を上げる指令 (指令°, 指令からのずれ°, 爪): (-3.9,+2.00,1) (-7.6,+2.37,1) (-9.5,+2.47,1) (-2.8,+1.22,1) (-0.9,+0.95,1) (-18.7,+2.44,0) (-26.5,+1.96,0) (-19.4,+0.90,0) (-1.7,+1.73,0)
  肩を下げる指令 (指令°, 指令からのずれ°, 爪): (+20.3,+0.93,0) (+23.0,+0.98,0) (+11.1,+1.16,0) (+2.9,+0.19,0) (+2.4,+0.63,0) (+13.6,+0.91,1)
  ブロックを持って上げた指令の合計 -24.6° / 実際に上がった量 -15.6°

全体: ブロックを持って肩を上げる指令 43 回  ずれ 最小 +0.77° 中央 +2.20° 最大 +2.80°  低いまま止まった回 43
```

**ブロックを持って肩を上げる指令は、43回とも目標に届かずに止まっていました。** 下げる向きの指令は、逆に約1°行き過ぎています。届かない分はどれも、到達の判定（3°以内なら着いた）より小さいので、クライアントは「着いた」として次の問い合わせへ進みます。AI はその低い角度を「いまの姿勢」として受け取り、そこからまた持ち上げの答えを返すので、足りない分は戻ってきません。

【図解】LOG361_lift_shortfall.html


## 同じ目標を送り直して詰める settle を足したが、ずれは縮まらなかった

最初に試したのは、届かなかったときに、同じ目標をもう一度送って詰めるやり方です。新しい目標は作らず、安全の検査を通った目標をそのまま送り直すだけにしました（Claude Code の実装）。Claude Code の報告です。

```
「送り直して詰める」を入れました。変更は pi05/run_policy_client.py の 1
  ファイルのみ（未コミット）。

  変えた行

  ┌─────────┬─────────────────────────────────────────────────────────────────┐
  │   行    │                              変更                               │
  ├─────────┼─────────────────────────────────────────────────────────────────┤
  │ 23-24   │ docstring の安全策に 1                                          │
  │         │ 項目（送り直しで詰める・新しい目標は作らない・0 で従来どおり）  │
  ├─────────┼─────────────────────────────────────────────────────────────────┤
  │ 199-245 │ settle_target(target, label, tol, retries) を新設（下記）       │
  ├─────────┼─────────────────────────────────────────────────────────────────┤
  │ 272-276 │ --settle-tol（既定 1.0）と --settle-retries（既定 2）を追加     │
  ├─────────┼─────────────────────────────────────────────────────────────────┤
  │         │ 送信後に rec["settle"], rec["settle_retries_used"] =            │
  │ 457-459 │ settle_target(target, f"pi05_chunk{i:03d}", args.settle_tol,    │
  │         │ args.settle_retries)                                            │
  └─────────┴─────────────────────────────────────────────────────────────────┘

  settle_target の中身:
  - retries <= 0 なら即
  return（関節角の読み取りもしないので、従来と完全に同じ動き）
  - 関節角を読み、|target − actual| の最大が tol 以下なら何もしない
  - 超えていたら _send_and_wait_arrival(tgt.tolist(), f"{label}_settle{n}", 3.0)
  で同じ目標を送り直し、読み直して記録。tol 以下になるか retries 回に達するまで
  - 送る値は引数の target そのもの（apply_limits と check_send_safe
  を通ったもの）。足し引きも再計算もしていません 
  - 最後まで詰まらなければ [WARN] を出して戻る（停止条件は増やしていません）
  - 関節角が読めなくなったら送り直しをやめて戻る

  _send_and_wait_arrival 本体（j0_sweep_scan.py）、HOME・SPEED・SEND_WAIT・J4_SAF
  E・J1_SAFE_MAX・apply_limits は一切触っていません。呼ぶ側で足しただけです。

  背景の裏取り（4 回分の記録）

  実装前に log.jsonl
  のチャンク間で「送った目標」と「次のチャンクの実測」を突き合わせました:

  - 肩を持ち上げる向き（j1 を小さくする指令）: 28 回、すべて届かず 
  0.77〜2.80°（中央 2.00°）低いところで停止。28 回すべて 3° 未満
  なので到達判定を通ってしまう
  確認結果（アームは動かさず・偽の daemon）

  偽の腕は「_send_and_wait_arrival を受けると姿勢 = 目標 + 残差（j1
  のみ）」にし、read_angles がそれを返します。開始 j1=60.0° → 目標 j1=50.0°（10°
  持ち上げ）。

  1. 1 回目 +2.0° → 送り直すと +0.4°（既定 tol 1.0 / retries 2）

  [000] 推論 0ms  5ステップ先  Δ= +0.0 -10.0  +0.0  +0.0  +0.0  +0.0
         [SETTLE] 送り直し 1 回目  最大ずれ 2.00°（関節 j1）→ 0.40°
  送信の履歴 (2 回):
    pi05_chunk000          目標 j1=+50.00 → 実際 j1=+52.00
    pi05_chunk000_settle1  目標 j1=+50.00 → 実際 j1=+50.40
  log: chunk=0 arrived=True settle_retries_used=1
       {"try": 1, "max_err_before": 2.0, "max_err_after": 0.4, "joint": 1,
  "actual": [0.0, 50.4, 0.0, 0.0, -40.0, -30.0]}

  0.40° ≤ 1.0° なので 2 回目には進まず、送り直し 1 回で終了。記録も残っています。

  2. 何度送っても +2.0° のまま

         [SETTLE] 送り直し 1 回目  最大ずれ 2.00°（関節 j1）→ 2.00°
         [SETTLE] 送り直し 2 回目  最大ずれ 2.00°（関節 j1）→ 2.00°
         [WARN] 送り直し 2 回でも最大ずれ 2.00° > 1.0°. 詰まりませんでした
  (止めずに次へ進みます)
  送信の履歴 (3 回): chunk000 / chunk000_settle1 / chunk000_settle2
  log: chunk=0 arrived=True settle_retries_used=2  (settle に 2 件)
  終了コード 0

  2 回で打ち切り、警告を出して次へ。終了コードは 0
  のまま（停止条件を増やしていない）。

  3. --settle-retries 0

  送信の履歴 (1 回): pi05_chunk000 のみ
  log: chunk=0 arrived=True settle_retries_used=0   ("settle": [])

  送り直しなし・[SETTLE] の表示なし = 従来どおり。

  おまけ: ドライラン（--execute なし） も確認しました —
  送信の呼び出しなし／グリッパーの呼び出しなし／settle キーも arrived
  キーも付かない（executed=False）。HOME
  復帰（h）とグリッパー開閉の経路は今回の差分に含まれていません。

  commit はしていません。codex レビューに出す準備ができています（出しますか？
  観点は「同じ目標の再送がアームに与える危険（再送で安全範囲を外れないか・h と
```

codex のレビューは「実機に進む前に直す点がある」でした。送り直しのあと動きが止まったかを確かめていないこと、呼び出し先が中で1回送り直すので、送る回数が上限を超えることなどです。

```
**現状では、settle有効の実機テストへ進む前に修正が必要です。** 同じtargetを再送する点は守られていますが、動作完了の確認、実際の再送回数、失敗の記録に抜けがあります。コード変更・アーム操作はしていません。

行番号は現在の [run_policy_client.py](/Users/shimazueiichi/r2r2r-scripts/pi05/run_policy_client.py) に対応します。

|項目|判定|確認結果・修正案|
|---|---|---|
|A1 同じ目標だけを再送|✅ OK|217行でtargetを取り出し、230行でそのまま送ります。加算・補正はありません。呼び出し元も安全検査済みtargetを渡しています。|
|A2 動作終了後に読む|❌ NG|**230〜233行**。再送でも許容3°の関数を呼ぶため、settle-tol=1°への収束も、停止も確認しません。後述のとおり1秒待機はありますが、動作完了保証ではありません。再送後は期限付きの読角で収束・安定を確認してから次の再送を判断する必要があります。|
|A3 同一目標が無視される可能性|⚠️ 要注意|ローカルのMacラッパーとdaemonには同一targetを省略する処理はなく、毎回`_mc.send_angles`へ渡します。ただし稼働Piのpymycobot・ファームウェアが同じ指令をどう扱うかは未確認です。**再送すれば詰まるとはコードだけでは証明できません。**|
|A4 詰めてから閉じる順序|✅ OK|458〜459行のsettle後に、460〜465行でグリッパー操作します。ただしsettle未収束・読角失敗でも、仕様どおりその後に閉じます。「順番は先」でも「詰まったこと」は保証しません。|
|A5 h・q・auto・二重送信|❌ NG|h/q/sはsettle前に分岐し、HOMEにsettleはかかりません。ただし**230行の呼び出し先自身が再送を最大1回行う**ため、settle-retries=2でも追加の実送信は最大4回になり得ます。「最大2回」とは不一致です。再送予算を実送信回数で管理する必要があります。|
|A6 読角失敗|✅／⚠️|222〜225行、233〜241行で読めなければ追加再送をやめます。HOME等を勝手に送りません。ただし最初の読角失敗はsettle記録が空になり、許容内で再送不要だった場合と区別できません。失敗理由を記録すべきです。|
|B1 既存経路の維持|✅ OK|retries=0は215〜216行で読角・送信なし。ドライラン、h/q/s、開閉指令そのものは変更されていません。有効時に開閉が遅れるのは追加処理の結果です。|
|B2 呼び出し先の変更|✅ OK|`j0_sweep_scan.py`に未コミット差分はありません。|
|C1 振動|⚠️ 要注意|同じ目標・有限回数なので、補正値を反転し続ける無限振動ロジックはありません。ただし動作途中の再指令による再始動や物理的な揺れは排除できません。A2の安定確認が必要です。|
|C2 関節制限|✅ OK|通常経路では405行の安全検査を通った同じtargetだけを再送します。今回の変更でJ4_SAFE・J1_SAFE_MAX外の**目標角**を生成する経路は見つかりません。実角度のオーバーシュート保証とは別です。|
|D1 send_coords|✅ OK|追加処理に使用はありません。|
|D2 固定値|✅ OK|HOMEは変更なし。呼び出し先のSPEED=20、SEND_WAIT_SEC=1.0も変更されていません。|

特に直すべき点は次の3つです。

1. **再送後の待ち方をsettle用にする。**  
   `_send_and_wait_arrival`からのreturn後、直ちに1回読むだけでは不十分です。ただし「送信直後に無待機で読む」という実装ではありません。ローカルdaemonはsend後に**1秒sleep**してから応答します（`mecharm_daemon.py:75–81`）。問題は、その1秒と3°判定で**動作終了・1°収束を保証できないこと**です。

2. **再送の失敗・内部再送を扱う。**  
   **230行で戻り値 `(success, retried)` を捨てています。** 呼び出し先が部分移動／ストール疑いでFalseを返しても、外側ループが再び送る場合があります。少なくとも失敗時はそのsettle内の追加再送をやめて警告し、戻り値・内部再送の有無を記録してください。「プログラム全体を止める条件を増やさない」という仕様とも両立できます。

3. **ログを実態に合わせる。**  
   現在の`settle_retries_used`は関数の呼び出し回数で、実送信回数ではありません。初回読角失敗、許容内、送信失敗、未収束を区別し、設定tol・最終状態も残す必要があります。
```

直した版の報告です。

```
 3 点を反映しました。変更は pi05/run_policy_client.py の settle_target
  周りのみ（未コミット）。

  変えた行
     
  ┌───────┬──────────────────────────────────────────────────────────────────┐
  │  行   │                               変更                               │
  ├───────┼──────────────────────────────────────────────────────────────────┤
  │ 23-25 │ docstring: 「動きが止まってから測る」「送信回数の上限」「どの終  │
  │       │ わり方でも止めずに次へ」                                         │
  ├───────┼──────────────────────────────────────────────────────────────────┤
  │ 94-96 │ 定数 3 つ追加: SETTLE_POLL_SEC=0.2 / SETTLE_STILL_DEG=0.2 /      │
  │       │ SETTLE_WAIT_SEC=2.0                                              │
  ├───────┼──────────────────────────────────────────────────────────────────┤
  │       │ read_until_still() を新設（A2）。0.2 秒おきに読み、連続 2        │
  │ 203-2 │ 回の差が 6 関節すべて 0.2° 未満で「止まった」。最長 2.0          │
  │ 25    │ 秒で打ち切り、そのときの値を返す。途中で読めなくなったら直前の値 │
  │       │ 、最初から読めなければ (None, False)                             │
  ├───────┼──────────────────────────────────────────────────────────────────┤
  │ 228-3 │ settle_target を書き直し（A5・A6）。下記                         │
  │ 20    │                                                                  │
  ├───────┼──────────────────────────────────────────────────────────────────┤
  │ 342-3 │ --settle-tol / --settle-retries のヘルプを「止まってから測る」「 │
  │ 47    │ 送信回数の上限（中の再送も数える）」に更新                       │
  ├───────┼──────────────────────────────────────────────────────────────────┤
  │ 530-5 │ 呼び出し側は変更なし（rec["settle"], rec["settle_retries_used"]  │
  │ 31    │ = settle_target(...)）                                           │
  └───────┴──────────────────────────────────────────────────────────────────┘

  settle_target の中身:

  - A2: 最初の判定も送り直し後の判定も read_until_still() で読む。その値で |目標 
  − 実際| の最大を求め、tol 以下で終了、超えていれば次の送り直しへ
  - A5: ok, retried = _send_and_wait_arrival(...) を受け取り、sends += 2 if 
  retried else 1。ループ条件は sends >= retries で打ち切り（=
  送信回数の上限）。ok が False ならその回の記録を残してから send_failed で終了
  - A6: 戻り値を dict にし、reason / tol / sends / final_err / joint /
  final_actual / tries（各回の max_err_before max_err_after joint sends success
  retried still
  actual）を残す。画面の最終行に理由・送信回数・最後の最大ずれを出す

  reason は指定の 5 つに加えて、--settle-retries 0 のときだけ "disabled" 
  を入れています（ログだけを見て「送り直し機能が切られていた」と分かるように）。
  不要なら外します。

  止める条件は増えていません（settle_target
  はどの経路でもチャンクループを抜けず、exit_code
  も触りません）。_send_and_wait_arrival 本体・HOME・SPEED・SEND_WAIT・J4_SAFE・J
  1_SAFE_MAX・apply_limits・h・q・グリッパー・ドライランは未変更です。

  確認結果（偽の daemon・偽の時計、アームは動かさず）

  偽の時計（sleep で進む）を使っているので、2.0
  秒の打ち切りを実時間なしで確かめています。開始 j1=60.0° → 目標 j1=50.0°。

  1. +2.0° → 送り直すと +0.4°（converged）
  [SETTLE] 送り直し 1 回目  最大ずれ 2.00°（関節 j1）→ 0.40°
  [SETTLE] converged (詰まった)  送信 1 回  最後の最大ずれ 0.40°（関節 j1）
  log: {"reason":"converged","tol":1.0,"sends":1,"final_err":0.4,"joint":1,"final
  _actual":[0.0,50.4,...]}

  2. +2.0° のまま（not_converged） — 送信 2 回で打ち切り、[WARN]
  を出して終了コード 0
  [SETTLE] not_converged (詰まらなかった)  送信 2 回  最後の最大ずれ 2.00°（関節
  j1）

  3. --settle-retries 0 — settle の read_angles 0 回・送信 0 回（本体の送信 1
  回のみ）
  log: {"reason":"disabled","tol":1.0,"sends":0}

  4. 読むたびに値が変わり続ける（0.5°/回のドリフト） — 2.0 秒＝10
  回ポーリングで打ち切り、そのときの値で判定
  [SETTLE] 送り直し 1 回目  最大ずれ 7.50°（関節 j1）→ 5.90°
  (動きが止まらないまま 2.0 秒で打ち切り)
  [SETTLE] 送り直し 2 回目  最大ずれ 5.90°（関節 j1）→ 5.90°
  (動きが止まらないまま 2.0 秒で打ち切り)
  try に "still": false が残る

  5. settle の送信が (False, True) を返す（send_failed） — 送信 2
  回と数え、その回でやめる
  [SETTLE] 送り直し 1 回目  最大ずれ 2.00°（関節 j1）→ 2.00°  (送信 2 回)
  [SETTLE] send_failed (送信が失敗)  送信 2 回  最後の最大ずれ 2.00°（関節 j1）
  log: {"reason":"send_failed","sends":2,...}  try:
  {"sends":2,"success":false,"retried":true}
  終了コード 0（止めずに次のチャンクへ）

  5b（追加）. (True, True)（中で 1 回再送して成功） — 2 回と数えて上限 2
  に達し、1 回の送り直しで not_converged
  終了。内部再送が予算に効いていることの確認です。

  6. 最初の読み取りに失敗（read_failed） — 送信 0 回で戻る
  [SETTLE] read_failed (関節角を読めない)  送信 0 回. 送り直しません
  log: {"reason":"read_failed","tol":1.0,"sends":0,"final_err":null,"joint":null,
  "final_actual":null}

  7（追加）. ドライラン（--execute なし） — 送信 0 回、settle
  キーなし、read_angles は main の分のみ。

  ひとつ補足です。ケース 5 で、_send_and_wait_arrival が チャンク本体の送信で
  (False, ...) を返した場合は、既存の「未到達 → --auto なら停止」が先に働くので
  settle には入りません（既存の停止条件をそのまま残しているためで、今回の変更で増
  えた停止ではありません）。手動モードでは警告のあと settle に入ります。
```

2回目のレビューです。

```
**R1は一部未解消、R2・R3の既存経路は維持されています。** 修正箇所だけ読み取り確認しました。コード変更・アーム操作はしていません。

### R1 ❌ 未解消の点があります

**A2：⚠️ 待機は追加されていますが、停止未確認でも再送します。**  
[203行以降](/Users/shimazueiichi/r2r2r-scripts/pi05/run_policy_client.py:203)で初回・再送後とも読角を待つようになりました。ただし257行の`_still`は無視され、再送後の`still=False`も記録するだけです。タイムアウト時に動作途中の値で判断する経路は残ります。

タイムアウト時も続行する仕様なら、その点は明示したうえで、**そのsettle内の追加再送はやめて警告で戻る**のが適切です。なお「2回の差が0.2°未満」は停止の近似判定で、低速移動や同じ読角値の再取得を排除するものではありません。

**A5：❌ 実送信回数の上限を超える経路があります。**  
[271〜277行](/Users/shimazueiichi/r2r2r-scripts/pi05/run_policy_client.py:271)は呼び出す前に`sends >= retries`を確認しますが、内部再送分は**送った後**に加算します。

例：

- 上限2回、最初の呼び出しで1回送信
- 残り1回で再び呼び出す
- 今回は内部再送され2回送信
- **合計3回となり上限超過**

残り予算が1回なら、内部再送し得る関数をそのまま呼べません。残り予算を守れる送信経路が必要です。

また、`retried=True`は厳密な実送信回数ではありません。呼び出し先の[302〜305行](/Users/shimazueiichi/r2r2r-scripts/dynamic_tracking_limits/place/place_modules/j0_sweep_scan.py:302)では、再送前の読角失敗でも`False, True`を返します。この場合、実際には2回目を送っていません。`success=False`で外側の再送をやめる修正自体はできています。

**A6・ログ：❌ 途中の読角失敗を見逃します。**  
[219〜221行](/Users/shimazueiichi/r2r2r-scripts/pi05/run_policy_client.py:219)で読角に失敗すると、`None`ではなく直前の角度を返します。呼び出し側はこれを有効値として扱うため、**読めなくなった後に古い値で再送したり、within_tol／convergedと記録したりできます。**

読角失敗と時間切れを別の状態で返し、読角失敗なら追加再送をやめて`read_failed`にしてください。直前の有効値は「最終確認値」として別途保存できます。

なお、disabledの[253〜254行](/Users/shimazueiichi/r2r2r-scripts/pi05/run_policy_client.py:253)だけは`final_err/joint/final_actual/tries`がありません。全reasonで同じログ形式にするなら、`None`と空配列を追加してください。

### R2 ✅ 既存の分岐・停止条件は維持

[503〜538行](/Users/shimazueiichi/r2r2r-scripts/pi05/run_policy_client.py:503)を確認しました。

- h・q・sはsettle前に分岐します。
- ドライランではsettleを呼びません。
- retries=0では追加の読角・送信がありません。
- グリッパー操作はsettle後です。
- settle失敗によるプログラム全体の停止条件は増えていません。
- 初回送信失敗時の`--auto`停止は従来どおりです。

ただし、R1の読角失敗を直前値に置き換える処理は、新しく入った問題です。

### R3 ✅ 安全範囲外の目標を新たに作る経路はなし

[255行・275行](/Users/shimazueiichi/r2r2r-scripts/pi05/run_policy_client.py:255)では、[477行](/Users/shimazueiichi/r2r2r-scripts/pi05/run_policy_client.py:477)の安全検査を通ったtargetを、そのまま再送しています。加算・差し替えはなく、J4_SAFE・J1_SAFE_MAX外の**指令値を生成する経路**は見つかりません。
```

もう一度直した版の報告です。このあと3回目のレビューを通し、11時24分にコミットしました（3回目のレビューの文は残していません）。

```
3 点を反映しました。変更は pi05/run_policy_client.py のみ（未コミット）。

  変えた行

  ┌─────────┬─────────────────────────────────────────────────────────────────┐
  │   行    │                              変更                               │
  ├─────────┼─────────────────────────────────────────────────────────────────┤
  │ 23-26   │ docstring: 「動きが止まらない / 読めない /                      │
  │         │ 送信が失敗したときは送り直しをやめる」                          │
  ├─────────┼─────────────────────────────────────────────────────────────────┤
  │         │ from j0_sweep_scan import SEND_WAIT_SEC, SPEED,                 │
  │ 81      │ _send_and_wait_arrival — SPEED=20 / SEND_WAIT=1.0               │
  │         │ は本線の値をそのまま import（二重定義しない）                   │
  ├─────────┼─────────────────────────────────────────────────────────────────┤
  │ 83-85   │ visual_servo_pick から daemon_send_angles を追加 import         │
  ├─────────┼─────────────────────────────────────────────────────────────────┤
  │ 205-206 │ _fmt6()（記録用に 6 関節を丸める小物）                          │
  ├─────────┼─────────────────────────────────────────────────────────────────┤
  │         │ read_until_still() を変更（A6）: 戻り値が (角度 or None,        │
  │ 209-235 │ 止まったか, 直前に読めた角度 or None) の 3                      │
  │         │ つに。読み取りに失敗したら 1 番目は                             │
  │         │ None（古い値を代わりに返さない）、3 番目に最後に読めた値        │
  ├─────────┼─────────────────────────────────────────────────────────────────┤
  │ 237-336 │ settle_target を変更（A5・A2・A6）                              │
  ├─────────┼─────────────────────────────────────────────────────────────────┤
  │ 550-551 │ 呼び出し側は変更なし                                            │
  └─────────┴─────────────────────────────────────────────────────────────────┘

  settle_target の変更点:

  - A5: 送り直しは _send_and_wait_arrival をやめ、その中で使っている 1
  回だけ送る層 daemon_send_angles(tgt.tolist(), speed=SPEED, wait=SEND_WAIT_SEC)
  を直接呼ぶ。中で再送しないので sends
  が実際の送信回数と一致し、上限を超えません。送ったあとは read_until_still()
  で止まるのを待ってから判定。例外が出たら sent: false と error を記録して
  send_failed で終了（チャンク本体の送信は今までどおり _send_and_wait_arrival）
  - A2: still=False（2.0 秒で打ち切り）なら追加の送り直しをやめ、[WARN] を出して
  not_still で戻る。判定順は「tol 以内か → 止まっているか → 上限か」。tol
  以内なら動いていても送らないので、そこでは警告を出しません
  - A6: 途中で読めなくなったら read_failed で終了し、final_err / joint /
  final_actual は null。最後に読めた値は last_valid_actual に別に残す。disabled
  も含め、どの reason でも同じ形（reason / tol / sends / final_err / joint /
  final_actual / last_valid_actual / tries）

  止める条件は増えていません（settle_target はチャンクループを抜けず、exit_code
  も触りません）。_send_and_wait_arrival 本体・HOME・SPEED・SEND_WAIT・J4_SAFE・J
  1_SAFE_MAX・apply_limits・h・q・グリッパー・ドライランは未変更です。

  確認結果（偽の daemon・偽の時計、10 ケースすべて OK）

  OK  1_converged              OK  6_read_failed_first
  OK  2_not_converged          OK  7_dryrun
  OK  3_retries0               OK  8_cap_2_sends
  OK  4_not_still_from_start   OK  9_not_still_after_1
  OK  5_send_failed            OK 10_read_failed_after_send

  前回の 7 つ（抜粋）:
  - 1 +2.0° → +0.4°: converged / settle の送信 1 回（daemon_send_angles(50.0, 
  speed=20, wait=1.0)）
  - 3 --settle-retries 0: {"reason":"disabled","sends":0,"final_err":null,"joint"
  :null,"final_actual":null,"last_valid_actual":null,"tries":[]} —
  ほかと同じ形、settle の読みも送りも 0 回
  - 5 送信が例外: send_failed / try に "sent": false, "error": "RuntimeError: 
  ..."
  - 7 ドライラン: 本体も settle も送信 0 回、settle キーなし

  今回ふえた 3 つ:

  8. 上限 2 回を超えない — どの経路でも daemon_send_angles の呼び出しは最大 2
  回。実測は本体 1 回 + settle 2 回で、sends: 2 と一致（旧版は内部再送で 3
  回になり得ました）

  9. 1 回目のあと止まらない → not_still
  [SETTLE] 送り直し 1 回目  最大ずれ 2.00°（関節 j1）→ 5.90°
  (動きが止まらないまま 2.0 秒で打ち切り)
  [SETTLE] not_still (動きが止まらない)  送信 1 回  最後の最大ずれ 5.90°（関節
  j1）
  [WARN] ...
  settle: {"reason":"not_still","sends":1,...}   try: {"still": false}
  送り直しは 1 回でやめ、2 回目は送っていません。

  10. 送り直しのあとの読み取り失敗 → 古い値で判定しない
  [SETTLE] 送り直し 1 回目  最大ずれ 2.00°（関節 j1）→ 読めず
  [SETTLE] read_failed (関節角を読めない)  送信 1 回  最後の最大ずれ 不明
  settle: {"reason":"read_failed","sends":1,"final_err":null,"joint":null,"final_
  actual":null,
           "last_valid_actual":[0.0, 50.4, 0.0, 0.0, -40.0, -30.0]}
  この last_valid_actual は目標から 0.4° のずれ、つまり古い値を使えば converged 
  と誤記録される状況です。新しい版では read_failed のままで、final_* は
  null、拾えた値は last_valid_actual に分けて残っています。

  また 4_not_still_from_start（settle
  に入った時点ですでに動き続けている）では、送信 0 回で not_still
  を返して何も送っていません。
```

コミットの説明文です。

```
commit c7e726aac6473cedfc5248e8dcfc583850cb3465
Date:   Thu Oct 22 11:24:03 2026 +0900

送った目標とのずれを同じ目標の送り直しで詰める (LOG359)

LOG359: ブロックを持って肩を持ち上げる指令 (j1 を小さくする向き) が毎回 約 2°
届かないまま, 次の予測に進んでいた. 到達判定は _send_and_wait_arrival(..., 3.0) の
3° なので, このずれは「着いた」と見なされる. モデルは実際の姿勢から次を予測するため,
持ち上げが毎回 2° ずつ失われ, ブロックがマットから離れない.
実機 4 回 (pi05_20261021_183245 / 20261022_095251 / 100713 / 102053) の log.jsonl で,
肩を上げる指令 28 回すべてが 0.77〜2.80° (中央 2.00°) 届かず, 28 回とも 3° 未満だった
(102053 は上げる指令の合計 41° に対して実際は 11°). 逆向き (下げる) は 0.5〜1° 行き過ぎる.

- settle_target(): チャンクの目標を送ったあと, 送った目標との |目標 - 実際| の最大が
  --settle-tol (既定 1.0°) を超えていたら, **同じ目標を** 最大 --settle-retries
  (既定 2) 回まで送り直して詰める. 新しい目標は作らない (apply_limits と
  check_send_safe を通った target をそのまま送り直すだけ). --settle-retries 0 で
  従来の動き (読みも送りもしない).
- 送り直しは _send_and_wait_arrival ではなく, その中で使っている 1 回だけ送る層
  daemon_send_angles(..., speed=SPEED, wait=SEND_WAIT_SEC) を直接呼ぶ (codex A5).
  中で再送しないので送信回数が上限を超えない. SPEED / SEND_WAIT_SEC は j0_sweep_scan
  から import して本線と同じ値 (20 / 1.0) を使う.
- read_until_still(): 0.2 秒おきに読み, 続けて読んだ 2 回の差が 6 関節すべて 0.2° 未満で
  「止まった」とみなしてから測る (codex A2). 2.0 秒で打ち切り. 読み取りに失敗したら
  古い値を返さず, 最後に読めた値は別に返す (codex A6).
- 動きが止まらない (not_still) / 読めない (read_failed) / 送信が例外 (send_failed) の
  ときは, その settle の送り直しをやめて [WARN] を出す. **止める条件は増やしていない**
  (どの終わり方でもチャンクループは続き, 終了コードも変えない).
- log.jsonl のチャンクの行に settle (reason / tol / sends / final_err / joint /
  final_actual / last_valid_actual / tries) と settle_retries_used を残す.
  reason は within_tol / converged / not_converged / not_still / send_failed /
  read_failed / disabled のいずれかで, どれでも同じ形.

変更なし: _send_and_wait_arrival 本体 (j0_sweep_scan), チャンク本体の送信,
HOME 復帰 (h) / q / グリッパーの開閉 / ドライラン, J4_SAFE, J1_SAFE_MAX, apply_limits.

偽の daemon で確認 (アームには送っていない. 10 ケースすべて期待どおり):
  +2.0° → 送り直して +0.4°        converged / settle の送信 1 回
  +2.0° のまま                    not_converged / 送信 2 回で打ち切り
  --settle-retries 0              disabled / settle の読み 0 回・送信 0 回
  2.0 秒で止まらない              not_still / 1 回目のあと送り直しをやめる
  送信が例外                      send_failed / try に sent=false と error
  読み取りが失敗                  read_failed / final_* は null, last_valid_actual に退避
  ドライラン                      送信 0 回・settle キーなし

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
```

11:46 に、送り直しを入れて動かしました。

```
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % python3 pi05/run_policy_client.py --raw-dir $RAW --steps-per-chunk 10 --execute
[SAFE  ] 安全範囲 (学習 19 本 ±10°): j0[-72,+55]  j1[-9,+88]  j2[-46,+41]  j3[-18,+27]  j4[-90,+10]  j5[-51,-14]
[SAFE  ] 肩 j1 の上限は J1_SAFE_MAX=88° で切った (これを超える指令はアームが黙って捨てる / LOG352)  元データ: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
[MODE  ] EXECUTE  steps/chunk=10  max_move=20.0°  log=/Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_114643
[CAMERA] 写り方 dy=-6.5 dx=+3.0 response=0.553 → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[CAMERA] 基準: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes/run_0001_20261019_183454/frames/000000.jpg
[POLICY] 接続 ws://localhost:8000  metadata={}
[GRIP  ] 開始時のグリッパー開放は, 最初の目標が検査を通ってから行います (爪が閉じていたら手で開けておく)
[000] 推論 1724ms  10ステップ先  Δ=-10.6 +20.0  +5.4  -2.5 -20.0  +2.2
       [LIMIT] j1 移動量 +20.4° を ±20° に制限
       [LIMIT] j4 移動量 -24.9° を ±20° に制限
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[GRIP  ] 開始時にグリッパーを開く
  [Pi] GRIPPER: OPEN result= -1
[SEND] pi05_chunk000: send_angles (single) [ -10.79,  +21.31,   +5.92,   -2.78,  -20.52,  -27.81]  speed=20 wait=1.0s  (pre max|Δ|=20.26°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.19° (tol 3.0°)
       [SETTLE] 送り直し 1 回目  最大ずれ 1.19°（関節 j4）→ 1.10°
       [SETTLE] 送り直し 2 回目  最大ずれ 1.10°（関節 j1）→ 1.10°
       [SETTLE] not_converged (詰まらなかった)  送信 2 回  最後の最大ずれ 1.10°（関節 j1）
       [WARN] 送り直しで詰めきれませんでした (止めずに次へ進みます)
[001] 推論 985ms  10ステップ先  Δ=-12.2 +20.0  +6.2  +0.0 -20.0  +0.5
       [LIMIT] j1 移動量 +23.1° を ±20° に制限
       [LIMIT] j4 移動量 -29.2° を ±20° に制限
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk001: send_angles (single) [ -23.15,  +42.41,  +12.88,   -2.24,  -40.12,  -27.60]  speed=20 wait=1.0s  (pre max|Δ|=20.00°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.09° (tol 3.0°)
       [SETTLE] 送り直し 1 回目  最大ずれ 1.09°（関節 j1）→ 1.09°

       [SETTLE] 送り直し 2 回目  最大ずれ 1.09°（関節 j1）→ 1.09°
       [SETTLE] not_converged (詰まらなかった)  送信 2 回  最後の最大ずれ 1.09°（関節 j1）
       [WARN] 送り直しで詰めきれませんでした (止めずに次へ進みます)
[002] 推論 899ms  10ステップ先  Δ=-10.0 +17.4  +6.2  +0.3 -20.0  +0.1
       [LIMIT] j4 移動量 -22.2° を ±20° に制限
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > [SEND] pi05_chunk002: send_angles (single) [ -33.61,  +60.85,  +19.60,   -2.36,  -59.55,  -27.68]  speed=20 wait=1.0s  (pre max|Δ|=20.00°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.76° (tol 3.0°)
       [SETTLE] 送り直し 1 回目  最大ずれ 2.67°（関節 j4）→ 2.23°
       [SETTLE] 送り直し 2 回目  最大ずれ 2.23°（関節 j4）→ 1.70°
       [SETTLE] not_converged (詰まらなかった)  送信 2 回  最後の最大ずれ 1.70°（関節 j4）
       [WARN] 送り直しで詰めきれませんでした (止めずに次へ進みます)
[003] 推論 874ms  7ステップ先  Δ= +0.4  +1.5  -1.4  -1.2  +0.8  +0.1  グリッパー→閉
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk003: send_angles (single) [ -33.03,  +62.97,  +17.57,   -3.64,  -60.42,  -27.93]  speed=20 wait=1.0s  (pre max|Δ|=1.54°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.92° (tol 3.0°)
  [Pi] GRIPPER: VALUE=20 speed=100 result= -1
[004] 推論 2135ms  10ステップ先  Δ=+15.5  -5.6  -1.2  +3.5  +0.2  -1.9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk004: send_angles (single) [ -17.96,  +56.85,  +15.90,   +0.30,  -60.68,  -30.24]  speed=20 wait=1.0s  (pre max|Δ|=15.52°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.85° (tol 3.0°)
       [SETTLE] 送り直し 1 回目  最大ずれ 2.85°（関節 j4）→ 2.15°
       [SETTLE] 送り直し 2 回目  最大ずれ 2.15°（関節 j4）→ 1.94°
       [SETTLE] not_converged (詰まらなかった)  送信 2 回  最後の最大ずれ 1.94°（関節 j1）
       [WARN] 送り直しで詰めきれませんでした (止めずに次へ進みます)
[005] 推論 802ms  10ステップ先  Δ=+20.0  -6.3  -5.8  +3.6  +4.3  -2.0
       [LIMIT] j0 移動量 +26.4° を ±20° に制限
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk005: send_angles (single) [  +2.08,  +52.52,  +10.95,   +3.51,  -54.67,  -31.60]  speed=20 wait=1.0s  (pre max|Δ|=20.00°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.32° (tol 3.0°)
       [SETTLE] 送り直し 1 回目  最大ずれ 2.32°（関節 j1）→ 2.32°
       [SETTLE] 送り直し 2 回目  最大ずれ 2.32°（関節 j1）→ 2.32°
       [SETTLE] not_converged (詰まらなかった)  送信 2 回  最後の最大ずれ 2.32°（関節 j1）
       [WARN] 送り直しで詰めきれませんでした (止めずに次へ進みます)

[006] 推論 877ms  10ステップ先  Δ=+20.0  -6.1  -5.9  +1.4  +6.7  -0.7
       [LIMIT] j0 移動量 +25.6° を ±20° に制限
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > [SEND] pi05_chunk006: send_angles (single) [ +21.75,  +48.76,   +6.40,   +4.73,  -48.37,  -31.97]  speed=20 wait=1.0s  (pre max|Δ|=20.00°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.65° (tol 3.0°)
       [SETTLE] 送り直し 1 回目  最大ずれ 2.65°（関節 j1）→ 2.65°
       [SETTLE] 送り直し 2 回目  最大ずれ 2.65°（関節 j1）→ 2.65°
       [SETTLE] not_converged (詰まらなかった)  送信 2 回  最後の最大ずれ 2.65°（関節 j1）
       [WARN] 送り直しで詰めきれませんでした (止めずに次へ進みます)
[007] 推論 2299ms  10ステップ先  Δ=+17.2  +2.7  -4.6  +1.3  +0.8  -0.6
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk007: send_angles (single) [ +38.83,  +54.10,   +3.28,   +6.46,  -47.93,  -32.36]  speed=20 wait=1.0s  (pre max|Δ|=17.21°, post-send timeout 8.0s)
  [WARN] _daemon_request timeout (timeout=4.0s, cmd=send_angles). socket closed.
[SEND] [ERROR] daemon_send_angles 例外: daemon timeout after 4.0s (cmd=send_angles)
       [WARN] 未到達. j4 の発熱などを確認してください
       [SETTLE] 送り直し 1 回目  最大ずれ 1.55°（関節 j2）→ 1.55°
       [SETTLE] 送り直し 2 回目  最大ずれ 1.55°（関節 j2）→ 1.55°
       [SETTLE] not_converged (詰まらなかった)  送信 2 回  最後の最大ずれ 1.55°（関節 j2）
       [WARN] 送り直しで詰めきれませんでした (止めずに次へ進みます)
[008] 推論 952ms  9ステップ先  Δ= +1.0  +9.8  -4.0  +1.0  -5.7  -0.4  グリッパー→開
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > h
[SEND] pi05_home: send_angles (single) [  +0.00,   +0.00,   +0.00,   +0.00,   +0.00,  -30.00]  speed=20 wait=1.0s  (pre max|Δ|=55.10°, post-send timeout 10.3s)
[SEND] arrival OK: max|Δ|=2.10° (tol 2.5°)
[DONE  ] 記録: /Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_114643
```

送り直しても、ずれはほとんど縮みませんでした。チャンク05 と 06 では、2回送り直しても j1 のずれが 2.32°・2.65° のまま、1つも動いていません。同じ目標を送っても、アームは「もう着いている」として動かないようです。チャンク07 では、daemon への送信が4秒で時間切れになっています。


## 上カメラの写り方は、macOS のセンターフレームで数秒後に変わっていた

朝、写り方の確認で続けて止まったとき、カメラを開いた直後と3秒後のコマを保存して比べました。上カメラは iPhone を連係カメラ（Continuity Camera）で Mac につないで使っています。

```python
# 動かすコマンド (run_policy_client.py) と同じ方法で上カメラを開き, 開いた直後と3秒後のコマを保存する (LOG359)
# 使い方: cd ~/r2r2r-scripts && python3 <このファイル>
import sys, time, os
R = os.path.expanduser("~/r2r2r-scripts")
for sub in ["", "pi05", "dynamic_tracking_limits/place/place_modules", "dynamic_tracking_limits/drag_teaching"]:
    sys.path.insert(0, os.path.join(R, sub))
import cv2, camera_resolver
cams = camera_resolver.resolve_cameras(require_top=True, require_side=False, verbose=True)
print("cams:", cams)
cap = cv2.VideoCapture(cams["top"])
out = os.path.dirname(os.path.abspath(__file__))
t0 = time.time(); n = 0; saved0 = False
while time.time() - t0 < 3.0:
    ok, f = cap.read()
    if ok and f is not None:
        n += 1
        if not saved0:
            cv2.imwrite(os.path.join(out, "snap_first.jpg"), f); saved0 = True
            print("first frame", f.shape, f"{time.time()-t0:.2f}s")
cv2.imwrite(os.path.join(out, "snap_3s.jpg"), f)
print("frames", n, "saved to", out)
```

macOS のセンターフレーム（人の顔に合わせて画角を自動で寄せる機能）が入っていると、カメラを開いて数秒のうちに画角が寄り、マットが大きく写ります。お手本を録ったときと写り方が変わるので、センターフレームは切って使うことにしました。

【画像】LOG361_08_center_stage.jpg 上カメラのコマを3枚並べたもの。左と中はお手本と同じ写り方、右はセンターフレームで画角が寄り、マットとアームが大きく写っている

11:27 には、写り方の確認が NO MATCH になりました。このときはアームが HOME の姿勢に戻っていませんでした。この日の午前には、手首 j4 が +51.94° のまま動かなくなったこともあり、そのときはアームの電源を入れ直すと動くようになっています。

【画像】LOG361_07_no_match_wrist.jpg camera_align.py の画面。左上に NO MATCH と dy −24.6・dx −3.8 が出ている。手首が曲がったままで、重ねたお手本の爪の位置と合っていない


## つかんだあと、お手本は 1.5 秒その場で持ち上げてから回っていた

送り直しでは詰まらなかったので、つかんだ直後の動きをお手本と比べました。お手本（位置C）で爪を閉じたステップから、1ステップ（0.1 秒）ごとに各関節がどれだけ動いたかと、実機で閉じた直後のチャンクの予測を並べるスクリプトです。

```python
# つかんだ直後の動きを、お手本 (位置C) と比べる (LOG361)
#  お手本: 閉じたステップから 15 ステップ (1.5 秒) の 6 関節の変化
#  実機: 閉じた直後のチャンクで、モデルが予測した 10 ステップ (1 秒) の変化
import os, json
import numpy as np
ROOT = os.environ.get("R2R2R_DATA", "/Volumes/KIOXIA/r2r2r-data"); os.chdir(ROOT)
z = np.load("datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes/run_0001_20261019_192343/episode.npz")["state"]
c = np.where(np.diff(z[:, 6]) > 0.5)[0][0] + 1
print("お手本 192343  閉じたステップ t =", c, " 姿勢", np.round(z[c, :6], 1).tolist())
for k in range(0, 16):
    print(f"  +{k:2d} ステップ  Δ " + " ".join(f"{x:+5.1f}" for x in z[c + k, :6] - z[c, :6]))
for r in ["20261022_114643", "20261022_181602"]:
    L = [json.loads(l) for l in open(f"runs/pi05_policy/pi05_{r}/log.jsonl")]
    L = [x for x in L if "chunk" in x]
    i = next(k for k, x in enumerate(L) if x["state"][6] == 1)
    d = L[i]; s = np.array(d["state"]); a = np.array(d["actions"])
    print(f"\n実機 {r}  閉じた直後のチャンク {d['chunk']:02d}  state", np.round(s[:6], 1).tolist())
    for k in range(10):
        print(f"  step {k+1:2d}  Δ " + " ".join(f"{x:+5.1f}" for x in a[k, :6] - s[:6]))
```

```
お手本 192343  閉じたステップ t = 56  姿勢 [-27.700000762939453, 63.70000076293945, 14.100000381469727, -7.599999904632568, -61.20000076293945, -27.899999618530273]
  + 0 ステップ  Δ  +0.0  +0.0  +0.0  +0.0  +0.0  +0.0
  + 1 ステップ  Δ  -0.0  +0.0  -0.0  -0.0  -0.0  +0.0
  + 2 ステップ  Δ  -0.1  +0.0  -0.2  -0.1  -0.5  +0.0
  + 3 ステップ  Δ  -0.1  +0.0  -0.2  -0.1  -0.6  +0.0
  + 4 ステップ  Δ  -0.1  -0.0  -0.2  -0.1  -0.9  +0.0
  + 5 ステップ  Δ  -0.1  -0.4  +0.4  +0.2  -1.6  +0.1
  + 6 ステップ  Δ  -0.1  -0.8  +0.9  +0.5  -2.2  +0.1
  + 7 ステップ  Δ  -0.1  -1.2  +1.5  +0.9  -2.9  +0.2
  + 8 ステップ  Δ  -0.1  -1.6  +2.1  +1.2  -3.5  +0.2
  + 9 ステップ  Δ  -0.1  -2.0  +2.6  +1.5  -4.1  +0.3
  +10 ステップ  Δ  -0.1  -2.4  +3.2  +1.9  -4.8  +0.3
  +11 ステップ  Δ  -0.1  -2.8  +3.8  +2.2  -5.4  +0.4
  +12 ステップ  Δ  -0.1  -3.2  +4.3  +2.5  -6.1  +0.4
  +13 ステップ  Δ  -0.1  -3.6  +4.9  +2.9  -6.7  +0.5
  +14 ステップ  Δ  -0.1  -4.0  +5.5  +3.2  -7.3  +0.5
  +15 ステップ  Δ  +0.9  -4.5  +5.5  +3.5  -7.4  +0.4

実機 20261022_114643  閉じた直後のチャンク 04  state [-33.5, 62.5, 17.1, -3.2, -60.9, -28.3]
  step  1  Δ  -0.1  -0.0  +0.1  +0.1  -0.4  -0.0
  step  2  Δ  -0.3  -0.1  +0.3  +0.2  -0.8  -0.0
  step  3  Δ  -0.3  -0.1  +0.6  +0.4  -1.3  -0.1
  step  4  Δ  +0.1  -0.5  +0.8  +0.6  -1.6  -0.2
  step  5  Δ  +1.5  -1.0  +0.8  +1.0  -1.8  -0.4
  step  6  Δ  +4.1  -2.0  +0.5  +1.5  -1.5  -0.7
  step  7  Δ  +7.1  -2.8  +0.2  +2.0  -1.2  -1.0
  step  8  Δ  +9.9  -3.8  -0.2  +2.5  -0.8  -1.4
  step  9  Δ +12.9  -4.7  -0.8  +3.0  -0.3  -1.7
  step 10  Δ +15.5  -5.6  -1.2  +3.5  +0.2  -1.9

実機 20261022_181602  閉じた直後のチャンク 06  state [-39.6, 80.6, 7.5, 3.4, -89.5, -29.8]
  step  1  Δ  -0.1  -0.7  +0.7  +0.0  -0.1  -0.1
  step  2  Δ  -0.1  -1.9  +1.5  +0.0  -0.1  -0.1
  step  3  Δ  -0.0  -3.6  +2.4  +0.0  -0.1  -0.1
  step  4  Δ  -0.1  -5.1  +3.4  +0.0  +0.0  -0.1
  step  5  Δ  -0.1  -6.4  +4.4  +0.0  +0.1  -0.1
  step  6  Δ  -0.2  -7.5  +5.2  +0.0  +0.2  -0.1
  step  7  Δ  -0.2  -8.7  +6.1  +0.0  +0.2  -0.1
  step  8  Δ  -0.3  -9.9  +7.1  +0.1  +0.5  -0.1
  step  9  Δ  -0.0 -11.4  +8.1  +0.1  +0.7  -0.1
  step 10  Δ  +0.7 -12.6  +8.9  +0.2  +1.1  -0.1
```

お手本は、閉じてから 1.5 秒（15ステップ）の間、土台 j0 をほぼ動かさず（−0.1°）、肩 j1 を −4.5° 上げています。11:46 の回の予測は、0.5 秒後には土台を回し始め、1秒で +15.5° 回っています。最後の姿勢だけを送るやり方だと、「持ち上げながら回る」1本の動きになり、持ち上げきる前に回り始めます。

1秒ごとの姿勢（j0・j1・j4）を、お手本4本と実機の回で並べたものです。

```python
# お手本 (位置C の 4 本) と実機の、つかんでから離すまでを 1 秒ごとに並べる (j0 / j1 / j4) (LOG361)
import os, json
import numpy as np
ROOT = os.environ.get("R2R2R_DATA", "/Volumes/KIOXIA/r2r2r-data"); os.chdir(ROOT)
RAW = "datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes"
for e in ["192343", "192438", "192539", "192633"]:
    C = np.load(f"{RAW}/run_0001_20261019_{e}/episode.npz")["state"]
    c = np.where(np.diff(C[:, 6]) > 0.5)[0][0] + 1; o = np.where(np.diff(C[:, 6]) < -0.5)[0]; o = o[o > c][0] + 1
    print(f"demo {e} " + " ".join(f"[{C[t,0]:+5.0f} {C[t,1]:4.0f} {C[t,4]:+4.0f}]" for t in range(c, o + 1, 10)))
for r in ["20261022_095251", "20261022_100713", "20261022_102053", "20261022_181602"]:
    L = [json.loads(l) for l in open(f"runs/pi05_policy/pi05_{r}/log.jsonl")][1:]
    S = [x.get("measured_state", x["state"]) for x in L if "chunk" in x and x["state"][6] == 1]
    print(f"run  {r} " + " ".join(f"[{s[0]:+5.0f} {s[1]:4.0f} {s[4]:+4.0f}]" for s in S))
```

```
demo 192343 [  -28   64  -61] [  -28   61  -66] [  -13   56  -66] [  +16   49  -60] [  +41   47  -54] [  +41   63  -68]
demo 192438 [  -28   64  -61] [  -28   61  -66] [  -22   58  -68] [   +6   51  -62] [  +36   45  -54] [  +41   59  -65]
demo 192539 [  -27   64  -61] [  -28   62  -65] [  -27   59  -70] [   +0   53  -64] [  +30   45  -55] [  +41   55  -61]
demo 192633 [  -27   64  -61] [  -28   61  -66] [  -28   60  -70] [   -2   53  -64] [  +28   46  -56] [  +41   54  -61]
run  20261022_095251 [  -33   63  -62] [  -20   59  -58] [   +0   56  -56] [  +20   51  -49] [  +39   53  -46]
run  20261022_100713 [  -37   63  -61] [  -24   58  -59] [   -4   55  -53] [  +16   51  -47] [  +36   51  -44] [  +40   65  -52] [  +40   67  -54] [  +41   67  -53]
run  20261022_102053 [  -31   69  -68] [  -31   69  -69] [  -30   68  -70] [  -30   67  -68] [  -29   66  -69] [  -24   65  -68] [  -15   64  -66] [   -5   62  -64] [   +5   61  -62] [   +8   60  -62] [  +11   59  -62] [  +12   59  -64] [  +12   59  -64] [  +15   59  -66] [  +16   59  -66] [  +21   58  -66] [  +23   58  -66] [  +29   58  -66] [  +30   62  -69]
run  20261022_181602 [  -39   82  -90] [  -38   71  -90] [  -16   59  -78] [  +13   47  -68] [  +40   39  -60] [  +43   61  -72]
```

モデルの予測そのものがお手本からずれていないかも、お手本の画像と角度をサーバーに渡して確かめました（前の回の答え合わせの記録 `lab/Log11/offline_eval/20261021_180539/rows.csv` の位置C の部分を並べ直したもの）。

```python
# 10/21 のお手本との答え合わせ (eval_policy_offline.py の rows.csv) から、位置C のつかむ前後〜運ぶ間を抜き出す (LOG361)
import os, csv
ROOT = os.environ.get("R2R2R_DATA", "/Volumes/KIOXIA/r2r2r-data"); os.chdir(ROOT)
R = [r for r in csv.DictReader(open("lab/Log11/offline_eval/20261021_180539/rows.csv")) if "192343" in r["episode"]]
print(" t     j0     j1     j4  g  ずれ平均  ずれ最大(関節)  お手本1秒  予測1秒")
for r in R:
    t = int(r["t"])
    if 36 <= t <= 110:
        print(f"{t:3d} {float(r['j0']):+6.1f} {float(r['j1']):+6.1f} {float(r['j4']):+6.1f}  {r['grip']}  {r['err_mean']:>6}°  {r['err_max']:>6}°(j{r['err_max_joint']})  {r['demo_move_1s']:>6}°  {r['pred_move_1s']:>6}°")
```

```
 t     j0     j1     j4  g  ずれ平均  ずれ最大(関節)  お手本1秒  予測1秒
 36  -26.4  +54.5  -67.3  0    0.24°    1.03°(j4)    5.59°    5.21°
 39  -27.6  +58.1  -69.3  0    0.29°    1.09°(j1)    4.72°    4.49°
 42  -27.6  +58.1  -70.3  0    0.24°    0.78°(j3)    8.32°    7.64°
 45  -27.6  +59.6  -68.1  0    0.29°     1.1°(j2)     6.9°    7.43°
 48  -27.6  +61.2  -65.5  0    0.16°    0.47°(j0)    3.78°    3.73°
 51  -27.7  +62.8  -62.9  0    0.21°    0.86°(j4)    0.71°    0.82°
 54  -27.7  +63.7  -61.3  0    0.24°    0.93°(j2)    3.35°    2.42°
 57  -27.7  +63.7  -61.2  1    0.16°    0.52°(j4)    5.38°    5.67°
 60  -27.8  +63.7  -62.1  1    0.55°    1.13°(j2)    6.41°    5.32°
 63  -27.8  +62.5  -64.0  1    0.18°    0.89°(j1)    6.45°    5.56°
 66  -27.8  +61.3  -66.0  1    0.31°    1.18°(j0)   14.63°   13.99°
 69  -27.8  +60.1  -67.9  1    2.28°    9.91°(j0)   22.82°    13.1°
 72  -24.1  +58.6  -68.1  1    0.34°    1.47°(j0)   27.47°   28.42°
 75  -15.9  +56.6  -66.6  1    0.12°    0.57°(j1)   28.55°   28.18°
 78   -7.7  +54.5  -65.1  1    0.29°    1.04°(j0)   29.49°   28.45°
 81   +0.5  +52.5  -63.6  1    0.27°    1.16°(j0)   30.08°   28.92°
 84   +9.6  +50.3  -61.2  1    0.17°    0.65°(j0)   29.89°   29.25°
 87  +18.8  +48.1  -58.6  1    0.21°    0.79°(j0)   22.29°   23.09°
 90  +27.7  +45.8  -56.1  1     0.4°    1.47°(j4)   13.43°   12.11°
 93  +36.5  +44.9  -53.6  1    0.81°    2.04°(j0)   14.26°   15.52°
 96  +41.0  +47.2  -54.2  1    0.12°    0.92°(j1)   15.73°   14.93°
 99  +41.1  +52.3  -58.6  1    0.13°    0.69°(j4)    10.6°   10.15°
102  +41.1  +57.5  -63.1  1    0.11°    0.88°(j4)    5.61°    5.81°
105  +41.1  +62.6  -67.6  1    0.27°    1.52°(j4)    5.94°    7.15°
108  +41.1  +62.9  -68.5  1    0.52°    2.69°(j4)   11.52°    9.58°
```

お手本の画像と角度を渡すと、持ち上げの場面のずれは平均 0.1〜0.5° で、予測はお手本に合っています。モデルはお手本どおりに答えられるのに、実機では答えの届け方で高さを失っている、ということになります。

爪先の高さでも比べました。関節の角度から爪先の位置を求める表（FK テーブル `fk_tables/fk_scan_motion_based_v2.csv`、読むだけ）で、近い40点から局所的に直線で当てはめて高さを出しています。

```python
# お手本(位置C)と実機の各回で、爪先の高さ (FK 表 fk_scan_motion_based_v2.csv の ee_y) を比べる (LOG359)
# 高さは j0 によらないので、(j1,j2,j3,j4) の近い 40 点で局所線形に当てはめて求める
import os, json, glob
import numpy as np, pandas as pd
ROOT = os.environ.get("R2R2R_DATA", "/Volumes/KIOXIA/r2r2r-data"); os.chdir(ROOT)
d = pd.read_csv("fk_tables/fk_scan_motion_based_v2.csv")
X = d[["j1", "j2", "j3", "j4"]].to_numpy(float); Y = d["ee_y"].to_numpy(float)
def h(q):
    q = np.asarray(q, float)[[1, 2, 3, 4]]
    dd = ((X - q) ** 2).sum(1); idx = np.argpartition(dd, 40)[:40]
    A = np.c_[np.ones(len(idx)), X[idx] - q]
    coef, *_ = np.linalg.lstsq(A, Y[idx], rcond=None)
    return coef[0] * 1000  # mm
def phases(states):
    g = states[:, 6]
    c = np.where(np.diff(g) > 0.5)[0][0] + 1
    o = np.where(np.diff(g) < -0.5)[0]; o = o[o > c][0] + 1 if (o > c).any() else len(states) - 1
    return c, o
print("== お手本 位置C (10 ステップ = 1 秒ごと, 閉じた瞬間から開くまで) 爪先の高さ mm")
for e in ["192343", "192438", "192539", "192633"]:
    z = np.load(f"datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes/run_0001_20261019_{e}/episode.npz")["state"]
    c, o = phases(z)
    hs = [h(z[t]) for t in range(c, o + 1, 10)]
    print(f"demo {e}  閉じた時 {h(z[c]):6.1f}  最高 {max(h(z[t]) for t in range(c, o+1)):6.1f}  1秒ごと " + " ".join(f"{v:5.0f}" for v in hs))
print("== 実機 (チャンクごと, 閉じたあと) 爪先の高さ mm")
for r in ["095251", "100713", "102053", "114643", "131036", "181602", "182650"]:
    L = [json.loads(l) for l in open(f"runs/pi05_policy/pi05_20261022_{r}/log.jsonl")]
    S = [x.get("measured_state", x["state"]) for x in L if "chunk" in x and x["state"][6] == 1]  # --state-from-target の回は実測 (measured_state) を使う
    first_closed = S[0]
    print(f"run  {r}  閉じた直後 {h(first_closed):6.1f}  最高 {max(h(s) for s in S):6.1f}  チャンクごと " + " ".join(f"{h(s):5.0f}" for s in S))
```

```
== お手本 位置C (10 ステップ = 1 秒ごと, 閉じた瞬間から開くまで) 爪先の高さ mm
demo 192343  閉じた時   41.4  最高  135.2  1秒ごと    41    40    51   111   103    86
demo 192438  閉じた時   41.7  最高  124.9  1秒ごと    42    39    56    96   122    96
demo 192539  閉じた時   41.6  最高  134.5  1秒ごと    42    44    23    89   120    82
demo 192633  閉じた時   41.3  最高  129.8  1秒ごと    41    38    22    86   120   110
== 実機 (チャンクごと, 閉じたあと) 爪先の高さ mm
run  095251  閉じた直後   28.6  最高   71.6  チャンクごと    29    33    48    72    71
run  100713  閉じた直後   25.7  最高   50.8  チャンクごと    26    34    41    51    21    35    34    26
run  102053  閉じた直後    9.8  最高   36.5  チャンクごと    10     4    15     4     7     6    32    28     9    32    12    37    34    34    34    35    35    35    26
run  114643  閉じた直後   27.0  最高   74.3  チャンクごと    27    39    49    74    63
run  131036  閉じた直後   33.9  最高   67.4  チャンクごと    34    35    50    67    67
run  181602  閉じた直後    2.1  最高   86.7  チャンクごと     2    47     7    80    87    82
run  182650  閉じた直後   11.8  最高   93.8  チャンクごと    12    35    56    94    75    44
```

お手本は約 41mm の高さでつかみ、125〜135mm まで持ち上げています。朝の回は、どれも 37〜74mm までしか上がっていません。


## 1秒分の途中の姿勢も送る --via-stride を足した

「持ち上げてから回る」順番を保つため、1秒分の予測のうち、最後の姿勢だけでなく途中の姿勢も3ステップおきに順に送るようにしました（`--via-stride 3` で 2・5・8・9 ステップ目を送る）。Claude Code の報告です。

```
--via-stride を足しました。変更は pi05/run_policy_client.py の 1
  ファイルのみ（未コミット、91 insertions / 12 deletions）。

  変えた行

  行: 7-8
  変更: docstring の流れに「--via-stride N で途中の姿勢も中継点として順に送る」
  ────────────────────────────────────────
  行: 239-272 
  変更: plan_vias() を新設。stride=0 なら [used] のみ、N>0 なら range(N-1, used, 
  N) + [used]。apply_limits は直前の中継点の目標から測る（最初だけ実測角 q
  から）。戻り値は [{"step","raw","target","notes","delta"}]
  ────────────────────────────────────────
  行: 397-399 
  変更: --via-stride（既定 0）を追加
  ────────────────────────────────────────
  行: 519-522 
  変更: plan_chunk の結果を plan_vias に渡し、target / notes
  は最終中継点のものを使う（rec["target"] / rec["notes"] / 既存の Δ           
  表示の意味は変えていません）
  ────────────────────────────────────────
  行: 534-547
  変更: rec["vias"] の初期化（step / raw / target / notes / sent / arrived /  
  actual_after）、[VIA ] 中継点 N 点: step … の一覧、中継点ごとの
  [LIMIT]、ドライランでは中継点ごとの Δ 行
  ────────────────────────────────────────
  行: 549-556 
  変更: 安全検査を全中継点に対して実施（stride>0 のときメッセージに step k:   
  を付ける）。引っかかったら従来と同じ扱い（[ABORT] → 記録 → flush → exit_code=1
   → h の選択 → break）
  ────────────────────────────────────────
  行: 599-629 
  変更: 送信を中継点のループに変更。各点で Δ ≤ 0.5°
  なら送らない（既存ガード）、_send_and_wait_arrival(..., 3.0) → read_angles()
  で actual_after を記録 → [VIA ] 行に着いたか。rec["arrived"] と settle
  は最後の中継点だけ。未到達＋--auto の停止も従来どおり

  _send_and_wait_arrival
  本体・HOME・SPEED・SEND_WAIT・J4_SAFE・J1_SAFE_MAX・max_move の値・plan_chunk
  の used の選び方・settle・Enter/s/h/q（チャンクごとに 1 回）は未変更です。

  設計上の判断を 1 つ: 安全検査は送り始める前に全中継点をまとめて行い、1
  つでも引っかかったらどれも送りません。apply_limits 
  が直前の「目標」から測るので計画は送信前に全部確定でき、途中まで動いて止まる状
  態を作らずに済みます（「今と同じ扱い＝送る前に止まる」も保てます）。

  確認結果（偽の daemon・7 ケースすべて OK）

  ┌───────────────────────────────────┬──────────────────────────────────────┐
  │              ケース               │                 結果                 │
  ├───────────────────────────────────┼──────────────────────────────────────┤
  │ 1 --via-stride 0                  │ 送信 1 回（pi05_chunk000）、vias     │
  │                                   │ キーなし = 従来どおり                │
  ├───────────────────────────────────┼──────────────────────────────────────┤
  │ 2 N=3 / used=9                    │ 送信 4 回を via02 → via05 → via08 →  │
  │                                   │ via09 の順                           │
  ├───────────────────────────────────┼──────────────────────────────────────┤
  │ 3 7 番目(index 6)で開閉 → used=6  │ 中継点は 2, 5, 6。送信は via02 →     │
  │                                   │ via05 の 2 回、最後に爪を閉じる      │
  ├───────────────────────────────────┼──────────────────────────────────────┤
  │ 3b 8 番目(index 7)で開閉 → used=7 │ 中継点 2, 5, 7 を 3                  │
  │                                   │ 回送ってから爪を閉じる               │
  ├───────────────────────────────────┼──────────────────────────────────────┤
  │ 4 中継点の 1 つが検査に引っかかる │ 送信 0 回・[ABORT] step 5:           │
  │                                   │ …・終了コード 1（残りも送らない）    │
  ├───────────────────────────────────┼──────────────────────────────────────┤
  │ 5                                 │ 送信 0 回・4 点すべての [ABORT]      │
  │ アームが範囲外から開始（j4=+100） │ を表示して停止                       │
  ├───────────────────────────────────┼──────────────────────────────────────┤
  │ 6 ドライラン                      │ 送信 0 回、中継点の一覧と各 Δ を表示 │
  └───────────────────────────────────┴──────────────────────────────────────┘

  max_move が「直前の中継点から」かかっていることは plan_vias
  単体でも確認しました（max_move=5 のとき）:

  step 2: raw j1=  -4.0 → target  -4.0  Δ -4.0  (直前の目標  +0.0)
  step 5: raw j1= -10.0 → target  -9.0  Δ -5.0  (直前の目標  -4.0)  j1 移動量
  -6.0° を ±5° に制限
  step 8: raw j1= -16.0 → target -14.0  Δ -5.0  (直前の目標  -9.0)  j1 移動量
  -7.0° を ±5° に制限
  step 9: raw j1= -18.0 → target -18.0  Δ -4.0  (直前の目標 -14.0)

  ケース 3 について補足: used=6（index 6 で開閉）のとき plan_chunk の目標は
  acts[5] なので、中継点 step 6 の目標は step 5 と同じ値になります。既存の「Δ
  0.5° 以下は送らない」ガードでこの 1 回は省かれ、画面は 送らず (0.5° 
  以下)、ログは "sent": false になります（中継点の一覧には 2, 5, 6 の 3
  点が残ります）。step 7 で開閉する 3b では 3
  点とも送られるので、重複するのは「開閉ステップの 1 
  つ前が中継点と一致したとき」だけです。この挙動でよければこのまま、毎回必ず最後
  も送るほうがよければ変えます。
```

codex のレビューです。小さい中継点がすべて「0.5° 以下なので送らない」に当たって消えること、最後の点を送らなかったときに到達の確認まで飛ばされることなど、直す点が出ました。

```
**`--via-stride > 0`の実機テスト前に修正すべき点があります。** 特に、小さい中継点の累積移動が消えることと、最後の点がスキップされるとsettleも実行されないことです。差分の読み取りのみ行いました。

行番号は現在の [run_policy_client.py](/Users/shimazueiichi/r2r2r-scripts/pi05/run_policy_client.py) です。

|項目|判定|確認結果・修正案|
|---|---|---|
|A1 選択順・開閉前の姿勢|✅／⚠️|[259〜265行](/Users/shimazueiichi/r2r2r-scripts/pi05/run_policy_client.py:259)は指定どおり昇順で、usedを超えません。開閉時の最終姿勢も`plan_chunk`が返す直前姿勢を使います。ただし開閉時のusedは切替ステップf、実際の最終rawはactions[f−1]なので、ログのstepとrawの元インデックスは一致しません。|
|A2 apply_limits・移動量|❌ NG|[262〜268行](/Users/shimazueiichi/r2r2r-scripts/pi05/run_policy_client.py:262)は指定どおり直前の**計画target**基準です。ただし送信時に実測との差を検査しないため、「各送信が実測から20°以内」は保証されません。直前target=20°、実測17°、次target=40°なら実測から23°です。送信直前に実測との差を確認し、超過時の扱いを定義してください。|
|A3 事前検査後のずれ|✅／⚠️|[552〜555行](/Users/shimazueiichi/r2r2r-scripts/pi05/run_policy_client.py:552)で全targetを送信前に検査します。途中の実測ずれで固定targetが安全角度範囲外へ変わることはありません。ただし実測からの移動量と、意図した持ち上げ経路は保証されません。|
|A4 途中未到達|✅／⚠️|[618〜630行](/Users/shimazueiichi/r2r2r-scripts/pi05/run_policy_client.py:618)。autoは次の点・グリッパーへ進まず停止します。手動は警告して次へ進むため従来方針どおりですが、未到達の持ち上げ点を飛ばして旋回点へ進めます。持ち上げ優先を保証するものではありません。|
|A5 h/q/s・dry-run・stride=0|✅ OK|確認入力はチャンクに1回。h/q/sは中継点送信前に分岐し、dry-runは送信しません。stride=0の1点計画は従来のapply_limits・送信ガードと同じです。|
|A6 viasの記録|❌ NG|[609〜612行](/Users/shimazueiichi/r2r2r-scripts/pi05/run_policy_client.py:609)。呼出先が**送信前の読角失敗**で戻った場合も`sent=True`になります。`sent`は送信関数を呼んだ意味と、実送信を分けてください。`actual_after`読取失敗を`None`にする点、スキップ点を`sent=False`にする点は正しいです。|
|C1 関節角度制限|✅ OK|検査済みtargetだけを送るため、今回の変更でJ4_SAFE・J1_SAFE_MAX外の指令値を作る経路は見つかりません。A2の移動量超過とは別です。|
|D1 send_coords|✅ OK|追加処理で使っていません。|
|D2 固定値|✅ OK|HOME、SPEED=20、SEND_WAIT_SEC=1.0、max_move既定20°は変更されていません。ただし20°制限の基準は中継点の計画targetへ変わっています。|

追加で、送信ガードに2つの不具合があります。

**❌ 小さい変位を積み重ねる軌道が、全点スキップされます。**  
[604〜608行](/Users/shimazueiichi/r2r2r-scripts/pi05/run_policy_client.py:604)は、送らなかった点も含む「直前の計画targetとの差」で判断します。

例えば現在0°、中継点0.4°→0.8°→1.2°なら、各deltaは0.4°なので**全部送られません**。従来なら最終1.2°を送ります。ガードは現在実測、または少なくとも最後に実行した点を基準にしてください。

**❌ 最終点のスキップでsettleまで消えます。**  
同じ`continue`が[625〜628行](/Users/shimazueiichi/r2r2r-scripts/pi05/run_policy_client.py:625)のsettleを飛ばします。特にstride=1で開閉がf番目に予測された場合、最後の中継点actions[f−1]と、最終raw_targetが重複し、最終delta=0になります。その結果、**最後に実送信した姿勢をsettleせず、そのまま爪を閉じる**経路になります。

重複する送信を省く処理と、チャンク最終姿勢の到達確認・settleは分離してください。
```

直した版の報告です。

```
3 点＋記録を直しました。変更は pi05/run_policy_client.py のみ（未コミット、176
  insertions / 43 deletions）。

  変えた行
     
  行: 239, 257-273
  変更: plan_vias(..., final_raw_index=None)。各中継点に raw_index（actions  
  の何行目を使ったか）を持たせる（codex A1）
  ────────────────────────────────────────                                   
  行: 526-531
  変更: final_raw_index を計算（開閉チャンクは used-1、used==0 なら None、通常は
  used）して plan_vias に渡す                                                
  ────────────────────────────────────────
  行: 545-549
  変更: rec["vias"] のキーを変更: sent/arrived → called / success /          
  retried、raw_index と planned_target を追加（codex A6）                    
  ────────────────────────────────────────
  行: 569 
  変更: 構造変更: if not unsafe and args.execute:
  にして、停止ブロックを送信ループの後ろに 1                                 
  か所だけ置く（計画の検査と送信直前の検査で同じ処理を使うため）。計画が危険なと
  きに確認入力より前で止まる順番は従来どおり
  ────────────────────────────────────────
  行: 588-619
  変更: 中継点ごとに、送る直前に read_angles() → apply_limits(v["raw"], 実測角, 
  …)
  でかけ直し → check_send_safe を通し直す（codex A2）。かけ直しで notes
  が変わったら [LIMIT] step k (実測から): … を表示し、記録の target/notes    
  をかけ直し後に更新。読めなければその点も残りも送らず [WARN] 2 
  行＋rec["arrived"]=False（--auto なら従来の未到達と同じく終了コード 1 で停止）
  ────────────────────────────────────────
  行: 619-625
  変更: 送らない判定を tgt - 実測角 で行う（codex ❌1。--via-stride 0 
  のときは従来どおり計画の Δ）
  ────────────────────────────────────────
  行: 627-647
  変更: 送信後の記録を called/success/retried/actual_after に変更
  ────────────────────────────────────────
  行: 648-655
  変更: 最後の中継点を送らなかった場合も、チャンクの最後の目標について 
  rec["arrived"]（実測との最大差 ≤ 3.0°）と settle を必ず行う（codex ❌2）
  ────────────────────────────────────────
  行: 656-664
  変更: broke のときはグリッパーと executed をスキップ
  ────────────────────────────────────────
  行: 665-690
  変更: 停止ブロック（送信直前の検査で引っかかった場合もここに合流。[ABORT]→記録→
  flush→exit_code=1→h
  の選択→break）

  --via-stride 0 のときは、送る直前の読み直し・かけ直し・再検査・item 3
  の後処理をすべて行いません（今までと同じ動き・新しい停止条件なし）。_send_and_w
  ait_arrival 本体・HOME・SPEED・SEND_WAIT・J4_SAFE・J1_SAFE_MAX・max_move
  の値・plan_chunk・Enter/s/h/q・ドライランは未変更です。

  確認結果（偽の daemon・11 ケースすべて OK）

  OK 1_stride0   OK 2_stride3_used9   OK 3_gripper_at6   OK 3b_gripper_at7
  OK 4_unsafe_middle   OK 5_unsafe_first   OK 6_dryrun
  OK 8_accumulate   OK 9_reclamp_from_actual   OK 10_last_skipped   OK
  11_read_fail_before_send

  8. 0.4° ずつ積み重なる中継点（1 ステップ 0.133°、中継点は累積 +0.4 / +0.8 /
  +1.2 / +1.33）

  step 2  Δ +0.4  送らず (0.5° 以下)      ← 実測は動かないまま
  step 5  Δ +0.8  着いた                   ← 積み重なって 0.5°
  を超えたので送られる
  step 8  Δ +0.4  送らず
  step 9  Δ +0.5  着いた                   ← 最後の点も送られる
  chunk: arrived=True settle=within_tol
  計画の Δ（毎回 0.4°）で見ていた前の版では 4 
  点とも送られず動きが消えていました。

  9. 直前の中継点で手前に止まった場合（j1 が毎回 25° 手前で止まる腕）

  [LIMIT] step 5 (実測から): j1 移動量 +43.0° を ±20° に制限
  via step=5 target=[... 7.0 ...] planned=[... 30.0 ...]
  [LIMIT] step 8 (実測から): j1 移動量 +66.0° を ±20° に制限
  via step=8 target=[... 2.0 ...] planned=[... 48.0 ...]
  target（かけ直し後）と planned_target（計画時）が別々に残り、移動量が実測から
  ±20° に制限されています。

  10. 最後の中継点が重複で送られない場合（開閉が index 6 → step 6 の目標が step 5
  と同値）

  via step=6 raw_index=5 called=False
  chunk: arrived=True settle=within_tol executed=True
  送信は 2 回のままで、チャンクの最後の目標について arrived と settle 
  が記録されています（raw_index=5 が step 6 とずれていることも記録）。

  11. 送る直前の読み取りに失敗

  [VIA   ] step  2  Δ= -3.0 ...  着いた
  [WARN] 送る直前の関節角を読めない. この中継点も残りの中継点も送りません
  [WARN] 未到達. j4 の発熱などを確認してください
  イベント順: 爪を開く → 送信 via02        ← 残り 3 点は送らない
  chunk: arrived=False settle=None executed=False / 終了コード 1 (--auto)

  前回の 7 ケース（stride 0 で送信 1 回・vias キーなし／2・5・8・9
  の順／開閉チャンク／検査で 0 回送信／範囲外からの開始／ドライラン）も引き続き
  OK です。

  判断を 1 つ確認させてください: 読み取り失敗で中断したとき、手動モードでもグリッ
  パーの開閉を行わないようにしました（executed=False）。今の未到達（手動）はグリ
  ッパーまで進みますが、腕の位置が読めず目標にも着いていない状態で爪を動かすのは
  危ないと判断しています。従来どおり爪を動かす方がよければ直します。
```

13:10 に、中継点を送るやり方で動かしました（送り直しは切っています）。

```
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % cd ~/r2r2r-scripts
RAW=/Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
python3 dynamic_tracking_limits/place/place_modules/08_home_from_anywhere.py
python3 -c "from visual_servo_pick import get_daemon_socket, daemon_set_gripper, close_daemon_socket; get_daemon_socket(); daemon_set_gripper(0); close_daemon_socket()"
python3 pi05/camera_align.py --raw-dir $RAW --episode run_0001_20261019_192343 --scale 5
[INIT] daemon 接続中...
  [WARN] fresh_mode切替不可: daemon error: set_fresh_mode is not available in this pymycobot environment
[INIT] fresh_mode=1
[PRE]  現在姿勢: [-0.43, 1.31, 1.05, -0.26, 0.26, -30.23]
[SEND] HOME へ移動指令
[WAIT] t=2.0s  max_err=1.31°
[DONE] HOME 到達 max_err=1.31°
[POST] 最終姿勢: [-0.43, 1.31, 1.05, -0.26, 0.26, -30.23]
  [WARN] fresh_mode切替不可: daemon error: set_fresh_mode is not available in this pymycobot environment
[EXIT] fresh_mode=0, socket close
  [Pi] GRIPPER: OPEN result= -1
[REF   ] 基準画像: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes/run_0001_20261019_192343/frames/000000.jpg
[REF   ] お手本 run_0001_20261019_192343 (つかんだ瞬間の j0 = -27.7°)
[REF   ] 重なった画像のブロックに実物のブロックを合わせると, お手本と同じ位置に置ける
[ALIGN ] |dy| <= 20 なら OK. アームは HOME に置いた状態で合わせる. q または Esc で終了 (ファイルには何も書かない)
[ALIGN ] dy=  -2.0  dx=  -0.9  response=0.725  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
^C
[STOP  ] Ctrl-C
[DONE  ] 終了 (何も書いていません)
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % python3 pi05/run_policy_client.py --raw-dir $RAW --steps-per-chunk 10 --via-stride 3 --settle-retries 0 --execute
[SAFE  ] 安全範囲 (学習 19 本 ±10°): j0[-72,+55]  j1[-9,+88]  j2[-46,+41]  j3[-18,+27]  j4[-90,+10]  j5[-51,-14]
[SAFE  ] 肩 j1 の上限は J1_SAFE_MAX=88° で切った (これを超える指令はアームが黙って捨てる / LOG352)  元データ: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
[MODE  ] EXECUTE  steps/chunk=10  max_move=20.0°  log=/Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_131036
[CAMERA] 写り方 dy=-6.9 dx=+1.8 response=0.581 → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[CAMERA] 基準: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes/run_0001_20261019_183454/frames/000000.jpg
[POLICY] 接続 ws://localhost:8000  metadata={}
[GRIP  ] 開始時のグリッパー開放は, 最初の目標が検査を通ってから行います (爪が閉じていたら手で開けておく)
[000] 推論 1601ms  10ステップ先  Δ=-10.3 +19.3  +4.8  -2.2 -22.3  +2.1
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[GRIP  ] 開始時にグリッパーを開く
  [Pi] GRIPPER: OPEN result= -1
[SEND] pi05_chunk000_via02: send_angles (single) [  -2.74,   +5.42,   +1.26,   -0.48,   -4.31,  -29.91]  speed=20 wait=1.0s  (pre max|Δ|=4.57°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.90° (tol 3.0°)
       [VIA   ] step  2  Δ= -2.3  +4.1  +0.2  -0.2  -4.6  +0.3  着いた
[SEND] pi05_chunk000_via05: send_angles (single) [  -5.89,  +11.97,   +3.01,   -1.27,  -11.79,  -29.24]  speed=20 wait=1.0s  (pre max|Δ|=8.28°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.03° (tol 3.0°)
       [VIA   ] step  5  Δ= -2.7  +5.7  +0.9  -1.1  -8.3  +0.9  着いた
[SEND] pi05_chunk000_via08: send_angles (single) [  -9.39,  +18.48,   +5.21,   -2.26,  -19.85,  -28.41]  speed=20 wait=1.0s  (pre max|Δ|=8.52°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.11° (tol 3.0°)
       [VIA   ] step  8  Δ= -3.2  +5.5  +1.4  -1.9  -8.5  +1.0  着いた
[SEND] pi05_chunk000_via09: send_angles (single) [ -10.69,  +20.56,   +5.81,   -2.46,  -22.05,  -28.16]  speed=20 wait=1.0s  (pre max|Δ|=2.46°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.97° (tol 3.0°)
       [VIA   ] step  9  Δ= -1.1  +1.0  -0.2  -0.9  -2.5  +0.5  着いた
[001] 推論 1155ms  10ステップ先  Δ=-12.7 +24.2  +6.4  -0.2 -30.2  +0.5
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk001_via02: send_angles (single) [ -14.40,  +28.34,   +8.35,   -2.63,  -30.70,  -28.10]  speed=20 wait=1.0s  (pre max|Δ|=8.20°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.10° (tol 3.0°)
       [VIA   ] step  2  Δ= -3.7  +6.8  +1.8  -0.5  -8.2  +0.3  着いた
[SEND] pi05_chunk001_via05: send_angles (single) [ -18.45,  +35.78,  +10.42,   -2.48,  -40.29,  -27.98]  speed=20 wait=1.0s  (pre max|Δ|=10.41°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.04° (tol 3.0°)
       [VIA   ] step  5  Δ= -4.5  +6.3  +1.3  -0.1 -10.4  +0.3  着いた
[SEND] pi05_chunk001_via08: send_angles (single) [ -22.14,  +42.89,  +12.27,   -2.27,  -49.57,  -27.88]  speed=20 wait=1.0s  (pre max|Δ|=9.94°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.05° (tol 3.0°)
       [VIA   ] step  8  Δ= -3.4  +6.1  +1.3  +0.6  -9.9  +0.3  着いた
[SEND] pi05_chunk001_via09: send_angles (single) [ -23.42,  +45.73,  +12.86,   -2.20,  -52.69,  -27.85]  speed=20 wait=1.0s  (pre max|Δ|=3.48°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.11° (tol 3.0°)
       [VIA   ] step  9  Δ= -1.6  +1.8  +0.0  +0.3  -3.5  +0.3  着いた
[002] 推論 852ms  10ステップ先  Δ= -6.9 +13.2  +4.7  +0.1 -16.6  +0.2
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk002_via02: send_angles (single) [ -27.32,  +53.33,  +14.88,   -2.61,  -61.20,  -27.93]  speed=20 wait=1.0s  (pre max|Δ|=8.65°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.89° (tol 3.0°)
       [VIA   ] step  2  Δ= -3.7  +6.5  +2.1  -0.2  -8.6  +0.1  着いた
[SEND] pi05_chunk002_via05: send_angles (single) [ -29.71,  +58.46,  +16.74,   -2.51,  -67.08,  -27.90]  speed=20 wait=1.0s  (pre max|Δ|=6.44°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.95° (tol 3.0°)
       [VIA   ] step  5  Δ= -2.6  +4.2  +1.4  -0.3  -6.4  +0.0  着いた
[SEND] pi05_chunk002_via08: send_angles (single) [ -30.61,  +59.98,  +17.59,   -2.24,  -69.14,  -27.82]  speed=20 wait=1.0s  (pre max|Δ|=2.17°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.92° (tol 3.0°)
       [VIA   ] step  8  Δ= -0.9  +0.6  +0.6  -0.0  -2.2  -0.1  着いた
[SEND] pi05_chunk002_via09: send_angles (single) [ -30.51,  +60.03,  +17.50,   -2.23,  -69.17,  -27.80]  speed=20 wait=1.0s  (pre max|Δ|=0.87°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.87° (tol 3.0°)
       [VIA   ] step  9  Δ= +0.6  -0.9  -0.2  -0.1  +0.2  -0.1  着いた
[003] 推論 884ms  10ステップ先  Δ= +0.1  +3.7  -4.3  -3.0  +5.2  +0.1  グリッパー→閉
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk003_via02: send_angles (single) [ -30.84,  +62.06,  +16.37,   -3.01,  -67.98,  -27.63]  speed=20 wait=1.0s  (pre max|Δ|=1.36°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.36° (tol 3.0°)
       [VIA   ] step  2  Δ= +0.3  +1.2  -1.3  -0.9  +1.4  +0.0  着いた
[SEND] pi05_chunk003_via05: send_angles (single) [ -30.83,  +63.52,  +14.31,   -4.36,  -65.23,  -27.59]  speed=20 wait=1.0s  (pre max|Δ|=4.11°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.21° (tol 3.0°)
       [VIA   ] step  5  Δ= +0.3  +0.4  -3.2  -1.7  +4.1  +0.1  着いた
[SEND] pi05_chunk003_via08: send_angles (single) [ -30.96,  +64.62,  +13.36,   -5.09,  -64.12,  -27.55]  speed=20 wait=1.0s  (pre max|Δ|=2.32°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.94° (tol 3.0°)
       [VIA   ] step  8  Δ= +0.1  +0.0  -2.0  -1.1  +2.3  +0.1  着いた
[SEND] pi05_chunk003_via09: send_angles (single) [ -30.96,  +64.62,  +13.36,   -5.09,  -64.12,  -27.55]  speed=20 wait=1.0s  (pre max|Δ|=0.94°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.94° (tol 3.0°)
       [VIA   ] step  9  Δ= +0.1  -0.9  -0.8  -0.4  +0.9  +0.2  着いた
  [Pi] GRIPPER: VALUE=20 speed=100 result= -1
[004] 推論 2181ms  10ステップ先  Δ= +6.6  -4.2  +2.0  +2.7  -1.7  -1.0
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk004_via02: send_angles (single) [ -31.25,  +64.76,  +15.14,   -3.97,  -66.91,  -27.92]  speed=20 wait=1.0s  (pre max|Δ|=1.26°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.08° (tol 3.0°)
       [VIA   ] step  2  Δ= -0.1  -0.8  +1.1  +0.8  -1.3  +0.0  着いた
[SEND] pi05_chunk004_via05: send_angles (single) [ -31.02,  +63.73,  +16.42,   -3.27,  -67.95,  -27.94]  speed=20 wait=1.0s  (pre max|Δ|=2.12°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.39° (tol 3.0°)
       [VIA   ] step  5  Δ= +0.2  -1.8  +2.1  +1.5  -2.1  +0.0  着いた
[SEND] pi05_chunk004_via08: send_angles (single) [ -26.69,  +62.03,  +16.41,   -2.37,  -67.85,  -28.67]  speed=20 wait=1.0s  (pre max|Δ|=4.07°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.13° (tol 3.0°)
       [VIA   ] step  8  Δ= +4.1  -3.1  +0.8  +1.5  -1.0  -0.8  着いた
[SEND] pi05_chunk004_via09: send_angles (single) [ -24.58,  +61.35,  +16.03,   -2.05,  -67.43,  -28.96]  speed=20 wait=1.0s  (pre max|Δ|=2.81°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.37° (tol 3.0°)
       [VIA   ] step  9  Δ= +1.8  -2.8  +0.3  +0.0  -1.2  -0.8  着いた
[005] 推論 890ms  10ステップ先  Δ=+22.8  -7.3  -4.5  +3.9  +5.5  -2.4
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk005_via02: send_angles (single) [ -18.47,  +62.07,  +14.97,   -0.18,  -64.93,  -29.26]  speed=20 wait=1.0s  (pre max|Δ|=5.78°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.65° (tol 3.0°)
       [VIA   ] step  2  Δ= +5.8  -1.6  -1.2  +1.2  +1.4  -0.8  着いた
[SEND] pi05_chunk005_via05: send_angles (single) [ -11.46,  +60.01,  +13.59,   +1.08,  -63.22,  -30.02]  speed=20 wait=1.0s  (pre max|Δ|=6.38°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.39° (tol 3.0°)
       [VIA   ] step  5  Δ= +6.4  -3.7  -2.4  +2.0  +2.8  -1.4  着いた
[SEND] pi05_chunk005_via08: send_angles (single) [  -4.02,  +57.44,  +12.21,   +2.29,  -61.42,  -30.73]  speed=20 wait=1.0s  (pre max|Δ|=7.66°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.58° (tol 3.0°)
       [VIA   ] step  8  Δ= +7.7  -5.0  -2.5  +1.1  +2.1  -1.5  着いた
[SEND] pi05_chunk005_via09: send_angles (single) [  -1.36,  +56.45,  +11.70,   +2.62,  -60.73,  -30.89]  speed=20 wait=1.0s  (pre max|Δ|=3.57°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.61° (tol 3.0°)
       [VIA   ] step  9  Δ= +2.7  -3.6  -1.6  -0.0  +1.0  -0.7  着いた
[006] 推論 1151ms  10ステップ先  Δ=+25.1  -8.1  -4.2  +1.4  +6.8  -0.4
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk006_via02: send_angles (single) [  +5.12,  +57.28,  +12.79,   +3.35,  -60.07,  -30.65]  speed=20 wait=1.0s  (pre max|Δ|=6.61°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.78° (tol 3.0°)
       [VIA   ] step  2  Δ= +6.6  -1.8  -0.6  +0.4  +0.9  -0.2  着いた
[SEND] pi05_chunk006_via05: send_angles (single) [ +13.07,  +54.60,  +11.55,   +3.89,  -57.99,  -30.74]  speed=20 wait=1.0s  (pre max|Δ|=8.15°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.52° (tol 3.0°)
       [VIA   ] step  5  Δ= +8.1  -4.5  -1.8  +0.5  +2.4  -0.2  着いた
[SEND] pi05_chunk006_via08: send_angles (single) [ +21.20,  +51.63,   +9.64,   +4.27,  -55.05,  -30.82]  speed=20 wait=1.0s  (pre max|Δ|=8.29°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.59° (tol 3.0°)
       [VIA   ] step  8  Δ= +8.3  -5.5  -3.7  +0.1  +3.3  -0.3  着いた
[SEND] pi05_chunk006_via09: send_angles (single) [ +23.62,  +50.98,   +9.11,   +4.34,  -54.23,  -30.86]  speed=20 wait=1.0s  (pre max|Δ|=3.24°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.63° (tol 3.0°)
       [VIA   ] step  9  Δ= +2.5  -3.2  -1.9  -0.0  +0.5  -0.3  着いた
[007] 推論 2162ms  10ステップ先  Δ=+15.9  +0.3  -7.3  +1.3  +3.7  -1.1
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk007_via02: send_angles (single) [ +30.17,  +52.29,   +7.90,   +5.04,  -50.99,  -31.17]  speed=20 wait=1.0s  (pre max|Δ|=6.62°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.59° (tol 3.0°)
       [VIA   ] step  2  Δ= +6.6  -1.3  -3.1  +0.5  +3.5  -0.6  着いた
[SEND] pi05_chunk007_via05: send_angles (single) [ +36.42,  +50.92,   +4.82,   +5.43,  -48.07,  -31.73]  speed=20 wait=1.0s  (pre max|Δ|=6.19°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.69° (tol 3.0°)
       [VIA   ] step  5  Δ= +6.2  -2.7  -4.7  +0.3  +3.0  -0.7  着いた
[SEND] pi05_chunk007_via08: send_angles (single) [ +39.25,  +52.67,   +3.82,   +5.75,  -49.47,  -31.69]  speed=20 wait=1.0s  (pre max|Δ|=2.87°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.62° (tol 3.0°)
       [VIA   ] step  8  Δ= +2.9  -0.9  -2.3  -0.0  -1.1  -0.1  着いた
[SEND] pi05_chunk007_via09: send_angles (single) [ +39.44,  +53.94,   +3.69,   +5.87,  -50.78,  -31.70]  speed=20 wait=1.0s  (pre max|Δ|=2.36°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.58° (tol 3.0°)
       [VIA   ] step  9  Δ= +0.2  +0.3  -1.8  -0.3  -2.4  +0.3  着いた
[008] 推論 883ms  8ステップ先  Δ= +0.6  +8.7  -2.5  +0.7  -6.2  -0.3  グリッパー→開
       [VIA   ] 中継点 3 点: step 2, 5, 7
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > h
[SEND] pi05_home: send_angles (single) [  +0.00,   +0.00,   +0.00,   +0.00,   +0.00,  -30.00]  speed=20 wait=1.0s  (pre max|Δ|=55.10°, post-send timeout 10.3s)
[SEND] arrival OK: max|Δ|=2.37° (tol 2.5°)
[DONE  ] 記録: /Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_131036
```

チャンク04 で閉じたあと、05 の途中の姿勢で肩を上げ、そのあと回る順番になりました。ただ、爪先の高さはいちばん上がったところで 67mm で、朝の回と変わっていません。持ち上げの順番は直せても、肩の不足は積み重なったままです。


## お手本の動きを実機でそのまま再生すると、ブロックは4回とも箱に入った

AI が悪いのか、アームが悪いのかを分けるため、お手本の動き（手でアームを動かして教えた要所の姿勢）を、同じアームでそのまま再生して、斜め上と横から撮りました。

daemon を起動し直し、上カメラでブロックと箱の位置を測ってから、まずドライラン（アームに何も送らない）で計画を確かめました。

```
(base) shimazueiichi@shimadzueiichinoMacBook-Pro ~ % ssh -i ~/.ssh/id_rsa_pi ubuntu@192.168.2.1 "setsid nohup python3 /home/ubuntu/mecharm_daemon.py </dev/null >>/home/ubuntu/daemon.log 2>&1 &"; sleep 8; ssh -i ~/.ssh/id_rsa_pi ubuntu@192.168.2.1 'tail -3 ~/daemon.log; ss -ltn | grep 5555'
[DAEMON 14:36:57] ✓ MyCobot 初期化完了
[DAEMON 14:36:57] startup_warmup angles=[1.14, 94.04, 9.05, -0.7, -104.5, -29.53]
[DAEMON 14:36:57] ポート 5555 で待ち受け中...
LISTEN0      1                                 0.0.0.0:5555        0.0.0.0:*    
(base) shimazueiichi@shimadzueiichinoMacBook-Pro ~ % cd ~/r2r2r-scripts/dynamic_tracking_limits/drag_teaching
python3 record_teach_demo.py measure --log 359
[RTD   ] 到達許容差は本線 run_pick_place.py の stage 値を使います（区間ごと。一律 8.0° は 2026-10-19 にやめた）:
[RTD   ]   HOME                       2.5°  ← rpp.TOL_HOME（stage1_to_home / HOME 復帰）
[RTD   ]   APPROACH_PICK              2.0°  ← rpp.TOL_APPROACH（approach 系）
[RTD   ]   PICK                       3.0°  ← rpp.TOL_PICK_PLACE（stage4_pick）
[RTD   ]   APPROACH_PICK (lift)       3.0°  ← rpp.TOL_LIFT_BACK（lift の残差 2.19° を吸収）
[RTD   ]   APPROACH_PLACE             3.0°  ← rpp.TOL_APPROACH_PLACE（stage7）
[RTD   ]   PLACE                      3.0°  ← rpp.TOL_PICK_PLACE（stage8_place）
[RTD   ]   APPROACH_PLACE (retreat)   3.0°  ← rpp.TOL_LIFT_BACK（stage10_lift_back）
[RTD   ] 到達を待つ最大時間 = clamp(2.0 + max|Δ|/20*3.0, 8.0, 30.0) 秒（本線と同じ wr._compute_arrival_timeout）
[RTD   ] measure: 上カメラで検出します（repeat=5 interval=0.3s）
[CAM] 接続中カメラ一覧:
  index=0  name=FaceTime HDカメラ
  index=1  name=Iriun Camera
  index=2  name=‎iPhone14 Pro MAXのカメラ
[CAM] 上カメラ(iPhone)  index=2
[CAM] 横カメラ(Iriun)   index=1
[DETECT] resolved top index: 2
[Mac] マット四隅検出中... (10フレーム)
[Mac] ✓ マット四隅検出: 10/10 フレーム成功
[Mac] ✓ 動的homography計算完了
[Mac] ✓ マット範囲: X=[270, 1717] Y=[0, 949]
[06f] TEMPLATES_DIR overridden to: /Users/shimazueiichi/r2r2r-scripts/dynamic_tracking_limits/place/templates
[06f] ROTATION_ANGLES_DEG overridden to: [0, 15, 30, 45, 60, 75]
[06f] SCALES overridden to: [0.85, 1.0, 1.15]
[テンプレ] loading white box templates from: /Users/shimazueiichi/r2r2r-scripts/dynamic_tracking_limits/place/templates
[テンプレ] glob '/Users/shimazueiichi/r2r2r-scripts/dynamic_tracking_limits/place/templates/*.png' → 8 file(s)
[テンプレ]   - white_box_20260520_163829_004.png
[テンプレ]   - white_box_20260520_163838_005.png
[テンプレ]   - white_box_20260520_163846_006.png
[テンプレ]   - white_box_20260520_163905_009.png
[テンプレ]   - white_box_20260520_163912_010.png
[テンプレ]   - white_box_20260520_163918_011.png
[テンプレ]   - white_box_20260520_163923_012.png
[テンプレ]   - white_box_20260520_163929_013.png
[テンプレ] 計 8 枚 (day165=8, auto=0)
[06f] WARN: 輪郭中心とテンプレ中心の距離が閾値超 |Δ|=101.2px > 60px → 輪郭捨てて fallback
[06f] DETECT: center=(1488,558) source=template_fallback score=0.654 angle=0° scale=1.15 size=(226x211) template=white_box_20260520_163838_005.png (eval 6.62s)
[DETECT][1/5] box Unity=(-0.214,+0.178) score=0.6539450883865356
  赤ブロック pixel=(698, 640) → Unity=(0.1276, 0.2168)
[DETECT][1/5] block Unity=(+0.128,+0.217) score=null
[06f] WARN: 輪郭中心とテンプレ中心の距離が閾値超 |Δ|=101.2px > 60px → 輪郭捨てて fallback
[06f] DETECT: center=(1488,558) source=template_fallback score=0.654 angle=0° scale=1.15 size=(226x211) template=white_box_20260520_163838_005.png (eval 6.65s)
[DETECT][2/5] box Unity=(-0.214,+0.178) score=0.6543152928352356
  赤ブロック pixel=(698, 640) → Unity=(0.1276, 0.2168)
[DETECT][2/5] block Unity=(+0.128,+0.217) score=null
[06f] WARN: 輪郭中心とテンプレ中心の距離が閾値超 |Δ|=103.6px > 60px → 輪郭捨てて fallback
[06f] DETECT: center=(1489,556) source=template_fallback score=0.654 angle=0° scale=0.85 size=(158x158) template=white_box_20260520_163923_012.png (eval 6.66s)
[DETECT][3/5] box Unity=(-0.214,+0.177) score=0.6544483304023743
  赤ブロック pixel=(697, 640) → Unity=(0.1281, 0.2168)
[DETECT][3/5] block Unity=(+0.128,+0.217) score=null
[06f] WARN: 輪郭中心とテンプレ中心の距離が閾値超 |Δ|=101.2px > 60px → 輪郭捨てて fallback
[06f] DETECT: center=(1488,558) source=template_fallback score=0.654 angle=0° scale=1.15 size=(226x211) template=white_box_20260520_163838_005.png (eval 6.67s)
[DETECT][4/5] box Unity=(-0.214,+0.178) score=0.6536625623703003
  赤ブロック pixel=(698, 640) → Unity=(0.1276, 0.2168)
[DETECT][4/5] block Unity=(+0.128,+0.217) score=null
[06f] WARN: 輪郭中心とテンプレ中心の距離が閾値超 |Δ|=104.3px > 60px → 輪郭捨てて fallback
[06f] DETECT: center=(1489,555) source=template_fallback score=0.654 angle=0° scale=0.85 size=(158x158) template=white_box_20260520_163923_012.png (eval 6.91s)
[DETECT][5/5] box Unity=(-0.214,+0.177) score=0.6535261869430542
  赤ブロック pixel=(698, 640) → Unity=(0.1276, 0.2168)
[DETECT][5/5] block Unity=(+0.128,+0.217) score=null
[RTD   ] measure: block = (+127.6, +216.8) mm
[RTD   ] measure: box   = (-213.6, +178.2) mm  score=0.6539450883865356
[RTD   ] 確認画像: /Volumes/KIOXIA/r2r2r-data/mecharm_calibration/teach_poses_LOG359/measure_20261022_164406.jpg
[RTD   ] homography のもとになった四隅と、測り直した四隅の差: 最大 1.0px（上限 15.0px・やり直し 1 回）
[RTD   ] ブロックのばらつき: 0.0px = 0.00mm（5 枚・上限 4.0mm）
[RTD   ] 元の検出と測り直しの差: 0.00mm（上限 3.0mm）
[RTD   ] 保存しました: /Volumes/KIOXIA/r2r2r-data/mecharm_calibration/teach_poses_LOG359/measure_20261022_164406.json
[RTD   ] 次は Pi で教示 → daemon 起動 → recorder.py --top --no-side 常駐 → run --teach <file> --execute
```

```
(base) shimazueiichi@shimadzueiichinoMacBook-Pro drag_teaching % python3 record_teach_demo.py run --teach drag_v2_20221013_231249.json
[RTD   ] 到達許容差は本線 run_pick_place.py の stage 値を使います（区間ごと。一律 8.0° は 2026-10-19 にやめた）:
[RTD   ]   HOME                       2.5°  ← rpp.TOL_HOME（stage1_to_home / HOME 復帰）
[RTD   ]   APPROACH_PICK              2.0°  ← rpp.TOL_APPROACH（approach 系）
[RTD   ]   PICK                       3.0°  ← rpp.TOL_PICK_PLACE（stage4_pick）
[RTD   ]   APPROACH_PICK (lift)       3.0°  ← rpp.TOL_LIFT_BACK（lift の残差 2.19° を吸収）
[RTD   ]   APPROACH_PLACE             3.0°  ← rpp.TOL_APPROACH_PLACE（stage7）
[RTD   ]   PLACE                      3.0°  ← rpp.TOL_PICK_PLACE（stage8_place）
[RTD   ]   APPROACH_PLACE (retreat)   3.0°  ← rpp.TOL_LIFT_BACK（stage10_lift_back）
[RTD   ] 到達を待つ最大時間 = clamp(2.0 + max|Δ|/20*3.0, 8.0, 30.0) 秒（本線と同じ wr._compute_arrival_timeout）
[RTD   ] モード: ドライラン（アームに何も送りません）
[RTD   ] Pi から教えた記録を取得します: ubuntu@192.168.2.1:r2r2r-scripts/dynamic_tracking_limits/drag_teaching/drag_v2_20221013_231249.json
[RTD   ] 取得しました → /var/folders/5w/2q2mc64n6yv63gfh31h34w6h0000gn/T/record_teach_demo_vu3bxjcs/drag_v2_20221013_231249.json
[RTD   ] 入力ファイル: drag_v2_20221013_231249.json
[RTD   ] 抽出ウェイポイント:
  APPROACH_PICK  <- phase APPROACH_PICK argmax_idx=146 (start=146 end=194, gap=12.04°)
                    angles = [ -28.12,  +57.21,  +19.86,   -3.60,  -71.80,  -27.50]
  PICK           <- gripper close mark idx=214（PICK phase 範囲内）
                    angles = [ -27.68,  +63.10,  +13.27,   -8.26,  -59.76,  -27.33]
  APPROACH_PLACE <- phase APPROACH_PLACE argmax_idx=286 (start=286 end=321, gap=20.83°)
                    angles = [ +41.04,  +42.36,   +1.66,   +2.54,  -49.39,  -31.90]
  PLACE          <- gripper open mark idx=345（PLACE phase 範囲内）
                    angles = [ +40.69,  +61.78,   +1.14,   +4.13,  -70.22,  -31.28]
[RTD   ] JOINT_LIMITS 一括検証 OK（全 endpoint + HOME）
[RTD   ] 姿勢検査 OK（全 137 姿勢が 有限値 + JOINT_LIMITS + J4_SAFE [-90.0, +60.0] 内）
[RTD   ] j4 の余裕は最小 18.20°（しきい値 3.0° 以上）
==============================================================================
[RTD   ] 実行プラン（daemon 経由・区間ごとに 1 回送信 → 到達待ち）
==============================================================================
  [STEP  1] MOVE → HOME (single send + settle)  speed=20
            current = 未取得（ドライラン・daemon に接続していない）
            to HOME = [  +0.00,   +0.00,   +0.00,   +0.00,   +0.00,  -30.00]
  [STEP  2] GRIPPER OPEN  daemon_set_gripper(0, 50, wait=0) ×1 回（daemon 事前 2.0s + 事後 2.0s + 待ち 2.0s）= 計 6.0s
            開いたかは確認しません（gv を使わず・開始前の y/n も無し。判定は終了後の y/n と動画）
  [STEP  3] MOVE → APPROACH_PICK  segment HOME → APPROACH_PICK  tol=2.0°  [rpp.TOL_APPROACH（approach 系）]
            from    = [  +0.00,   +0.00,   +0.00,   +0.00,   +0.00,  -30.00]
            to      = [ -28.12,  +57.21,  +19.86,   -3.60,  -71.80,  -27.50]
            max |Δ| = 71.80°  1 回送信 speed=20  (~ 3.6s @ 20°/s 目安・到達待ち 最大 12.8s)
  [STEP  4] MOVE → PICK  segment APPROACH_PICK → PICK  [critical]  tol=3.0°  [rpp.TOL_PICK_PLACE（stage4_pick）]
            from    = [ -28.12,  +57.21,  +19.86,   -3.60,  -71.80,  -27.50]
            to      = [ -27.68,  +63.10,  +13.27,   -8.26,  -59.76,  -27.33]
            max |Δ| = 12.04°  1 回送信 speed=20  (~ 0.6s @ 20°/s 目安・到達待ち 最大 8.0s)
  [STEP  5] GRIPPER CLOSE  daemon_set_gripper_value(20, 50) + sleep(2.0s)
  [STEP  6] MOVE → APPROACH_PICK (lift)  segment PICK → APPROACH_PICK (lift)  tol=3.0°  [rpp.TOL_LIFT_BACK（lift の残差 2.19° を吸収）]
            from    = [ -27.68,  +63.10,  +13.27,   -8.26,  -59.76,  -27.33]
            to      = [ -28.12,  +57.21,  +19.86,   -3.60,  -71.80,  -27.50]
            max |Δ| = 12.04°  1 回送信 speed=20  (~ 0.6s @ 20°/s 目安・到達待ち 最大 8.0s)
  [STEP  7] MOVE → APPROACH_PLACE  segment APPROACH_PICK → APPROACH_PLACE  tol=3.0°  [rpp.TOL_APPROACH_PLACE（stage7）]
            from    = [ -28.12,  +57.21,  +19.86,   -3.60,  -71.80,  -27.50]
            to      = [ +41.04,  +42.36,   +1.66,   +2.54,  -49.39,  -31.90]
            max |Δ| = 69.16°  1 回送信 speed=20  (~ 3.5s @ 20°/s 目安・到達待ち 最大 12.4s)
  [STEP  8] MOVE → PLACE  segment APPROACH_PLACE → PLACE  [critical]  tol=3.0°  [rpp.TOL_PICK_PLACE（stage8_place）]
            from    = [ +41.04,  +42.36,   +1.66,   +2.54,  -49.39,  -31.90]
            to      = [ +40.69,  +61.78,   +1.14,   +4.13,  -70.22,  -31.28]
            max |Δ| = 20.83°  1 回送信 speed=20  (~ 1.0s @ 20°/s 目安・到達待ち 最大 8.0s)
  [STEP  9] GRIPPER OPEN  daemon_set_gripper(0, 50, wait=0) ×1 回（daemon 事前 2.0s + 事後 2.0s + 待ち 2.0s）= 計 6.0s
            開いたかは確認しません（gv を使わず・開始前の y/n も無し。判定は終了後の y/n と動画）
  [STEP 10] MOVE → APPROACH_PLACE (retreat)  segment PLACE → APPROACH_PLACE (retreat)  tol=3.0°  [rpp.TOL_LIFT_BACK（stage10_lift_back）]
            from    = [ +40.69,  +61.78,   +1.14,   +4.13,  -70.22,  -31.28]
            to      = [ +41.04,  +42.36,   +1.66,   +2.54,  -49.39,  -31.90]
            max |Δ| = 20.83°  1 回送信 speed=20  (~ 1.0s @ 20°/s 目安・到達待ち 最大 8.0s)
  [STEP 11] MOVE → HOME  segment APPROACH_PLACE → HOME  tol=2.5°  [rpp.TOL_HOME（stage1_to_home / HOME 復帰）]
            from    = [ +41.04,  +42.36,   +1.66,   +2.54,  -49.39,  -31.90]
            to      = [  +0.00,   +0.00,   +0.00,   +0.00,   +0.00,  -30.00]
            max |Δ| = 49.39°  1 回送信 speed=20  (~ 2.5s @ 20°/s 目安・到達待ち 最大 9.4s)
==============================================================================
[RTD   ] 送信 = 8 回（STEP 1 + move 7 区間）, 想定所要時間 ≈ 29.8s（最悪 73.0s）
[RTD   ]   内訳: 先頭 settle 3.0s + 移動 12.8s（max|Δ| 合計 256.1° @ 20°/s 目安） + gripper 14.0s
[RTD   ]   到達確認: 許容は区間ごと（本線 run_pick_place.py の stage 値）/ 最大は clamp(2.0 + max|Δ|/20*3.0, 8.0, 30.0) 秒
[RTD   ]   届かないとき: 送信前から 1.0° 未満しか動いていなければ 5.0s 待って**同じ目標へ 1 回だけ**再送（本線と同じ）。それでも届かなければ ABORT（HOME へ自動で戻らない）
[RTD   ]   実測 j4: [-90.0, +60.0] の外は WARN / [-98.0, +68.0] の外は ABORT
==============================================================================
[RTD   ] measure: /Volumes/KIOXIA/r2r2r-data/mecharm_calibration/teach_poses_LOG359/measure_20261022_164406.json
[RTD   ]   measured_at = 2026-10-22T16:44:08.337908  block = (+127.6, +216.8) mm  box = (-213.6, +178.2) mm
[RTD   ] 再生直前: 上カメラでマット四隅とブロック画素を確認します
[RTD   ] 再生直前: block = (+127.2, +216.8) mm（measure の homography で換算）
[RTD   ] 確認画像: /Volumes/KIOXIA/r2r2r-data/mecharm_calibration/teach_poses_LOG359/prerun_20261022_164432.jpg
[RTD   ] ブロック位置の照合 OK（画素の差 1.0px <= 許容 10.6px = 5.0mm / mm 換算の差 0.43mm）
[RTD   ] マット四隅のずれ 最大 4.5px（上限 15.0px・やり直し 1 回）
[RTD   ] ドライランなので、ここで終了します（アームには何も送っていません）
[RTD   ] Pi 版と比べる点: 抽出ウェイポイント 4 姿勢と各区間の max|Δ| は同じ。送り方は単発（Pi 版は 0.1s 補間ストリーミング）なので n_steps / ticks は比較対象外。送信 8 回 / 想定所要 ≈ 29.8s
(base) shimazueiichi@shimadzueiichinoMacBook-Pro drag_teaching % 
```

実機で再生した回です（16:46）。

```
(base) shimazueiichi@shimadzueiichinoMacBook-Pro drag_teaching % python3 record_teach_demo.py run --teach drag_v2_20221013_231249.json --execute --no-record
[RTD   ] 到達許容差は本線 run_pick_place.py の stage 値を使います（区間ごと。一律 8.0° は 2026-10-19 にやめた）:
[RTD   ]   HOME                       2.5°  ← rpp.TOL_HOME（stage1_to_home / HOME 復帰）
[RTD   ]   APPROACH_PICK              2.0°  ← rpp.TOL_APPROACH（approach 系）
[RTD   ]   PICK                       3.0°  ← rpp.TOL_PICK_PLACE（stage4_pick）
[RTD   ]   APPROACH_PICK (lift)       3.0°  ← rpp.TOL_LIFT_BACK（lift の残差 2.19° を吸収）
[RTD   ]   APPROACH_PLACE             3.0°  ← rpp.TOL_APPROACH_PLACE（stage7）
[RTD   ]   PLACE                      3.0°  ← rpp.TOL_PICK_PLACE（stage8_place）
[RTD   ]   APPROACH_PLACE (retreat)   3.0°  ← rpp.TOL_LIFT_BACK（stage10_lift_back）
[RTD   ] 到達を待つ最大時間 = clamp(2.0 + max|Δ|/20*3.0, 8.0, 30.0) 秒（本線と同じ wr._compute_arrival_timeout）
[RTD   ] モード: EXECUTE（実機）  記録: OFF (--no-record)
[RTD   ] Pi から教えた記録を取得します: ubuntu@192.168.2.1:r2r2r-scripts/dynamic_tracking_limits/drag_teaching/drag_v2_20221013_231249.json
[RTD   ] 取得しました → /var/folders/5w/2q2mc64n6yv63gfh31h34w6h0000gn/T/record_teach_demo_fu0xc9ff/drag_v2_20221013_231249.json
[RTD   ] 入力ファイル: drag_v2_20221013_231249.json
[RTD   ] 抽出ウェイポイント:
  APPROACH_PICK  <- phase APPROACH_PICK argmax_idx=146 (start=146 end=194, gap=12.04°)
                    angles = [ -28.12,  +57.21,  +19.86,   -3.60,  -71.80,  -27.50]
  PICK           <- gripper close mark idx=214（PICK phase 範囲内）
                    angles = [ -27.68,  +63.10,  +13.27,   -8.26,  -59.76,  -27.33]
  APPROACH_PLACE <- phase APPROACH_PLACE argmax_idx=286 (start=286 end=321, gap=20.83°)
                    angles = [ +41.04,  +42.36,   +1.66,   +2.54,  -49.39,  -31.90]
  PLACE          <- gripper open mark idx=345（PLACE phase 範囲内）
                    angles = [ +40.69,  +61.78,   +1.14,   +4.13,  -70.22,  -31.28]
[RTD   ] JOINT_LIMITS 一括検証 OK（全 endpoint + HOME）
[RTD   ] 姿勢検査 OK（全 137 姿勢が 有限値 + JOINT_LIMITS + J4_SAFE [-90.0, +60.0] 内）
[RTD   ] j4 の余裕は最小 18.20°（しきい値 3.0° 以上）
[RTD   ] 現在姿勢を daemon から取得します
[RTD   ] 現在姿勢 = [  +0.17,   +1.31,   +2.10,   +0.26,   -0.26,  -30.23]
==============================================================================
[RTD   ] 実行プラン（daemon 経由・区間ごとに 1 回送信 → 到達待ち）
==============================================================================
  [STEP  1] MOVE → HOME (single send + settle)  speed=20
            current = [  +0.17,   +1.31,   +2.10,   +0.26,   -0.26,  -30.23]
            to HOME = [  +0.00,   +0.00,   +0.00,   +0.00,   +0.00,  -30.00]
            max |Δ| = 2.10°  (settle 3.0s)
  [STEP  2] GRIPPER OPEN  daemon_set_gripper(0, 50, wait=0) ×1 回（daemon 事前 2.0s + 事後 2.0s + 待ち 2.0s）= 計 6.0s
            開いたかは確認しません（gv を使わず・開始前の y/n も無し。判定は終了後の y/n と動画）
  [STEP  3] MOVE → APPROACH_PICK  segment HOME → APPROACH_PICK  tol=2.0°  [rpp.TOL_APPROACH（approach 系）]
            from    = [  +0.00,   +0.00,   +0.00,   +0.00,   +0.00,  -30.00]
            to      = [ -28.12,  +57.21,  +19.86,   -3.60,  -71.80,  -27.50]
            max |Δ| = 71.80°  1 回送信 speed=20  (~ 3.6s @ 20°/s 目安・到達待ち 最大 12.8s)
  [STEP  4] MOVE → PICK  segment APPROACH_PICK → PICK  [critical]  tol=3.0°  [rpp.TOL_PICK_PLACE（stage4_pick）]
            from    = [ -28.12,  +57.21,  +19.86,   -3.60,  -71.80,  -27.50]
            to      = [ -27.68,  +63.10,  +13.27,   -8.26,  -59.76,  -27.33]
            max |Δ| = 12.04°  1 回送信 speed=20  (~ 0.6s @ 20°/s 目安・到達待ち 最大 8.0s)
  [STEP  5] GRIPPER CLOSE  daemon_set_gripper_value(20, 50) + sleep(2.0s)
  [STEP  6] MOVE → APPROACH_PICK (lift)  segment PICK → APPROACH_PICK (lift)  tol=3.0°  [rpp.TOL_LIFT_BACK（lift の残差 2.19° を吸収）]
            from    = [ -27.68,  +63.10,  +13.27,   -8.26,  -59.76,  -27.33]
            to      = [ -28.12,  +57.21,  +19.86,   -3.60,  -71.80,  -27.50]
            max |Δ| = 12.04°  1 回送信 speed=20  (~ 0.6s @ 20°/s 目安・到達待ち 最大 8.0s)
  [STEP  7] MOVE → APPROACH_PLACE  segment APPROACH_PICK → APPROACH_PLACE  tol=3.0°  [rpp.TOL_APPROACH_PLACE（stage7）]
            from    = [ -28.12,  +57.21,  +19.86,   -3.60,  -71.80,  -27.50]
            to      = [ +41.04,  +42.36,   +1.66,   +2.54,  -49.39,  -31.90]
            max |Δ| = 69.16°  1 回送信 speed=20  (~ 3.5s @ 20°/s 目安・到達待ち 最大 12.4s)
  [STEP  8] MOVE → PLACE  segment APPROACH_PLACE → PLACE  [critical]  tol=3.0°  [rpp.TOL_PICK_PLACE（stage8_place）]
            from    = [ +41.04,  +42.36,   +1.66,   +2.54,  -49.39,  -31.90]
            to      = [ +40.69,  +61.78,   +1.14,   +4.13,  -70.22,  -31.28]
            max |Δ| = 20.83°  1 回送信 speed=20  (~ 1.0s @ 20°/s 目安・到達待ち 最大 8.0s)
  [STEP  9] GRIPPER OPEN  daemon_set_gripper(0, 50, wait=0) ×1 回（daemon 事前 2.0s + 事後 2.0s + 待ち 2.0s）= 計 6.0s
            開いたかは確認しません（gv を使わず・開始前の y/n も無し。判定は終了後の y/n と動画）
  [STEP 10] MOVE → APPROACH_PLACE (retreat)  segment PLACE → APPROACH_PLACE (retreat)  tol=3.0°  [rpp.TOL_LIFT_BACK（stage10_lift_back）]
            from    = [ +40.69,  +61.78,   +1.14,   +4.13,  -70.22,  -31.28]
            to      = [ +41.04,  +42.36,   +1.66,   +2.54,  -49.39,  -31.90]
            max |Δ| = 20.83°  1 回送信 speed=20  (~ 1.0s @ 20°/s 目安・到達待ち 最大 8.0s)
  [STEP 11] MOVE → HOME  segment APPROACH_PLACE → HOME  tol=2.5°  [rpp.TOL_HOME（stage1_to_home / HOME 復帰）]
            from    = [ +41.04,  +42.36,   +1.66,   +2.54,  -49.39,  -31.90]
            to      = [  +0.00,   +0.00,   +0.00,   +0.00,   +0.00,  -30.00]
            max |Δ| = 49.39°  1 回送信 speed=20  (~ 2.5s @ 20°/s 目安・到達待ち 最大 9.4s)
==============================================================================
[RTD   ] 送信 = 8 回（STEP 1 + move 7 区間）, 想定所要時間 ≈ 29.8s（最悪 73.0s）
[RTD   ]   内訳: 先頭 settle 3.0s + 移動 12.8s（max|Δ| 合計 256.1° @ 20°/s 目安） + gripper 14.0s
[RTD   ]   到達確認: 許容は区間ごと（本線 run_pick_place.py の stage 値）/ 最大は clamp(2.0 + max|Δ|/20*3.0, 8.0, 30.0) 秒
[RTD   ]   届かないとき: 送信前から 1.0° 未満しか動いていなければ 5.0s 待って**同じ目標へ 1 回だけ**再送（本線と同じ）。それでも届かなければ ABORT（HOME へ自動で戻らない）
[RTD   ]   実測 j4: [-90.0, +60.0] の外は WARN / [-98.0, +68.0] の外は ABORT
==============================================================================
[RTD   ] measure: /Volumes/KIOXIA/r2r2r-data/mecharm_calibration/teach_poses_LOG359/measure_20261022_164406.json
[RTD   ]   measured_at = 2026-10-22T16:44:08.337908  block = (+127.6, +216.8) mm  box = (-213.6, +178.2) mm
[RTD   ] 再生直前: 上カメラでマット四隅とブロック画素を確認します
[RTD   ] 再生直前: block = (+134.5, +221.9) mm（measure の homography で換算）
[RTD   ] 確認画像: /Volumes/KIOXIA/r2r2r-data/mecharm_calibration/teach_poses_LOG359/prerun_20261022_164609.jpg
[RTD   ] [WARN] ブロックが measure 時から動いています（止めません・項目8）: ブロックが measure 時から 19.4px（≒8.6mm）動いています（許容 10.6px = 5.0mm）。ブロックを戻すか measure をやり直してください
[RTD   ] [WARN]   画素の差 19.4px（許容 10.6px = 5.0mm）/ mm 換算の差 8.60mm
[RTD   ] [WARN]   つかみ損ねる可能性があります。気になるなら Enter の前に measure を取り直してください
[RTD   ] [SAFETY] 再生中はグリッパーが実機で開閉します。爪に指を挟まないこと。
[RTD   ] [SAFETY] 止めるときはアームの電源を切ること。Ctrl-C は新しい送信をやめるだけで、進行中の移動は止まりません。
[RTD   ] [SAFETY] 開いたかの自動確認はしません（gv は使わない）。STEP 2 で open を送ってから PICK へ降ります。
[RTD   ] 周囲に手・物が無いか確認してください。OK なら Enter で開始

[RTD   ] 試行フォルダ: /Volumes/KIOXIA/r2r2r-data/runs/run_pick_place/run_0001_20261022_164615
[RTD   ] 教えた記録のコピー: /Volumes/KIOXIA/r2r2r-data/runs/run_pick_place/run_0001_20261022_164615/teach/drag_v2_20221013_231249.json
  [WARN] fresh_mode切替不可: daemon error: set_fresh_mode is not available in this pymycobot environment
[RTD   ] daemon_set_fresh_mode(1)（最新コマンド優先・本線 run_pick_place.py L3976 と同じ。647 試行の実績はこの状態）
[STEP  1] MOVE → HOME  daemon_send_angles(HOME, 20)
[STEP  1] 到達待ち 許容 2.5°[TOL_HOME（stage1_to_home / HOME 復帰）] / 最大 8.0s
[RTD   ] 先頭移動: 送信直前の実測で max|Δ| = 2.10° / 到達待ち 最大 8.0s
[STEP  1] 3.0s 待ちます（settle）
[RTD   ] arrival OK (current → HOME, max|Δ|=2.10° <= tol 2.5°)
[STEP  2] GRIPPER OPEN → daemon_set_gripper(0, 50, wait=0)
[RTD   ] 静止確認 OK（step2_open: 連続 3 回・連続差 最大 0.00° <= 1.0°）
  [Pi] GRIPPER: OPEN result= -1
[RTD   ] gripper open (1/1 回目) の daemon 往復 = 3.559s
[STEP  2] open 後 2.0s 待ちます（本線の daemon wait=2 相当・読み取りなし）
[STEP  2] gripper dwell 2.0s（読み取りなし）
[STEP  3] MOVE → APPROACH_PICK  segment HOME → APPROACH_PICK  (1 回送信 speed=20 → 到達待ち 許容 2.0°[TOL_APPROACH（approach 系）] / 最大 12.8s)
[RTD   ] 送信 OK（daemon 往復 2.559s）
[RTD   ] arrival OK (HOME → APPROACH_PICK, max|Δ|=1.32° <= tol 2.0°)
[STEP  4] MOVE → PICK  segment APPROACH_PICK → PICK  (1 回送信 speed=20 → 到達待ち 許容 3.0°[TOL_PICK_PLACE（stage4_pick）] / 最大 8.0s)  [critical]
[RTD   ] 送信 OK（daemon 往復 2.565s）
[RTD   ] arrival OK (APPROACH_PICK → PICK, max|Δ|=1.32° <= tol 3.0°)
[STEP  5] GRIPPER CLOSE → daemon_set_gripper_value(20, 50)
[RTD   ] 静止確認 OK（step5_close: 連続 3 回・連続差 最大 0.09° <= 1.0°）
  [Pi] GRIPPER: VALUE=20 speed=50 result= -1
[RTD   ] gripper close (1/1 回目) の daemon 往復 = 1.553s
[STEP  5] gripper dwell 2.0s（読み取りなし）
[STEP  6] MOVE → APPROACH_PICK (lift)  segment PICK → APPROACH_PICK (lift)  (1 回送信 speed=20 → 到達待ち 許容 3.0°[TOL_LIFT_BACK（lift の残差 2.19° を吸収）] / 最大 8.0s)
[RTD   ] 送信 OK（daemon 往復 2.555s）
[RTD   ] arrival OK (PICK → APPROACH_PICK (lift), max|Δ|=2.64° <= tol 3.0°)
[STEP  7] MOVE → APPROACH_PLACE  segment APPROACH_PICK → APPROACH_PLACE  (1 回送信 speed=20 → 到達待ち 許容 3.0°[TOL_APPROACH_PLACE（stage7）] / 最大 12.4s)
[RTD   ] 送信 OK（daemon 往復 2.548s）
[RTD   ] arrival OK (APPROACH_PICK → APPROACH_PLACE, max|Δ|=2.55° <= tol 3.0°)
[STEP  8] MOVE → PLACE  segment APPROACH_PLACE → PLACE  (1 回送信 speed=20 → 到達待ち 許容 3.0°[TOL_PICK_PLACE（stage8_place）] / 最大 8.0s)  [critical]
[RTD   ] 送信 OK（daemon 往復 2.567s）
[RTD   ] arrival OK (APPROACH_PLACE → PLACE, max|Δ|=2.20° <= tol 3.0°)
[STEP  9] GRIPPER OPEN → daemon_set_gripper(0, 50, wait=0)
[RTD   ] 静止確認 OK（step9_open: 連続 3 回・連続差 最大 1.32° <= 1.0°）
  [Pi] GRIPPER: OPEN result= -1
[RTD   ] gripper open (1/1 回目) の daemon 往復 = 3.575s
[STEP  9] open 後 2.0s 待ちます（本線の daemon wait=2 相当・読み取りなし）
[STEP  9] gripper dwell 2.0s（読み取りなし）
[STEP 10] MOVE → APPROACH_PLACE (retreat)  segment PLACE → APPROACH_PLACE (retreat)  (1 回送信 speed=20 → 到達待ち 許容 3.0°[TOL_LIFT_BACK（stage10_lift_back）] / 最大 8.0s)
[RTD   ] 送信 OK（daemon 往復 2.553s）
[RTD   ] arrival OK (PLACE → APPROACH_PLACE (retreat), max|Δ|=2.11° <= tol 3.0°)
[STEP 11] MOVE → HOME  segment APPROACH_PLACE → HOME  (1 回送信 speed=20 → 到達待ち 許容 2.5°[TOL_HOME（stage1_to_home / HOME 復帰）] / 最大 9.4s)
[RTD   ] 送信 OK（daemon 往復 2.594s）
[RTD   ] arrival OK (APPROACH_PLACE → HOME, max|Δ|=1.93° <= tol 2.5°)
  [WARN] fresh_mode切替不可: daemon error: set_fresh_mode is not available in this pymycobot environment
[RTD   ] daemon_set_fresh_mode(0) 完了
[RTD   ] 実測角の読み取り: ok 40/40 回, 実効 0.86 Hz（目標 3.0 Hz 以上）
[RTD   ] [WARN] 実測角の読み取りが目標 3.0 Hz を下回りました（0.86 Hz）。学習データの state 密度が 19 本より薄くなります
[RTD   ] send_angles の daemon 往復 (7 回): 平均 2.563s / p50 2.559s / 最大 2.594s（timeout 6.0s）
[RTD   ] [WARN] 送信 1 回に 2.594s かかった回があります。daemon は送信後に角度を読み直すので、動き始めで読めないと伸びます（単発送信なので試行全体への影響は小さい）
[RTD   ] 区間の所要（送信→到達確認まで）(8 区間): 平均 3.09s / 最大 5.93s
==============================================================================
[RTD   ] 再生 完了
==============================================================================
[RTD   ] つかめたか (y/n) > y
[RTD   ] 箱に入ったか (y/n) > y
[RTD   ] 試行 JSON: /Volumes/KIOXIA/r2r2r-data/runs/run_pick_place/run_0001_20261022_164615/run_0001_20261022_164615.json
[LEDGER] append OK: /Volumes/KIOXIA/r2r2r-data/runs/pick_place_ledger_v3.csv (pick=yes place=yes recording_status=none)
[RTD   ] 次に進むには: python3 /Users/shimazueiichi/r2r2r-scripts/pi05/build_demo_episodes.py --run run_0001_20261022_164615 --dataset mecharm_redblock_box_teach_v1
(base) shimazueiichi@shimadzueiichinoMacBook-Pro drag_teaching % 
```

16:45〜17:06 に4回再生し、4回とも区間ごとの到達の判定は OK で、最後まで進みました。4回の区間ごとの動きを、試行の記録から並べたスクリプトと出力です。

```python
# お手本の再生 (record_teach_demo.py run --execute) 4 回の、区間ごとの記録を並べる (LOG361)
import os, json, glob
ROOT = os.environ.get("R2R2R_DATA", "/Volumes/KIOXIA/r2r2r-data"); os.chdir(ROOT)
for p in sorted(glob.glob("runs/run_pick_place/run_0001_20261022_1[67]*/run_*.json")):
    d = json.load(open(p))
    print(f"== {d['run_stem']}  result={d['result']}  始まり {d['started_at']}")
    for s in d.get("segments", []):
        if s["kind"] == "move":
            print(f"  STEP {s['step']:2d}  {s['from_name']:>15s} → {s['to_name']:<26s} max|Δ|={s['max_delta_deg']:6.2f}°  arrival_ok={s['arrival_ok']}")
        else:
            print(f"  STEP {s['step']:2d}  gripper {s['action']:<5s}  daemon 往復 {s['daemon_roundtrip_sec']:.2f}s")
    fa = d.get("final_actual")
    print("  最後の実測:", fa)
```

```
== run_0001_20261022_164511  result=completed  始まり 2026-10-22T16:45:11.399023
  STEP  1          current → HOME                       max|Δ|=  1.66°  arrival_ok=True
  STEP  2  gripper open   daemon 往復 3.57s
  STEP  3             HOME → APPROACH_PICK              max|Δ|= 71.80°  arrival_ok=True
  STEP  4    APPROACH_PICK → PICK                       max|Δ|= 12.04°  arrival_ok=True
  STEP  5  gripper close  daemon 往復 1.56s
  STEP  6             PICK → APPROACH_PICK (lift)       max|Δ|= 12.04°  arrival_ok=True
  STEP  7    APPROACH_PICK → APPROACH_PLACE             max|Δ|= 69.16°  arrival_ok=True
  STEP  8   APPROACH_PLACE → PLACE                      max|Δ|= 20.83°  arrival_ok=True
  STEP  9  gripper open   daemon 往復 3.57s
  STEP 10            PLACE → APPROACH_PLACE (retreat)   max|Δ|= 20.83°  arrival_ok=True
  STEP 11   APPROACH_PLACE → HOME                       max|Δ|= 49.39°  arrival_ok=True
  最後の実測: [0.26, 1.31, 2.1, 0.52, -1.05, -30.93]
== run_0001_20261022_164615  result=completed  始まり 2026-10-22T16:46:15.645051
  STEP  1          current → HOME                       max|Δ|=  2.10°  arrival_ok=True
  STEP  2  gripper open   daemon 往復 3.56s
  STEP  3             HOME → APPROACH_PICK              max|Δ|= 71.80°  arrival_ok=True
  STEP  4    APPROACH_PICK → PICK                       max|Δ|= 12.04°  arrival_ok=True
  STEP  5  gripper close  daemon 往復 1.55s
  STEP  6             PICK → APPROACH_PICK (lift)       max|Δ|= 12.04°  arrival_ok=True
  STEP  7    APPROACH_PICK → APPROACH_PLACE             max|Δ|= 69.16°  arrival_ok=True
  STEP  8   APPROACH_PLACE → PLACE                      max|Δ|= 20.83°  arrival_ok=True
  STEP  9  gripper open   daemon 往復 3.58s
  STEP 10            PLACE → APPROACH_PLACE (retreat)   max|Δ|= 20.83°  arrival_ok=True
  STEP 11   APPROACH_PLACE → HOME                       max|Δ|= 49.39°  arrival_ok=True
  最後の実測: [0.08, 1.4, 1.93, 0.52, -1.05, -30.93]
== run_0001_20261022_165216  result=completed  始まり 2026-10-22T16:52:16.862441
  STEP  1          current → HOME                       max|Δ|=  1.84°  arrival_ok=True
  STEP  2  gripper open   daemon 往復 3.56s
  STEP  3             HOME → APPROACH_PICK              max|Δ|= 71.80°  arrival_ok=True
  STEP  4    APPROACH_PICK → PICK                       max|Δ|= 12.04°  arrival_ok=True
  STEP  5  gripper close  daemon 往復 1.55s
  STEP  6             PICK → APPROACH_PICK (lift)       max|Δ|= 12.04°  arrival_ok=True
  STEP  7    APPROACH_PICK → APPROACH_PLACE             max|Δ|= 69.16°  arrival_ok=True
  STEP  8   APPROACH_PLACE → PLACE                      max|Δ|= 20.83°  arrival_ok=True
  STEP  9  gripper open   daemon 往復 3.56s
  STEP 10            PLACE → APPROACH_PLACE (retreat)   max|Δ|= 20.83°  arrival_ok=True
  STEP 11   APPROACH_PLACE → HOME                       max|Δ|= 49.39°  arrival_ok=True
  最後の実測: [0.43, 1.4, 2.1, 0.52, -1.05, -30.93]
== run_0001_20261022_170626  result=completed  始まり 2026-10-22T17:06:26.805636
  STEP  1          current → HOME                       max|Δ|=  2.10°  arrival_ok=True
  STEP  2  gripper open   daemon 往復 3.57s
  STEP  3             HOME → APPROACH_PICK              max|Δ|= 71.80°  arrival_ok=True
  STEP  4    APPROACH_PICK → PICK                       max|Δ|= 12.04°  arrival_ok=True
  STEP  5  gripper close  daemon 往復 1.56s
  STEP  6             PICK → APPROACH_PICK (lift)       max|Δ|= 12.04°  arrival_ok=True
  STEP  7    APPROACH_PICK → APPROACH_PLACE             max|Δ|= 69.16°  arrival_ok=True
  STEP  8   APPROACH_PLACE → PLACE                      max|Δ|= 20.83°  arrival_ok=True
  STEP  9  gripper open   daemon 往復 3.57s
  STEP 10            PLACE → APPROACH_PLACE (retreat)   max|Δ|= 20.83°  arrival_ok=True
  STEP 11   APPROACH_PLACE → HOME                       max|Δ|= 49.39°  arrival_ok=True
  最後の実測: [0.08, 1.49, 2.1, 0.52, -1.14, -31.02]
```

【画像】LOG361_06_teach_replay_side.jpg お手本を再生した回を横から撮った動画のコマ。0:24 でブロックを持ち上げ、0:25〜0:27 で箱のふちより上を通って箱の上へ回り、0:33 で離している

【動画】LOG361_v2_teach_replay_side.mp4 お手本を再生した回を横から撮った動画（約44秒）

横から見ると、ブロックは箱のふちより十分高いところを通っています。お手本の高さに余裕がなかったわけではありません。再生では、つかむ区間（PICK）から持ち上げる区間（APPROACH_PICK (lift)）へ、決まった絶対の角度を目標に送ります。持ち上げでも肩は少し届かずに止まりますが、その不足は次の区間に持ち越されず、次の区間はまた決まった角度を目標にします。AI で動かすときとの違いはここでした。


## AI に渡す角度を、直前に送った目標にする --state-from-target を足した

AI に渡す「いまの角度」を、測った値ではなく、直前のチャンクで最後に送った目標にするオプションを足しました。グリッパーの値は今までどおり測った値です。目標と測った値の差が 6° を超えたら（腕がどこかに当たって止まっているときなど）、その回だけ測った値に戻します。安全の検査と移動量の制限は、今までどおり測った値を基準にしています。Claude Code の報告です。

```
--state-from-target を足して commit
  しました（483a82c、pi05/run_policy_client.py のみ個別指定）。

  変えた行
     
  ┌─────────┬────────────────────────────────────────────────────────────────┐
  │   行    │                              変更                              │
  ├─────────┼────────────────────────────────────────────────────────────────┤
  │ 25-28   │ docstring の安全策に 1 項目（state だけを目標にする／6°        │
  │         │ 超で実測に戻す）                                               │
  ├─────────┼────────────────────────────────────────────────────────────────┤
  │ 105-107 │ STATE_TARGET_MAX_GAP_DEG = 6.0 を追加                          │
  ├─────────┼────────────────────────────────────────────────────────────────┤
  │ 446     │ last_sent_target = None                                        │
  │         │ を初期化（直前のチャンクで最後に送った目標）                   │
  ├─────────┼────────────────────────────────────────────────────────────────┤
  │ 396-398 │ --state-from-target（既定 off）を追加                          │
  ├─────────┼────────────────────────────────────────────────────────────────┤
  │         │ モデルに渡す state の決定。measured_state を保持しつつ、on     │
  │ 531-549 │ かつ last_sent_target ありで差が 6°                            │
  │         │ 以内なら目標を渡す。超えたら [WARN] + 実測。[STATE ]           │
  │         │ 行でどちらを渡したかと最大差（関節名つき）を表示               │
  ├─────────┼────────────────────────────────────────────────────────────────┤
  │ 564-566 │ rec に state_source と measured_state を追加（state            │
  │         │ はモデルに渡したほう）                                         │
  ├─────────┼────────────────────────────────────────────────────────────────┤
  │ 598-601 │ 送信ブロックの先頭で last_sent_target = None（s                │
  │         │ で飛ばす・中断の経路で残さない）                               │
  ├─────────┼────────────────────────────────────────────────────────────────┤
  │ 620,    │ sent_any を追加（実際に送ったか）                              │
  │ 659     │                                                                │
  ├─────────┼────────────────────────────────────────────────────────────────┤
  │ 690-694 │ チャンクを送り終えたら last_sent_target =                      │
  │         │ 最後の中継点の目標（送っていなければ None）                    │
  └─────────┴────────────────────────────────────────────────────────────────┘

  apply_limits / check_send_safe / 中継点の実測からのかけ直し / plan_chunk /
  --via-stride / settle / h・q・s / グリッパー / _send_and_wait_arrival
  本体は未変更です。変えたのはモデルに渡す state だけです。

  確認結果（偽の daemon・アームは動かさず）

  偽の腕は「送ると j1 が目標より 2.5°
  高いところで止まる」、偽のモデルは「受け取った state の j1 から 6°
  持ち上げる予測を返す」。開始 j1 = 60.0°。

  1. off（既定）— 今までどおり実測

  モデルに渡した state の j1: +60.00, +56.50, +53.00
  送った目標 j1 → 実測 j1    : +54.00→+56.50, +50.50→+53.00, +47.00→+49.50
  state_source: measured, measured, measured
  3 チャンクで目標は 47.0 = 開始 −13°（−18° のはずが 2.5°×2
  ぶん積み重なって足りない）。

  2. on — 2 チャンク目以降は直前の目標

  [STATE ] 実測を渡す (直前に送った目標がない)
  [STATE ] 目標を渡す  目標と実測の最大差 2.50°（関節 j1）
  モデルに渡した state の j1: +60.00, +54.00, +48.00
  送った目標 j1 → 実測 j1    : +54.00→+56.50, +48.00→+50.50, +42.00→+44.50
  state_source: measured, target, target
  最後の目標は 42.0 = 開始 −18° ちょうど。不足は毎回 2.5°
  のままで積み重なりません。

  3. 差が 6° を超えたとき（2 チャンク目だけ 8° 足りない腕）

  [WARN  ] 目標と実測の差が 8.00° > 6° なので実測を渡します
  (腕がどこかに当たって止まっている可能性)
  [STATE ] 実測を渡す  目標と実測の最大差 8.00°（関節 j1）
  state_source: measured, target, measured
  止めずに次へ進みます。

  4. s で飛ばした次のチャンク（手動で Enter → s → Enter）

  state_source: measured, target, measured
  送った目標: 54.0, 50.5   ← s のチャンクは送っていない

  5. ドライラン — 送信 0 回、3 チャンクとも measured。

  --via-stride の 11 ケースも再実行して全部 OK のままです。

  実機では --state-from-target --settle-retries 0
  の組み合わせになると思います。--via-stride
```

コミットの説明文です。中継点を送る `--via-stride` も、このコミットで一緒に入っています。

```
commit 483a82ce6d8ac6a71569bbfba5a1cdbe0e9abd2c
Date:   Thu Oct 22 17:22:45 2026 +0900

モデルに渡す state を直前に送った目標にできるようにする (--state-from-target / LOG359)

LOG359: ブロックを持つと肩 j1 が毎チャンク 2.4〜2.6° 指令より低いところで止まる
(持つ前は約 1°). 同じ目標を送り直しても縮まらない (settle で確認済み). モデルは
実測の state から次を予測するので, この不足がチャンクごとに積み重わる. つかんだあとの
3 チャンクで, 予測した持ち上げ 約 20° に対して実際は 約 12° しか上がらず, ブロックが
箱の壁に当たった. お手本の再生 (record_teach_demo.py) は毎回 絶対の角度を目標に送るので
不足は 2〜3° のまま積み重ならず, 箱に入る (2026-10-22 の動画で確認).

- --state-from-target (既定 off = 今までどおり実測を渡す) を追加. on のとき, モデルに
  渡す state の 6 関節を「直前のチャンクで最後に送った目標」(中継点を使う場合は最後の
  中継点の目標) にする. グリッパーの値は今までどおり実測.
- 最初のチャンク / 直前のチャンクを送らなかった場合 (s で飛ばした・送信なし・中断・
  ドライラン) は実測を渡す.
- 送った目標と実測の差が どれかの関節で STATE_TARGET_MAX_GAP_DEG (6°) を超えていたら,
  そのチャンクは実測を渡して [WARN] を出す (腕がどこかに当たって止まっているときに
  目標だけが先へ進むのを防ぐ). 止めはしない.
- apply_limits / check_send_safe / 中継点の「実測からのかけ直し」は今までどおり実測が
  基準. 変えるのは **モデルに渡す state だけ**.
- 記録: log.jsonl のチャンクの行に state_source ("measured" / "target") と
  measured_state (実測) を追加. state はモデルに渡したほう. 画面にも [STATE] で
  どちらを渡したかと 目標と実測の最大差を 1 行出す.

変更なし: _send_and_wait_arrival 本体, HOME, SPEED, SEND_WAIT_SEC, J4_SAFE,
J1_SAFE_MAX, max_move の値, plan_chunk, --via-stride, settle, h / q / s, グリッパー.

偽の daemon で確認 (アームには送っていない. 5 ケースすべて期待どおり):
  off                 : 渡した state j1 60.00 → 56.50 → 53.00 / 送った目標 54.0 → 50.5 → 47.0
                        (1 チャンクごとに 2.5° の不足が積み重なる)
  on                  : 渡した state j1 60.00 → 54.00 → 48.00 / 送った目標 54.0 → 48.0 → 42.0
                        (開始 60° から 3 チャンクでちょうど -18°)
  差が 6° 超          : その回だけ実測に戻して [WARN] (state_source=measured)
  s で飛ばした次      : 実測に戻る
  ドライラン          : 送信 0 回・毎チャンク実測

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
```

偽の腕（送ると j1 が目標より 2.5° 高いところで止まる）での確認では、測った値を渡すと3チャンクで −18° のはずが −13° になり、目標を渡すと −18° ちょうどになっています。


## 18:16 の回で、π0.5 がブロックを初めて箱に入れた

夕方、Pod を借り直してサーバーを起動し、目標を渡すやり方（`--state-from-target`）と中継点（`--via-stride 3`）を合わせて動かしました。1回目（18:13）は、最初の問い合わせがコンパイルで約60秒かかり、途中で止めています。ターミナルに貼り付けた行がくずれたところも、そのまま載せています。

```
Last login: Thu Oct 22 09:18:22 on ttys008
(base) shimazueiichi@shimadzueiichinoMacBook-Pro ~ % python3 pi05/run_policy_client.py --raw-dir $RAW --steps-per-chunk 10 --via-stride 3 --settle-retries 0 --state-from-target --execute
python3: can't open file '/Users/shimazueiichi/pi05/run_policy_client.py': [Errno 2] No such file or directory
(base) shimazueiichi@shimadzueiichinoMacBook-Pro ~ % cd ~/r2r2r-scripts
RAW=/Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
python3 pi05/run_policy_client.py --raw-dir $RAW --steps-per-chunk 10 --via-stride 3 --settle-retries 0 --state-from-target --execute
[SAFE  ] 安全範囲 (学習 19 本 ±10°): j0[-72,+55]  j1[-9,+88]  j2[-46,+41]  j3[-18,+27]  j4[-90,+10]  j5[-51,-14]
[SAFE  ] 肩 j1 の上限は J1_SAFE_MAX=88° で切った (これを超える指令はアームが黙って捨てる / LOG352)  元データ: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
[MODE  ] EXECUTE  steps/chunk=10  max_move=20.0°  log=/Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_181339
[CAMERA] 写り方 dy=-5.2 dx=+0.2 response=0.551 → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[CAMERA] 基準: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes/run_0001_20261019_183454/frames/000000.jpg
[POLICY] 接続 ws://localhost:8000  metadata={}
[GRIP  ] 開始時のグリッパー開放は, 最初の目標が検査を通ってから行います (爪が閉じていたら手で開けておく)
[STATE ] 実測を渡す (直前に送った目標がない)
[000] 推論 59829ms  10ステップ先  Δ=-11.6 +19.8  +3.1  +2.4 -25.0  +0.4
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[GRIP  ] 開始時にグリッパーを開く
  [Pi] GRIPPER: OPEN result= -1
[SEND] pi05_chunk000_via02: send_angles (single) [  -2.70,   +5.66,   +2.69,   +0.84,   -5.76,  -30.12]  speed=20 wait=1.0s  (pre max|Δ|=5.50°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.00° (tol 3.0°)
       [VIA   ] step  2  Δ= -2.4  +4.2  +0.6  +0.6  -5.5  +0.1  着いた
[SEND] pi05_chunk000_via05: send_angles (single) [  -6.51,  +12.20,   +3.72,   +1.64,  -14.10,  -29.97]  speed=20 wait=1.0s  (pre max|Δ|=9.18°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.98° (tol 3.0°)
       [VIA   ] step  5  Δ= -3.7  +5.7  +0.0  +1.3  -9.2  +0.3  着いた
[SEND] pi05_chunk000_via08: send_angles (single) [ -10.62,  +18.97,   +4.86,   +2.38,  -22.54,  -29.82]  speed=20 wait=1.0s  (pre max|Δ|=9.19°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.98° (tol 3.0°)
       [VIA   ] step  8  Δ= -3.9  +5.8  +0.3  +1.4  -9.2  +0.3  着いた
[SEND] pi05_chunk000_via09: send_angles (single) [ -11.93,  +21.26,   +5.19,   +2.62,  -25.21,  -29.80]  speed=20 wait=1.0s  (pre max|Δ|=3.33°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.97° (tol 3.0°)
       [VIA   ] step  9  Δ= -1.6  +1.3  -0.3  +0.2  -3.3  +0.2  着いた
[STATE ] 目標を渡す  目標と実測の最大差 0.97°（関節 j1）
[001] 推論 642ms  10ステップ先  Δ=-12.9 +22.7  +3.8  +1.6 -30.1  +0.3
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk001_via02: send_angles (single) [ -16.38,  +28.04,   +6.64,   +3.06,  -33.96,  -29.76]  speed=20 wait=1.0s  (pre max|Δ|=8.74°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.05° (tol 3.0°)
       [VIA   ] step  2  Δ= -4.2  +5.8  +0.8  +0.8  -8.7  +0.1  着いた
[SEND] pi05_chunk001_via05: send_angles (single) [ -20.36,  +35.26,   +8.11,   +3.59,  -43.43,  -29.66]  speed=20 wait=1.0s  (pre max|Δ|=9.77°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.03° (tol 3.0°)
       [VIA   ] step  5  Δ= -4.2  +6.2  +0.9  -0.1  -9.8  +0.1  着いた
[SEND] pi05_chunk001_via08: send_angles (single) [ -24.02,  +42.54,   +9.39,   +3.78,  -52.59,  -29.61]  speed=20 wait=1.0s  (pre max|Δ|=9.53°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.05° (tol 3.0°)
       [VIA   ] step  8  Δ= -3.4  +6.2  +0.6  -0.2  -9.5  +0.2  着いた
[SEND] pi05_chunk001_via09: send_angles (single) [ -25.16,  +44.96,   +9.64,   +3.90,  -55.30,  -29.58]  speed=20 wait=1.0s  (pre max|Δ|=3.10°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.09° (tol 3.0°)
       [VIA   ] step  9  Δ= -1.3  +1.4  -0.5  -0.1  -3.1  +0.1  着いた
[STATE ] 目標を渡す  目標と実測の最大差 1.09°（関節 j1）
[002] 推論 464ms  10ステップ先  Δ=-11.3 +16.2  +3.0  -0.3 -21.5  +0.0
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk002_via02: send_angles (single) [ -29.70,  +51.65,  +10.98,   +3.64,  -64.69,  -29.60]  speed=20 wait=1.0s  (pre max|Δ|=9.32°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.90° (tol 3.0°)
       [VIA   ] step  2  Δ= -4.0  +5.6  +0.9  -0.8  -9.3  +0.1  着いた
[SEND] pi05_chunk002_via05: send_angles (single) [ -34.15,  +58.02,  +12.20,   +3.62,  -72.67,  -29.65]  speed=20 wait=1.0s  (pre max|Δ|=8.69°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.95° (tol 3.0°)
       [VIA   ] step  5  Δ= -4.9  +5.5  +0.8  -0.4  -8.7  -0.1  着いた
[SEND] pi05_chunk002_via08: send_angles (single) [ -36.77,  +62.03,  +13.19,   +3.98,  -76.70,  -29.67]  speed=20 wait=1.0s  (pre max|Δ|=4.63°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.07° (tol 3.0°)
       [VIA   ] step  8  Δ= -3.0  +3.1  +0.7  -0.1  -4.6  -0.1  着いた
[SEND] pi05_chunk002_via09: send_angles (single) [ -37.00,  +62.25,  +13.14,   +4.13,  -76.83,  -29.68]  speed=20 wait=1.0s  (pre max|Δ|=0.85°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.85° (tol 3.0°)
       [VIA   ] step  9  Δ= +0.1  -0.9  -0.3  +0.0  +0.2  -0.1  着いた
[STATE ] 目標を渡す  目標と実測の最大差 0.85°（関節 j1）
[003] 推論 563ms  10ステップ先  Δ= -1.2  +3.6  +0.4  -0.5  -4.2  -0.3
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk003_via02: send_angles (single) [ -38.00,  +64.32,  +14.31,   +4.10,  -80.10,  -29.72]  speed=20 wait=1.0s  (pre max|Δ|=3.11°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.89° (tol 3.0°)
       [VIA   ] step  2  Δ= -0.9  +1.2  +0.9  -0.0  -3.1  -0.2  着いた
       [VIA   ] step  5  Δ= +0.4  -0.3  +0.0  -0.2  -0.4  -0.2  送らず (0.5° 以下)
[SEND] pi05_chunk003_via08: send_angles (single) [ -38.23,  +66.06,  +14.15,   +3.72,  -81.11,  -29.77]  speed=20 wait=1.0s  (pre max|Δ|=0.85°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.00° (tol 3.0°)
       [VIA   ] step  8  Δ= +0.3  +0.8  -0.4  -0.5  -0.7  -0.2  着いた
[SEND] pi05_chunk003_via09: send_angles (single) [ -38.29,  +66.70,  +13.84,   +3.63,  -81.19,  -29.78]  speed=20 wait=1.0s  (pre max|Δ|=0.66°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.88° (tol 3.0°)
       [VIA   ] step  9  Δ= +0.2  -0.4  -0.7  -0.4  +0.0  -0.3  着いた
[STATE ] 目標を渡す  目標と実測の最大差 0.88°（関節 j1）
[004] 推論 3182ms  10ステップ先  Δ= +0.0  +5.2  -3.1  -1.7  -0.7  -0.5
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > h
[SEND] pi05_home: send_angles (single) [  +0.00,   +0.00,   +0.00,   +0.00,   +0.00,  -30.00]  speed=20 wait=1.0s  (pre max|Δ|=81.21°, post-send timeout 14.2s)
[SEND] arrival OK: max|Δ|=2.46° (tol 2.5°)
[DONE  ] 記録: /Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_181339
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % >....          
o 2] No such file or directory
(base) shimazueiichi@shimadzueiichinoMacBook-Pro ~ % cd ~/r2r2r-scripts
RAW=/Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
python3 pi05/run_policy_client.py --raw-dir $RAW --steps-per-chunk 10 --via-stride 3 --settle-retries 0 --state-from-target --execute
[SAFE  ] 安全範囲 (学習 19 本 ±10°): j0[-72,+55]  j1[-9,+88]  j2[-46,+41]  j3[-18,+27]  j4[-90,+10]  j5[-51,-14]
[SAFE  ] 肩 j1 の上限は J1_SAFE_MAX=88° で切った (これを超える指令はアームが黙って捨てる / LOG352)  元データ: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
[MODE  ] EXECUTE  steps/chunk=10  max_move=20.0°  log=/Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_181339
[CAMERA] 写り方 dy=-5.2 dx=+0.2 response=0.551 → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[CAMERA] 基準: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes/run_0001_20261019_183454/frames/000000.jpg
[POLICY] 接続 ws://localhost:8000  metadata={}
[GRIP  ] 開始時のグリッパー開放は, 最初の目標が検査を通ってから行います (爪が閉 じていたら手で開けておく)
[STATE ] 実測を渡す (直前に送った目標がない)


zsh: parse error near `shimazueiichi@shimad...'
```

2回目（18:16）です。

```
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % cd ~/r2r2r-scripts
RAW=/Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
python3 pi05/run_policy_client.py --raw-dir $RAW --steps-per-chunk 10 --via-stride 3 --settle-retries 0 --state-from-target --execute
[SAFE  ] 安全範囲 (学習 19 本 ±10°): j0[-72,+55]  j1[-9,+88]  j2[-46,+41]  j3[-18,+27]  j4[-90,+10]  j5[-51,-14]
[SAFE  ] 肩 j1 の上限は J1_SAFE_MAX=88° で切った (これを超える指令はアームが黙って捨てる / LOG352)  元データ: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
[MODE  ] EXECUTE  steps/chunk=10  max_move=20.0°  log=/Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_181602
[CAMERA] 写り方 dy=-5.5 dx=+0.3 response=0.533 → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[CAMERA] 基準: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes/run_0001_20261019_183454/frames/000000.jpg
[POLICY] 接続 ws://localhost:8000  metadata={}
[GRIP  ] 開始時のグリッパー開放は, 最初の目標が検査を通ってから行います (爪が閉じていたら手で開けておく)
[STATE ] 実測を渡す (直前に送った目標がない)
[000] 推論 1769ms  10ステップ先  Δ=-10.3 +21.0  +2.5  +2.8 -27.1  -0.1
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[GRIP  ] 開始時にグリッパーを開く
  [Pi] GRIPPER: OPEN result= -1
[SEND] pi05_chunk000_via02: send_angles (single) [  -2.41,   +5.85,   +2.67,   +0.61,   -6.26,  -29.48]  speed=20 wait=1.0s  (pre max|Δ|=6.00°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.69° (tol 3.0°)
       [VIA   ] step  2  Δ= -2.2  +4.4  +0.7  +0.5  -6.0  +0.1  着いた
[SEND] pi05_chunk000_via05: send_angles (single) [  -6.03,  +13.28,   +3.53,   +1.57,  -16.04,  -29.52]  speed=20 wait=1.0s  (pre max|Δ|=11.47°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.87° (tol 3.0°)
       [VIA   ] step  5  Δ= -3.7  +6.6  -0.2  +1.5 -11.5  +0.1  着いた
[SEND] pi05_chunk000_via08: send_angles (single) [  -9.54,  +20.31,   +4.35,   +2.58,  -24.91,  -29.63]  speed=20 wait=1.0s  (pre max|Δ|=9.71°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.95° (tol 3.0°)
       [VIA   ] step  8  Δ= -3.6  +6.2  -0.0  +1.7  -9.7  -0.0  着いた
[SEND] pi05_chunk000_via09: send_angles (single) [ -10.60,  +22.50,   +4.54,   +2.85,  -27.39,  -29.74]  speed=20 wait=1.0s  (pre max|Δ|=3.14°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.96° (tol 3.0°)
       [VIA   ] step  9  Δ= -1.5  +1.2  -0.5  +0.2  -3.1  -0.1  着いた
[STATE ] 目標を渡す  目標と実測の最大差 0.96°（関節 j1）
[001] 推論 1140ms  10ステップ先  Δ=-14.5 +21.0  +3.6  +1.7 -30.2  +0.2
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk001_via02: send_angles (single) [ -15.08,  +28.73,   +6.00,   +3.35,  -35.71,  -29.69]  speed=20 wait=1.0s  (pre max|Δ|=8.38°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.97° (tol 3.0°)
       [VIA   ] step  2  Δ= -4.4  +5.3  +1.0  +0.5  -8.4  +0.0  着いた
[SEND] pi05_chunk001_via05: send_angles (single) [ -19.61,  +35.39,   +7.29,   +4.01,  -45.04,  -29.62]  speed=20 wait=1.0s  (pre max|Δ|=9.98°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.99° (tol 3.0°)
       [VIA   ] step  5  Δ= -4.9  +5.7  +0.6  +0.3 -10.0  +0.1  着いた
[SEND] pi05_chunk001_via08: send_angles (single) [ -23.73,  +42.28,   +8.27,   +4.44,  -54.59,  -29.53]  speed=20 wait=1.0s  (pre max|Δ|=9.77°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.96° (tol 3.0°)
       [VIA   ] step  8  Δ= -3.7  +5.9  +0.4  -0.0  -9.8  +0.2  着いた
[SEND] pi05_chunk001_via09: send_angles (single) [ -25.11,  +44.51,   +8.64,   +4.55,  -57.54,  -29.49]  speed=20 wait=1.0s  (pre max|Δ|=3.14°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.01° (tol 3.0°)
       [VIA   ] step  9  Δ= -1.7  +1.3  -0.2  -0.5  -3.1  +0.2  着いた
[STATE ] 目標を渡す  目標と実測の最大差 1.01°（関節 j1）
[002] 推論 744ms  10ステップ先  Δ=-12.1 +17.2  +3.7  -0.1 -23.1  +0.1
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk002_via02: send_angles (single) [ -29.58,  +51.26,   +9.99,   +4.21,  -67.18,  -29.51]  speed=20 wait=1.0s  (pre max|Δ|=9.53°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.94° (tol 3.0°)
       [VIA   ] step  2  Δ= -4.4  +5.7  +1.1  -0.8  -9.5  +0.2  着いた
[SEND] pi05_chunk002_via05: send_angles (single) [ -34.01,  +57.74,  +11.30,   +4.37,  -75.53,  -29.56]  speed=20 wait=1.0s  (pre max|Δ|=8.74°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.88° (tol 3.0°)
       [VIA   ] step  5  Δ= -4.7  +5.5  +0.8  -0.1  -8.7  +0.1  着いた
[SEND] pi05_chunk002_via08: send_angles (single) [ -36.86,  +62.18,  +12.44,   +4.82,  -80.71,  -29.58]  speed=20 wait=1.0s  (pre max|Δ|=5.30°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.01° (tol 3.0°)
       [VIA   ] step  8  Δ= -2.8  +3.6  +0.7  +0.2  -5.3  +0.1  着いた
[SEND] pi05_chunk002_via09: send_angles (single) [ -37.36,  +62.73,  +12.54,   +4.99,  -80.79,  -29.57]  speed=20 wait=1.0s  (pre max|Δ|=0.63°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.99° (tol 3.0°)
       [VIA   ] step  9  Δ= -0.6  -0.5  -0.0  +0.2  -0.5  +0.1  着いた
[STATE ] 目標を渡す  目標と実測の最大差 0.99°（関節 j1）
[003] 推論 583ms  10ステップ先  Δ= -1.7  +5.3  +1.1  -0.5  -6.8  +0.1
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk003_via02: send_angles (single) [ -38.23,  +65.18,  +13.70,   +4.96,  -84.08,  -29.55]  speed=20 wait=1.0s  (pre max|Δ|=3.75°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.91° (tol 3.0°)
       [VIA   ] step  2  Δ= -0.8  +1.5  +1.1  +0.1  -3.7  +0.1  着いた
[SEND] pi05_chunk003_via05: send_angles (single) [ -38.79,  +66.66,  +14.22,   +4.82,  -85.95,  -29.54]  speed=20 wait=1.0s  (pre max|Δ|=1.40°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.01° (tol 3.0°)
       [VIA   ] step  5  Δ= -0.4  +0.6  +0.2  -0.0  -1.4  +0.2  着いた
[SEND] pi05_chunk003_via08: send_angles (single) [ -39.10,  +68.49,  +13.73,   +4.43,  -86.91,  -29.57]  speed=20 wait=1.0s  (pre max|Δ|=1.05°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.94° (tol 3.0°)
       [VIA   ] step  8  Δ= -0.7  +0.8  -0.2  -0.4  -1.0  +0.1  着いた
       [VIA   ] step  9  Δ= -0.0  -0.4  -0.3  -0.4  +0.1  +0.1  送らず (0.5° 以下)
[STATE ] 目標を渡す  目標と実測の最大差 0.42°（関節 j1）
[004] 推論 650ms  10ステップ先  Δ= -0.5  +9.5  -5.7  -1.2  -2.0  -0.0
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk004_via02: send_angles (single) [ -39.30,  +72.85,  +11.94,   +4.10,  -88.42,  -29.58]  speed=20 wait=1.0s  (pre max|Δ|=3.42°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.15° (tol 3.0°)
       [VIA   ] step  2  Δ= -0.1  +3.4  -2.0  -0.6  -1.2  +0.1  着いた
[SEND] pi05_chunk004_via05: send_angles (single) [ -39.51,  +76.02,  +10.17,   +3.86,  -88.91,  -29.64]  speed=20 wait=1.0s  (pre max|Δ|=2.92°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.99° (tol 3.0°)
       [VIA   ] step  5  Δ= -0.3  +2.2  -2.9  -0.5  -0.9  +0.1  着いた
[SEND] pi05_chunk004_via08: send_angles (single) [ -39.54,  +78.58,   +8.60,   +3.61,  -89.19,  -29.69]  speed=20 wait=1.0s  (pre max|Δ|=2.56°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.98° (tol 3.0°)
       [VIA   ] step  8  Δ= -0.3  +1.6  -2.6  -0.5  -0.5  +0.0  着いた
[SEND] pi05_chunk004_via09: send_angles (single) [ -39.58,  +78.96,   +8.32,   +3.52,  -89.27,  -29.70]  speed=20 wait=1.0s  (pre max|Δ|=1.26°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.26° (tol 3.0°)
       [VIA   ] step  9  Δ= -0.4  -0.6  -1.3  -0.3  -0.2  -0.0  着いた
[STATE ] 目標を渡す  目標と実測の最大差 1.26°（関節 j2）
[005] 推論 607ms  4ステップ先  Δ= -0.4  +0.7  -2.1  -0.4  -0.5  -0.1  グリッパー→閉
       [VIA   ] 中継点 2 点: step 2, 3
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk005_via02: send_angles (single) [ -39.63,  +80.64,   +7.46,   +3.41,  -89.50,  -29.76]  speed=20 wait=1.0s  (pre max|Δ|=2.12°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.01° (tol 3.0°)
       [VIA   ] step  2  Δ= -0.4  +0.7  -2.1  -0.4  -0.5  -0.1  着いた
[SEND] pi05_chunk005_via03: send_angles (single) [ -39.63,  +80.64,   +7.46,   +3.41,  -89.50,  -29.76]  speed=20 wait=1.0s  (pre max|Δ|=1.01°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.01° (tol 3.0°)
       [VIA   ] step  3  Δ= -0.4  -1.0  -1.0  -0.3  -0.2  -0.1  着いた
  [Pi] GRIPPER: VALUE=20 speed=100 result= -1
[STATE ] 目標を渡す  目標と実測の最大差 1.01°（関節 j1）
[006] 推論 559ms  10ステップ先  Δ= +0.3 -13.6  +7.9  -0.1  +1.3  -0.2
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk006_via02: send_angles (single) [ -39.68,  +77.07,   +9.90,   +3.46,  -89.55,  -29.87]  speed=20 wait=1.0s  (pre max|Δ|=4.58°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.20° (tol 3.0°)
       [VIA   ] step  2  Δ= -0.5  -4.6  +1.5  -0.2  +0.2  -0.2  着いた
[SEND] pi05_chunk006_via05: send_angles (single) [ -39.86,  +73.10,  +12.69,   +3.43,  -89.30,  -29.87]  speed=20 wait=1.0s  (pre max|Δ|=6.17°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.13° (tol 3.0°)
       [VIA   ] step  5  Δ= -0.7  -6.2  +2.2  -0.3  +0.6  -0.2  着いた
[SEND] pi05_chunk006_via08: send_angles (single) [ -39.67,  +69.26,  +15.59,   +3.53,  -88.84,  -29.88]  speed=20 wait=1.0s  (pre max|Δ|=5.97°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.10° (tol 3.0°)
       [VIA   ] step  8  Δ= +0.4  -6.0  +2.4  -0.1  +1.1  -0.2  着いた
[SEND] pi05_chunk006_via09: send_angles (single) [ -38.89,  +68.03,  +16.34,   +3.63,  -88.42,  -29.89]  speed=20 wait=1.0s  (pre max|Δ|=3.33°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.54° (tol 3.0°)
       [VIA   ] step  9  Δ= +1.2  -3.3  +0.2  +0.0  +1.5  -0.2  着いた
[STATE ] 目標を渡す  目標と実測の最大差 2.54°（関節 j1）
[007] 推論 648ms  10ステップ先  Δ=+22.7 -14.3  +1.3  +2.9 +11.6  -0.4
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk007_via02: send_angles (single) [ -33.94,  +64.77,  +17.17,   +4.28,  -86.42,  -29.93]  speed=20 wait=1.0s  (pre max|Δ|=5.80°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.20° (tol 3.0°)
       [VIA   ] step  2  Δ= +4.5  -5.8  +1.0  +0.9  +3.0  -0.2  着いた
[SEND] pi05_chunk007_via05: send_angles (single) [ -26.46,  +61.14,  +17.40,   +5.13,  -82.85,  -29.90]  speed=20 wait=1.0s  (pre max|Δ|=7.64°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.58° (tol 3.0°)
       [VIA   ] step  5  Δ= +7.6  -5.8  -0.3  +1.1  +4.2  -0.2  着いた
[SEND] pi05_chunk007_via08: send_angles (single) [ -18.62,  +57.65,  +17.49,   +6.08,  -79.39,  -30.01]  speed=20 wait=1.0s  (pre max|Δ|=8.09°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.55° (tol 3.0°)
       [VIA   ] step  8  Δ= +8.1  -6.1  -0.2  +1.3  +4.0  -0.3  着いた
[SEND] pi05_chunk007_via09: send_angles (single) [ -15.67,  +56.27,  +17.49,   +6.32,  -78.11,  -30.09]  speed=20 wait=1.0s  (pre max|Δ|=3.93°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.44° (tol 3.0°)
       [VIA   ] step  9  Δ= +3.2  -3.9  -0.2  +0.4  +1.7  -0.4  着いた
[STATE ] 目標を渡す  目標と実測の最大差 2.44°（関節 j1）
[008] 推論 1547ms  10ステップ先  Δ=+28.8 -14.4  -0.4  +0.4 +10.3  -0.5
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk008_via02: send_angles (single) [  -7.18,  +52.94,  +17.30,   +6.53,  -74.96,  -30.12]  speed=20 wait=1.0s  (pre max|Δ|=8.55°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.51° (tol 3.0°)
       [VIA   ] step  2  Δ= +8.5  -5.8  -0.4  +0.5  +3.2  -0.3  着いた
[SEND] pi05_chunk008_via05: send_angles (single) [  +1.16,  +49.26,  +17.12,   +6.35,  -71.17,  -30.09]  speed=20 wait=1.0s  (pre max|Δ|=8.63°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.41° (tol 3.0°)
       [VIA   ] step  5  Δ= +8.6  -6.2  -0.5  +0.3  +4.0  -0.3  着いた
[SEND] pi05_chunk008_via08: send_angles (single) [ +10.55,  +45.15,  +17.30,   +6.35,  -68.18,  -30.14]  speed=20 wait=1.0s  (pre max|Δ|=9.76°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.39° (tol 3.0°)
       [VIA   ] step  8  Δ= +9.8  -6.5  -0.4  +0.1  +3.2  -0.3  着いた
[SEND] pi05_chunk008_via09: send_angles (single) [ +13.11,  +44.33,  +17.28,   +6.41,  -67.85,  -30.17]  speed=20 wait=1.0s  (pre max|Δ|=3.21°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.42° (tol 3.0°)
       [VIA   ] step  9  Δ= +2.7  -3.2  -0.4  +0.2  +0.4  -0.4  着いた
[STATE ] 目標を渡す  目標と実測の最大差 2.42°（関節 j1）
[009] 推論 634ms  10ステップ先  Δ=+27.0  -8.5  -2.2  +0.4  +7.4  -0.5
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk009_via02: send_angles (single) [ +21.90,  +40.81,  +17.46,   +6.67,  -65.00,  -30.26]  speed=20 wait=1.0s  (pre max|Δ|=8.72°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.34° (tol 3.0°)
       [VIA   ] step  2  Δ= +8.7  -5.9  -0.2  +0.2  +2.9  -0.4  着いた
[SEND] pi05_chunk009_via05: send_angles (single) [ +31.05,  +37.10,  +17.50,   +6.74,  -61.59,  -30.27]  speed=20 wait=1.0s  (pre max|Δ|=9.35°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.36° (tol 3.0°)
       [VIA   ] step  5  Δ= +9.3  -6.0  -0.2  +0.2  +3.4  -0.4  着いた
[SEND] pi05_chunk009_via08: send_angles (single) [ +39.43,  +37.15,  +16.11,   +6.93,  -60.01,  -30.37]  speed=20 wait=1.0s  (pre max|Δ|=8.50°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.31° (tol 3.0°)
       [VIA   ] step  8  Δ= +8.5  -2.3  -1.6  +0.2  +1.6  -0.4  着いた
[SEND] pi05_chunk009_via09: send_angles (single) [ +40.14,  +38.24,  +15.42,   +6.91,  -60.52,  -30.39]  speed=20 wait=1.0s  (pre max|Δ|=2.15°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.98° (tol 3.0°)
       [VIA   ] step  9  Δ= +0.9  -1.2  -2.1  +0.1  -0.7  -0.4  着いた
[STATE ] 目標を渡す  目標と実測の最大差 1.98°（関節 j2）
[010] 推論 641ms  10ステップ先  Δ= +3.2 +20.4 -11.5  +1.9 -12.4  -0.7
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk010_via02: send_angles (single) [ +41.74,  +44.82,  +12.41,   +7.47,  -63.53,  -30.50]  speed=20 wait=1.0s  (pre max|Δ|=5.36°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.66° (tol 3.0°)
       [VIA   ] step  2  Δ= +1.4  +5.4  -5.0  +0.5  -3.7  -0.5  着いた
[SEND] pi05_chunk010_via05: send_angles (single) [ +42.97,  +52.31,   +8.95,   +8.28,  -67.42,  -30.59]  speed=20 wait=1.0s  (pre max|Δ|=6.44°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.42° (tol 3.0°)
       [VIA   ] step  5  Δ= +1.0  +6.4  -5.0  +1.2  -5.5  -0.3  着いた
[SEND] pi05_chunk010_via08: send_angles (single) [ +43.48,  +58.54,   +6.40,   +8.86,  -71.25,  -30.74]  speed=20 wait=1.0s  (pre max|Δ|=5.02°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.33° (tol 3.0°)
       [VIA   ] step  8  Δ= +0.2  +5.0  -4.0  +0.9  -4.5  -0.4  着いた
[SEND] pi05_chunk010_via09: send_angles (single) [ +43.57,  +59.84,   +5.93,   +8.89,  -72.24,  -30.79]  speed=20 wait=1.0s  (pre max|Δ|=1.80°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.80° (tol 3.0°)
       [VIA   ] step  9  Δ= +0.3  +0.3  -1.8  +0.5  -1.7  -0.3  着いた
[STATE ] 目標を渡す  目標と実測の最大差 1.80°（関節 j2）
[011] 推論 609ms  4ステップ先  Δ= +0.4  +1.2  -2.3  +0.4  -1.3  -0.3  グリッパー→開
       [VIA   ] 中継点 2 点: step 2, 3
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk011_via02: send_angles (single) [ +43.52,  +62.11,   +5.46,   +9.04,  -73.43,  -30.81]  speed=20 wait=1.0s  (pre max|Δ|=2.27°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.39° (tol 3.0°)
       [VIA   ] step  2  Δ= +0.4  +1.2  -2.3  +0.4  -1.3  -0.3  着いた
[SEND] pi05_chunk011_via03: send_angles (single) [ +43.52,  +62.11,   +5.46,   +9.04,  -73.43,  -30.81]  speed=20 wait=1.0s  (pre max|Δ|=1.39°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.39° (tol 3.0°)
       [VIA   ] step  3  Δ= +0.5  -1.2  -1.4  +0.3  -0.2  -0.3  着いた
  [Pi] GRIPPER: OPEN result= -1
[STATE ] 目標を渡す  目標と実測の最大差 1.39°（関節 j2）
[012] 推論 1560ms  10ステップ先  Δ= -0.9 -21.1  +2.9  -1.5 +15.5  -0.5
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk012_via02: send_angles (single) [ +43.41,  +56.73,   +7.00,   +8.65,  -69.99,  -30.78]  speed=20 wait=1.0s  (pre max|Δ|=6.55°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.24° (tol 3.0°)
       [VIA   ] step  2  Δ= +0.4  -6.5  +0.2  -0.1  +3.2  -0.3  着いた
[SEND] pi05_chunk012_via05: send_angles (single) [ +43.54,  +50.64,   +8.81,   +8.20,  -65.91,  -30.77]  speed=20 wait=1.0s  (pre max|Δ|=8.33°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.00° (tol 3.0°)
       [VIA   ] step  5  Δ= +0.5  -8.3  +1.3  -0.6  +5.7  -0.3  着いた
[SEND] pi05_chunk012_via08: send_angles (single) [ +42.91,  +43.98,   +9.89,   +7.61,  -60.08,  -30.85]  speed=20 wait=1.0s  (pre max|Δ|=8.66°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.98° (tol 3.0°)
       [VIA   ] step  8  Δ= -0.1  -8.7  +0.5  -1.3  +6.8  -0.3  着いた
[SEND] pi05_chunk012_via09: send_angles (single) [ +42.12,  +42.14,   +9.75,   +7.31,  -57.73,  -30.94]  speed=20 wait=1.0s  (pre max|Δ|=3.82°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.33° (tol 3.0°)
       [VIA   ] step  9  Δ= -0.8  -3.8  -0.7  -1.0  +3.0  -0.4  着いた
[STATE ] 目標を渡す  目標と実測の最大差 2.33°（関節 j1）
[013] 推論 634ms  10ステップ先  Δ=-17.2 -22.6  -1.7  -4.5 +26.3  +0.1
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk013_via02: send_angles (single) [ +38.69,  +35.80,  +10.59,   +6.30,  -51.57,  -30.88]  speed=20 wait=1.0s  (pre max|Δ|=8.67°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.08° (tol 3.0°)
       [VIA   ] step  2  Δ= -3.4  -8.7  +0.1  -1.4  +6.6  -0.1  着いた
[SEND] pi05_chunk013_via05: send_angles (single) [ +33.34,  +29.76,  +10.04,   +4.99,  -43.45,  -30.74]  speed=20 wait=1.0s  (pre max|Δ|=8.31°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.05° (tol 3.0°)
       [VIA   ] step  5  Δ= -5.6  -8.1  -1.0  -1.5  +8.3  +0.0  着いた
[SEND] pi05_chunk013_via08: send_angles (single) [ +26.95,  +23.51,   +8.96,   +3.61,  -34.09,  -30.65]  speed=20 wait=1.0s  (pre max|Δ|=9.67°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.06° (tol 3.0°)
       [VIA   ] step  8  Δ= -6.6  -8.3  -2.1  -1.7  +9.7  +0.2  着いた
[SEND] pi05_chunk013_via09: send_angles (single) [ +24.92,  +21.83,   +8.71,   +3.30,  -31.89,  -30.64]  speed=20 wait=1.0s  (pre max|Δ|=3.74°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.27° (tol 3.0°)
       [VIA   ] step  9  Δ= -2.5  -3.7  -2.3  -0.5  +2.4  +0.2  着いた
[STATE ] 目標を渡す  目標と実測の最大差 2.27°（関節 j2）
[014] 推論 639ms  10ステップ先  Δ=-20.2 -19.0  -8.1  -2.0 +28.3  +0.1
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk014_via02: send_angles (single) [ +19.31,  +16.58,   +6.97,   +2.22,  -23.67,  -30.64]  speed=20 wait=1.0s  (pre max|Δ|=8.41°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.90° (tol 3.0°)
       [VIA   ] step  2  Δ= -5.6  -7.2  -4.0  -0.4  +8.4  +0.2  着いた
[SEND] pi05_chunk014_via05: send_angles (single) [ +12.52,  +10.42,   +5.03,   +1.33,  -13.55,  -30.70]  speed=20 wait=1.0s  (pre max|Δ|=10.44°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.91° (tol 3.0°)
       [VIA   ] step  5  Δ= -7.4  -8.0  -3.8  -1.5 +10.4  +0.2  着いた
[SEND] pi05_chunk014_via08: send_angles (single) [  +6.18,   +5.48,   +3.37,   +0.68,   -4.93,  -30.70]  speed=20 wait=1.0s  (pre max|Δ|=8.86°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.90° (tol 3.0°)
       [VIA   ] step  8  Δ= -6.7  -6.6  -3.6  -1.1  +8.9  +0.2  着いた
[SEND] pi05_chunk014_via09: send_angles (single) [  +4.67,   +4.77,   +2.88,   +0.60,   -3.78,  -30.75]  speed=20 wait=1.0s  (pre max|Δ|=2.39°, post-send timeout 8.0s)

[SEND] arrival OK: max|Δ|=2.39° (tol 3.0°)
       [VIA   ] step  9  Δ= -1.6  -2.3  -2.4  -0.4  +1.4  +0.2  着いた
[STATE ] 目標を渡す  目標と実測の最大差 2.39°（関節 j2）
[015] 推論 813ms  10ステップ先  Δ= -3.0  -3.1  -2.7  -0.4  +1.3  +0.3
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > [SEND] pi05_chunk015_via02: send_angles (single) [  +1.57,   +3.38,   +2.51,   +0.52,   -2.21,  -30.70]  speed=20 wait=1.0s  (pre max|Δ|=3.12°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.76° (tol 3.0°)
       [VIA   ] step  2  Δ= -2.9  -3.1  -2.8  -0.4  +1.6  +0.2  着いた
[SEND] pi05_chunk015_via05: send_angles (single) [  +1.39,   +3.44,   +2.55,   +0.50,   -2.48,  -30.70]  speed=20 wait=1.0s  (pre max|Δ|=2.72°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.72° (tol 3.0°)
       [VIA   ] step  5  Δ= -0.1  -1.4  -2.7  -0.2  -0.0  +0.2  着いた
[SEND] pi05_chunk015_via08: send_angles (single) [  +1.37,   +3.37,   +2.53,   +0.46,   -2.43,  -30.67]  speed=20 wait=1.0s  (pre max|Δ|=2.74°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.74° (tol 3.0°)
       [VIA   ] step  8  Δ= -0.1  -1.5  -2.7  -0.2  +0.0  +0.3  着いた
[SEND] pi05_chunk015_via09: send_angles (single) [  +1.43,   +3.40,   +2.54,   +0.47,   -2.54,  -30.66]  speed=20 wait=1.0s  (pre max|Δ|=2.73°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.73° (tol 3.0°)
       [VIA   ] step  9  Δ= -0.1  -1.4  -2.7  -0.2  -0.1  +0.2  着いた
[STATE ] 目標を渡す  目標と実測の最大差 2.73°（関節 j2）
[016] 推論 1562ms  10ステップ先  Δ= -1.0  -1.9  -2.8  -0.3  -0.1  +0.1
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk016_via02: send_angles (single) [  +0.65,   +3.20,   +2.41,   +0.48,   -2.49,  -30.69]  speed=20 wait=1.0s  (pre max|Δ|=2.86°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.86° (tol 3.0°)
       [VIA   ] step  2  Δ= -0.8  -1.6  -2.9  -0.2  -0.0  +0.2  着いた
[SEND] pi05_chunk016_via05: send_angles (single) [  +0.48,   +3.13,   +2.43,   +0.46,   -2.53,  -30.71]  speed=20 wait=1.0s  (pre max|Δ|=2.84°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.84° (tol 3.0°)
       [VIA   ] step  5  Δ= +0.1  -1.7  -2.8  -0.2  -0.1  +0.1  着いた
[SEND] pi05_chunk016_via08: send_angles (single) [  +0.39,   +3.03,   +2.45,   +0.44,   -2.54,  -30.72]  speed=20 wait=1.0s  (pre max|Δ|=2.82°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.82° (tol 3.0°)
       [VIA   ] step  8  Δ= -0.0  -1.8  -2.8  -0.3  -0.1  +0.1  着いた
[SEND] pi05_chunk016_via09: send_angles (single) [  +0.48,   +2.97,   +2.45,   +0.45,   -2.51,  -30.71]  speed=20 wait=1.0s  (pre max|Δ|=2.82°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.82° (tol 3.0°)
       [VIA   ] step  9  Δ= +0.1  -1.6  -2.8  -0.3  -0.1  +0.1  着いた
[STATE ] 目標を渡す  目標と実測の最大差 2.82°（関節 j2）
[017] 推論 631ms  10ステップ先  Δ= -0.7  -1.6  -2.8  -0.2  -0.5  +0.1
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk017_via02: send_angles (single) [  -0.10,   +3.02,   +2.44,   +0.46,   -2.67,  -30.74]  speed=20 wait=1.0s  (pre max|Δ|=2.83°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.83° (tol 3.0°)
       [VIA   ] step  2  Δ= -0.5  -1.5  -2.8  -0.2  -0.2  +0.1  着いた
[SEND] pi05_chunk017_via05: send_angles (single) [  -0.20,   +2.94,   +2.43,   +0.45,   -2.80,  -30.76]  speed=20 wait=1.0s  (pre max|Δ|=2.84°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.84° (tol 3.0°)
       [VIA   ] step  5  Δ= -0.6  -1.6  -2.8  -0.2  -0.3  +0.1  着いた
[SEND] pi05_chunk017_via08: send_angles (single) [  -0.27,   +2.98,   +2.45,   +0.47,   -2.90,  -30.75]  speed=20 wait=1.0s  (pre max|Δ|=2.82°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.82° (tol 3.0°)
       [VIA   ] step  8  Δ= -0.6  -1.6  -2.8  -0.2  -0.4  +0.1  着いた
[SEND] pi05_chunk017_via09: send_angles (single) [  -0.25,   +2.97,   +2.45,   +0.47,   -2.92,  -30.75]  speed=20 wait=1.0s  (pre max|Δ|=2.82°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.82° (tol 3.0°)
       [VIA   ] step  9  Δ= -0.6  -1.6  -2.8  -0.2  -0.5  +0.1  着いた
[STATE ] 目標を渡す  目標と実測の最大差 2.82°（関節 j2）
[018] 推論 616ms  10ステップ先  Δ= -1.0  -1.8  -2.8  -0.2  -0.7  +0.0
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > h
[SEND] pi05_home: send_angles (single) [  +0.00,   +0.00,   +0.00,   +0.00,   +0.00,  -30.00]  speed=20 wait=1.0s  (pre max|Δ|=5.27°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.49° (tol 2.5°)
[DONE  ] 記録: /Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_181602
```

チャンク05 で、お手本より深いところ（肩 j1 ≈ 80°）で爪を閉じ、06 で回る前に肩を上げ、07〜09 で箱の方へ回り、10 で少し下げて、11 で爪を開きました。チャンク01 以降は、モデルに渡した角度が「直前に送った目標」になっていて（`[STATE ] 目標を渡す`）、目標と測った値の差は最大 2.82° に収まっています。爪先の高さは、閉じたとき 2.1mm、いちばん上がったところで 86.7mm です。お手本の 125〜135mm には届いていませんが、横から撮った動画では、ブロックは箱のふちを越えて箱の中に落ちています。

モデルに渡した角度の出どころごとに、肩を上げる指令の合計と実際に上がった量を比べると、次のようになります（「肩を上げる指令43回」の節の出力から）。

| 記録 | モデルに渡した角度 | ブロックを持って上げた指令の合計 | 実際に上がった量 |
|---|---|---|---|
| 10:07（100713） | 測った値 | −20.3° | −12.0° |
| 10:20（102053） | 測った値 | −41.2° | −11.1° |
| 13:10（131036） | 測った値 | −19.6° | −11.9° |
| 18:16（181602） | 直前の目標 | −50.8° | −42.2° |
| 18:26（182650） | 直前の目標 | −24.6° | −15.6° |


## 続く4回は、2回を1チャンクで止め、1回は箱の位置で離し、2回はつかみ損ねた

18:24 と 18:25 の回は、最初のチャンクを送ったあと h で止めました。

```
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % cd ~/r2r2r-scripts
RAW=/Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
python3 pi05/run_policy_client.py --raw-dir $RAW --steps-per-chunk 10 --via-stride 3 --settle-retries 0 --state-from-target --execute
[SAFE  ] 安全範囲 (学習 19 本 ±10°): j0[-72,+55]  j1[-9,+88]  j2[-46,+41]  j3[-18,+27]  j4[-90,+10]  j5[-51,-14]
[SAFE  ] 肩 j1 の上限は J1_SAFE_MAX=88° で切った (これを超える指令はアームが黙って捨てる / LOG352)  元データ: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
[MODE  ] EXECUTE  steps/chunk=10  max_move=20.0°  log=/Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_182419
[CAMERA] 写り方 dy=-5.3 dx=+2.6 response=0.452 → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[CAMERA] 基準: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes/run_0001_20261019_183454/frames/000000.jpg
[POLICY] 接続 ws://localhost:8000  metadata={}
[GRIP  ] 開始時のグリッパー開放は, 最初の目標が検査を通ってから行います (爪が閉じていたら手で開けておく)
[STATE ] 実測を渡す (直前に送った目標がない)
[000] 推論 1119ms  10ステップ先  Δ=-10.0 +20.0  +5.4  -2.5 -24.2  +2.2
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[GRIP  ] 開始時にグリッパーを開く
  [Pi] GRIPPER: OPEN result= -1
[SEND] pi05_chunk000_via02: send_angles (single) [  -2.03,   +5.88,   +2.39,   -0.19,   -6.04,  -29.78]  speed=20 wait=1.0s  (pre max|Δ|=5.78°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.21° (tol 3.0°)
       [VIA   ] step  2  Δ= -2.4  +4.7  +0.9  -0.4  -5.8  +0.4  着いた
[SEND] pi05_chunk000_via05: send_angles (single) [  -5.30,  +12.70,   +4.36,   -1.09,  -14.12,  -29.06]  speed=20 wait=1.0s  (pre max|Δ|=9.29°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.03° (tol 3.0°)
       [VIA   ] step  5  Δ= -3.2  +6.0  +0.9  -1.2  -9.3  +0.9  着いた
[SEND] pi05_chunk000_via08: send_angles (single) [  -8.59,  +19.20,   +6.40,   -2.01,  -22.13,  -28.27]  speed=20 wait=1.0s  (pre max|Δ|=9.04°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.01° (tol 3.0°)
       [VIA   ] step  8  Δ= -3.2  +5.5  +1.2  -1.1  -9.0  +1.0  着いた
[SEND] pi05_chunk000_via09: send_angles (single) [  -9.66,  +21.19,   +6.91,   -2.20,  -24.45,  -28.06]  speed=20 wait=1.0s  (pre max|Δ|=2.75°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.87° (tol 3.0°)
       [VIA   ] step  9  Δ= -1.0  +1.0  -0.4  -0.3  -2.8  +0.4  着いた
[STATE ] 目標を渡す  目標と実測の最大差 0.87°（関節 j1）
[001] 推論 1334ms  10ステップ先  Δ=-12.3 +21.8  +6.1  -0.1 -28.9  +0.7
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > h
[SEND] pi05_home: send_angles (single) [  +0.00,   +0.00,   +0.00,   +0.00,   +0.00,  -30.00]  speed=20 wait=1.0s  (pre max|Δ|=24.69°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.84° (tol 2.5°)
[DONE  ] 記録: /Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_182419
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % python3 pi05/camera_align.py --raw-dir $RAW --episode run_0001_20261019_192343 --scale 5
[REF   ] 基準画像: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes/run_0001_20261019_192343/frames/000000.jpg
[REF   ] お手本 run_0001_20261019_192343 (つかんだ瞬間の j0 = -27.7°)
[REF   ] 重なった画像のブロックに実物のブロックを合わせると, お手本と同じ位置に置ける
[ALIGN ] |dy| <= 20 なら OK. アームは HOME に置いた状態で合わせる. q または Esc で終了 (ファイルには何も書かない)
[ALIGN ] dy=  -1.0  dx=  -3.1  response=0.710  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
^C
[STOP  ] Ctrl-C
[DONE  ] 終了 (何も書いていません)
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % python3 pi05/run_policy_client.py --raw-dir $RAW --steps-per-chunk 10 --via-stride 3 --settle-retries 0 --state-from-target --execute
[SAFE  ] 安全範囲 (学習 19 本 ±10°): j0[-72,+55]  j1[-9,+88]  j2[-46,+41]  j3[-18,+27]  j4[-90,+10]  j5[-51,-14]
[SAFE  ] 肩 j1 の上限は J1_SAFE_MAX=88° で切った (これを超える指令はアームが黙って捨てる / LOG352)  元データ: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
[MODE  ] EXECUTE  steps/chunk=10  max_move=20.0°  log=/Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_182519
[CAMERA] 写り方 dy=-5.4 dx=+0.4 response=0.620 → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[CAMERA] 基準: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes/run_0001_20261019_183454/frames/000000.jpg
[POLICY] 接続 ws://localhost:8000  metadata={}
[GRIP  ] 開始時のグリッパー開放は, 最初の目標が検査を通ってから行います (爪が閉じていたら手で開けておく)
[STATE ] 実測を渡す (直前に送った目標がない)
[000] 推論 1008ms  10ステップ先  Δ= -9.8 +20.2  +5.4  -2.4 -26.3  +1.3
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[GRIP  ] 開始時にグリッパーを開く
  [Pi] GRIPPER: OPEN result= -1
[SEND] pi05_chunk000_via02: send_angles (single) [  -2.60,   +6.24,   +2.86,   -0.82,   -6.49,  -29.49]  speed=20 wait=1.0s  (pre max|Δ|=6.23°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.31° (tol 3.0°)
       [VIA   ] step  2  Δ= -2.3  +5.0  +1.0  -0.6  -6.2  +0.2  着いた
[SEND] pi05_chunk000_via05: send_angles (single) [  -5.57,  +12.81,   +4.78,   -1.63,  -14.83,  -29.06]  speed=20 wait=1.0s  (pre max|Δ|=9.65°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.04° (tol 3.0°)
       [VIA   ] step  5  Δ= -2.6  +5.7  +0.9  -1.4  -9.6  +0.6  着いた
[SEND] pi05_chunk000_via08: send_angles (single) [  -8.87,  +19.33,   +6.78,   -2.46,  -23.87,  -28.52]  speed=20 wait=1.0s  (pre max|Δ|=10.08°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.06° (tol 3.0°)
       [VIA   ] step  8  Δ= -3.1  +5.5  +1.1  -1.7 -10.1  +1.2  着いた
[SEND] pi05_chunk000_via09: send_angles (single) [ -10.06,  +21.47,   +7.28,   -2.68,  -26.56,  -28.35]  speed=20 wait=1.0s  (pre max|Δ|=3.19°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.94° (tol 3.0°)
       [VIA   ] step  9  Δ= -1.1  +1.1  -0.3  -0.6  -3.2  +0.8  着いた
[STATE ] 目標を渡す  目標と実測の最大差 0.94°（関節 j1）
[001] 推論 1762ms  10ステップ先  Δ=-12.4 +23.1  +5.7  -0.4 -29.8  +0.8
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > h
[SEND] pi05_home: send_angles (single) [  +0.00,   +0.00,   +0.00,   +0.00,   +0.00,  -30.00]  speed=20 wait=1.0s  (pre max|Δ|=26.63°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.84° (tol 2.5°)
[DONE  ] 記録: /Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_182519
```

18:26 の回は、チャンク04 でつかみ、09 で箱の位置（土台 j0 ≈ +41°）まで回り、10 で爪を開きました。爪先の高さはいちばん上で 93.8mm です。この回は動画を撮っていないので、ブロックが箱に入ったかは確かめていません。

```
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % python3 pi05/run_policy_client.py --raw-dir $RAW --steps-per-chunk 10 --via-stride 3 --settle-retries 0 --state-from-target --execute
[SAFE  ] 安全範囲 (学習 19 本 ±10°): j0[-72,+55]  j1[-9,+88]  j2[-46,+41]  j3[-18,+27]  j4[-90,+10]  j5[-51,-14]
[SAFE  ] 肩 j1 の上限は J1_SAFE_MAX=88° で切った (これを超える指令はアームが黙って捨てる / LOG352)  元データ: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
[MODE  ] EXECUTE  steps/chunk=10  max_move=20.0°  log=/Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_182650
[CAMERA] 写り方 dy=-5.4 dx=-0.2 response=0.599 → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[CAMERA] 基準: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes/run_0001_20261019_183454/frames/000000.jpg
[POLICY] 接続 ws://localhost:8000  metadata={}
[GRIP  ] 開始時のグリッパー開放は, 最初の目標が検査を通ってから行います (爪が閉じていたら手で開けておく)
[STATE ] 実測を渡す (直前に送った目標がない)
[000] 推論 747ms  10ステップ先  Δ= -9.7 +20.3  +5.8  -2.7 -25.8  +1.1
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[GRIP  ] 開始時にグリッパーを開く
  [Pi] GRIPPER: OPEN result= -1
[SEND] pi05_chunk000_via02: send_angles (single) [  -2.73,   +6.30,   +2.91,   -0.88,   -6.09,  -29.55]  speed=20 wait=1.0s  (pre max|Δ|=5.83°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.26° (tol 3.0°)
       [VIA   ] step  2  Δ= -2.3  +4.9  +1.1  -0.6  -5.8  +0.1  着いた
[SEND] pi05_chunk000_via05: send_angles (single) [  -5.57,  +12.42,   +4.87,   -1.79,  -14.31,  -29.18]  speed=20 wait=1.0s  (pre max|Δ|=9.48°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.93° (tol 3.0°)
       [VIA   ] step  5  Δ= -2.8  +5.2  +1.0  -1.5  -9.5  +0.5  着いた
[SEND] pi05_chunk000_via08: send_angles (single) [  -9.08,  +19.44,   +7.03,   -2.76,  -23.28,  -28.70]  speed=20 wait=1.0s  (pre max|Δ|=9.84°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.03° (tol 3.0°)
       [VIA   ] step  8  Δ= -3.5  +6.1  +1.2  -1.7  -9.8  +1.0  着いた
[SEND] pi05_chunk000_via09: send_angles (single) [ -10.14,  +21.65,   +7.68,   -2.99,  -26.02,  -28.57]  speed=20 wait=1.0s  (pre max|Δ|=3.35°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.93° (tol 3.0°)
       [VIA   ] step  9  Δ= -1.3  +1.2  -0.1  -0.7  -3.3  +0.8  着いた
[STATE ] 目標を渡す  目標と実測の最大差 0.93°（関節 j1）
[001] 推論 614ms  10ステップ先  Δ=-12.6 +23.0  +6.3  +0.3 -30.6  +0.7
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk001_via02: send_angles (single) [ -14.78,  +28.78,   +9.82,   -3.17,  -35.28,  -28.43]  speed=20 wait=1.0s  (pre max|Δ|=9.18°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.92° (tol 3.0°)
       [VIA   ] step  2  Δ= -4.8  +6.2  +1.4  -0.4  -9.2  +0.5  着いた
[SEND] pi05_chunk001_via05: send_angles (single) [ -18.40,  +35.78,  +11.98,   -2.74,  -44.60,  -28.37]  speed=20 wait=1.0s  (pre max|Δ|=9.98°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.04° (tol 3.0°)
       [VIA   ] step  5  Δ= -3.2  +6.1  +1.4  +0.2 -10.0  +0.4  着いた
[SEND] pi05_chunk001_via08: send_angles (single) [ -21.47,  +42.96,  +14.01,   -2.60,  -53.56,  -28.34]  speed=20 wait=1.0s  (pre max|Δ|=9.09°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.07° (tol 3.0°)
       [VIA   ] step  8  Δ= -3.5  +6.1  +1.4  +0.4  -9.1  +0.2  着いた
[SEND] pi05_chunk001_via09: send_angles (single) [ -22.59,  +45.60,  +14.68,   -2.54,  -56.68,  -28.32]  speed=20 wait=1.0s  (pre max|Δ|=3.16°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.98° (tol 3.0°)
       [VIA   ] step  9  Δ= -0.8  +1.6  +0.1  +0.1  -3.2  +0.2  着いた
[STATE ] 目標を渡す  目標と実測の最大差 0.98°（関節 j1）
[002] 推論 625ms  10ステップ先  Δ= -5.8 +11.1  +4.2  +0.4 -13.1  +0.4
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk002_via02: send_angles (single) [ -26.26,  +52.49,  +16.69,   -2.73,  -65.51,  -28.32]  speed=20 wait=1.0s  (pre max|Δ|=8.91°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.12° (tol 3.0°)
       [VIA   ] step  2  Δ= -3.3  +5.9  +1.5  -0.2  -8.9  +0.2  着いた
[SEND] pi05_chunk002_via05: send_angles (single) [ -28.28,  +56.82,  +18.65,   -2.37,  -69.60,  -28.23]  speed=20 wait=1.0s  (pre max|Δ|=4.57°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.09° (tol 3.0°)
       [VIA   ] step  5  Δ= -2.2  +3.2  +1.5  -0.1  -4.6  +0.3  着いた
[SEND] pi05_chunk002_via08: send_angles (single) [ -28.84,  +57.91,  +19.62,   -2.10,  -70.08,  -28.14]  speed=20 wait=1.0s  (pre max|Δ|=0.72°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.97° (tol 3.0°)
       [VIA   ] step  8  Δ= -0.7  -0.0  +0.6  -0.1  -0.2  +0.2  着いた
[SEND] pi05_chunk002_via09: send_angles (single) [ -28.69,  +57.72,  +19.42,   -2.10,  -69.73,  -28.12]  speed=20 wait=1.0s  (pre max|Δ|=1.16°, post-send timeout 8.0s)

[SEND] arrival OK: max|Δ|=1.16° (tol 3.0°)
       [VIA   ] step  9  Δ= +0.5  -1.2  -0.1  -0.2  +0.5  +0.3  着いた
[STATE ] 目標を渡す  目標と実測の最大差 1.16°（関節 j1）
[003] 推論 558ms  10ステップ先  Δ= +0.4  +2.9  -3.6  -3.1  +5.1  +0.4
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 >        [VIA   ] step  2  Δ= +0.5  -0.2  +0.1  -0.4  +0.0  +0.2  送らず (0.5° 以下)
[SEND] pi05_chunk003_via05: send_angles (single) [ -28.59,  +59.72,  +18.49,   -3.27,  -68.75,  -27.96]  speed=20 wait=1.0s  (pre max|Δ|=1.47°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.00° (tol 3.0°)
       [VIA   ] step  5  Δ= +0.6  +0.8  -1.0  -1.3  +1.5  +0.3  着いた
[SEND] pi05_chunk003_via08: send_angles (single) [ -28.76,  +61.29,  +16.54,   -4.70,  -66.06,  -27.89]  speed=20 wait=1.0s  (pre max|Δ|=4.69°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.93° (tol 3.0°)
       [VIA   ] step  8  Δ= +0.4  +0.9  -3.0  -1.9  +4.7  -0.6  着いた
[SEND] pi05_chunk003_via09: send_angles (single) [ -28.76,  +61.77,  +15.87,   -5.03,  -65.15,  -27.87]  speed=20 wait=1.0s  (pre max|Δ|=3.84°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.43° (tol 3.0°)
       [VIA   ] step  9  Δ= +0.4  -0.0  -1.2  -0.6  +3.8  -1.0  着いた
[STATE ] 目標を渡す  目標と実測の最大差 2.43°（関節 j4）
[004] 推論 562ms  8ステップ先  Δ= +0.8  +2.4  -2.8  -2.2  +5.8  -0.7  グリッパー→閉
       [VIA   ] 中継点 3 点: step 2, 5, 7
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk004_via02: send_angles (single) [ -28.35,  +63.41,  +14.21,   -6.32,  -62.97,  -27.84]  speed=20 wait=1.0s  (pre max|Δ|=1.96°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.81° (tol 3.0°)
       [VIA   ] step  2  Δ= +0.6  +0.7  -2.0  -0.4  -1.1  +1.3  着いた
[SEND] pi05_chunk004_via05: send_angles (single) [ -28.37,  +64.50,  +13.14,   -7.13,  -61.55,  -27.81]  speed=20 wait=1.0s  (pre max|Δ|=1.71°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.02° (tol 3.0°)
       [VIA   ] step  5  Δ= +0.5  +0.4  -1.7  -1.2  +0.7  +0.8  着いた
[SEND] pi05_chunk004_via07: send_angles (single) [ -28.32,  +64.40,  +13.23,   -7.15,  -61.77,  -27.78]  speed=20 wait=1.0s  (pre max|Δ|=0.80°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.80° (tol 3.0°)
       [VIA   ] step  7  Δ= +0.4  -0.6  -0.6  -0.7  +0.8  +0.6  着いた
  [Pi] GRIPPER: VALUE=20 speed=100 result= -1
[STATE ] 目標を渡す  目標と実測の最大差 0.89°（関節 j4）
[005] 推論 1531ms  10ステップ先  Δ= +0.6  -3.9  +5.1  +2.1  -4.8  +0.1
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk005_via02: send_angles (single) [ -28.41,  +63.39,  +14.65,   -6.29,  -63.46,  -27.66]  speed=20 wait=1.0s  (pre max|Δ|=1.64°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.30° (tol 3.0°)
       [VIA   ] step  2  Δ= +0.3  -1.6  +1.6  +0.6  -0.8  -0.1  着いた
[SEND] pi05_chunk005_via05: send_angles (single) [ -28.42,  +62.44,  +16.36,   -5.48,  -65.33,  -27.54]  speed=20 wait=1.0s  (pre max|Δ|=3.01°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.45° (tol 3.0°)
       [VIA   ] step  5  Δ= +0.3  -2.2  +3.0  +1.2  -2.7  +0.0  着いた
[SEND] pi05_chunk005_via08: send_angles (single) [ -28.32,  +61.40,  +17.96,   -4.81,  -67.00,  -27.45]  speed=20 wait=1.0s  (pre max|Δ|=2.49°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.70° (tol 3.0°)
       [VIA   ] step  8  Δ= +0.4  -2.5  +2.4  +1.6  -2.4  -0.3  着いた
[SEND] pi05_chunk005_via09: send_angles (single) [ -28.19,  +61.10,  +18.20,   -4.67,  -67.51,  -27.46]  speed=20 wait=1.0s  (pre max|Δ|=2.00°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.00° (tol 3.0°)
       [VIA   ] step  9  Δ= -0.1  -2.0  +0.8  +0.7  -1.6  -0.5  着いた
[STATE ] 目標を渡す  目標と実測の最大差 2.00°（関節 j1）
[006] 推論 560ms  10ステップ先  Δ=+16.5  -7.6  -1.5  +4.2  +0.5  -2.4
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk006_via02: send_angles (single) [ -28.44,  +60.45,  +19.32,   -4.25,  -68.70,  -27.37]  speed=20 wait=1.0s  (pre max|Δ|=2.65°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.95° (tol 3.0°)
       [VIA   ] step  2  Δ= -0.5  -2.7  +1.9  +0.8  -2.3  -0.4  着いた
[SEND] pi05_chunk006_via05: send_angles (single) [ -23.02,  +58.91,  +18.29,   -3.08,  -68.19,  -28.03]  speed=20 wait=1.0s  (pre max|Δ|=4.92°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.34° (tol 3.0°)
       [VIA   ] step  5  Δ= +4.9  -3.5  -0.8  +1.4  -0.7  -1.0  着いた
[SEND] pi05_chunk006_via08: send_angles (single) [ -13.90,  +56.20,  +16.48,   -1.34,  -66.40,  -29.08]  speed=20 wait=1.0s  (pre max|Δ|=9.21°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.68° (tol 3.0°)
       [VIA   ] step  8  Δ= +9.2  -5.0  -2.8  +0.8  +1.1  -1.9  着いた
[SEND] pi05_chunk006_via09: send_angles (single) [ -11.44,  +55.54,  +15.90,   -0.88,  -65.74,  -29.32]  speed=20 wait=1.0s  (pre max|Δ|=3.34°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.37° (tol 3.0°)
       [VIA   ] step  9  Δ= +2.7  -3.3  -1.9  +0.1  +1.6  -1.0  着いた
[STATE ] 目標を渡す  目標と実測の最大差 2.37°（関節 j1）
[007] 推論 560ms  10ステップ先  Δ=+29.2  -9.5  -8.6  +3.4  +7.7  -1.8
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk007_via02: send_angles (single) [  -3.36,  +53.63,  +14.16,   +0.57,  -64.07,  -30.18]  speed=20 wait=1.0s  (pre max|Δ|=8.15°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.44° (tol 3.0°)
       [VIA   ] step  2  Δ= +8.2  -4.3  -3.6  +1.5  +2.0  -1.3  着いた
[SEND] pi05_chunk007_via05: send_angles (single) [  +5.63,  +51.36,  +12.00,   +1.84,  -62.23,  -30.64]  speed=20 wait=1.0s  (pre max|Δ|=9.14°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.42° (tol 3.0°)
       [VIA   ] step  5  Δ= +9.1  -4.7  -3.6  +1.3  +2.1  -0.8  着いた
[SEND] pi05_chunk007_via08: send_angles (single) [ +14.74,  +49.02,   +9.69,   +2.40,  -59.56,  -30.64]  speed=20 wait=1.0s  (pre max|Δ|=9.30°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.57° (tol 3.0°)
       [VIA   ] step  8  Δ= +9.3  -4.8  -3.8  +0.6  +2.9  -0.3  着いた
[SEND] pi05_chunk007_via09: send_angles (single) [ +17.71,  +48.41,   +9.10,   +2.47,  -58.59,  -30.66]  speed=20 wait=1.0s  (pre max|Δ|=3.21°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.47° (tol 3.0°)
       [VIA   ] step  9  Δ= +3.2  -3.2  -2.1  +0.1  +1.3  -0.3  着いた
[STATE ] 目標を渡す  目標と実測の最大差 2.47°（関節 j1）
[008] 推論 652ms  10ステップ先  Δ=+23.0  -2.8  -7.6  +0.4  +4.3  -0.5
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk008_via02: send_angles (single) [ +26.07,  +46.36,   +6.91,   +2.70,  -55.58,  -30.75]  speed=20 wait=1.0s  (pre max|Δ|=8.41°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.41° (tol 3.0°)
       [VIA   ] step  2  Δ= +8.4  -4.5  -4.1  +0.1  +3.2  -0.4  着いた
[SEND] pi05_chunk008_via05: send_angles (single) [ +35.26,  +44.84,   +4.67,   +2.88,  -52.83,  -30.82]  speed=20 wait=1.0s  (pre max|Δ|=9.34°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.53° (tol 3.0°)
       [VIA   ] step  5  Δ= +9.3  -3.9  -3.8  +0.2  +3.1  -0.4  着いた
[SEND] pi05_chunk008_via08: send_angles (single) [ +40.73,  +46.67,   +3.33,   +3.01,  -53.48,  -30.86]  speed=20 wait=1.0s  (pre max|Δ|=5.32°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.50° (tol 3.0°)
       [VIA   ] step  8  Δ= +5.3  -0.7  -2.9  +0.1  -0.6  -0.4  着いた
[SEND] pi05_chunk008_via09: send_angles (single) [ +40.69,  +48.08,   +3.36,   +3.05,  -54.51,  -30.84]  speed=20 wait=1.0s  (pre max|Δ|=1.60°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.47° (tol 3.0°)
       [VIA   ] step  9  Δ= -0.2  +0.3  -1.5  -0.2  -1.6  -0.3  着いた
[STATE ] 目標を渡す  目標と実測の最大差 1.47°（関節 j2）
[009] 推論 1568ms  10ステップ先  Δ= +0.2 +13.6  -2.0  +0.5 -14.8  -0.3
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk009_via02: send_angles (single) [ +40.93,  +53.30,   +3.28,   +3.26,  -59.32,  -30.85]  speed=20 wait=1.0s  (pre max|Δ|=5.45°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.55° (tol 3.0°)
       [VIA   ] step  2  Δ= -0.1  +4.0  -1.5  +0.1  -5.5  -0.3  着いた
[SEND] pi05_chunk009_via05: send_angles (single) [ +41.38,  +58.49,   +3.15,   +3.45,  -63.95,  -30.81]  speed=20 wait=1.0s  (pre max|Δ|=4.98°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.68° (tol 3.0°)
       [VIA   ] step  5  Δ= +0.3  +4.0  -1.7  +0.3  -5.0  -0.2  着いた
[SEND] pi05_chunk009_via08: send_angles (single) [ +41.19,  +62.24,   +2.83,   +3.62,  -67.30,  -30.83]  speed=20 wait=1.0s  (pre max|Δ|=3.85°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.00° (tol 3.0°)
       [VIA   ] step  8  Δ= +0.2  +2.7  -2.0  +0.5  -3.8  -0.3  着いた
[SEND] pi05_chunk009_via09: send_angles (single) [ +41.27,  +62.89,   +2.80,   +3.64,  -67.87,  -30.83]  speed=20 wait=1.0s  (pre max|Δ|=2.03°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.94° (tol 3.0°)
       [VIA   ] step  9  Δ= +0.2  -0.4  -2.0  +0.4  +0.4  +0.3  着いた
[STATE ] 目標を渡す  目標と実測の最大差 1.94°（関節 j2）
[010] 推論 560ms  2ステップ先  Δ= +0.1  -0.9  -2.0  +0.5  +0.3  +0.7  グリッパー→開
       [VIA   ] 中継点 1 点: step 1
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk010_via01: send_angles (single) [ +41.22,  +62.94,   +2.75,   +3.72,  -68.11,  -30.85]  speed=20 wait=1.0s  (pre max|Δ|=1.99°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.99° (tol 3.0°)
       [VIA   ] step  1  Δ= -0.0  -0.9  -2.0  +0.4  +0.3  +0.5  着いた
  [Pi] GRIPPER: OPEN result= -1
[STATE ] 目標を渡す  目標と実測の最大差 1.99°（関節 j2）
[011] 推論 641ms  10ステップ先  Δ= -0.2 -18.7  -2.0  -0.5 +17.8  -0.7
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk011_via02: send_angles (single) [ +41.21,  +57.80,   +2.65,   +3.69,  -63.13,  -31.08]  speed=20 wait=1.0s  (pre max|Δ|=6.09°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.31° (tol 3.0°)
       [VIA   ] step  2  Δ= -0.0  -6.1  -2.1  -0.5  +5.2  -0.1  着いた
[SEND] pi05_chunk011_via05: send_angles (single) [ +41.70,  +52.66,   +2.59,   +3.69,  -57.71,  -31.38]  speed=20 wait=1.0s  (pre max|Δ|=7.45°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.15° (tol 3.0°)
       [VIA   ] step  5  Δ= +0.5  -7.4  -2.2  -0.5  +6.8  -0.6  着いた
[SEND] pi05_chunk011_via08: send_angles (single) [ +41.55,  +47.10,   +2.77,   +3.75,  -52.37,  -31.68]  speed=20 wait=1.0s  (pre max|Δ|=7.65°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.20° (tol 3.0°)
       [VIA   ] step  8  Δ= +0.3  -7.7  -2.0  -0.5  +6.2  -0.9  着いた
[SEND] pi05_chunk011_via09: send_angles (single) [ +41.05,  +45.19,   +2.76,   +3.68,  -50.54,  -31.76]  speed=20 wait=1.0s  (pre max|Δ|=4.11°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.44° (tol 3.0°)
       [VIA   ] step  9  Δ= -0.2  -4.1  -2.0  -0.5  +2.4  -0.8  着いた
[STATE ] 目標を渡す  目標と実測の最大差 2.44°（関節 j1）
[012] 推論 1488ms  10ステップ先  Δ=-21.4 -26.5  -2.7  -3.7 +30.7  +0.1
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk012_via02: send_angles (single) [ +35.76,  +38.39,   +2.55,   +2.82,  -42.22,  -31.64]  speed=20 wait=1.0s  (pre max|Δ|=9.24°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.21° (tol 3.0°)
       [VIA   ] step  2  Δ= -5.5  -9.2  -2.2  -1.2  +8.5  -0.4  着いた
[SEND] pi05_chunk012_via05: send_angles (single) [ +29.05,  +31.04,   +2.29,   +1.68,  -32.65,  -31.39]  speed=20 wait=1.0s  (pre max|Δ|=9.97°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.18° (tol 3.0°)
       [VIA   ] step  5  Δ= -7.2  -9.6  -2.4  -1.1 +10.0  -0.1  着いた
[SEND] pi05_chunk012_via08: send_angles (single) [ +22.25,  +23.59,   +2.07,   +0.63,  -23.14,  -31.18]  speed=20 wait=1.0s  (pre max|Δ|=9.90°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.98° (tol 3.0°)
       [VIA   ] step  8  Δ= -6.8  -9.6  -2.0  -1.4  +9.9  +0.1  着いた
[SEND] pi05_chunk012_via09: send_angles (single) [ +19.83,  +21.15,   +1.99,   +0.34,  -20.03,  -31.11]  speed=20 wait=1.0s  (pre max|Δ|=4.42°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.05° (tol 3.0°)
       [VIA   ] step  9  Δ= -2.4  -4.4  -2.0  -0.6  +3.3  +0.2  着いた
[STATE ] 目標を渡す  目標と実測の最大差 2.05°（関節 j2）
[013] 推論 568ms  10ステップ先  Δ=-16.6 -19.4  -1.8  +0.3 +16.3  +0.4
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk013_via02: send_angles (single) [ +12.95,  +12.64,   +2.19,   +0.15,  -11.38,  -31.00]  speed=20 wait=1.0s  (pre max|Δ|=10.47°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.85° (tol 3.0°)
       [VIA   ] step  2  Δ= -6.6 -10.5  -1.8  +0.2  +8.8  +0.3  着いた
[SEND] pi05_chunk013_via05: send_angles (single) [  +6.10,   +5.31,   +2.24,   +0.18,   -4.14,  -30.92]  speed=20 wait=1.0s  (pre max|Δ|=8.92°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.80° (tol 3.0°)
       [VIA   ] step  5  Δ= -7.2  -8.9  -1.8  -0.2  +7.5  +0.4  着いた
[SEND] pi05_chunk013_via08: send_angles (single) [  +2.84,   +3.23,   +2.24,   +0.22,   -3.26,  -30.90]  speed=20 wait=1.0s  (pre max|Δ|=3.57°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.80° (tol 3.0°)
       [VIA   ] step  8  Δ= -3.6  -3.5  -1.8  +0.1  +1.2  +0.4  着いた
[SEND] pi05_chunk013_via09: send_angles (single) [  +3.02,   +3.67,   +2.21,   +0.27,   -3.93,  -30.90]  speed=20 wait=1.0s  (pre max|Δ|=1.83°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.83° (tol 3.0°)
       [VIA   ] step  9  Δ= +0.5  -0.9  -1.8  +0.2  -0.4  +0.4  着いた
[STATE ] 目標を渡す  目標と実測の最大差 1.83°（関節 j2）

[014] 推論 1648ms  10ステップ先  Δ= -1.4  -1.7  -2.0  +0.2  +0.5  +0.4
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > [SEND] pi05_chunk014_via02: send_angles (single) [  +1.32,   +2.98,   +2.12,   +0.26,   -3.26,  -30.90]  speed=20 wait=1.0s  (pre max|Δ|=1.92°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.92° (tol 3.0°)
       [VIA   ] step  2  Δ= -1.2  -1.6  -1.9  +0.2  +0.3  +0.4  着いた
[SEND] pi05_chunk014_via05: send_angles (single) [  +1.16,   +2.91,   +2.09,   +0.24,   -3.17,  -30.90]  speed=20 wait=1.0s  (pre max|Δ|=1.95°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.95° (tol 3.0°)
       [VIA   ] step  5  Δ= +0.2  -1.7  -2.0  +0.2  +0.3  +0.4  着いた
[SEND] pi05_chunk014_via08: send_angles (single) [  +1.12,   +2.85,   +2.08,   +0.25,   -2.98,  -30.90]  speed=20 wait=1.0s  (pre max|Δ|=1.96°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.96° (tol 3.0°)
       [VIA   ] step  8  Δ= +0.3  -1.7  -2.0  +0.2  +0.5  +0.3  着いた
[SEND] pi05_chunk014_via09: send_angles (single) [  +1.16,   +2.84,   +2.07,   +0.26,   -3.03,  -30.90]  speed=20 wait=1.0s  (pre max|Δ|=1.97°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.97° (tol 3.0°)
       [VIA   ] step  9  Δ= +0.3  -1.7  -2.0  +0.2  +0.4  +0.3  着いた
[STATE ] 目標を渡す  目標と実測の最大差 1.97°（関節 j2）
[015] 推論 810ms  10ステップ先  Δ= -0.3  -1.8  -2.0  +0.1  +0.6  +0.3
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > h
[SEND] pi05_home: send_angles (single) [  +0.00,   +0.00,   +0.00,   +0.00,   +0.00,  -30.00]  speed=20 wait=1.0s  (pre max|Δ|=4.57°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.58° (tol 2.5°)
[DONE  ] 記録: /Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_182650
```

18:30 と 18:32 の回は、爪を閉じたときにブロックが爪の間に入っておらず、つかみ損ねたので途中で h で止めました。動画では、爪の先がブロックの手前に下り、ブロックを押して位置をずらしています。

```
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % python3 pi05/run_policy_client.py --raw-dir $RAW --steps-per-chunk 10 --via-stride 3 --settle-retries 0 --state-from-target --execute
[SAFE  ] 安全範囲 (学習 19 本 ±10°): j0[-72,+55]  j1[-9,+88]  j2[-46,+41]  j3[-18,+27]  j4[-90,+10]  j5[-51,-14]
[SAFE  ] 肩 j1 の上限は J1_SAFE_MAX=88° で切った (これを超える指令はアームが黙って捨てる / LOG352)  元データ: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
[MODE  ] EXECUTE  steps/chunk=10  max_move=20.0°  log=/Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_183027
[CAMERA] 写り方 dy=-5.1 dx=+0.3 response=0.502 → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[CAMERA] 基準: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes/run_0001_20261019_183454/frames/000000.jpg
[POLICY] 接続 ws://localhost:8000  metadata={}
[GRIP  ] 開始時のグリッパー開放は, 最初の目標が検査を通ってから行います (爪が閉じていたら手で開けておく)
[STATE ] 実測を渡す (直前に送った目標がない)
[000] 推論 750ms  10ステップ先  Δ=-10.6 +21.7  +5.6  -2.5 -25.1  +2.2
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[GRIP  ] 開始時にグリッパーを開く
  [Pi] GRIPPER: OPEN result= -1
[SEND] pi05_chunk000_via02: send_angles (single) [  -3.03,   +6.71,   +2.52,   -0.45,   -6.12,  -29.69]  speed=20 wait=1.0s  (pre max|Δ|=6.29°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.29° (tol 3.0°)
       [VIA   ] step  2  Δ= -2.9  +5.4  +0.9  -0.5  -6.3  +0.5  着いた
[SEND] pi05_chunk000_via05: send_angles (single) [  -6.17,  +13.65,   +4.37,   -1.23,  -13.97,  -28.97]  speed=20 wait=1.0s  (pre max|Δ|=9.14°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.11° (tol 3.0°)
       [VIA   ] step  5  Δ= -3.0  +6.0  +0.9  -1.2  -9.1  +0.9  着いた
[SEND] pi05_chunk000_via08: send_angles (single) [  -9.54,  +20.44,   +6.55,   -2.18,  -22.05,  -28.21]  speed=20 wait=1.0s  (pre max|Δ|=9.14°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.00° (tol 3.0°)
       [VIA   ] step  8  Δ= -3.2  +5.7  +1.2  -1.3  -9.1  +1.0  着いた
[SEND] pi05_chunk000_via09: send_angles (single) [ -10.84,  +22.97,   +7.17,   -2.43,  -24.95,  -28.01]  speed=20 wait=1.0s  (pre max|Δ|=3.42°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.93° (tol 3.0°)
       [VIA   ] step  9  Δ= -1.1  +1.5  -0.3  -0.5  -3.4  +0.4  着いた
[STATE ] 目標を渡す  目標と実測の最大差 0.93°（関節 j1）
[001] 推論 1490ms  10ステップ先  Δ=-12.1 +21.9  +5.4  -0.3 -28.5  +0.6
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk001_via02: send_angles (single) [ -14.93,  +29.78,   +9.28,   -3.15,  -33.04,  -27.74]  speed=20 wait=1.0s  (pre max|Δ|=8.17°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.98° (tol 3.0°)
       [VIA   ] step  2  Δ= -3.8  +5.9  +1.4  -0.9  -8.2  +0.5  着いた
[SEND] pi05_chunk001_via05: send_angles (single) [ -18.68,  +36.59,  +11.32,   -2.94,  -41.96,  -27.69]  speed=20 wait=1.0s  (pre max|Δ|=9.09°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.11° (tol 3.0°)
       [VIA   ] step  5  Δ= -3.7  +5.8  +1.1  +0.2  -9.1  +0.2  着いた
[SEND] pi05_chunk001_via08: send_angles (single) [ -22.21,  +43.46,  +12.95,   -2.69,  -50.75,  -27.64]  speed=20 wait=1.0s  (pre max|Δ|=9.18°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.01° (tol 3.0°)
       [VIA   ] step  8  Δ= -3.8  +5.8  +0.9  +0.7  -9.2  +0.2  着いた
[SEND] pi05_chunk001_via09: send_angles (single) [ -23.29,  +45.75,  +13.31,   -2.59,  -53.40,  -27.61]  speed=20 wait=1.0s  (pre max|Δ|=2.96°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.09° (tol 3.0°)
       [VIA   ] step  9  Δ= -1.4  +1.3  -0.2  +0.3  -3.0  +0.3  着いた
[STATE ] 目標を渡す  目標と実測の最大差 1.09°（関節 j1）
[002] 推論 565ms  10ステップ先  Δ= -6.2 +13.3  +3.9  +0.7 -17.1  +0.4
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk002_via02: send_angles (single) [ -26.67,  +52.59,  +15.16,   -2.82,  -62.09,  -27.55]  speed=20 wait=1.0s  (pre max|Δ|=8.75°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.02° (tol 3.0°)
       [VIA   ] step  2  Δ= -2.9  +5.7  +1.4  +0.1  -8.7  +0.3  着いた
[SEND] pi05_chunk002_via05: send_angles (single) [ -29.26,  +58.25,  +16.98,   -2.63,  -68.33,  -27.53]  speed=20 wait=1.0s  (pre max|Δ|=6.90°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.07° (tol 3.0°)
       [VIA   ] step  5  Δ= -2.9  +4.6  +1.3  -0.2  -6.9  +0.2  着いた
[SEND] pi05_chunk002_via08: send_angles (single) [ -29.96,  +60.18,  +17.74,   -2.22,  -70.52,  -27.51]  speed=20 wait=1.0s  (pre max|Δ|=2.67°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.99° (tol 3.0°)
       [VIA   ] step  8  Δ= -1.1  +0.9  +0.4  -0.1  -2.7  +0.3  着いた
[SEND] pi05_chunk002_via09: send_angles (single) [ -29.97,  +60.18,  +17.66,   -2.20,  -70.43,  -27.49]  speed=20 wait=1.0s  (pre max|Δ|=0.99°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.99° (tol 3.0°)
       [VIA   ] step  9  Δ= +0.4  -1.0  +0.4  -0.3  +0.8  +0.2  着いた
[STATE ] 目標を渡す  目標と実測の最大差 0.99°（関節 j1）
[003] 推論 565ms  10ステップ先  Δ= +0.8  +3.8  -4.4  -4.2  +8.9  +0.2
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk003_via02: send_angles (single) [ -29.67,  +61.77,  +16.02,   -3.54,  -68.27,  -27.46]  speed=20 wait=1.0s  (pre max|Δ|=2.92°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.20° (tol 3.0°)
       [VIA   ] step  2  Δ= +0.7  +0.6  -1.3  -1.6  +2.9  +0.2  着いた
[SEND] pi05_chunk003_via05: send_angles (single) [ -29.40,  +63.39,  +14.33,   -4.89,  -65.00,  -27.46]  speed=20 wait=1.0s  (pre max|Δ|=4.43°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.13° (tol 3.0°)
       [VIA   ] step  5  Δ= -0.1  +0.6  -2.9  -1.8  +4.4  +0.2  着いた
[SEND] pi05_chunk003_via08: send_angles (single) [ -29.50,  +64.74,  +13.12,   -5.97,  -62.56,  -27.44]  speed=20 wait=1.0s  (pre max|Δ|=3.18°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.33° (tol 3.0°)
       [VIA   ] step  8  Δ= +0.0  +0.5  -2.3  -1.5  +3.2  +0.2  着いた
[SEND] pi05_chunk003_via09: send_angles (single) [ -29.58,  +64.95,  +12.91,   -6.15,  -62.29,  -27.44]  speed=20 wait=1.0s  (pre max|Δ|=1.60°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.16° (tol 3.0°)
       [VIA   ] step  9  Δ= +0.3  -0.5  -0.9  -0.6  +1.6  +0.4  着いた
[STATE ] 目標を渡す  目標と実測の最大差 1.16°（関節 j4）
[004] 推論 1555ms  4ステップ先  Δ= +0.5  -0.1  -1.5  -1.1  +2.0  +0.5  グリッパー→閉
       [VIA   ] 中継点 2 点: step 2, 3
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk004_via02: send_angles (single) [ -29.39,  +65.50,  +12.29,   -6.84,  -61.49,  -27.38]  speed=20 wait=1.0s  (pre max|Δ|=1.79°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.00° (tol 3.0°)
       [VIA   ] step  2  Δ= +0.5  -0.1  -1.5  -1.1  +1.8  +0.5  着いた
[SEND] pi05_chunk004_via03: send_angles (single) [ -29.39,  +65.50,  +12.29,   -6.84,  -61.49,  -27.38]  speed=20 wait=1.0s  (pre max|Δ|=1.00°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.00° (tol 3.0°)
       [VIA   ] step  3  Δ= +0.6  -0.4  -0.4  -0.4  +1.0  +0.4  着いた
  [Pi] GRIPPER: VALUE=20 speed=100 result= -1
[STATE ] 目標を渡す  目標と実測の最大差 1.00°（関節 j4）
[005] 推論 652ms  10ステップ先  Δ= +0.9  -3.6  +5.5  +1.8  -3.8  +0.4
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk005_via02: send_angles (single) [ -29.47,  +64.68,  +13.56,   -6.19,  -62.76,  -27.35]  speed=20 wait=1.0s  (pre max|Δ|=1.61°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.35° (tol 3.0°)
       [VIA   ] step  2  Δ= +0.5  -1.2  +1.6  +0.6  -0.3  +0.2  着いた
[SEND] pi05_chunk005_via05: send_angles (single) [ -29.42,  +63.52,  +15.47,   -5.50,  -64.47,  -27.23]  speed=20 wait=1.0s  (pre max|Δ|=3.26°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.81° (tol 3.0°)
       [VIA   ] step  5  Δ= +0.6  -2.1  +3.3  +1.1  -2.0  +0.4  着いた
[SEND] pi05_chunk005_via08: send_angles (single) [ -29.13,  +62.65,  +17.19,   -5.09,  -65.94,  -27.16]  speed=20 wait=1.0s  (pre max|Δ|=3.28°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.24° (tol 3.0°)
       [VIA   ] step  8  Δ= +0.7  -1.7  +3.1  +1.3  -3.3  +0.3  着いた
[SEND] pi05_chunk005_via09: send_angles (single) [ -29.07,  +62.34,  +17.48,   -5.01,  -66.32,  -27.17]  speed=20 wait=1.0s  (pre max|Δ|=1.55°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.46° (tol 3.0°)
       [VIA   ] step  9  Δ= +0.4  -1.6  +1.4  +0.6  -1.5  -0.0  着いた
[STATE ] 目標を渡す  目標と実測の最大差 1.46°（関節 j1）
[006] 推論 560ms  10ステップ先  Δ= +1.2  -2.9  +2.8  +1.2  -3.6  -0.4
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk006_via02: send_angles (single) [ -29.11,  +61.47,  +18.86,   -4.28,  -67.72,  -27.13]  speed=20 wait=1.0s  (pre max|Δ|=2.52°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.63° (tol 3.0°)
       [VIA   ] step  2  Δ= +0.2  -2.3  +2.5  +1.0  -2.3  -0.3  着いた
[SEND] pi05_chunk006_via05: send_angles (single) [ -29.37,  +61.19,  +19.53,   -4.13,  -68.63,  -27.06]  speed=20 wait=1.0s  (pre max|Δ|=1.91°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.91° (tol 3.0°)
       [VIA   ] step  5  Δ= -0.6  -1.9  +1.2  +0.3  -1.7  -0.5  着いた
[SEND] pi05_chunk006_via08: send_angles (single) [ -28.89,  +61.10,  +19.34,   -4.22,  -69.07,  -27.12]  speed=20 wait=1.0s  (pre max|Δ|=2.00°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.00° (tol 3.0°)
       [VIA   ] step  8  Δ= -0.1  -2.0  +0.5  +0.1  -1.4  -0.6  着いた
[SEND] pi05_chunk006_via09: send_angles (single) [ -28.11,  +60.88,  +19.11,   -4.14,  -68.95,  -27.24]  speed=20 wait=1.0s  (pre max|Δ|=2.22°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.13° (tol 3.0°)
       [VIA   ] step  9  Δ= +0.6  -2.2  +0.3  +0.1  -0.9  -0.6  着いた
[STATE ] 目標を渡す  目標と実測の最大差 2.13°（関節 j1）
[007] 推論 580ms  10ステップ先  Δ=+16.6  -5.9  -3.0  +2.5  +1.4  -2.4
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk007_via02: send_angles (single) [ -28.08,  +60.55,  +19.64,   -4.18,  -69.69,  -27.22]  speed=20 wait=1.0s  (pre max|Δ|=2.46°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.46° (tol 3.0°)
       [VIA   ] step  2  Δ= +0.2  -2.5  +0.7  -0.7  -1.7  -0.5  着いた
[SEND] pi05_chunk007_via05: send_angles (single) [ -23.10,  +59.56,  +18.31,   -3.30,  -69.02,  -27.76]  speed=20 wait=1.0s  (pre max|Δ|=5.20°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.40° (tol 3.0°)
       [VIA   ] step  5  Δ= +5.2  -3.4  -1.4  +0.2  +0.1  -1.1  着いた
[SEND] pi05_chunk007_via08: send_angles (single) [ -14.01,  +57.49,  +16.38,   -1.48,  -67.23,  -28.82]  speed=20 wait=1.0s  (pre max|Δ|=9.45°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.53° (tol 3.0°)
       [VIA   ] step  8  Δ= +9.5  -4.5  -3.1  +1.9  +1.9  -1.8  着いた
[SEND] pi05_chunk007_via09: send_angles (single) [ -11.72,  +57.11,  +15.88,   -0.97,  -66.65,  -29.07]  speed=20 wait=1.0s  (pre max|Δ|=2.91°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.47° (tol 3.0°)
       [VIA   ] step  9  Δ= +2.4  -2.9  -1.8  +0.6  +1.7  -0.9  着いた
[STATE ] 目標を渡す  目標と実測の最大差 2.47°（関節 j1）
[008] 推論 1493ms  10ステップ先  Δ=+28.8  -9.1  -8.3  +3.8  +8.2  -1.9
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk008_via02: send_angles (single) [  -3.88,  +55.16,  +14.27,   +0.57,  -64.85,  -29.99]  speed=20 wait=1.0s  (pre max|Δ|=7.98°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.32° (tol 3.0°)
       [VIA   ] step  2  Δ= +8.0  -4.3  -3.3  +1.7  +2.3  -1.2  着いた
[SEND] pi05_chunk008_via05: send_angles (single) [  +4.94,  +53.10,  +12.16,   +1.88,  -63.12,  -30.55]  speed=20 wait=1.0s  (pre max|Δ|=8.98°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.27° (tol 3.0°)
       [VIA   ] step  5  Δ= +9.0  -4.4  -3.5  +1.9  +2.1  -0.9  着いた
[SEND] pi05_chunk008_via08: send_angles (single) [ +14.22,  +50.96,   +9.86,   +2.66,  -60.21,  -30.71]  speed=20 wait=1.0s  (pre max|Δ|=9.48°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.47° (tol 3.0°)
       [VIA   ] step  8  Δ= +9.5  -4.4  -3.5  +0.7  +3.1  -0.5  着いた
[SEND] pi05_chunk008_via09: send_angles (single) [ +16.90,  +50.51,   +9.28,   +2.74,  -59.25,  -30.67]  speed=20 wait=1.0s  (pre max|Δ|=2.92°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.48° (tol 3.0°)
       [VIA   ] step  9  Δ= +2.8  -2.9  -1.9  -0.1  +1.2  -0.4  着いた
[STATE ] 目標を渡す  目標と実測の最大差 2.48°（関節 j1）
[009] 推論 584ms  10ステップ先  Δ=+22.2  -4.6  -7.1  +0.5  +4.9  -0.5
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > h
[SEND] pi05_home: send_angles (single) [  +0.00,   +0.00,   +0.00,   +0.00,   +0.00,  -30.00]  speed=20 wait=1.0s  (pre max|Δ|=59.32°, post-send timeout 10.9s)
[SEND] arrival OK: max|Δ|=1.93° (tol 2.5°)
[DONE  ] 記録: /Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_183027
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % python3 pi05/run_policy_client.py --raw-dir $RAW --steps-per-chunk 10 --via-stride 3 --settle-retries 0 --state-from-target --execute
[SAFE  ] 安全範囲 (学習 19 本 ±10°): j0[-72,+55]  j1[-9,+88]  j2[-46,+41]  j3[-18,+27]  j4[-90,+10]  j5[-51,-14]
[SAFE  ] 肩 j1 の上限は J1_SAFE_MAX=88° で切った (これを超える指令はアームが黙って捨てる / LOG352)  元データ: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
[MODE  ] EXECUTE  steps/chunk=10  max_move=20.0°  log=/Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_183241
[CAMERA] 写り方 dy=-5.9 dx=-0.5 response=0.369 → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[CAMERA] 基準: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes/run_0001_20261019_183454/frames/000000.jpg
[POLICY] 接続 ws://localhost:8000  metadata={}
[GRIP  ] 開始時のグリッパー開放は, 最初の目標が検査を通ってから行います (爪が閉じていたら手で開けておく)
[STATE ] 実測を渡す (直前に送った目標がない)
[000] 推論 561ms  10ステップ先  Δ=-10.1 +19.3  +3.6  +1.0 -22.1  +1.3
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[GRIP  ] 開始時にグリッパーを開く
  [Pi] GRIPPER: OPEN result= -1
[SEND] pi05_chunk000_via02: send_angles (single) [  -1.77,   +4.35,   +2.61,   +0.46,   -3.99,  -30.10]  speed=20 wait=1.0s  (pre max|Δ|=3.73°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.62° (tol 3.0°)
       [VIA   ] step  2  Δ= -1.6  +2.9  +0.7  +0.2  -3.7  +0.1  着いた
[SEND] pi05_chunk000_via05: send_angles (single) [  -5.14,  +11.07,   +3.91,   +0.64,  -11.97,  -29.59]  speed=20 wait=1.0s  (pre max|Δ|=9.34°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.90° (tol 3.0°)
       [VIA   ] step  5  Δ= -3.0  +5.9  +0.4  +0.5  -9.4  +0.6  着いた
[SEND] pi05_chunk000_via08: send_angles (single) [  -8.98,  +18.26,   +5.15,   +1.08,  -19.68,  -29.22]  speed=20 wait=1.0s  (pre max|Δ|=8.61°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.07° (tol 3.0°)
       [VIA   ] step  8  Δ= -3.7  +6.3  +0.5  +0.8  -8.6  +0.6  着いた
[SEND] pi05_chunk000_via09: send_angles (single) [ -10.31,  +20.75,   +5.49,   +1.28,  -22.40,  -29.12]  speed=20 wait=1.0s  (pre max|Δ|=3.16°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.13° (tol 3.0°)
       [VIA   ] step  9  Δ= -1.3  +1.4  -0.5  +0.6  -3.2  +0.2  着いた
[STATE ] 目標を渡す  目標と実測の最大差 1.13°（関節 j1）
[001] 推論 600ms  10ステップ先  Δ=-12.7 +22.6  +5.3  +0.3 -30.3  +0.7
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk001_via02: send_angles (single) [ -13.75,  +27.44,   +7.27,   +1.02,  -30.77,  -28.89]  speed=20 wait=1.0s  (pre max|Δ|=8.27°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.03° (tol 3.0°)
       [VIA   ] step  2  Δ= -3.2  +5.6  +1.1  +0.2  -8.3  +0.5  着いた
[SEND] pi05_chunk001_via05: send_angles (single) [ -17.68,  +34.52,   +9.19,   +1.06,  -40.13,  -28.79]  speed=20 wait=1.0s  (pre max|Δ|=9.72°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.89° (tol 3.0°)
       [VIA   ] step  5  Δ= -3.8  +6.0  +1.2  -0.1  -9.7  +0.3  着いた
[SEND] pi05_chunk001_via08: send_angles (single) [ -21.89,  +42.08,  +11.03,   +1.15,  -49.89,  -28.70]  speed=20 wait=1.0s  (pre max|Δ|=10.34°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.98° (tol 3.0°)
       [VIA   ] step  8  Δ= -4.7  +6.7  +1.3  -0.3 -10.3  +0.3  着いた
[SEND] pi05_chunk001_via09: send_angles (single) [ -23.24,  +44.48,  +11.46,   +1.18,  -52.81,  -28.64]  speed=20 wait=1.0s  (pre max|Δ|=2.89°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.95° (tol 3.0°)
       [VIA   ] step  9  Δ= -1.7  +1.4  -0.2  -0.3  -2.9  +0.3  着いた
[STATE ] 目標を渡す  目標と実測の最大差 0.95°（関節 j1）
[002] 推論 568ms  10ステップ先  Δ= -9.7 +16.3  +4.3  -0.1 -21.5  +0.2
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk002_via02: send_angles (single) [ -27.47,  +51.17,  +13.32,   +0.86,  -62.23,  -28.63]  speed=20 wait=1.0s  (pre max|Δ|=9.32°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.94° (tol 3.0°)
       [VIA   ] step  2  Δ= -4.1  +5.7  +1.4  -0.5  -9.3  +0.2  着いた
[SEND] pi05_chunk002_via05: send_angles (single) [ -31.04,  +57.71,  +15.00,   +0.88,  -70.24,  -28.63]  speed=20 wait=1.0s  (pre max|Δ|=8.55°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.00° (tol 3.0°)
       [VIA   ] step  5  Δ= -4.1  +5.6  +1.1  -0.5  -8.6  +0.2  着いた
[SEND] pi05_chunk002_via08: send_angles (single) [ -33.00,  +61.34,  +16.14,   +1.22,  -74.09,  -28.60]  speed=20 wait=1.0s  (pre max|Δ|=4.22°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=0.97° (tol 3.0°)
       [VIA   ] step  8  Δ= -2.2  +2.6  +0.8  -0.1  -4.2  +0.2  着いた
[SEND] pi05_chunk002_via09: send_angles (single) [ -33.06,  +61.74,  +16.27,   +1.30,  -74.43,  -28.59]  speed=20 wait=1.0s  (pre max|Δ|=0.57°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.01° (tol 3.0°)
       [VIA   ] step  9  Δ= +0.1  -0.6  -0.1  -0.2  -0.3  +0.2  着いた
[STATE ] 目標を渡す  目標と実測の最大差 1.01°（関節 j1）
[003] 推論 1551ms  10ステップ先  Δ= -0.6  +2.7  -0.2  -1.1  -0.9  +0.2
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk003_via02: send_angles (single) [ -33.55,  +63.68,  +17.21,   +1.33,  -76.20,  -28.58]  speed=20 wait=1.0s  (pre max|Δ|=2.03°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.00° (tol 3.0°)
       [VIA   ] step  2  Δ= -0.4  +0.9  +0.9  -0.2  -2.0  +0.2  着いた
       [VIA   ] step  5  Δ= -0.5  -0.5  +0.2  -0.2  +0.4  -0.1  送らず (0.5° 以下)
[SEND] pi05_chunk003_via08: send_angles (single) [ -33.66,  +65.04,  +16.60,   +0.72,  -75.70,  -28.57]  speed=20 wait=1.0s  (pre max|Δ|=1.11°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.73° (tol 3.0°)
       [VIA   ] step  8  Δ= -0.5  +0.4  -0.7  -0.8  +1.1  -0.1  着いた
[SEND] pi05_chunk003_via09: send_angles (single) [ -33.70,  +65.50,  +16.11,   +0.42,  -75.03,  -28.57]  speed=20 wait=1.0s  (pre max|Δ|=2.40°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.11° (tol 3.0°)
       [VIA   ] step  9  Δ= -0.5  -0.5  -1.2  -0.7  +2.4  -0.5  着いた
[STATE ] 目標を渡す  目標と実測の最大差 1.11°（関節 j2）
[004] 推論 706ms  9ステップ先  Δ= -0.3  +1.3  -2.9  -1.2  +3.0  -0.6  グリッパー→閉
       [VIA   ] 中継点 3 点: step 2, 5, 8
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk004_via02: send_angles (single) [ -33.57,  +66.08,  +15.98,   +0.26,  -74.66,  -28.58]  speed=20 wait=1.0s  (pre max|Δ|=1.24°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.24° (tol 3.0°)
       [VIA   ] step  2  Δ= -0.3  -0.4  -1.2  -0.4  +1.0  -0.5  着いた
[SEND] pi05_chunk004_via05: send_angles (single) [ -33.69,  +66.99,  +15.05,   -0.31,  -73.65,  -28.60]  speed=20 wait=1.0s  (pre max|Δ|=2.17°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.12° (tol 3.0°)
       [VIA   ] step  5  Δ= -0.4  +0.0  -2.2  -0.9  +1.6  -0.6  着いた
[SEND] pi05_chunk004_via08: send_angles (single) [ -33.60,  +67.72,  +14.35,   -0.54,  -73.03,  -28.59]  speed=20 wait=1.0s  (pre max|Δ|=1.82°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.29° (tol 3.0°)
       [VIA   ] step  8  Δ= -0.2  -0.3  -1.8  -0.5  +0.5  -0.5  着いた
  [Pi] GRIPPER: VALUE=20 speed=100 result= -1
[STATE ] 目標を渡す  目標と実測の最大差 1.20°（関節 j2）
[005] 推論 564ms  10ステップ先  Δ=+20.9  -7.3  -3.2  +3.4  +4.0  -2.6
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > 
[SEND] pi05_chunk005_via02: send_angles (single) [ -29.43,  +66.53,  +14.00,   +0.19,  -72.25,  -29.25]  speed=20 wait=1.0s  (pre max|Δ|=3.96°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.02° (tol 3.0°)
       [VIA   ] step  2  Δ= +4.0  -2.1  -1.5  +0.5  +1.1  -0.7  着いた
[SEND] pi05_chunk005_via05: send_angles (single) [ -22.51,  +64.49,  +13.44,   +1.52,  -70.89,  -30.19]  speed=20 wait=1.0s  (pre max|Δ|=6.58°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.39° (tol 3.0°)
       [VIA   ] step  5  Δ= +6.6  -4.1  -1.6  +1.9  +1.8  -1.2  着いた
[SEND] pi05_chunk005_via08: send_angles (single) [ -14.96,  +62.26,  +12.73,   +2.82,  -69.80,  -30.98]  speed=20 wait=1.0s  (pre max|Δ|=7.10°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.33° (tol 3.0°)
       [VIA   ] step  8  Δ= +7.1  -4.6  -2.2  +1.9  +0.7  -1.2  着いた
[SEND] pi05_chunk005_via09: send_angles (single) [ -12.51,  +61.30,  +12.34,   +3.09,  -69.42,  -31.13]  speed=20 wait=1.0s  (pre max|Δ|=3.29°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=2.42° (tol 3.0°)
       [VIA   ] step  9  Δ= +2.8  -3.3  -1.5  +0.5  +0.0  -0.6  着いた
[STATE ] 目標を渡す  目標と実測の最大差 2.42°（関節 j1）
[006] 推論 564ms  10ステップ先  Δ=+25.5  -9.4  -6.3  +2.4  +6.6  -1.8
       [VIA   ] 中継点 4 点: step 2, 5, 8, 9
       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > h
[SEND] pi05_home: send_angles (single) [  +0.00,   +0.00,   +0.00,   +0.00,   +0.00,  -30.00]  speed=20 wait=1.0s  (pre max|Δ|=69.25°, post-send timeout 12.4s)
[SEND] arrival OK: max|Δ|=1.93° (tol 2.5°)
[DONE  ] 記録: /Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_183241
```

【画像】LOG361_09_missed_grasp.jpg つかみ損ねた回（18:30 か 18:32 の回）を横から撮った動画のコマ。0:52 で爪がブロックに当たり、1:02 でブロックが押されて位置がずれ、1:10 で何もない所で爪を閉じている


## 位置D に移ろうとしたところで、手首 j4 が +45.87° のまま動かなくなった

次に位置D を試そうとすると、写り方の確認で止まりました。HOME に戻す前の姿勢を見ると、手首 j4 が +54.93° になっていました。

```
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % python3 pi05/run_policy_client.py --raw-dir $RAW --steps-per-chunk 10 --via-stride 3 --settle-retries 0 --state-from-target --execute
[SAFE  ] 安全範囲 (学習 19 本 ±10°): j0[-72,+55]  j1[-9,+88]  j2[-46,+41]  j3[-18,+27]  j4[-90,+10]  j5[-51,-14]
[SAFE  ] 肩 j1 の上限は J1_SAFE_MAX=88° で切った (これを超える指令はアームが黙って捨てる / LOG352)  元データ: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
[MODE  ] EXECUTE  steps/chunk=10  max_move=20.0°  log=/Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_183456
[CAMERA] 写り方 dy=-10.2 dx=+2.5 response=-0.027 → 測れない (相関が弱く dx/dy が当てにならない (response=-0.027 < 0.20))
[CAMERA] 基準: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes/run_0001_20261019_183454/frames/000000.jpg
[DONE  ] 記録: /Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_183456
[ABORT ] 上カメラの写り方が『測れない』. アームには何も送らずに終了しました.
         相関が弱く dx/dy が当てにならない (response=-0.027 < 0.20)
         pi05/camera_align.py で合わせ直す (iPhone を付け直す / 連係カメラを開き直す).
         この写り方のまま続けるなら --ignore-framing
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % python3 pi05/camera_align.py --raw-dir $RAW --episode run_0001_20261019_193404 --scale 5
[REF   ] 基準画像: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes/run_0001_20261019_193404/frames/000000.jpg
[REF   ] お手本 run_0001_20261019_193404 (つかんだ瞬間の j0 = -61.6°)
[REF   ] 重なった画像のブロックに実物のブロックを合わせると, お手本と同じ位置に置ける
[ALIGN ] |dy| <= 20 なら OK. アームは HOME に置いた状態で合わせる. q または Esc で終了 (ファイルには何も書かない)
[ALIGN ] dy=  -8.2  dx=  -4.8  response=0.400  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -9.5  dx=  -5.1  response=0.286  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -8.5  dx=  -3.2  response=0.237  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy= -10.8  dx=  -3.9  response=0.245  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy= -12.3  dx=  -4.0  response=0.266  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy= -14.4  dx=  -4.0  response=0.184  → 測れない (相関が弱く dx/dy が当てにならない (response=0.184 < 0.20))
[ALIGN ] dy= -19.0  dx=  -5.2  response=0.135  → 測れない (相関が弱く dx/dy が当てにならない (response=0.135 < 0.20))
[ALIGN ] dy= -16.7  dx=  -3.2  response=0.138  → 測れない (相関が弱く dx/dy が当てにならない (response=0.138 < 0.20))
[ALIGN ] dy= -19.0  dx=  -3.5  response=0.144  → 測れない (相関が弱く dx/dy が当てにならない (response=0.144 < 0.20))
[ALIGN ] dy= -25.2  dx=  -5.3  response=0.121  → 測れない (相関が弱く dx/dy が当てにならない (response=0.121 < 0.20))
[ALIGN ] dy= -26.7  dx=  -5.1  response=0.155  → 測れない (相関が弱く dx/dy が当てにならない (response=0.155 < 0.20))
[ALIGN ] dy= -30.1  dx=  -5.5  response=0.152  → 測れない (相関が弱く dx/dy が当てにならない (response=0.152 < 0.20))
[ALIGN ] dy= -31.2  dx=  -5.5  response=0.134  → 測れない (相関が弱く dx/dy が当てにならない (response=0.134 < 0.20))
[ALIGN ] dy= -32.4  dx=  -6.0  response=0.128  → 測れない (相関が弱く dx/dy が当てにならない (response=0.128 < 0.20))
[ALIGN ] dy= -34.4  dx=  -4.9  response=0.045  → 測れない (相関が弱く dx/dy が当てにならない (response=0.045 < 0.20))
[ALIGN ] dy= -36.9  dx=  -4.5  response=0.069  → 測れない (相関が弱く dx/dy が当てにならない (response=0.069 < 0.20))
[ALIGN ] dy= -62.0  dx= -33.4  response=-0.003  → 測れない (相関が弱く dx/dy が当てにならない (response=-0.003 < 0.20))
[ALIGN ] dy= -42.2  dx=  -4.9  response=-0.038  → 測れない (相関が弱く dx/dy が当てにならない (response=-0.038 < 0.20))
[ALIGN ] dy= -47.6  dx=  -0.9  response=-0.007  → 測れない (相関が弱く dx/dy が当てにならない (response=-0.007 < 0.20))
[ALIGN ] dy= -44.1  dx=  -0.8  response=-0.013  → 測れない (相関が弱く dx/dy が当てにならない (response=-0.013 < 0.20))
[ALIGN ] dy= -42.1  dx=  -4.0  response=-0.037  → 測れない (相関が弱く dx/dy が当てにならない (response=-0.037 < 0.20))
[ALIGN ] dy= -37.4  dx=  -8.1  response=0.041  → 測れない (相関が弱く dx/dy が当てにならない (response=0.041 < 0.20))
[ALIGN ] dy= -30.7  dx= -16.8  response=0.008  → 測れない (相関が弱く dx/dy が当てにならない (response=0.008 < 0.20))
[ALIGN ] dy= -43.1  dx=  -3.2  response=-0.018  → 測れない (相関が弱く dx/dy が当てにならない (response=-0.018 < 0.20))
[ALIGN ] dy= -36.0  dx= -22.3  response=0.005  → 測れない (相関が弱く dx/dy が当てにならない (response=0.005 < 0.20))
[ALIGN ] dy= -37.2  dx=  -7.0  response=0.052  → 測れない (相関が弱く dx/dy が当てにならない (response=0.052 < 0.20))
[ALIGN ] dy= -34.2  dx= -11.3  response=0.011  → 測れない (相関が弱く dx/dy が当てにならない (response=0.011 < 0.20))
[ALIGN ] dy= -35.5  dx=  -8.6  response=0.070  → 測れない (相関が弱く dx/dy が当てにならない (response=0.070 < 0.20))
[ALIGN ] dy= -34.4  dx=  -7.4  response=0.090  → 測れない (相関が弱く dx/dy が当てにならない (response=0.090 < 0.20))
[ALIGN ] dy= -29.9  dx=  -2.2  response=0.095  → 測れない (相関が弱く dx/dy が当てにならない (response=0.095 < 0.20))
[ALIGN ] dy= -36.1  dx=  -8.0  response=0.063  → 測れない (相関が弱く dx/dy が当てにならない (response=0.063 < 0.20))
[ALIGN ] dy= -35.0  dx=  -7.6  response=0.064  → 測れない (相関が弱く dx/dy が当てにならない (response=0.064 < 0.20))
[ALIGN ] dy= -30.8  dx=  -2.3  response=0.085  → 測れない (相関が弱く dx/dy が当てにならない (response=0.085 < 0.20))
[ALIGN ] dy= -35.9  dx=  -6.8  response=0.066  → 測れない (相関が弱く dx/dy が当てにならない (response=0.066 < 0.20))
^C
[STOP  ] Ctrl-C
[DONE  ] 終了 (何も書いていません)
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % python3 dynamic_tracking_limits/place/place_modules/08_home_from_anywhere.py
python3 -c "from visual_servo_pick import get_daemon_socket, daemon_set_gripper, close_daemon_socket; get_daemon_socket(); daemon_set_gripper(0); close_daemon_socket()"
[INIT] daemon 接続中...
  [WARN] fresh_mode切替不可: daemon error: set_fresh_mode is not available in this pymycobot environment
[INIT] fresh_mode=1
[PRE]  現在姿勢: [-0.61, 1.49, 1.93, -0.26, 54.93, -30.23]
[SEND] HOME へ移動指令
[WAIT] t=2.0s  max_err=2.02°
[DONE] HOME 到達 max_err=2.02°
[POST] 最終姿勢: [-0.61, 1.49, 1.93, -0.17, 2.02, -30.23]
  [WARN] fresh_mode切替不可: daemon error: set_fresh_mode is not available in this pymycobot environment
[EXIT] fresh_mode=0, socket close
  [Pi] GRIPPER: OPEN result= -1
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % python3 pi05/camera_align.py --raw-dir $RAW --episode run_0001_20261019_193404 --scale 5
[REF   ] 基準画像: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes/run_0001_20261019_193404/frames/000000.jpg
[REF   ] お手本 run_0001_20261019_193404 (つかんだ瞬間の j0 = -61.6°)
[REF   ] 重なった画像のブロックに実物のブロックを合わせると, お手本と同じ位置に置ける
[ALIGN ] |dy| <= 20 なら OK. アームは HOME に置いた状態で合わせる. q または Esc で終了 (ファイルには何も書かない)
[ALIGN ] dy=  -8.5  dx=  -5.1  response=0.702  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -9.6  dx=  -4.9  response=0.709  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -8.6  dx=  -4.5  response=0.600  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy= -10.6  dx=  -6.0  response=0.699  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy= -12.5  dx=  -7.0  response=0.691  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy= -13.6  dx=  -6.8  response=0.711  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy= -12.6  dx=  -7.4  response=0.653  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy= -10.6  dx=  -7.9  response=0.691  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -7.6  dx=  -6.5  response=0.716  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -3.5  dx=  -6.7  response=0.562  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -1.0  dx=  -6.6  response=0.581  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -3.6  dx=  -5.6  response=0.296  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -5.2  dx=  -7.5  response=0.510  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -6.4  dx=  -8.3  response=0.479  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -8.6  dx=  -7.4  response=0.566  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy= -10.6  dx=  -8.0  response=0.687  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -9.2  dx=  -7.0  response=0.723  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy= -10.5  dx=  -8.5  response=0.646  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -9.1  dx=  -6.9  response=0.725  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -6.8  dx=  -7.9  response=0.688  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -5.3  dx=  -7.7  response=0.685  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -3.5  dx=  -7.8  response=0.625  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -1.6  dx=  -8.1  response=0.702  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +1.1  dx=  -7.9  response=0.539  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +2.2  dx=  -7.8  response=0.610  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +4.6  dx=  -7.9  response=0.622  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +2.3  dx=  -7.5  response=0.698  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +0.9  dx=  -8.1  response=0.700  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -1.0  dx=  -8.5  response=0.623  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +2.3  dx= -16.8  response=0.569  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +5.4  dx= -20.5  response=0.624  → ずれ (|dx|=20.5 > 20)
[ALIGN ] dy=  +3.8  dx= -14.7  response=0.591  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +5.2  dx=  -5.8  response=0.634  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +6.3  dx=  -6.8  response=0.656  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +7.4  dx=  -9.6  response=0.702  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +6.3  dx=  -9.5  response=0.645  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +3.3  dx=  -8.7  response=0.671  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +0.7  dx=  -8.7  response=0.715  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +3.3  dx= -17.5  response=0.440  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  +2.1  dx= -25.3  response=0.412  → ずれ (|dx|=25.3 > 20)
[ALIGN ] dy=  +0.4  dx= -18.9  response=0.531  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -0.8  dx= -12.4  response=0.704  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -2.4  dx=  -0.5  response=0.768  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -3.4  dx=  -1.5  response=0.759  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -5.0  dx=  -2.2  response=0.693  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -6.3  dx=  -2.2  response=0.637  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -7.4  dx=  -1.6  response=0.757  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -1.5  dx=  -2.5  response=0.721  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -3.6  dx=  -2.0  response=0.670  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -5.3  dx=  -2.4  response=0.763  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -3.7  dx=  -2.0  response=0.666  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -2.6  dx=  -2.4  response=0.651  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -1.5  dx=  -2.0  response=0.682  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -0.4  dx=  -1.5  response=0.221  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -2.9  dx=  -1.9  response=0.250  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy=  -6.4  dx=  -3.2  response=0.202  → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[ALIGN ] dy= -11.2  dx=  -2.9  response=0.153  → 測れない (相関が弱く dx/dy が当てにならない (response=0.153 < 0.20))
[ALIGN ] dy=  -9.3  dx=  -0.7  response=0.069  → 測れない (相関が弱く dx/dy が当てにならない (response=0.069 < 0.20))
[ALIGN ] dy= -10.8  dx=  -1.4  response=0.097  → 測れない (相関が弱く dx/dy が当てにならない (response=0.097 < 0.20))
[ALIGN ] dy= -16.1  dx=  -2.9  response=0.110  → 測れない (相関が弱く dx/dy が当てにならない (response=0.110 < 0.20))
[ALIGN ] dy= -20.6  dx=  -3.8  response=0.097  → 測れない (相関が弱く dx/dy が当てにならない (response=0.097 < 0.20))
[ALIGN ] dy= -19.6  dx=  -3.6  response=0.023  → 測れない (相関が弱く dx/dy が当てにならない (response=0.023 < 0.20))
[ALIGN ] dy= -18.4  dx=  -4.0  response=0.019  → 測れない (相関が弱く dx/dy が当てにならない (response=0.019 < 0.20))
[ALIGN ] dy= -20.4  dx=  -3.7  response=0.032  → 測れない (相関が弱く dx/dy が当てにならない (response=0.032 < 0.20))
[ALIGN ] dy= -18.5  dx=  -3.8  response=0.019  → 測れない (相関が弱く dx/dy が当てにならない (response=0.019 < 0.20))
[ALIGN ] dy= -11.8  dx=  -3.6  response=0.007  → 測れない (相関が弱く dx/dy が当てにならない (response=0.007 < 0.20))
[ALIGN ] dy= -20.9  dx=  -3.4  response=0.097  → 測れない (相関が弱く dx/dy が当てにならない (response=0.097 < 0.20))
[ALIGN ] dy=  +3.1  dx=  -9.2  response=0.003  → 測れない (相関が弱く dx/dy が当てにならない (response=0.003 < 0.20))
[ALIGN ] dy= -20.9  dx=  -3.4  response=0.096  → 測れない (相関が弱く dx/dy が当てにならない (response=0.096 < 0.20))
[ALIGN ] dy=  -7.6  dx=  -7.8  response=0.004  → 測れない (相関が弱く dx/dy が当てにならない (response=0.004 < 0.20))
[ALIGN ] dy= -21.0  dx=  -3.4  response=0.103  → 測れない (相関が弱く dx/dy が当てにならない (response=0.103 < 0.20))
[ALIGN ] dy=  -9.1  dx=  -4.7  response=0.006  → 測れない (相関が弱く dx/dy が当てにならない (response=0.006 < 0.20))
[ALIGN ] dy= -21.0  dx=  -3.4  response=0.101  → 測れない (相関が弱く dx/dy が当てにならない (response=0.101 < 0.20))
[ALIGN ] dy=  +3.5  dx=  -7.5  response=0.003  → 測れない (相関が弱く dx/dy が当てにならない (response=0.003 < 0.20))
[ALIGN ] dy= +28.4  dx=  -7.9  response=0.001  → 測れない (相関が弱く dx/dy が当てにならない (response=0.001 < 0.20))
[ALIGN ] dy= +13.0  dx=  -9.9  response=0.002  → 測れない (相関が弱く dx/dy が当てにならない (response=0.002 < 0.20))
[ALIGN ] dy= -21.2  dx=  -3.4  response=0.105  → 測れない (相関が弱く dx/dy が当てにならない (response=0.105 < 0.20))
[ALIGN ] dy=  -3.2  dx=  -7.1  response=0.004  → 測れない (相関が弱く dx/dy が当てにならない (response=0.004 < 0.20))
[ALIGN ] dy= -11.2  dx=  -5.6  response=0.006  → 測れない (相関が弱く dx/dy が当てにならない (response=0.006 < 0.20))
[ALIGN ] dy= -21.3  dx=  -3.3  response=0.109  → 測れない (相関が弱く dx/dy が当てにならない (response=0.109 < 0.20))
[ALIGN ] dy=  -4.2  dx=  -9.0  response=0.004  → 測れない (相関が弱く dx/dy が当てにならない (response=0.004 < 0.20))
[ALIGN ] dy=  +9.6  dx= -11.6  response=0.002  → 測れない (相関が弱く dx/dy が当てにならない (response=0.002 < 0.20))
[ALIGN ] dy=  -5.5  dx=  -6.8  response=0.005  → 測れない (相関が弱く dx/dy が当てにならない (response=0.005 < 0.20))
[ALIGN ] dy= -21.3  dx=  -3.3  response=0.107  → 測れない (相関が弱く dx/dy が当てにならない (response=0.107 < 0.20))
[ALIGN ] dy= -13.5  dx=  -5.1  response=0.009  → 測れない (相関が弱く dx/dy が当てにならない (response=0.009 < 0.20))
[ALIGN ] dy=  -9.4  dx=  -7.5  response=0.006  → 測れない (相関が弱く dx/dy が当てにならない (response=0.006 < 0.20))
[ALIGN ] dy= -12.5  dx=  -5.0  response=0.008  → 測れない (相関が弱く dx/dy が当てにならない (response=0.008 < 0.20))
[ALIGN ] dy= -13.9  dx=  -6.5  response=0.009  → 測れない (相関が弱く dx/dy が当てにならない (response=0.009 < 0.20))
[ALIGN ] dy= -17.3  dx=  -4.4  response=0.015  → 測れない (相関が弱く dx/dy が当てにならない (response=0.015 < 0.20))
[ALIGN ] dy= -12.6  dx=  -5.6  response=0.008  → 測れない (相関が弱く dx/dy が当てにならない (response=0.008 < 0.20))
^C
[STOP  ] Ctrl-C
[DONE  ] 終了 (何も書いていません)
```

HOME に戻すと一度は戻りましたが、その後、手首 j4 が +45.87° のまま、指令を送っても動かなくなりました。daemon を起動し直しても、アームの電源を入れ直しても変わりません。手首を触っても熱くはなっていませんでした。この日の実機はここで終えています。

```
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % python3 dynamic_tracking_limits/place/place_modules/08_home_from_anywhere.py
python3 -c "from visual_servo_pick import get_daemon_socket, daemon_set_gripper, close_daemon_socket; get_daemon_socket(); daemon_set_gripper(0); close_daemon_socket()"
[INIT] daemon 接続中...
  [WARN] fresh_mode切替不可: daemon error: set_fresh_mode is not available in this pymycobot environment
[INIT] fresh_mode=1
[PRE]  現在姿勢: [-0.61, 1.49, 1.93, -0.17, 45.87, -30.23]
[SEND] HOME へ移動指令
[WAIT] t=2.0s  max_err=45.87°
[WAIT] t=2.6s  max_err=45.87°
[WAIT] t=3.1s  max_err=45.87°
[WAIT] t=3.6s  max_err=45.87°
[WAIT] t=4.2s  max_err=45.87°
[WAIT] t=4.7s  max_err=45.87°
[WAIT] t=5.2s  max_err=45.87°
[WAIT] t=5.7s  max_err=45.87°
[WAIT] t=6.2s  max_err=45.87°
[WAIT] t=6.8s  max_err=45.87°
[WAIT] t=7.3s  max_err=45.87°
[WAIT] t=7.8s  max_err=45.87°
[WAIT] t=8.3s  max_err=45.87°
^C[INTERRUPT] Ctrl+C 検出
[POST] 最終姿勢: [-0.61, 1.49, 1.93, -0.17, 45.87, -30.23]
  [Pi] fresh_mode=0
[EXIT] fresh_mode=0, socket close
^CTraceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/Users/shimazueiichi/r2r2r-scripts/visual_servo_pick.py", line 746, in daemon_set_gripper
    resp = _daemon_request({
           ^^^^^^^^^^^^^^^^^
  File "/Users/shimazueiichi/r2r2r-scripts/visual_servo_pick.py", line 670, in _daemon_request
    chunk = sock.recv(4096)
            ^^^^^^^^^^^^^^^
KeyboardInterrupt

(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % python3 dynamic_tracking_limits/place/place_modules/08_home_from_anywhere.py
python3 -c "from visual_servo_pick import get_daemon_socket, daemon_set_gripper, close_daemon_socket; get_daemon_socket(); daemon_set_gripper(0); close_daemon_socket()"
[INIT] daemon 接続中...
  [WARN] fresh_mode切替不可: daemon error: set_fresh_mode is not available in this pymycobot environment
[INIT] fresh_mode=1
[PRE]  現在姿勢: [-0.61, 1.49, 1.93, -0.17, 45.87, -30.23]
[SEND] HOME へ移動指令
[WAIT] t=2.1s  max_err=44.91°
[WAIT] t=2.6s  max_err=45.00°
[WAIT] t=3.1s  max_err=45.08°
[WAIT] t=3.6s  max_err=45.17°
[WAIT] t=4.1s  max_err=45.26°
[WAIT] t=4.7s  max_err=45.35°
^C[INTERRUPT] Ctrl+C 検出
[POST] 最終姿勢: [0.08, 0.70, 0.52, 0.00, 45.35, -30.23]
  [WARN] fresh_mode切替不可: daemon error: set_fresh_mode is not available in this pymycobot environment
[EXIT] fresh_mode=0, socket close
  [Pi] GRIPPER: OPEN result= -1
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % python3 pi05/run_policy_client.py --raw-dir $RAW --steps-per-chunk 10 --via-stride 3 --settle-retries 0 --state-from-target --execute
[SAFE  ] 安全範囲 (学習 19 本 ±10°): j0[-72,+55]  j1[-9,+88]  j2[-46,+41]  j3[-18,+27]  j4[-90,+10]  j5[-51,-14]
[SAFE  ] 肩 j1 の上限は J1_SAFE_MAX=88° で切った (これを超える指令はアームが黙って捨てる / LOG352)  元データ: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
[MODE  ] EXECUTE  steps/chunk=10  max_move=20.0°  log=/Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_183801
[CAMERA] 写り方 dy=-34.0 dx=+12.3 response=0.019 → 測れない (相関が弱く dx/dy が当てにならない (response=0.019 < 0.20))
[CAMERA] 基準: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes/run_0001_20261019_183454/frames/000000.jpg
[DONE  ] 記録: /Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261022_183801
[ABORT ] 上カメラの写り方が『測れない』. アームには何も送らずに終了しました.
         相関が弱く dx/dy が当てにならない (response=0.019 < 0.20)
         pi05/camera_align.py で合わせ直す (iPhone を付け直す / 連係カメラを開き直す).
         この写り方のまま続けるなら --ignore-framing
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % cd ~/r2r2r-scripts
python3 dynamic_tracking_limits/place/place_modules/08_home_from_anywhere.py
python3 -c "from visual_servo_pick import get_daemon_socket, daemon_set_gripper, close_daemon_socket; get_daemon_socket(); daemon_set_gripper(0); close_daemon_socket()"
[INIT] daemon 接続中...
  [WARN] fresh_mode切替不可: daemon error: set_fresh_mode is not available in this pymycobot environment
[INIT] fresh_mode=1
[PRE]  現在姿勢: [-0.26, 0.70, 0.79, 0.35, 45.87, -29.61]
[SEND] HOME へ移動指令
[WAIT] t=2.1s  max_err=45.87°
[WAIT] t=2.6s  max_err=45.87°
[WAIT] t=3.1s  max_err=45.87°
[WAIT] t=3.6s  max_err=45.87°
[WAIT] t=4.2s  max_err=45.87°
[WAIT] t=4.7s  max_err=45.87°
[WAIT] t=5.2s  max_err=45.87°
[WAIT] t=5.7s  max_err=45.87°
[WAIT] t=6.2s  max_err=45.87°
[WAIT] t=6.8s  max_err=45.87°
[WAIT] t=7.3s  max_err=45.87°
[WAIT] t=7.8s  max_err=45.87°
^C[WAIT] t=8.3s  max_err=45.87°
[WAIT] t=8.9s  max_err=45.87°
[WAIT] t=9.4s  max_err=45.87°
[WAIT] t=9.9s  max_err=45.87°
[WAIT] t=10.4s  max_err=45.87°
^C[INTERRUPT] Ctrl+C 検出
[POST] 最終姿勢: [-0.26, 0.70, 0.79, 0.26, 45.87, -29.61]
  [WARN] fresh_mode切替不可: daemon error: set_fresh_mode is not available in this pymycobot environment
[EXIT] fresh_mode=0, socket close
^CTraceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/Users/shimazueiichi/r2r2r-scripts/visual_servo_pick.py", line 746, in daemon_set_gripper
    resp = _daemon_request({
           ^^^^^^^^^^^^^^^^^
  File "/Users/shimazueiichi/r2r2r-scripts/visual_servo_pick.py", line 670, in _daemon_request
    chunk = sock.recv(4096)
            ^^^^^^^^^^^^^^^
KeyboardInterrupt

(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % ssh -i ~/.ssh/id_rsa_pi ubuntu@192.168.2.1 "pkill -f '[m]echarm_daemon.py'; sleep 1; pgrep -af '[m]echarm_daemon' || echo 止まっています"
止まっています
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % ssh -i ~/.ssh/id_rsa_pi ubuntu@192.168.2.1 "setsid nohup python3 /home/ubuntu/mecharm_daemon.py </dev/null >>/home/ubuntu/daemon.log 2>&1 &"; sleep 8; ssh -i ~/.ssh/id_rsa_pi ubuntu@192.168.2.1 'tail -3 ~/daemon.log; ss -ltn | grep 5555'
[DAEMON 16:35:15] ✓ MyCobot 初期化完了
[DAEMON 16:35:15] startup_warmup angles=[-0.26, 0.7, 0.79, 0.26, 45.87, -29.7]
[DAEMON 16:35:15] ポート 5555 で待ち受け中...
LISTEN0      1                                 0.0.0.0:5555        0.0.0.0:*    
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % cd ~/r2r2r-scripts
python3 dynamic_tracking_limits/place/place_modules/08_home_from_anywhere.py
python3 -c "from visual_servo_pick import get_daemon_socket, daemon_set_gripper, close_daemon_socket; get_daemon_socket(); daemon_set_gripper(0); close_daemon_socket()"
[INIT] daemon 接続中...
  [WARN] fresh_mode切替不可: daemon error: set_fresh_mode is not available in this pymycobot environment
[INIT] fresh_mode=1
[PRE]  現在姿勢: [-0.26, 0.70, 0.79, 0.26, 45.87, -29.70]
[SEND] HOME へ移動指令
[WAIT] t=2.0s  max_err=45.87°
[WAIT] t=2.6s  max_err=45.87°
[WAIT] t=3.1s  max_err=45.87°
[WAIT] t=3.6s  max_err=45.87°
[WAIT] t=4.1s  max_err=45.87°
[WAIT] t=4.7s  max_err=45.87°
[WAIT] t=5.2s  max_err=45.87°
[WAIT] t=5.7s  max_err=45.87°
[WAIT] t=6.2s  max_err=45.87°
[WAIT] t=6.8s  max_err=45.87°
^C[INTERRUPT] Ctrl+C 検出
[POST] 最終姿勢: [-0.26, 0.70, 0.79, 0.26, 45.87, -29.70]
  [WARN] fresh_mode切替不可: daemon error: set_fresh_mode is not available in this pymycobot environment
[EXIT] fresh_mode=0, socket close
  [Pi] GRIPPER: OPEN result= -1
```

最後に、夕方の Pod のサーバーのログを KIOXIA に持ち帰りました。

```
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % scp -P <SSH_PORT> -i ~/.ssh/id_ed25519 root@<POD_IP>:/workspace/logs/serve.log /Volumes/KIOXIA/r2r2r-data/lab/Log12/serve_evening.log
serve.log                                     100% 3581     9.3KB/s   00:00    
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % 
```

```
INFO:root:Loading model...
INFO:2026-10-22 09:12:17,659:jax._src.xla_bridge:925: Unable to initialize backend 'rocm': module 'jaxlib.xla_extension' has no attribute 'GpuAllocatorConfig'
INFO:jax._src.xla_bridge:Unable to initialize backend 'rocm': module 'jaxlib.xla_extension' has no attribute 'GpuAllocatorConfig'
INFO:2026-10-22 09:12:17,662:jax._src.xla_bridge:925: Unable to initialize backend 'tpu': INTERNAL: Failed to open libtpu.so: libtpu.so: cannot open shared object file: No such file or directory
INFO:jax._src.xla_bridge:Unable to initialize backend 'tpu': INTERNAL: Failed to open libtpu.so: libtpu.so: cannot open shared object file: No such file or directory
INFO:absl:orbax-checkpoint version: 0.11.13
INFO:absl:Created BasePyTreeCheckpointHandler: use_ocdbt=True, use_zarr3=False, pytree_metadata_options=PyTreeMetadataOptions(support_rich_types=False), array_metadata_store=<orbax.checkpoint._src.metadata.array_metadata_store.Store object at 0x7b3c425f5150>
INFO:absl:Restoring checkpoint from /workspace/ckpt/3999/params.
INFO:absl:[thread=MainThread] Failed to get flag value for EXPERIMENTAL_ORBAX_USE_DISTRIBUTED_PROCESS_ID.
INFO:absl:[process=0] /jax/checkpoint/read/bytes_per_sec: 1.1 GiB/s (total bytes: 6.3 GiB) (time elapsed: 5 seconds) (per-host)
INFO:absl:Finished restoring checkpoint in 5.91 seconds from /workspace/ckpt/3999/params.
INFO:openpi.shared.download:Downloading gs://big_vision/paligemma_tokenizer.model to /root/.cache/openpi/big_vision/paligemma_tokenizer.model
INFO:tqdm_loggable.tqdm_logging:Progress on: -/4264023 rate:- remaining:? elapsed:00:00 postfix:-
INFO:tqdm_loggable.tqdm_logging:Progress on: 4.07MiB/4.07MiB rate:2,389,589.0iB/s remaining:00:00 elapsed:00:02 postfix:-
INFO:root:Loaded norm stats from /workspace/openpi/assets/pi05_mecharm_trim_lora/local/mecharm_redblock_box_teach_v1_trim2
INFO:root:Loaded norm stats from /workspace/ckpt/3999/assets/local/mecharm_redblock_box_teach_v1_trim2
INFO:root:Creating server (host: 2e414bb6abef, ip: 172.25.0.2)
INFO:websockets.server:server listening on 0.0.0.0:8000
INFO:websockets.server:connection open
INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 33536) opened
INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 33536) closed
INFO:websockets.server:connection open
INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 58130) opened
INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 58130) closed
INFO:websockets.server:connection open
INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 45448) opened
INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 45448) closed
INFO:websockets.server:connection open
INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 55964) opened
INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 55964) closed
INFO:websockets.server:connection open
INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 58606) opened
INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 58606) closed
INFO:websockets.server:connection open
INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 57282) opened
INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 57282) closed
INFO:websockets.server:connection open
INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 37682) opened
INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 37682) closed
```

`connection open` が7回あり、夕方に AI へ問い合わせた7回（18:13・18:16・18:24・18:25・18:26・18:30・18:32）と数が合います。


## 実機の回すべてのチャンクの記録

この日の π0.5 の回すべてについて、`log.jsonl` からチャンクごとの表を作りました。推論にかかった時間、使ったステップ、モデルに渡した角度（state）とその出どころ、送った目標、爪の指令、送ったか・着いたか、中継点の数、送り直しの結果です。モデルに渡した角度が目標だった行には、そのとき測った角度（measured）を次の行に出しています。

```python
"""LOG361: 2026-10-22 の π0.5 実機の回を, チャンクごとの表にする (読むだけ).
runs/pi05_policy/pi05_20261022_*/log.jsonl を読み, 1 行 = 1 チャンクで
推論時間 / 使ったステップ / モデルに渡した state / 送った目標 / グリッパー /
送ったか / 着いたか / state の出どころ / 中継点の数 / settle の結果 を出す.
"""
import json, glob, os
ROOT = os.environ.get("PI05_RUNS", "/Volumes/KIOXIA/r2r2r-data/runs/pi05_policy")
def f6(v):
    return "[" + " ".join(f"{x:+6.1f}" for x in v[:6]) + "]" if v else "-"
for d in sorted(glob.glob(ROOT + "/pi05_20261022_*")):
    L = [json.loads(l) for l in open(d + "/log.jsonl")]
    fr = [l for l in L if l.get("type") == "framing"]
    ch = [l for l in L if "chunk" in l]
    print(f"== {os.path.basename(d)}  チャンク {len(ch)}")
    for f in fr:
        print(f"  framing dy={f['dy']} dx={f['dx']} response={f['response']} -> {f['verdict']}")
    for c in ch:
        src = c.get("state_source", "measured")
        vias = len(c.get("vias") or [])
        st = c.get("settle") or {}
        print(f"  {c['chunk']:02d} {c['latency_s']*1000:6.0f}ms used={c.get('used_step')} "
              f"state={f6(c['state'])} src={src:8s} target={f6(c.get('target'))} "
              f"grip={c.get('grip_cmd')} exec={c.get('executed')} arrived={c.get('arrived')} "
              f"vias={vias} settle={st.get('reason','-')}")
        if src == "target" and c.get("measured_state"):
            print(f"       measured={f6(c['measured_state'])}")
```

```
== pi05_20261022_095251  チャンク 9
  framing dy=-0.49 dx=0.62 response=0.524 -> OK
  00  52684ms used=9 state=[  -0.3   +1.2   +0.7   +0.3   -0.3  -29.8] src=measured target=[ -10.7  +21.2   +5.7   -2.8  -20.3  -27.7] grip=None exec=True arrived=True vias=0 settle=-
  01    861ms used=9 state=[ -10.7  +22.2   +6.4   -3.1  -19.2  -28.3] src=measured target=[ -23.2  +42.2  +12.7   -2.9  -39.2  -27.8] grip=None exec=True arrived=True vias=0 settle=-
  02    804ms used=9 state=[ -23.5  +43.2  +13.3   -2.2  -39.0  -27.9] src=measured target=[ -33.0  +59.7  +18.8   -2.2  -59.0  -27.8] grip=None exec=True arrived=True vias=0 settle=-
  03   2310ms used=6 state=[ -33.0  +60.4  +18.4   -2.0  -60.5  -27.9] src=measured target=[ -32.8  +62.2  +16.8   -3.1  -59.5  -27.9] grip=1 exec=True arrived=True vias=0 settle=-
  04    804ms used=9 state=[ -33.0  +62.6  +16.5   -2.5  -61.6  -28.3] src=measured target=[ -19.5  +57.4  +15.3   +0.1  -61.4  -30.0] grip=None exec=True arrived=True vias=0 settle=-
  05    806ms used=9 state=[ -19.6  +59.3  +16.1   +0.2  -58.4  -29.3] src=measured target=[  +0.4  +53.6  +11.2   +3.7  -54.9  -31.2] grip=None exec=True arrived=True vias=0 settle=-
  06   2172ms used=9 state=[  +0.1  +56.0  +12.6   +2.8  -55.9  -30.6] src=measured target=[ +20.1  +48.1   +8.2   +3.7  -48.7  -30.8] grip=None exec=True arrived=True vias=0 settle=-
  07   1081ms used=9 state=[ +19.7  +50.7   +9.8   +3.8  -49.0  -30.8] src=measured target=[ +39.4  +52.1   +3.4   +5.3  -46.2  -31.7] grip=None exec=True arrived=True vias=0 settle=-
  08   2683ms used=9 state=[ +39.3  +53.1   +4.7   +6.0  -46.5  -31.5] src=measured target=[ +40.0  +64.0   +2.3   +6.9  -55.7  -31.6] grip=0 exec=False arrived=None vias=0 settle=-
== pi05_20261022_095832  チャンク 0
  framing dy=-6.67 dx=7.18 response=-0.059 -> 測れない
== pi05_20261022_100108  チャンク 0
  framing dy=-28.14 dx=5.92 response=0.015 -> 測れない
== pi05_20261022_100202  チャンク 0
  framing dy=-26.8 dx=6.27 response=0.015 -> 測れない
== pi05_20261022_100648  チャンク 2
  framing dy=-6.7 dx=2.85 response=0.585 -> OK
  00   1306ms used=9 state=[  -0.2   +1.5   +1.9   -0.3   -0.3  -29.7] src=measured target=[  -9.7  +21.5   +7.3   -2.7  -20.3  -28.4] grip=None exec=True arrived=True vias=0 settle=-
  01   1350ms used=9 state=[  -9.8  +22.6   +8.2   -1.9  -19.2  -29.2] src=measured target=[ -23.4  +42.6  +14.8   -1.9  -39.2  -28.8] grip=None exec=False arrived=None vias=0 settle=-
== pi05_20261022_100713  チャンク 14
  framing dy=-6.94 dx=2.67 response=0.542 -> OK
  00   1998ms used=9 state=[  -0.3   +1.3   +1.8   -0.3   -0.5  -29.4] src=measured target=[  -9.7  +21.3   +6.9   -2.5  -20.5  -29.0] grip=None exec=True arrived=True vias=0 settle=-
  01   1084ms used=9 state=[  -9.8  +22.4   +7.7   -1.7  -19.2  -29.6] src=measured target=[ -24.4  +42.4  +14.2   -1.8  -39.2  -29.2] grip=None exec=True arrived=True vias=0 settle=-
  02    983ms used=9 state=[ -24.7  +43.5  +14.8   -1.8  -38.5  -29.7] src=measured target=[ -37.6  +60.6  +20.6   -1.3  -58.5  -29.8] grip=None exec=True arrived=True vias=0 settle=-
  03    812ms used=6 state=[ -37.1  +61.1  +20.0   -1.6  -61.1  -30.1] src=measured target=[ -37.0  +63.5  +18.5   -1.8  -60.2  -30.4] grip=1 exec=True arrived=True vias=0 settle=-
  04    806ms used=9 state=[ -37.0  +62.8  +17.9   -1.8  -61.2  -30.0] src=measured target=[ -23.8  +56.9  +18.2   +0.9  -61.4  -31.3] grip=None exec=True arrived=True vias=0 settle=-
  05   2176ms used=9 state=[ -23.9  +58.4  +18.1   +1.3  -58.5  -30.7] src=measured target=[  -3.9  +52.1  +15.4   +3.4  -52.5  -31.2] grip=None exec=True arrived=True vias=0 settle=-
  06   1006ms used=9 state=[  -4.2  +54.6  +16.9   +2.5  -53.3  -30.8] src=measured target=[ +15.8  +47.9  +12.7   +3.4  -47.1  -31.1] grip=None exec=True arrived=True vias=0 settle=-
  07   2526ms used=9 state=[ +15.6  +50.7  +14.2   +3.3  -47.5  -30.8] src=measured target=[ +35.5  +49.2   +7.6   +4.4  -43.9  -31.3] grip=None exec=True arrived=True vias=0 settle=-
  08    994ms used=9 state=[ +35.9  +50.7   +9.2   +4.7  -44.1  -31.0] src=measured target=[ +40.4  +64.3   +2.6   +6.1  -49.8  -32.0] grip=None exec=True arrived=True vias=0 settle=-
  09    876ms used=3 state=[ +39.9  +64.9   +3.4   +6.8  -51.9  -32.4] src=measured target=[ +39.8  +65.4   +3.4   +7.0  -53.0  -32.5] grip=0 exec=True arrived=True vias=0 settle=-
  10    801ms used=3 state=[ +39.9  +66.0   +3.3   +6.8  -51.7  -32.4] src=measured target=[ +39.9  +65.9   +3.5   +7.0  -52.3  -32.5] grip=1 exec=True arrived=True vias=0 settle=-
  11    842ms used=2 state=[ +40.3  +66.6   +3.3   +6.5  -54.4  -32.2] src=measured target=[ +40.1  +66.7   +3.4   +6.6  -54.8  -32.3] grip=0 exec=True arrived=None vias=0 settle=-
  12   2247ms used=3 state=[ +40.4  +66.6   +3.0   +7.0  -51.2  -32.5] src=measured target=[ +40.5  +67.0   +3.1   +7.3  -52.2  -32.6] grip=1 exec=True arrived=True vias=0 settle=-
  13    811ms used=4 state=[ +40.5  +67.3   +2.5   +6.9  -53.2  -32.4] src=measured target=[ +40.4  +67.6   +2.5   +7.2  -54.3  -32.6] grip=0 exec=False arrived=None vias=0 settle=-
== pi05_20261022_102053  チャンク 31
  framing dy=-6.87 dx=2.23 response=0.598 -> OK
  00   1613ms used=4 state=[  -0.3   +1.5   +2.5   +0.3   -0.3  -29.7] src=measured target=[  -4.7   +9.7   +4.5   -0.8  -11.3  -29.1] grip=None exec=True arrived=True vias=0 settle=-
  01   1030ms used=4 state=[  -4.9  +10.7   +5.4   -0.6   -9.7  -29.7] src=measured target=[ -10.4  +22.2   +8.3   -1.9  -23.5  -28.7] grip=None exec=True arrived=True vias=0 settle=-
  02    814ms used=4 state=[ -10.4  +23.2   +9.1   -2.4  -22.9  -29.3] src=measured target=[ -18.5  +35.6  +13.0   -2.4  -39.2  -29.1] grip=None exec=True arrived=True vias=0 settle=-
  03   2323ms used=4 state=[ -18.5  +36.7  +13.7   -2.6  -39.0  -29.3] src=measured target=[ -24.4  +47.9  +17.2   -2.8  -54.5  -29.2] grip=None exec=True arrived=True vias=0 settle=-
  04    967ms used=4 state=[ -24.7  +48.9  +17.7   -2.5  -54.4  -29.3] src=measured target=[ -30.8  +57.6  +20.9   -2.1  -65.4  -29.3] grip=None exec=True arrived=True vias=0 settle=-
  05    814ms used=4 state=[ -31.0  +58.4  +20.7   -2.0  -64.7  -29.3] src=measured target=[ -31.3  +60.5  +20.4   -2.5  -65.1  -29.2] grip=None exec=True arrived=True vias=0 settle=-
  06   2170ms used=4 state=[ -31.1  +61.5  +20.7   -2.1  -66.8  -29.3] src=measured target=[ -31.0  +63.3  +19.3   -3.0  -65.5  -29.3] grip=None exec=True arrived=True vias=0 settle=-
  07    861ms used=4 state=[ -31.1  +63.7  +20.1   -2.5  -67.1  -29.5] src=measured target=[ -30.9  +66.3  +17.8   -3.8  -64.5  -29.6] grip=None exec=True arrived=True vias=0 settle=-
  08    806ms used=4 state=[ -31.2  +65.9  +17.8   -3.3  -67.1  -29.6] src=measured target=[ -31.1  +67.8  +15.6   -5.2  -63.4  -29.6] grip=None exec=True arrived=True vias=0 settle=-
  09    841ms used=4 state=[ -31.3  +67.3  +15.3   -4.6  -65.9  -29.7] src=measured target=[ -31.0  +69.3  +13.3   -6.5  -62.1  -29.8] grip=None exec=True arrived=True vias=0 settle=-
  10   2362ms used=3 state=[ -31.3  +68.5  +12.6   -6.0  -63.6  -29.7] src=measured target=[ -31.1  +69.0  +12.0   -6.3  -62.9  -29.7] grip=1 exec=True arrived=True vias=0 settle=-
  11   1132ms used=4 state=[ -31.2  +69.3  +11.3   -7.4  -67.6  -29.5] src=measured target=[ -31.0  +67.0  +14.1   -6.2  -69.7  -29.4] grip=None exec=True arrived=True vias=0 settle=-
  12   2652ms used=4 state=[ -31.0  +68.7  +13.3   -6.9  -69.1  -29.6] src=measured target=[ -30.7  +66.7  +15.9   -5.7  -71.1  -29.6] grip=None exec=True arrived=True vias=0 settle=-
  13   1500ms used=4 state=[ -30.5  +68.2  +15.1   -6.0  -70.3  -29.8] src=measured target=[ -30.2  +66.3  +17.5   -4.8  -71.3  -29.9] grip=None exec=True arrived=True vias=0 settle=-
  14   1138ms used=4 state=[ -30.2  +67.1  +15.6   -5.3  -68.4  -29.8] src=measured target=[ -28.5  +65.0  +18.0   -4.0  -69.6  -30.1] grip=None exec=True arrived=True vias=0 settle=-
  15    805ms used=4 state=[ -28.7  +66.4  +17.0   -2.6  -69.2  -30.0] src=measured target=[ -23.6  +63.9  +17.7   -1.7  -68.4  -30.7] grip=None exec=True arrived=True vias=0 settle=-
  16    811ms used=4 state=[ -23.5  +65.5  +17.0   -1.1  -67.8  -30.0] src=measured target=[ -15.3  +62.0  +17.1   +0.4  -66.7  -31.0] grip=None exec=True arrived=True vias=0 settle=-
  17   2172ms used=4 state=[ -15.1  +64.0  +17.0   -0.1  -65.8  -30.2] src=measured target=[  -4.8  +60.4  +16.7   +1.6  -64.6  -31.2] grip=None exec=True arrived=True vias=0 settle=-
  18    807ms used=4 state=[  -4.7  +62.3  +17.1   +2.1  -63.9  -30.8] src=measured target=[  +4.7  +59.1  +17.1   +2.9  -62.6  -31.1] grip=None exec=True arrived=True vias=0 settle=-
  19    804ms used=4 state=[  +4.7  +61.2  +17.1   +3.0  -62.1  -30.9] src=measured target=[  +7.9  +58.3  +18.9   +3.4  -63.0  -31.1] grip=None exec=True arrived=True vias=0 settle=-
  20   2181ms used=4 state=[  +8.3  +60.3  +19.0   +3.3  -62.1  -31.5] src=measured target=[ +10.5  +57.2  +20.5   +3.5  -62.3  -31.7] grip=None exec=True arrived=True vias=0 settle=-
  21    861ms used=4 state=[ +11.0  +59.3  +20.6   +3.1  -62.2  -31.6] src=measured target=[ +12.5  +57.4  +22.1   +3.4  -63.2  -32.0] grip=None exec=True arrived=True vias=0 settle=-
  22    804ms used=4 state=[ +12.4  +59.3  +21.9   +3.8  -63.5  -31.7] src=measured target=[ +12.9  +58.2  +23.0   +3.8  -64.8  -31.8] grip=None exec=True arrived=True vias=0 settle=-
  23    817ms used=4 state=[ +12.4  +59.3  +22.6   +3.8  -64.4  -31.7] src=measured target=[ +14.4  +56.9  +24.2   +4.0  -65.5  -31.9] grip=None exec=True arrived=True vias=0 settle=-
  24   2448ms used=4 state=[ +14.7  +59.0  +23.9   +4.3  -65.7  -31.7] src=measured target=[ +15.9  +57.9  +24.7   +4.5  -66.9  -31.8] grip=None exec=True arrived=True vias=0 settle=-
  25    803ms used=4 state=[ +16.1  +59.0  +24.0   +4.6  -66.1  -31.7] src=measured target=[ +20.7  +56.1  +24.9   +4.9  -66.1  -32.0] grip=None exec=True arrived=True vias=0 settle=-
  26    903ms used=4 state=[ +20.8  +58.3  +24.9   +4.2  -66.4  -31.8] src=measured target=[ +23.4  +56.1  +25.6   +4.2  -66.4  -32.0] grip=None exec=True arrived=True vias=0 settle=-
  27    920ms used=4 state=[ +23.5  +58.3  +25.0   +3.9  -66.4  -31.8] src=measured target=[ +28.9  +55.9  +25.2   +4.1  -65.7  -32.4] grip=None exec=True arrived=True vias=0 settle=-
  28   2120ms used=4 state=[ +29.3  +58.3  +25.0   +4.0  -66.4  -32.1] src=measured target=[ +30.1  +61.5  +22.6   +4.3  -67.9  -32.2] grip=None exec=True arrived=True vias=0 settle=-
  29    837ms used=2 state=[ +29.8  +62.0  +23.3   +4.6  -69.3  -31.9] src=measured target=[ +29.9  +62.2  +23.1   +4.6  -69.7  -31.9] grip=0 exec=True arrived=None vias=0 settle=-
  30    865ms used=4 state=[ +29.9  +62.0  +23.3   +4.9  -67.8  -31.9] src=measured target=[ +30.2  +63.6  +22.7   +5.2  -68.8  -32.0] grip=1 exec=False arrived=None vias=0 settle=-
== pi05_20261022_112718  チャンク 0
  framing dy=-41.15 dx=3.71 response=-0.066 -> 測れない
== pi05_20261022_114643  チャンク 9
  framing dy=-6.54 dx=3.01 response=0.553 -> OK
  00   1724ms used=9 state=[  -0.2   +1.3   +0.5   -0.3   -0.5  -30.0] src=measured target=[ -10.8  +21.3   +5.9   -2.8  -20.5  -27.8] grip=None exec=True arrived=True vias=0 settle=not_converged
  01    985ms used=9 state=[ -11.0  +22.4   +6.7   -2.3  -20.1  -28.1] src=measured target=[ -23.2  +42.4  +12.9   -2.2  -40.1  -27.6] grip=None exec=True arrived=True vias=0 settle=not_converged
  02    899ms used=9 state=[ -23.6  +43.5  +13.4   -2.6  -39.5  -27.8] src=measured target=[ -33.6  +60.9  +19.6   -2.4  -59.5  -27.7] grip=None exec=True arrived=True vias=0 settle=not_converged
  03    874ms used=6 state=[ -33.4  +61.4  +19.0   -2.5  -61.2  -28.0] src=measured target=[ -33.0  +63.0  +17.6   -3.6  -60.4  -27.9] grip=1 exec=True arrived=True vias=0 settle=within_tol
  04   2135ms used=9 state=[ -33.5  +62.5  +17.1   -3.2  -60.9  -28.3] src=measured target=[ -18.0  +56.8  +15.9   +0.3  -60.7  -30.2] grip=None exec=True arrived=True vias=0 settle=not_converged
  05    802ms used=9 state=[ -17.9  +58.8  +16.8   -0.1  -59.0  -29.6] src=measured target=[  +2.1  +52.5  +11.0   +3.5  -54.7  -31.6] grip=None exec=True arrived=True vias=0 settle=not_converged
  06    877ms used=9 state=[  +1.8  +54.8  +12.3   +3.3  -55.1  -31.3] src=measured target=[ +21.8  +48.8   +6.4   +4.7  -48.4  -32.0] grip=None exec=True arrived=True vias=0 settle=not_converged
  07   2299ms used=9 state=[ +21.6  +51.4   +7.9   +5.2  -48.7  -31.7] src=measured target=[ +38.8  +54.1   +3.3   +6.5  -47.9  -32.4] grip=None exec=True arrived=False vias=0 settle=not_converged
  08    952ms used=8 state=[ +38.9  +55.1   +4.8   +6.3  -48.2  -32.6] src=measured target=[ +39.9  +64.9   +0.9   +7.3  -53.8  -33.0] grip=0 exec=False arrived=None vias=0 settle=-
== pi05_20261022_131036  チャンク 9
  framing dy=-6.87 dx=1.81 response=0.581 -> OK
  00   1601ms used=9 state=[  -0.4   +1.3   +1.0   -0.3   +0.3  -30.2] src=measured target=[ -10.7  +20.6   +5.8   -2.5  -22.0  -28.2] grip=None exec=True arrived=True vias=4 settle=disabled
  01   1155ms used=9 state=[ -10.7  +21.5   +6.5   -2.0  -22.5  -28.4] src=measured target=[ -23.4  +45.7  +12.9   -2.2  -52.7  -27.9] grip=None exec=True arrived=True vias=4 settle=disabled
  02    852ms used=9 state=[ -23.6  +46.8  +12.8   -2.4  -52.5  -28.0] src=measured target=[ -30.5  +60.0  +17.5   -2.2  -69.2  -27.8] grip=None exec=True arrived=True vias=4 settle=disabled
  03    884ms used=9 state=[ -31.1  +60.9  +17.7   -2.1  -69.3  -27.7] src=measured target=[ -31.0  +64.6  +13.4   -5.1  -64.1  -27.6] grip=1 exec=True arrived=True vias=4 settle=disabled
  04   2181ms used=9 state=[ -31.2  +65.6  +14.1   -4.7  -65.7  -27.9] src=measured target=[ -24.6  +61.3  +16.0   -2.1  -67.4  -29.0] grip=None exec=True arrived=True vias=4 settle=disabled
  05    890ms used=9 state=[ -24.2  +63.7  +16.2   -1.3  -66.2  -28.5] src=measured target=[  -1.4  +56.5  +11.7   +2.6  -60.7  -30.9] grip=None exec=True arrived=True vias=4 settle=disabled
  06   1151ms used=9 state=[  -1.5  +59.1  +13.4   +3.0  -61.0  -30.5] src=measured target=[ +23.6  +51.0   +9.1   +4.3  -54.2  -30.9] grip=None exec=True arrived=True vias=4 settle=disabled
  07   2162ms used=9 state=[ +23.5  +53.6  +11.0   +4.6  -54.5  -30.6] src=measured target=[ +39.4  +53.9   +3.7   +5.9  -50.8  -31.7] grip=None exec=True arrived=True vias=4 settle=disabled
  08    883ms used=7 state=[ +39.3  +55.1   +5.3   +6.2  -49.6  -32.0] src=measured target=[ +39.9  +63.8   +2.8   +6.9  -55.8  -32.3] grip=0 exec=False arrived=None vias=3 settle=-
== pi05_20261022_181339  チャンク 5
  framing dy=-5.17 dx=0.25 response=0.551 -> OK
  00  59829ms used=9 state=[  -0.3   +1.5   +2.1   +0.3   -0.3  -30.2] src=measured target=[ -11.9  +21.3   +5.2   +2.6  -25.2  -29.8] grip=None exec=True arrived=True vias=4 settle=disabled
  01    642ms used=9 state=[ -11.9  +21.3   +5.2   +2.6  -25.2  -29.8] src=target   target=[ -25.2  +45.0   +9.6   +3.9  -55.3  -29.6] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ -12.2  +22.2   +5.9   +2.3  -25.2  -29.9]
  02    464ms used=9 state=[ -25.2  +45.0   +9.6   +3.9  -55.3  -29.6] src=target   target=[ -37.0  +62.2  +13.1   +4.1  -76.8  -29.7] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ -25.7  +46.0  +10.1   +4.4  -55.4  -29.7]
  03    563ms used=9 state=[ -37.0  +62.2  +13.1   +4.1  -76.8  -29.7] src=target   target=[ -38.3  +66.7  +13.8   +3.6  -81.2  -29.8] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ -37.1  +63.1  +13.4   +4.1  -77.0  -29.5]
  04   3182ms used=9 state=[ -38.3  +66.7  +13.8   +3.6  -81.2  -29.8] src=target   target=[ -38.4  +72.8  +11.4   +2.2  -81.9  -29.9] grip=None exec=False arrived=None vias=4 settle=-
       measured=[ -38.5  +67.6  +14.5   +4.0  -81.2  -29.4]
== pi05_20261022_181602  チャンク 19
  framing dy=-5.54 dx=0.25 response=0.533 -> OK
  00   1769ms used=9 state=[  -0.3   +1.5   +2.0   +0.1   -0.3  -29.6] src=measured target=[ -10.6  +22.5   +4.5   +2.9  -27.4  -29.7] grip=None exec=True arrived=True vias=4 settle=disabled
  01   1140ms used=9 state=[ -10.6  +22.5   +4.5   +2.9  -27.4  -29.7] src=target   target=[ -25.1  +44.5   +8.6   +4.6  -57.5  -29.5] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ -10.6  +23.5   +5.0   +2.9  -27.3  -29.7]
  02    744ms used=9 state=[ -25.1  +44.5   +8.6   +4.6  -57.5  -29.5] src=target   target=[ -37.4  +62.7  +12.5   +5.0  -80.8  -29.6] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ -25.2  +45.5   +8.9   +5.1  -57.7  -29.7]
  03    583ms used=9 state=[ -37.4  +62.7  +12.5   +5.0  -80.8  -29.6] src=target   target=[ -39.1  +69.0  +13.6   +4.4  -87.1  -29.6] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ -37.4  +63.7  +12.6   +4.8  -80.3  -29.7]
  04    650ms used=9 state=[ -39.1  +69.0  +13.6   +4.4  -87.1  -29.6] src=target   target=[ -39.6  +79.0   +8.3   +3.5  -89.3  -29.7] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ -39.1  +69.4  +14.0   +4.7  -87.3  -29.7]
  05    607ms used=3 state=[ -39.6  +79.0   +8.3   +3.5  -89.3  -29.7] src=target   target=[ -39.6  +80.6   +7.5   +3.4  -89.5  -29.8] grip=1 exec=True arrived=True vias=2 settle=disabled
       measured=[ -39.2  +79.9   +9.6   +3.8  -89.0  -29.7]
  06    559ms used=9 state=[ -39.6  +80.6   +7.5   +3.4  -89.5  -29.8] src=target   target=[ -38.9  +68.0  +16.3   +3.6  -88.4  -29.9] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ -39.2  +81.7   +8.4   +3.7  -89.7  -29.7]
  07    648ms used=9 state=[ -38.9  +68.0  +16.3   +3.6  -88.4  -29.9] src=target   target=[ -15.7  +56.3  +17.5   +6.3  -78.1  -30.1] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ -38.4  +70.6  +16.2   +3.4  -89.7  -29.7]
  08   1547ms used=9 state=[ -15.7  +56.3  +17.5   +6.3  -78.1  -30.1] src=target   target=[ +13.1  +44.3  +17.3   +6.4  -67.8  -30.2] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ -15.7  +58.7  +17.7   +6.1  -78.1  -29.7]
  09    634ms used=9 state=[ +13.1  +44.3  +17.3   +6.4  -67.8  -30.2] src=target   target=[ +40.1  +38.2  +15.4   +6.9  -60.5  -30.4] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ +13.2  +46.8  +17.7   +6.5  -67.9  -29.9]
  10    641ms used=9 state=[ +40.1  +38.2  +15.4   +6.9  -60.5  -30.4] src=target   target=[ +43.6  +59.8   +5.9   +8.9  -72.2  -30.8] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ +40.3  +39.5  +17.4   +6.9  -59.8  -30.0]
  11    609ms used=3 state=[ +43.6  +59.8   +5.9   +8.9  -72.2  -30.8] src=target   target=[ +43.5  +62.1   +5.5   +9.0  -73.4  -30.8] grip=0 exec=True arrived=True vias=2 settle=disabled
       measured=[ +43.2  +60.9   +7.7   +8.6  -72.2  -30.5]
  12   1560ms used=9 state=[ +43.5  +62.1   +5.5   +9.0  -73.4  -30.8] src=target   target=[ +42.1  +42.1   +9.8   +7.3  -57.7  -30.9] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ +43.1  +63.3   +6.8   +8.8  -73.2  -30.5]
  13    634ms used=9 state=[ +42.1  +42.1   +9.8   +7.3  -57.7  -30.9] src=target   target=[ +24.9  +21.8   +8.7   +3.3  -31.9  -30.6] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ +42.1  +44.5  +10.4   +7.8  -58.2  -30.8]
  14    639ms used=9 state=[ +24.9  +21.8   +8.7   +3.3  -31.9  -30.6] src=target   target=[  +4.7   +4.8   +2.9   +0.6   -3.8  -30.7] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ +24.9  +23.8  +11.0   +2.6  -32.1  -30.8]
  15    813ms used=9 state=[  +4.7   +4.8   +2.9   +0.6   -3.8  -30.7] src=target   target=[  +1.4   +3.4   +2.5   +0.5   -2.5  -30.7] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[  +4.5   +6.5   +5.3   +0.9   -3.9  -30.9]
  16   1562ms used=9 state=[  +1.4   +3.4   +2.5   +0.5   -2.5  -30.7] src=target   target=[  +0.5   +3.0   +2.4   +0.4   -2.5  -30.7] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[  +1.5   +4.8   +5.3   +0.7   -2.5  -30.8]
  17    631ms used=9 state=[  +0.5   +3.0   +2.4   +0.4   -2.5  -30.7] src=target   target=[  -0.2   +3.0   +2.5   +0.5   -2.9  -30.7] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[  +0.4   +4.6   +5.3   +0.7   -2.5  -30.8]
  18    616ms used=9 state=[  -0.2   +3.0   +2.5   +0.5   -2.9  -30.7] src=target   target=[  -0.7   +2.8   +2.4   +0.5   -3.1  -30.8] grip=None exec=False arrived=None vias=4 settle=-
       measured=[  +0.3   +4.6   +5.3   +0.7   -2.5  -30.8]
== pi05_20261022_182419  チャンク 2
  framing dy=-5.25 dx=2.58 response=0.452 -> OK
  00   1119ms used=9 state=[  +0.3   +1.1   +1.5   +0.3   -0.3  -30.2] src=measured target=[  -9.7  +21.2   +6.9   -2.2  -24.5  -28.1] grip=None exec=True arrived=True vias=4 settle=disabled
  01   1334ms used=9 state=[  -9.7  +21.2   +6.9   -2.2  -24.5  -28.1] src=target   target=[ -21.9  +43.9  +13.6   -2.4  -53.6  -27.6] grip=None exec=False arrived=None vias=4 settle=-
       measured=[  -9.6  +22.1   +7.5   -2.3  -24.7  -28.3]
== pi05_20261022_182519  チャンク 2
  framing dy=-5.36 dx=0.35 response=0.62 -> OK
  00   1008ms used=9 state=[  -0.3   +1.2   +1.8   -0.3   -0.3  -29.7] src=measured target=[ -10.1  +21.5   +7.3   -2.7  -26.6  -28.4] grip=None exec=True arrived=True vias=4 settle=disabled
  01   1762ms used=9 state=[ -10.1  +21.5   +7.3   -2.7  -26.6  -28.4] src=target   target=[ -22.3  +45.5  +13.7   -2.5  -56.5  -28.0] grip=None exec=False arrived=None vias=4 settle=-
       measured=[  -9.9  +22.4   +8.0   -2.1  -26.6  -28.8]
== pi05_20261022_182650  チャンク 16
  framing dy=-5.41 dx=-0.15 response=0.599 -> OK
  00    747ms used=9 state=[  -0.4   +1.4   +1.8   -0.3   -0.3  -29.7] src=measured target=[ -10.1  +21.7   +7.7   -3.0  -26.0  -28.6] grip=None exec=True arrived=True vias=4 settle=disabled
  01    614ms used=9 state=[ -10.1  +21.7   +7.7   -3.0  -26.0  -28.6] src=target   target=[ -22.6  +45.6  +14.7   -2.5  -56.7  -28.3] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ -10.0  +22.6   +8.4   -2.8  -26.1  -29.0]
  02    625ms used=9 state=[ -22.6  +45.6  +14.7   -2.5  -56.7  -28.3] src=target   target=[ -28.7  +57.7  +19.4   -2.1  -69.7  -28.1] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ -22.9  +46.6  +15.2   -2.5  -56.6  -28.6]
  03    558ms used=9 state=[ -28.7  +57.7  +19.4   -2.1  -69.7  -28.1] src=target   target=[ -28.8  +61.8  +15.9   -5.0  -65.2  -27.9] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ -29.2  +58.9  +19.5   -1.9  -70.2  -28.3]
  04    562ms used=7 state=[ -28.8  +61.8  +15.9   -5.0  -65.2  -27.9] src=target   target=[ -28.3  +64.4  +13.2   -7.2  -61.8  -27.8] grip=1 exec=True arrived=True vias=3 settle=disabled
       measured=[ -29.2  +62.0  +16.1   -4.9  -67.6  -27.1]
  05   1531ms used=9 state=[ -28.3  +64.4  +13.2   -7.2  -61.8  -27.8] src=target   target=[ -28.2  +61.1  +18.2   -4.7  -67.5  -27.5] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ -28.7  +65.0  +13.1   -6.8  -62.7  -27.6]
  06    560ms used=9 state=[ -28.2  +61.1  +18.2   -4.7  -67.5  -27.5] src=target   target=[ -11.4  +55.5  +15.9   -0.9  -65.7  -29.3] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ -27.9  +63.1  +17.4   -5.1  -66.3  -26.9]
  07    560ms used=9 state=[ -11.4  +55.5  +15.9   -0.9  -65.7  -29.3] src=target   target=[ +17.7  +48.4   +9.1   +2.5  -58.6  -30.7] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ -11.5  +57.9  +17.8   -1.0  -66.3  -28.8]
  08    652ms used=9 state=[ +17.7  +48.4   +9.1   +2.5  -58.6  -30.7] src=target   target=[ +40.7  +48.1   +3.4   +3.1  -54.5  -30.8] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ +17.7  +50.9  +11.0   +2.6  -58.8  -30.3]
  09   1568ms used=9 state=[ +40.7  +48.1   +3.4   +3.1  -54.5  -30.8] src=target   target=[ +41.3  +62.9   +2.8   +3.6  -67.9  -30.8] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ +41.0  +49.3   +4.8   +3.2  -53.1  -30.6]
  10    560ms used=1 state=[ +41.3  +62.9   +2.8   +3.6  -67.9  -30.8] src=target   target=[ +41.2  +62.9   +2.8   +3.7  -68.1  -30.8] grip=0 exec=True arrived=True vias=1 settle=disabled
       measured=[ +41.1  +63.8   +4.7   +3.2  -68.4  -31.5]
  11    641ms used=9 state=[ +41.2  +62.9   +2.8   +3.7  -68.1  -30.8] src=target   target=[ +41.1  +45.2   +2.8   +3.7  -50.5  -31.8] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ +41.2  +63.9   +4.7   +4.2  -68.4  -31.0]
  12   1488ms used=9 state=[ +41.1  +45.2   +2.8   +3.7  -50.5  -31.8] src=target   target=[ +19.8  +21.1   +2.0   +0.3  -20.0  -31.1] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ +41.2  +47.6   +4.7   +4.0  -50.7  -31.2]
  13    568ms used=9 state=[ +19.8  +21.1   +2.0   +0.3  -20.0  -31.1] src=target   target=[  +3.0   +3.7   +2.2   +0.3   -3.9  -30.9] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ +19.6  +23.1   +4.0   +0.0  -20.2  -31.3]
  14   1648ms used=9 state=[  +3.0   +3.7   +2.2   +0.3   -3.9  -30.9] src=target   target=[  +1.2   +2.8   +2.1   +0.3   -3.0  -30.9] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[  +2.5   +4.6   +4.0   +0.1   -3.5  -31.3]
  15    810ms used=9 state=[  +1.2   +2.8   +2.1   +0.3   -3.0  -30.9] src=target   target=[  +0.6   +2.8   +2.0   +0.2   -2.8  -30.9] grip=None exec=False arrived=None vias=4 settle=-
       measured=[  +0.9   +4.6   +4.0   +0.1   -3.4  -31.2]
== pi05_20261022_183027  チャンク 10
  framing dy=-5.15 dx=0.3 response=0.502 -> OK
  00    750ms used=9 state=[  -0.3   +1.3   +1.6   +0.1   +0.2  -30.2] src=measured target=[ -10.8  +23.0   +7.2   -2.4  -24.9  -28.0] grip=None exec=True arrived=True vias=4 settle=disabled
  01   1490ms used=9 state=[ -10.8  +23.0   +7.2   -2.4  -24.9  -28.0] src=target   target=[ -23.3  +45.8  +13.3   -2.6  -53.4  -27.6] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ -11.2  +23.9   +7.9   -2.3  -24.9  -28.2]
  02    565ms used=9 state=[ -23.3  +45.8  +13.3   -2.6  -53.4  -27.6] src=target   target=[ -30.0  +60.2  +17.7   -2.2  -70.4  -27.5] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ -23.8  +46.8  +13.8   -2.9  -53.3  -27.9]
  03    565ms used=9 state=[ -30.0  +60.2  +17.7   -2.2  -70.4  -27.5] src=target   target=[ -29.6  +65.0  +12.9   -6.2  -62.3  -27.4] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ -30.4  +61.2  +17.3   -1.9  -71.2  -27.7]
  04   1555ms used=3 state=[ -29.6  +65.0  +12.9   -6.2  -62.3  -27.4] src=target   target=[ -29.4  +65.5  +12.3   -6.8  -61.5  -27.4] grip=1 exec=True arrived=True vias=2 settle=disabled
       measured=[ -29.9  +65.6  +13.8   -5.7  -63.5  -27.9]
  05    652ms used=9 state=[ -29.4  +65.5  +12.3   -6.8  -61.5  -27.4] src=target   target=[ -29.1  +62.3  +17.5   -5.0  -66.3  -27.2] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ -30.0  +65.9  +11.9   -6.8  -62.5  -27.6]
  06    560ms used=9 state=[ -29.1  +62.3  +17.5   -5.0  -66.3  -27.2] src=target   target=[ -28.1  +60.9  +19.1   -4.1  -68.9  -27.2] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ -29.4  +63.8  +16.3   -5.4  -65.4  -26.8]
  07    580ms used=9 state=[ -28.1  +60.9  +19.1   -4.1  -68.9  -27.2] src=target   target=[ -11.7  +57.1  +15.9   -1.0  -66.7  -29.1] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ -28.3  +63.0  +18.9   -3.5  -68.0  -26.7]
  08   1493ms used=9 state=[ -11.7  +57.1  +15.9   -1.0  -66.7  -29.1] src=target   target=[ +16.9  +50.5   +9.3   +2.7  -59.2  -30.7] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ -11.9  +59.6  +17.6   -1.0  -67.4  -28.8]
  09    584ms used=9 state=[ +16.9  +50.5   +9.3   +2.7  -59.2  -30.7] src=target   target=[ +39.2  +48.4   +4.0   +3.4  -54.4  -30.9] grip=None exec=False arrived=None vias=4 settle=-
       measured=[ +17.0  +53.0  +11.2   +2.9  -59.3  -30.4]
== pi05_20261022_183241  チャンク 7
  framing dy=-5.91 dx=-0.51 response=0.369 -> OK
  00    561ms used=9 state=[  -0.2   +1.5   +1.9   +0.3   -0.3  -30.4] src=measured target=[ -10.3  +20.8   +5.5   +1.3  -22.4  -29.1] grip=None exec=True arrived=True vias=4 settle=disabled
  01    600ms used=9 state=[ -10.3  +20.8   +5.5   +1.3  -22.4  -29.1] src=target   target=[ -23.2  +44.5  +11.5   +1.2  -52.8  -28.6] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ -10.5  +21.9   +6.2   +0.9  -22.5  -29.4]
  02    568ms used=9 state=[ -23.2  +44.5  +11.5   +1.2  -52.8  -28.6] src=target   target=[ -33.1  +61.7  +16.3   +1.3  -74.4  -28.6] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ -23.4  +45.4  +11.9   +1.4  -52.9  -28.8]
  03   1551ms used=9 state=[ -33.1  +61.7  +16.3   +1.3  -74.4  -28.6] src=target   target=[ -33.7  +65.5  +16.1   +0.4  -75.0  -28.6] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ -33.1  +62.8  +16.3   +1.5  -74.2  -28.8]
  04    706ms used=8 state=[ -33.7  +65.5  +16.1   +0.4  -75.0  -28.6] src=target   target=[ -33.6  +67.7  +14.4   -0.5  -73.0  -28.6] grip=1 exec=True arrived=True vias=3 settle=disabled
       measured=[ -33.3  +66.4  +17.2   +0.7  -76.0  -28.0]
  05    564ms used=9 state=[ -33.6  +67.7  +14.4   -0.5  -73.0  -28.6] src=target   target=[ -12.5  +61.3  +12.3   +3.1  -69.4  -31.1] grip=None exec=True arrived=True vias=4 settle=disabled
       measured=[ -33.4  +68.6  +15.6   -0.3  -73.4  -28.6]
  06    564ms used=9 state=[ -12.5  +61.3  +12.3   +3.1  -69.4  -31.1] src=target   target=[ +13.0  +54.3   +7.6   +5.6  -62.7  -32.5] grip=None exec=False arrived=None vias=4 settle=-
       measured=[ -12.6  +63.7  +13.9   +3.2  -69.2  -30.8]
== pi05_20261022_183456  チャンク 0
  framing dy=-10.19 dx=2.49 response=-0.027 -> 測れない
== pi05_20261022_183801  チャンク 0
  framing dy=-34.02 dx=12.29 response=0.019 -> 測れない
```

チャンクごとの姿勢を、お手本（位置C）からの距離と、移動量の上限で削られた関節と一緒に並べた表です。

```python
# 実機の各回を、お手本 19 本と比べる (LOG361)
#  1) 各チャンクの状態と、お手本でいちばん近い状態との距離 (6 関節の差の大きさ, 同じグリッパー状態の中で)
#  2) 送った目標 (上限・検査のあと) と予測 (actions の使った行) の差 = 上限で削られた量
import os, json, glob
import numpy as np
ROOT = os.environ.get("R2R2R_DATA", "/Volumes/KIOXIA/r2r2r-data"); os.chdir(ROOT)
RAW = "datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes"
A = np.concatenate([np.load(p)["state"] for p in sorted(glob.glob(RAW + "/*/episode.npz"))])
RUNS = ["20261021_183245", "20261022_095251", "20261022_100713", "20261022_102053",
        "20261022_114643", "20261022_131036", "20261022_181602", "20261022_182650"]
for r in RUNS:
    L = [json.loads(l) for l in open(f"runs/pi05_policy/pi05_{r}/log.jsonl")]
    L = [x for x in L if "chunk" in x]
    print(f"== {r}  チャンク数 {len(L)}")
    print(" ch  g |     j0     j1     j2     j4 | お手本との距離 | 上限で削られた関節")
    for d in L:
        s = np.array(d.get("measured_state", d["state"]))
        m = A[:, 6] == s[6]
        dist = np.linalg.norm(A[m][:, :6] - s[:6], axis=1).min()
        notes = " / ".join(n.split(" ")[0] for n in d.get("notes", []))
        print(f" {d['chunk']:02d}  {int(s[6])} | {s[0]:+6.1f} {s[1]:+6.1f} {s[2]:+6.1f} {s[4]:+6.1f} | {dist:6.1f}° | {notes}")
```

```
== 20261021_183245  チャンク数 13
 ch  g |     j0     j1     j2     j4 | お手本との距離 | 上限で削られた関節
 00  0 |   -0.2   +1.0   +0.9   +1.0 |    1.0° | j1 / j4
 01  0 |  -11.3  +22.1   +0.9  -17.9 |    4.8° | j1 / j4
 02  0 |  -27.2  +43.1   +0.9  -37.7 |   11.1° | j1 / j4
 03  0 |  -39.6  +64.2   +1.8  -57.4 |   16.9° | 
 04  1 |  -39.7  +66.4   +2.6  -57.6 |   18.7° | 
 05  1 |  -29.9  +63.2   +4.4  -55.7 |   19.1° | j0
 06  1 |  -10.3  +56.1   +6.2  -49.8 |   19.5° | j0
 07  1 |   +9.4  +48.7   +6.2  -43.2 |   19.5° | j0
 08  1 |  +29.3  +46.8   +6.1  -38.8 |   17.9° | 
 09  1 |  +41.0  +58.1   +1.1  -42.3 |   12.7° | 
 10  0 |  +41.2  +65.9   -0.5  -46.6 |   12.6° | 
 11  1 |  +41.2  +69.9   -2.4  -50.7 |   11.4° | 
 12  0 |  +41.2  +71.1   -2.4  -52.5 |   11.2° | 
== 20261022_095251  チャンク数 9
 ch  g |     j0     j1     j2     j4 | お手本との距離 | 上限で削られた関節
 00  0 |   -0.3   +1.2   +0.7   -0.3 |    0.5° | j1 / j4
 01  0 |  -10.7  +22.2   +6.4  -19.2 |    4.8° | j1 / j4
 02  0 |  -23.5  +43.2  +13.3  -39.0 |   10.0° | j4
 03  0 |  -33.0  +60.4  +18.4  -60.5 |    8.1° | 
 04  1 |  -33.0  +62.6  +16.5  -61.6 |    7.1° | 
 05  1 |  -19.6  +59.3  +16.1  -58.4 |    9.6° | j0
 06  1 |   +0.1  +56.0  +12.6  -55.9 |    8.7° | j0
 07  1 |  +19.7  +50.7   +9.8  -49.0 |    9.8° | 
 08  1 |  +39.3  +53.1   +4.7  -46.5 |    7.4° | 
== 20261022_100713  チャンク数 14
 ch  g |     j0     j1     j2     j4 | お手本との距離 | 上限で削られた関節
 00  0 |   -0.3   +1.3   +1.8   -0.5 |    0.7° | j1 / j4
 01  0 |   -9.8  +22.4   +7.7  -19.2 |    4.9° | j1 / j4
 02  0 |  -24.7  +43.5  +14.8  -38.5 |   11.7° | j4
 03  0 |  -37.1  +61.1  +20.0  -61.1 |   11.7° | 
 04  1 |  -37.0  +62.8  +17.9  -61.2 |   11.1° | 
 05  1 |  -23.9  +58.4  +18.1  -58.5 |   10.8° | j0
 06  1 |   -4.2  +54.6  +16.9  -53.3 |   11.7° | j0
 07  1 |  +15.6  +50.7  +14.2  -47.5 |   12.9° | j0
 08  1 |  +35.9  +50.7   +9.2  -44.1 |   10.6° | 
 09  1 |  +39.9  +64.9   +3.4  -51.9 |   10.0° | 
 10  0 |  +39.9  +66.0   +3.3  -51.7 |   11.0° | 
 11  1 |  +40.3  +66.6   +3.3  -54.4 |    9.4° | 
 12  0 |  +40.4  +66.6   +3.0  -51.2 |   11.1° | 
 13  1 |  +40.5  +67.3   +2.5  -53.2 |    9.5° | 
== 20261022_102053  チャンク数 31
 ch  g |     j0     j1     j2     j4 | お手本との距離 | 上限で削られた関節
 00  0 |   -0.3   +1.5   +2.5   -0.3 |    0.6° | 
 01  0 |   -4.9  +10.7   +5.4   -9.7 |    1.9° | 
 02  0 |  -10.4  +23.2   +9.1  -22.9 |    3.6° | 
 03  0 |  -18.5  +36.7  +13.7  -39.0 |    4.5° | 
 04  0 |  -24.7  +48.9  +17.7  -54.4 |    5.5° | 
 05  0 |  -31.0  +58.4  +20.7  -64.7 |    6.0° | 
 06  0 |  -31.1  +61.5  +20.7  -66.8 |    5.4° | 
 07  0 |  -31.1  +63.7  +20.1  -67.1 |    6.0° | 
 08  0 |  -31.2  +65.9  +17.8  -67.1 |    6.7° | 
 09  0 |  -31.3  +67.3  +15.3  -65.9 |    7.0° | 
 10  0 |  -31.3  +68.5  +12.6  -63.6 |    6.9° | 
 11  1 |  -31.2  +69.3  +11.3  -67.6 |    9.1° | 
 12  1 |  -31.0  +68.7  +13.3  -69.1 |    9.2° | 
 13  1 |  -30.5  +68.2  +15.1  -70.3 |    9.1° | 
 14  1 |  -30.2  +67.1  +15.6  -68.4 |    7.1° | 
 15  1 |  -28.7  +66.4  +17.0  -69.2 |    7.3° | 
 16  1 |  -23.5  +65.5  +17.0  -67.8 |    7.9° | 
 17  1 |  -15.1  +64.0  +17.0  -65.8 |    7.9° | 
 18  1 |   -4.7  +62.3  +17.1  -63.9 |    9.0° | 
 19  1 |   +4.7  +61.2  +17.1  -62.1 |   10.5° | 
 20  1 |   +8.3  +60.3  +19.0  -62.1 |    8.3° | 
 21  1 |  +11.0  +59.3  +20.6  -62.2 |    7.2° | 
 22  1 |  +12.4  +59.3  +21.9  -63.5 |    7.9° | 
 23  1 |  +12.4  +59.3  +22.6  -64.4 |    8.1° | 
 24  1 |  +14.7  +59.0  +23.9  -65.7 |    9.3° | 
 25  1 |  +16.1  +59.0  +24.0  -66.1 |   10.0° | 
 26  1 |  +20.8  +58.3  +24.9  -66.4 |   12.4° | 
 27  1 |  +23.5  +58.3  +25.0  -66.4 |   14.1° | 
 28  1 |  +29.3  +58.3  +25.0  -66.4 |   16.2° | 
 29  1 |  +29.8  +62.0  +23.3  -69.3 |   20.0° | 
 30  0 |  +29.9  +62.0  +23.3  -67.8 |   20.3° | 
== 20261022_114643  チャンク数 9
 ch  g |     j0     j1     j2     j4 | お手本との距離 | 上限で削られた関節
 00  0 |   -0.2   +1.3   +0.5   -0.5 |    0.5° | j1 / j4
 01  0 |  -11.0  +22.4   +6.7  -20.1 |    4.5° | j1 / j4
 02  0 |  -23.6  +43.5  +13.4  -39.5 |   10.0° | j4
 03  0 |  -33.4  +61.4  +19.0  -61.2 |    8.0° | 
 04  1 |  -33.5  +62.5  +17.1  -60.9 |    7.5° | 
 05  1 |  -17.9  +58.8  +16.8  -59.0 |    8.5° | j0
 06  1 |   +1.8  +54.8  +12.3  -55.1 |    8.9° | j0
 07  1 |  +21.6  +51.4   +7.9  -48.7 |   10.2° | 
 08  1 |  +38.9  +55.1   +4.8  -48.2 |    7.8° | 
== 20261022_131036  チャンク数 9
 ch  g |     j0     j1     j2     j4 | お手本との距離 | 上限で削られた関節
 00  0 |   -0.4   +1.3   +1.0   +0.3 |    0.2° | 
 01  0 |  -10.7  +21.5   +6.5  -22.5 |    2.5° | 
 02  0 |  -23.6  +46.8  +12.8  -52.5 |    4.6° | 
 03  0 |  -31.1  +60.9  +17.7  -69.3 |    4.0° | 
 04  1 |  -31.2  +65.6  +14.1  -65.7 |    5.5° | 
 05  1 |  -24.2  +63.7  +16.2  -66.2 |    6.4° | 
 06  1 |   -1.5  +59.1  +13.4  -61.0 |    7.2° | 
 07  1 |  +23.5  +53.6  +11.0  -54.5 |    8.2° | 
 08  1 |  +39.3  +55.1   +5.3  -49.6 |    7.4° | 
== 20261022_181602  チャンク数 19
 ch  g |     j0     j1     j2     j4 | お手本との距離 | 上限で削られた関節
 00  0 |   -0.3   +1.5   +2.0   -0.3 |    0.5° | 
 01  0 |  -10.6  +23.5   +5.0  -27.3 |    2.2° | 
 02  0 |  -25.2  +45.5   +8.9  -57.7 |    3.0° | 
 03  0 |  -37.4  +63.7  +12.6  -80.3 |    3.4° | 
 04  0 |  -39.1  +69.4  +14.0  -87.3 |    3.3° | 
 05  0 |  -39.2  +79.9   +9.6  -89.0 |    3.4° | 
 06  1 |  -39.2  +81.7   +8.4  -89.7 |    3.3° | 
 07  1 |  -38.4  +70.6  +16.2  -89.7 |    2.7° | 
 08  1 |  -15.7  +58.7  +17.7  -78.1 |    2.4° | 
 09  1 |  +13.2  +46.8  +17.7  -67.9 |    1.9° | 
 10  1 |  +40.3  +39.5  +17.4  -59.8 |    2.8° | 
 11  1 |  +43.2  +60.9   +7.7  -72.2 |    2.3° | 
 12  0 |  +43.1  +63.3   +6.8  -73.2 |    3.4° | 
 13  0 |  +42.1  +44.5  +10.4  -58.2 |    7.6° | 
 14  0 |  +24.9  +23.8  +11.0  -32.1 |    5.0° | 
 15  0 |   +4.5   +6.5   +5.3   -3.9 |    3.7° | 
 16  0 |   +1.5   +4.8   +5.3   -2.5 |    3.6° | 
 17  0 |   +0.4   +4.6   +5.3   -2.5 |    3.5° | 
 18  0 |   +0.3   +4.6   +5.3   -2.5 |    3.5° | 
== 20261022_182650  チャンク数 16
 ch  g |     j0     j1     j2     j4 | お手本との距離 | 上限で削られた関節
 00  0 |   -0.4   +1.4   +1.8   -0.3 |    0.4° | 
 01  0 |  -10.0  +22.6   +8.4  -26.1 |    0.8° | 
 02  0 |  -22.9  +46.6  +15.2  -56.6 |    1.5° | 
 03  0 |  -29.2  +58.9  +19.5  -70.2 |    1.8° | 
 04  0 |  -29.2  +62.0  +16.1  -67.6 |    2.4° | 
 05  1 |  -28.7  +65.0  +13.1  -62.7 |    2.1° | 
 06  1 |  -27.9  +63.1  +17.4  -66.3 |    2.0° | 
 07  1 |  -11.5  +57.9  +17.8  -66.3 |    2.9° | 
 08  1 |  +17.7  +50.9  +11.0  -58.8 |    3.2° | 
 09  1 |  +41.0  +49.3   +4.8  -53.1 |    2.6° | 
 10  1 |  +41.1  +63.8   +4.7  -68.4 |    2.2° | 
 11  0 |  +41.2  +63.9   +4.7  -68.4 |    2.3° | 
 12  0 |  +41.2  +47.6   +4.7  -50.7 |    3.7° | 
 13  0 |  +19.6  +23.1   +4.0  -20.2 |    4.6° | 
 14  0 |   +2.5   +4.6   +4.0   -3.5 |    2.6° | 
 15  0 |   +0.9   +4.6   +4.0   -3.4 |    2.4° | 
```


## この回で変えた2つのファイルの全文（run_policy_client.py・camera_align.py）

アームを動かすクライアント `pi05/run_policy_client.py` の、この回の最後（コミット 483a82c）の全文です。

```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 点だけ送る従来どおり)
  → グリッパーの開閉がチャンク内で切り替わるなら, その直前の姿勢まで動いてから開閉
  → 撮り直して次のチャンクへ

安全策:
  - 既定はドライラン (アームに送らない). 送るには --execute
  - --execute でも既定は 1 チャンクごとに Enter で確認 (--auto で連続)
  - 学習データで通った関節範囲 ±ENVELOPE_MARGIN_DEG の外へは出さない (クランプ)
  - 肩 j1 の上限は J1_SAFE_MAX (88°) で更に切る. これを超える指令はアームが黙って捨てる (LOG352)
  - 送る直前に最終検査. 6 関節のどれかが安全範囲の外か非有限値なら, 送信もグリッパー操作もせず
    停止 (codex R1 / C2). HOME 復帰 (h) はこの検査を通さずに送れる
  - 1 回の移動量を --max-move-deg で制限 (クランプ), j4 は J4_SAFE 範囲内
  - グリッパー操作後は 2 秒待つ (DAY175 対策・本線と同じ)
  - --raw-dir は必須. 安全範囲は **学習に使ったデータ** から作る (別のデータだと範囲が合わない)
  - 開始時に上カメラの写り方をお手本と比べ, OK 以外ならアームに何も送らずに終了
    (ずれ / 測れない. --ignore-framing で続行). この確認が通るまで daemon にも触らない
  - 開始時のグリッパー開放も, 最初に送る目標が検査を通ってから (codex R2)
  - --state-from-target を付けると, モデルに渡す state の 6 関節を「直前に送った目標」に
    する (既定 off = 実測). 肩の不足 (ブロックを持つと毎チャンク 2.4〜2.6°) が
    チャンクごとに積み重なるのを防ぐ. 目標と実測の差が 6° を超えたチャンクは実測に戻す.
    クランプ・検査・中継点のかけ直しは今までどおり実測が基準 (変わるのは state だけ)
  - 送ったあとに残ったずれ (動きが止まってから測る. > --settle-tol) は, **同じ目標を
    もう一度送って** 詰める (送信 --settle-retries 回まで. LOG359. 0 で従来どおり
    送り直さない). 新しい目標は作らない. 動きが止まらない / 読めない / 送信が失敗した
    ときは送り直しをやめる. どの終わり方でも止めずに次のチャンクへ進む
  - 止まったときに finally でアームを動かさない. 戻すときは Enter 確認の h で明示的に送る

終了コード: 0 = 最後まで / q / h / Ctrl-C,  1 = 安全停止・写り方の不一致・途中のエラー

前提:
  - Pi の daemon が待ち受け中 / 上カメラ (iPhone 連係) が見えている
  - Runpod で serve_policy が起動し, Mac から SSH トンネル (localhost:8000) が張れている
  - pip install msgpack "websockets>=11"

Usage:
  RAW=/Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
  python3 pi05/camera_align.py --raw-dir $RAW                   # 先に上カメラの写り方を合わせる
  python3 pi05/run_policy_client.py --raw-dir $RAW              # ドライラン (予測を表示・記録するだけ)
  python3 pi05/run_policy_client.py --raw-dir $RAW --execute    # 1 チャンクごとに Enter で実行
  python3 pi05/run_policy_client.py --raw-dir $RAW --execute --auto --max-chunks 40
記録: /Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/{stamp}/ (log.jsonl + 各チャンクの入力画像)
--record を付けると recorder.py --top にも trial_start/trial_end を送り, 上カメラ動画を残す.
"""
import argparse
import json
import socket
import sys
import time
import types
from datetime import datetime
from pathlib import Path

import cv2
import numpy as np

# ---- パス (run_pick_place.py と同じ構成) ----------------------------------------
_HERE = Path(__file__).resolve().parent
_ROOT = _HERE.parent
_PLACE = _ROOT / "dynamic_tracking_limits" / "place" / "place_modules"
_DRAG = _ROOT / "dynamic_tracking_limits" / "drag_teaching"
for p in (_HERE, _ROOT, _PLACE, _DRAG):
    sys.path.insert(0, str(p))

# pymycobot スタブ (waypoint_replay 経由の import を Mac 上で通すため. アーム制御は daemon 経由のみ)
if "pymycobot" not in sys.modules:
    _pkg = types.ModuleType("pymycobot"); _mod = types.ModuleType("pymycobot.mycobot")

    class _MyCobotStub:
        def __init__(self, *a, **k):
            raise RuntimeError("MyCobot は直接使わない (daemon 経由のみ)")
    _mod.MyCobot = _MyCobotStub
    sys.modules["pymycobot"] = _pkg; sys.modules["pymycobot.mycobot"] = _mod

import camera_resolver  # noqa: E402
import waypoint_replay as wr  # noqa: E402
from camera_align import (  # noqa: E402
    FRAMING_MAX_DX, FRAMING_MAX_DY, FRAMING_MIN_RESPONSE, framing_verdict, load_reference, measure_framing,
)
from fk_lookup import J1_SAFE_MAX  # noqa: E402  88.0. 本線と二重定義しない
from j0_sweep_scan import SEND_WAIT_SEC, SPEED, _send_and_wait_arrival  # noqa: E402  本線と同じ 20 / 1.0
from policy_ws import PolicyClient  # noqa: E402
from visual_servo_pick import (  # noqa: E402
    close_daemon_socket, daemon_get_angles, daemon_send_angles, daemon_set_gripper,
    daemon_set_gripper_value, get_daemon_socket,
)

TASK = "put the red block in the white box"
IMG_LONG = 384                  # build_demo_episodes.py と同じ (学習画像の長辺)
HOME = [0.0, 0.0, 0.0, 0.0, 0.0, -30.0]
GRIP_VALUE = 20                 # run_pick_place.py の close 値
GRIPPER_SLEEP = 2.0
J4_SAFE = (-90.0, 60.0)         # run_pick_place.py の J4_SAFE_MIN/MAX
ENVELOPE_MARGIN_DEG = 10.0
SEND_EPS_DEG = 1e-6             # 送信前の検査の余裕 (小数の誤差で止まらないように)
SETTLE_POLL_SEC = 0.2           # 送り直しの前後, 関節角をこの間隔で読む (codex A2)
SETTLE_STILL_DEG = 0.2          # 続けて読んだ 2 回の差が 6 関節すべてこれ未満なら「止まった」
SETTLE_WAIT_SEC = 2.0           # 止まらなくてもここで待つのをやめ, そのときの値で判定する
# --state-from-target で「直前に送った目標」を渡すのをやめる差 (LOG359).
# 腕がどこかに当たって止まっているときに, 目標だけが先へ進むのを防ぐ.
STATE_TARGET_MAX_GAP_DEG = 6.0
DATA_ROOT = Path("/Volumes/KIOXIA/r2r2r-data")
LOG_ROOT = DATA_ROOT / "runs" / "pi05_policy"
RECORDER = ("127.0.0.1", 5556)


def load_envelope(raw_dir: Path):
    """学習データで通った各関節の範囲 ± マージン. 物理可動域 (wr.JOINT_LIMITS)・J4_SAFE・J1_SAFE_MAX で更に絞る."""
    qs = [np.load(p)["state"][:, :6] for p in raw_dir.glob("*/episode.npz")]
    if not qs:
        sys.exit(f"[ERROR] 学習エピソードが見つからない (安全範囲を作れない): {raw_dir}")
    q = np.concatenate(qs)
    lo = q.min(axis=0) - ENVELOPE_MARGIN_DEG
    hi = q.max(axis=0) + ENVELOPE_MARGIN_DEG
    for k, (plo, phi) in enumerate(wr.JOINT_LIMITS):
        lo[k], hi[k] = max(lo[k], plo), min(hi[k], phi)
    lo[4], hi[4] = max(lo[4], J4_SAFE[0]), min(hi[4], J4_SAFE[1])
    # 肩 j1: wr.JOINT_LIMITS[1] の上限は +123° なので, マージンを足すと +98° まで通ってしまう.
    # 88° を超える指令はアームが黙って捨てる (LOG352) ので, ここで切る.
    hi[1] = min(hi[1], J1_SAFE_MAX)
    # codex R3: lo > hi や非有限値のまま運転しない (np.clip は例外を出さないので黙って通る).
    # lo を書き換えて辻褄を合わせるのではなく, 起動を中止する.
    bad = [k for k in range(6)
           if not (np.isfinite(lo[k]) and np.isfinite(hi[k])) or lo[k] > hi[k]]
    if bad:
        sys.exit("[ERROR] 安全範囲が不整合 (lo > hi か非有限値): "
                 + "  ".join(f"j{k}[{lo[k]:+.1f},{hi[k]:+.1f}]" for k in bad)
                 + f"\n        学習データが安全制約 (J1_SAFE_MAX={J1_SAFE_MAX:.0f}° / J4_SAFE / "
                 f"JOINT_LIMITS) と合っていない: {raw_dir}")
    return lo, hi, len(qs)


def read_angles():
    for _ in range(5):
        try:
            a = daemon_get_angles()
        except Exception:
            a = None
        if wr._is_valid_angles(a):
            return np.array([float(x) for x in a])
        time.sleep(0.1)
    return None


def grab_rgb(cap):
    for _ in range(3):            # バッファに溜まった古いフレームを捨てる
        cap.grab()
    ok, frame = cap.read()
    if not ok or frame is None:
        return None, None
    h, w = frame.shape[:2]
    s = IMG_LONG / max(h, w)
    small = cv2.resize(frame, (round(w * s), round(h * s)), interpolation=cv2.INTER_AREA)
    return cv2.cvtColor(small, cv2.COLOR_BGR2RGB), small   # モデルへは RGB, 保存は BGR


def plan_chunk(actions, q, grip, n_steps):
    """チャンクから今回動かす目標を決める. 戻り値: (目標6軸, グリッパー指令 None/0/1, 使ったステップ)."""
    want = (actions[:, 6] > 0.5).astype(int)
    for f in range(min(n_steps, len(actions))):
        if want[f] != grip:
            target = q.copy() if f == 0 else actions[f - 1, :6]
            return np.asarray(target, dtype=float), int(want[f]), f
    k = min(n_steps, len(actions)) - 1
    return np.asarray(actions[k, :6], dtype=float), None, k


def apply_limits(target, q, lo, hi, max_move):
    notes = []
    t = target.copy()
    clipped = np.clip(t, lo, hi)
    for k in np.where(np.abs(clipped - t) > 1e-6)[0]:
        notes.append(f"j{k} 安全範囲でクランプ {t[k]:+.1f}→{clipped[k]:+.1f}")
    t = clipped
    d = t - q
    big = np.abs(d) > max_move
    for k in np.where(big)[0]:
        notes.append(f"j{k} 移動量 {d[k]:+.1f}° を ±{max_move:.0f}° に制限")
    t = q + np.clip(d, -max_move, max_move)
    return t, notes


def check_send_safe(target, lo, hi):
    """送る直前の最終検査 (codex R1 / C2). 違反の理由を返す (空なら送って良い).

    apply_limits は「安全範囲でクランプ → 移動量の上限」の順なので, 現在角が安全範囲の
    外にあると, クランプで範囲内に入れた目標が移動量の制限でまた範囲の外に戻る.
      j1 (codex R1): 現在 110° / 予測 100° / 上限 20° → 88° にクランプ後, 110-20 = 90° を送る
      j4 (codex C2): 現在 100° / 予測  90° / 上限 20° → 60° にクランプ後, 100-20 = 80° を送る
    j1 だけでなく 6 関節すべてを見る. ここで再クランプすると移動量の上限を破るので, 送らずに止める.
    HOME 復帰 (Enter 確認の h) はこの検査を通さない: 範囲の外にいるアームを戻す手段として残す.
    """
    if not np.all(np.isfinite(target)):
        return ["目標に非有限値が入っている: " + " ".join(f"j{k}={v}" for k, v in enumerate(target))]
    bad = []
    for k in range(6):
        if target[k] < lo[k] - SEND_EPS_DEG or target[k] > hi[k] + SEND_EPS_DEG:
            msg = f"j{k} {target[k]:+.2f}° が安全範囲 [{lo[k]:+.2f}, {hi[k]:+.2f}] の外"
            if k == 1 and target[k] > hi[k] and abs(hi[k] - J1_SAFE_MAX) < 1e-9:
                msg += (f" (上限は J1_SAFE_MAX={J1_SAFE_MAX:.0f}°. "
                        "これを超える指令はアームが黙って捨てる / LOG352)")
            elif k == 4:
                msg += f" (j4 の範囲は 学習データ ∩ J4_SAFE [{J4_SAFE[0]:+.0f}, {J4_SAFE[1]:+.0f}])"
            bad.append(msg)
    return bad


def _fmt6(a):
    return None if a is None else [round(float(v), 2) for v in a[:6]]


def read_until_still():
    """関節角が止まるまで待ってから読む (codex A2/A6).

    戻り値: (角度 or None, 止まったか, 直前に読めた角度 or None)
      1 番目は **読めたときだけ** 値が入る. 読み取りに失敗したら None で,
      古い値を代わりに返さない (A6: 失敗を隠さない). 3 番目に最後に読めた値を別に返す.

    _send_and_wait_arrival も daemon_send_angles も, 戻った直後はまだ動いている
    ことがある. その値で残りのずれを測ると, 動いている途中の姿勢で判断してしまう.
    SETTLE_POLL_SEC おきに読み, 続けて読んだ 2 回の差が 6 関節すべてで
    SETTLE_STILL_DEG 未満になったら「止まった」とみなす.
    SETTLE_WAIT_SEC まで止まらなければ打ち切り, そのときの値を still=False で返す.
    """
    prev = read_angles()
    if prev is None:
        return None, False, None
    t0 = time.time()
    while time.time() - t0 < SETTLE_WAIT_SEC:
        time.sleep(SETTLE_POLL_SEC)
        cur = read_angles()
        if cur is None:
            return None, False, prev
        if np.max(np.abs(cur[:6] - prev[:6])) < SETTLE_STILL_DEG:
            return cur, True, cur
        prev = cur
    return prev, False, prev


def plan_vias(acts, q, final_target, used, stride, lo, hi, max_move, final_raw_index=None):
    """チャンクの途中の姿勢も中継点として順に通る計画を作る (LOG359).

    今までは plan_chunk が選んだ 1 点だけを送っていたので, アームはそこへ一直線に動き,
    チャンクの中の順番が消えていた. 2026-10-22 の実機 114643 のチャンク 04 では,
    予測が「最初の 0.4 秒は持ち上げだけ (j0 はほぼ動かない) → 0.5 秒から土台 j0 が回る」
    だったのに, 上げながら回る動きになっていた (お手本は つかんだあと 1.5 秒 j0 を止めて
    持ち上げている).

    stride=0 (既定) なら中継点なし = used の 1 点だけ (従来と同じ計算).
    stride=N なら 0 始まりで N-1, 2N-1, ... のうち used より小さいステップを中継点にし,
    最後に used (plan_chunk が選んだ姿勢) を置く. 例: N=3 used=9 → 2, 5, 8, 9 /
    N=3 used=6 (7 番目でグリッパーが変わる) → 2, 5, 6.

    移動量の制限 (apply_limits) は **直前の中継点の目標から** 測る. 最初の中継点だけ
    今の実測角 q から測る. 実測ではなく目標から測るので, 送る前に全部計算できる
    (= 送り始める前に全部の中継点を check_send_safe にかけられる).

    final_raw_index は, 最後の点 (used) の raw が actions の何行目か. グリッパーが
    切り替わるチャンクでは plan_chunk が used-1 行目を返すので step とずれる (codex A1).

    戻り値: [{"step", "raw_index", "raw", "target", "notes", "delta"}] の並び
    (target は ndarray). target は計画時のもので, 送る直前に実測角からかけ直す.
    """
    steps = [k for k in range(stride - 1, used, stride)] if stride and stride > 0 else []
    steps.append(int(used))
    plan = []
    prev = np.asarray(q, dtype=float).copy()
    for k in steps:
        last = k == used
        raw = (np.asarray(final_target, dtype=float) if last
               else np.asarray(acts[k, :6], dtype=float))
        t, notes = apply_limits(raw, prev, lo, hi, max_move)
        plan.append({"step": int(k), "raw_index": (final_raw_index if last else int(k)),
                     "raw": raw, "target": t, "notes": notes, "delta": t - prev})
        prev = t
    return plan


def settle_target(target, label, tol, retries):
    """送ったあとに残ったずれを, **同じ目標をもう一度送って** 詰める (LOG359).

    2026-10-21/22 の実機 4 回 (183245 / 095251 / 100713 / 102053) で, ブロックを持って
    肩を持ち上げる指令 (j1 を小さくする向き) は 28 回すべて指令まで届かず,
    0.77〜2.80° (中央 2.00°) 低いところで止まっていた. 逆向き (下げる) は 0.5〜1° 行き過ぎる.
    到達判定は _send_and_wait_arrival(..., 3.0) の 3° なので, このずれは「着いた」と
    見なされ, モデルは実際の姿勢から次を予測する. その結果 持ち上げが毎回 2° ずつ失われ,
    ブロックがマットから離れない (102053 は上げる指令の合計 41° に対して実際は 11°).

    新しい目標は作らない. 渡された target (apply_limits と check_send_safe を通ったもの) を
    そのまま送り直すだけ. どの終わり方でも止めない (警告を出して呼び出し側が次へ進む).

    retries は **settle で送る送信回数の上限** (codex A5). 送り直しは
    _send_and_wait_arrival ではなく, その中で使っている 1 回だけ送る層
    daemon_send_angles(..., speed=SPEED, wait=SEND_WAIT_SEC) を直接呼ぶ.
    中で再送しないので送信回数を正確に数えられる (上限を超えない).
    送ったあとは read_until_still() で止まるのを待ってから測る.
    チャンク本体の送信は今までどおり _send_and_wait_arrival のまま.

    戻り値: (記録用の dict, 送信回数).  dict の reason は
      within_tol    tol 以内 (送っていない)
      converged     送り直して tol 以内に入った
      not_converged 送信回数の上限まで送っても tol を超えたまま
      not_still     SETTLE_WAIT_SEC 待っても動きが止まらない (動いている最中には送らない)
      send_failed   daemon_send_angles が例外を投げた
      read_failed   関節角を読めない (古い値で判定しない)
      disabled      --settle-retries 0 (何も読まない・何も送らない)
    どの reason でも形は同じ (final_err / joint / final_actual / last_valid_actual / tries).
    """
    out = {"reason": "disabled", "tol": tol, "sends": 0, "final_err": None, "joint": None,
           "final_actual": None, "last_valid_actual": None, "tries": []}
    if retries <= 0:                   # --settle-retries 0 で従来と同じ動き (読みも送りもしない)
        return out, 0

    tgt = np.asarray(target, dtype=float)[:6]
    tries, sends, n = [], 0, 0
    actual, still, last_valid = read_until_still()
    while True:
        if actual is None:             # 読めない値で判定しない (A6)
            reason = "read_failed"
            break
        err = np.abs(tgt - actual[:6])
        k = int(err.argmax())
        cur_err = float(err[k])
        if cur_err <= tol:
            reason = "converged" if sends else "within_tol"
            break
        if not still:                  # 動いている最中には送らない (A2)
            reason = "not_still"
            break
        if sends >= retries:
            reason = "not_converged"
            break
        n += 1
        entry = {"try": n, "max_err_before": round(cur_err, 2), "joint": k, "sends": 1,
                 "sent": True, "still": None, "max_err_after": None, "actual": None}
        sends += 1
        try:
            daemon_send_angles(tgt.tolist(), speed=SPEED, wait=SEND_WAIT_SEC)
        except Exception as e:
            entry["sent"] = False
            entry["error"] = f"{type(e).__name__}: {e}"
            tries.append(entry)
            print(f"       [SETTLE] 送り直し {n} 回目の送信に失敗: {entry['error']}")
            reason = "send_failed"
            break
        after, still, lv = read_until_still()
        if lv is not None:
            last_valid = lv
        if after is None:
            tries.append(entry)
            print(f"       [SETTLE] 送り直し {n} 回目  最大ずれ {cur_err:.2f}°（関節 j{k}）→ 読めず")
            actual = None
            reason = "read_failed"
            break
        entry["still"] = bool(still)
        after_err = float(np.abs(tgt - after[:6]).max())
        entry["max_err_after"] = round(after_err, 2)
        entry["actual"] = _fmt6(after)
        tries.append(entry)
        print(f"       [SETTLE] 送り直し {n} 回目  最大ずれ {cur_err:.2f}°（関節 j{k}）→ {after_err:.2f}°"
              + ("" if still else f"  (動きが止まらないまま {SETTLE_WAIT_SEC:.1f} 秒で打ち切り)"))
        actual = after

    out.update(reason=reason, sends=sends, tries=tries, last_valid_actual=_fmt6(last_valid))
    if actual is not None:
        err = np.abs(tgt - actual[:6])
        k = int(err.argmax())
        out.update(final_err=round(float(err[k]), 2), joint=k, final_actual=_fmt6(actual))
    if sends or reason != "within_tol":
        gloss = {"within_tol": "もともと範囲内", "converged": "詰まった",
                 "not_converged": "詰まらなかった", "not_still": "動きが止まらない",
                 "send_failed": "送信が失敗", "read_failed": "関節角を読めない"}[reason]
        tail = ("最後の最大ずれ 不明" if out["final_err"] is None
                else f"最後の最大ずれ {out['final_err']:.2f}°（関節 j{out['joint']}）")
        print(f"       [SETTLE] {reason} ({gloss})  送信 {sends} 回  {tail}")
        if reason != "converged":
            print("       [WARN] 送り直しで詰めきれませんでした (止めずに次へ進みます)")
    return out, sends


def notify_recorder(sock, payload):
    try:
        payload = dict(payload, ts=time.time())
        sock.sendto((json.dumps(payload) + "\n").encode(), RECORDER)
    except Exception:
        pass


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--host", default="localhost")
    ap.add_argument("--port", type=int, default=8000)
    ap.add_argument("--execute", action="store_true", help="アームに送る (未指定はドライラン)")
    ap.add_argument("--auto", action="store_true", help="Enter 確認なしで連続実行")
    ap.add_argument("--steps-per-chunk", type=int, default=5, help="1 チャンクで何ステップ先まで進むか (0.1 秒単位)")
    ap.add_argument("--max-chunks", type=int, default=60)
    ap.add_argument("--max-move-deg", type=float, default=20.0, help="1 回の移動で各関節が動ける上限")
    ap.add_argument("--raw-dir", required=True,
                    help="安全範囲の算出に使う学習エピソード (必須. 学習に使った raw_episodes を指定する)")
    ap.add_argument("--prompt", default=TASK)
    ap.add_argument("--record", action="store_true", help="recorder.py --top に上カメラ動画を記録させる")
    ap.add_argument("--ignore-framing", action="store_true",
                    help="上カメラの写り方がお手本と違っても続ける (既定は何も送らずに終了)")
    ap.add_argument("--state-from-target", action="store_true",
                    help="モデルに渡す state の 6 関節を, 実測ではなく直前に送った目標にする "
                         "(既定 off = 実測). 肩の不足がチャンクごとに積み重なるのを防ぐ")
    ap.add_argument("--via-stride", type=int, default=0,
                    help="チャンクの途中の姿勢も中継点として順に送る (0 始まりで N-1, 2N-1, ... の "
                         "ステップ. 既定 0 = 従来どおり選んだ 1 点だけ送る)")
    ap.add_argument("--settle-tol", type=float, default=1.0,
                    help="送ったあとの残りのずれ (動きが止まってから測る) がこれを超えていたら "
                         "同じ目標を送り直す (度)")
    ap.add_argument("--settle-retries", type=int, default=2,
                    help="settle で同じ目標を送り直す回数の上限 (送信の試行回数). "
                         "0 で送り直さない = 従来の動き")
    args = ap.parse_args()

    if not DATA_ROOT.exists():
        sys.exit(f"[ERROR] SSD 未マウント: {DATA_ROOT}")
    lo, hi, n_eps = load_envelope(Path(args.raw_dir))
    print(f"[SAFE  ] 安全範囲 (学習 {n_eps} 本 ±{ENVELOPE_MARGIN_DEG:.0f}°): "
          + "  ".join(f"j{k}[{lo[k]:+.0f},{hi[k]:+.0f}]" for k in range(6)))
    print(f"[SAFE  ] 肩 j1 の上限は J1_SAFE_MAX={J1_SAFE_MAX:.0f}° で切った "
          f"(これを超える指令はアームが黙って捨てる / LOG352)  元データ: {args.raw_dir}")

    stamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    log_dir = LOG_ROOT / f"pi05_{stamp}"
    (log_dir / "frames").mkdir(parents=True, exist_ok=True)
    log_f = (log_dir / "log.jsonl").open("w")
    run_stem = f"pi05_{stamp}"
    mode = "EXECUTE" if args.execute else "DRY-RUN (アームには送らない)"
    print(f"[MODE  ] {mode}  steps/chunk={args.steps_per_chunk}  max_move={args.max_move_deg}°  log={log_dir}")

    # 以降は try/finally の中だけで資源を触る (codex R3: 途中で終了しても cap / log_f を必ず閉じる).
    # sys.exit は SystemExit を投げるので, この finally を通って後始末される.
    cap = policy = rec_sock = None
    exit_code = 0
    grip = 0
    grip_opened = False          # 開始時のグリッパー開放を済ませたか (codex R2)
    last_sent_target = None      # 直前のチャンクで最後に送った目標 (--state-from-target 用)
    try:
        cams = camera_resolver.resolve_cameras(require_top=True, require_side=False, verbose=False)
        cap = cv2.VideoCapture(cams["top"])
        if not cap.isOpened():
            sys.exit("[ERROR] 上カメラを開けない")
        t_cam = time.time()
        while time.time() - t_cam < 8.0:       # 連係カメラは映像が来るまで数秒かかることがある
            ok, _f = cap.read()
            if ok and _f is not None:
                break
            time.sleep(0.2)
        else:
            sys.exit("[ERROR] 上カメラから映像が来ない. iPhone のロック解除・連係カメラの接続を確認 "
                     "(Photo Booth の『カメラ』メニューに iPhone が出るか)")

        # E (2026-10-21): 上カメラの写り方は 2 通りあり, カメラを開くたびに切り替わることがある.
        # お手本と違う写り方のまま動かすと, 学習と別の画像を見せることになる
        # (082645 は dy=+37.5 のまま実機を動かした. その 1 分前のドライラン 082512 は dy=-7.8).
        # アームは HOME に置いた状態で, 1 枚目を お手本の 1 枚目 (同じく HOME) と比べる.
        # **この確認が通るまで daemon にも触らない** (アームには何も送らない).
        ref_bgr, ref_path = load_reference(Path(args.raw_dir))
        bgr0 = None
        for _ in range(10):
            _rgb0, bgr0 = grab_rgb(cap)
            if bgr0 is not None:
                break
            time.sleep(0.2)
        if bgr0 is None:
            sys.exit("[ERROR] 上カメラの 1 枚目を撮れない")
        dx, dy, resp = measure_framing(ref_bgr, bgr0)
        verdict, why = framing_verdict(dx, dy, resp)
        print(f"[CAMERA] 写り方 dy={dy:+.1f} dx={dx:+.1f} response={resp:.3f} → {verdict} ({why})")
        print(f"[CAMERA] 基準: {ref_path}")
        log_f.write(json.dumps({"type": "framing", "dy": round(dy, 2), "dx": round(dx, 2),
                                "response": round(resp, 3), "verdict": verdict, "why": why,
                                "max_dy": FRAMING_MAX_DY, "max_dx": FRAMING_MAX_DX,
                                "min_response": FRAMING_MIN_RESPONSE,
                                "ok": verdict == "OK", "ignored": bool(args.ignore_framing),
                                "reference": str(ref_path)}) + "\n")
        log_f.flush()
        if verdict != "OK":
            if not args.ignore_framing:
                sys.exit(f"[ABORT ] 上カメラの写り方が『{verdict}』. アームには何も送らずに終了しました.\n"
                         f"         {why}\n"
                         "         pi05/camera_align.py で合わせ直す "
                         "(iPhone を付け直す / 連係カメラを開き直す).\n"
                         "         この写り方のまま続けるなら --ignore-framing")
            print(f"[WARN  ] 写り方が『{verdict}』だが --ignore-framing が指定されたので続けます")

        # ---- ここから先でアームに触る (写り方の確認を通ったあと) ----
        get_daemon_socket()
        policy = PolicyClient(args.host, args.port)
        print(f"[POLICY] 接続 {policy.uri}  metadata={policy.metadata}")
        rec_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        if args.record:
            notify_recorder(rec_sock, {"type": "trial_start", "run_stem": run_stem})

        q = read_angles()
        if q is None:
            sys.exit("[ERROR] 関節角を読めない (daemon を確認)")
        if np.max(np.abs(q - np.array(HOME))) > 5.0:
            print(f"[WARN  ] HOME から離れています (max|Δ|={np.max(np.abs(q - np.array(HOME))):.1f}°). "
                  "学習データは HOME から始まっています")
            print("         現在角: " + " ".join(f"j{k}={v:+.1f}" for k, v in enumerate(q)))
        if args.execute:
            # 開始時の開放は, 最初に送る目標が検査を通ってからにする (codex R2).
            # 以前はここで開いていたので, 1 チャンク目が安全ガードで止まる場合でも
            # 爪だけ先に開いてしまっていた (物を持っていれば落とす).
            print("[GRIP  ] 開始時のグリッパー開放は, 最初の目標が検査を通ってから行います "
                  "(爪が閉じていたら手で開けておく)")

        for i in range(args.max_chunks):
            q = read_angles()
            if q is None:
                print("[ERROR] 関節角を読めない (daemon を確認). 停止"); exit_code = 1; break
            rgb = bgr_small = None
            for _ in range(10):
                rgb, bgr_small = grab_rgb(cap)
                if rgb is not None:
                    break
                time.sleep(0.2)
            if rgb is None:
                print("[ERROR] 上カメラの映像が途切れた (iPhone のスリープ等). 停止")
                exit_code = 1; break
            # モデルに渡す state の 6 関節 (--state-from-target のときだけ「直前に送った目標」).
            # apply_limits / check_send_safe / 中継点のかけ直しは今までどおり実測 q を使う.
            measured_state = np.concatenate([q, [float(grip)]]).astype(np.float32)
            state_joints, state_source = q, "measured"
            if args.state_from_target:
                if last_sent_target is None:
                    print("[STATE ] 実測を渡す (直前に送った目標がない)")
                else:
                    gap = float(np.max(np.abs(last_sent_target - q[:6])))
                    if gap > STATE_TARGET_MAX_GAP_DEG:
                        print(f"[WARN  ] 目標と実測の差が {gap:.2f}° > {STATE_TARGET_MAX_GAP_DEG:.0f}° "
                              "なので実測を渡します (腕がどこかに当たって止まっている可能性)")
                    else:
                        state_joints, state_source = last_sent_target, "target"
                    print(f"[STATE ] {'目標' if state_source == 'target' else '実測'}を渡す  "
                          f"目標と実測の最大差 {gap:.2f}°"
                          f"（関節 j{int(np.argmax(np.abs(last_sent_target - q[:6])))}）")
            state = np.concatenate([state_joints, [float(grip)]]).astype(np.float32)
            t0 = time.time()
            out = policy.infer({"observation/image": rgb, "observation/state": state, "prompt": args.prompt})
            latency = time.time() - t0
            acts = np.asarray(out["actions"], dtype=float)
            raw_target, grip_cmd, used = plan_chunk(acts, q, grip, args.steps_per_chunk)
            # plan_chunk は, グリッパーが切り替わるチャンクでは used-1 行目 (used=0 なら実測角)
            # を目標に返す. actions の何行目を使ったかを記録に残す (codex A1).
            final_raw_index = (used if grip_cmd is None else (used - 1 if used > 0 else None))
            # 中継点の計画 (--via-stride 0 なら used の 1 点だけ = 従来と同じ).
            plan = plan_vias(acts, q, raw_target, used, args.via_stride, lo, hi,
                             args.max_move_deg, final_raw_index)
            target, notes = plan[-1]["target"], plan[-1]["notes"]     # チャンクの最終目標
            delta = target - q

            cv2.imwrite(str(log_dir / "frames" / f"{i:04d}.jpg"), bgr_small)
            rec = {"chunk": i, "t": time.time(), "latency_s": round(latency, 3), "state": state.tolist(),
                   "state_source": state_source, "measured_state": measured_state.tolist(),
                   "actions": acts.tolist(), "used_step": used, "target": target.tolist(),
                   "grip_cmd": grip_cmd, "notes": notes, "executed": False}
            gtxt = "" if grip_cmd is None else ("  グリッパー→閉" if grip_cmd == 1 else "  グリッパー→開")
            print(f"[{i:03d}] 推論 {latency*1000:.0f}ms  {used + 1}ステップ先  Δ="
                  + " ".join(f"{d:+5.1f}" for d in delta) + gtxt)
            for n in notes:
                print(f"       [LIMIT] {n}")
            if args.via_stride > 0:
                rec["vias"] = [{"step": v["step"], "raw_index": v["raw_index"],
                                "raw": _fmt6(v["raw"]), "planned_target": _fmt6(v["target"]),
                                "target": _fmt6(v["target"]), "notes": v["notes"],
                                "called": False, "success": None, "retried": None,
                                "actual_after": None} for v in plan]
                print(f"       [VIA   ] 中継点 {len(plan)} 点: step "
                      + ", ".join(str(v["step"]) for v in plan))
                for v in plan:
                    for n in v["notes"]:
                        print(f"       [LIMIT] step {v['step']}: {n}")
                    if not args.execute:   # ドライランは中継点の一覧だけ出して送らない
                        print(f"       [VIA   ] step {v['step']:2d}  Δ="
                              + " ".join(f"{d:+5.1f}" for d in v["delta"]))

            # 送る直前の最終検査 (codex R1 / C2). 中継点は 1 点でも引っかかったら
            # **どれも送らずに** 止める (途中まで動かして止まる方が危ない).
            # 送信にもグリッパー操作にも入らず止める.
            # HOME 復帰 (h) だけはこの検査を通さずに送れる (範囲の外にいるアームを戻す手段).
            unsafe = []
            for v in plan:
                for u in check_send_safe(v["target"], lo, hi):
                    unsafe.append(u if args.via_stride <= 0 else f"step {v['step']}: {u}")

            stopped = False
            if not unsafe and args.execute:
                # ここから先で送れなかった経路 (s / 送信なし / 中断) は, 次のチャンクで
                # 実測を渡すために None のままにする (--state-from-target 用).
                last_sent_target = None
                if not args.auto:
                    ans = input("       Enter=実行 / s=送らず次へ / h=HOMEに戻して終了 / q=終了 > ").strip().lower()
                    if ans == "q":
                        log_f.write(json.dumps(rec) + "\n"); break
                    if ans == "h":
                        ok_home, _ = _send_and_wait_arrival(HOME, "pi05_home", 2.5)
                        rec["home_requested"] = True
                        rec["home_arrived"] = bool(ok_home)
                        log_f.write(json.dumps(rec) + "\n"); break
                    if ans == "s":
                        log_f.write(json.dumps(rec) + "\n"); continue
                if not grip_opened:
                    # 開始時の開放はここで 1 度だけ (写り方の確認と目標の検査を通り, 送ると決めてから)
                    print("[GRIP  ] 開始時にグリッパーを開く")
                    daemon_set_gripper(0)
                    time.sleep(GRIPPER_SLEEP)
                    grip_opened = True
                    rec["initial_gripper_open"] = True
                broke, final_target, final_sent, sent_any = False, None, False, False
                for vi, v in enumerate(plan):
                    v_last = vi == len(plan) - 1
                    tag = (f"pi05_chunk{i:03d}" if args.via_stride <= 0
                           else f"pi05_chunk{i:03d}_via{v['step']:02d}")
                    tgt, vdelta = v["target"], v["delta"]
                    if args.via_stride > 0:
                        # 送る直前に実測角を読み, そこから apply_limits と check_send_safe を
                        # かけ直す (codex A2: 1 点だけ送る従来の方式と同じ基準にそろえる).
                        qa = read_angles()
                        if qa is None:
                            print("       [WARN] 送る直前の関節角を読めない. "
                                  "この中継点も残りの中継点も送りません")
                            print("       [WARN] 未到達. j4 の発熱などを確認してください")
                            rec["arrived"] = False
                            broke = True
                            if args.auto:
                                exit_code = 1
                                log_f.write(json.dumps(rec) + "\n")
                                stopped = True
                            break
                        tgt, notes_now = apply_limits(v["raw"], qa, lo, hi, args.max_move_deg)
                        if notes_now != v["notes"]:
                            for n in notes_now:
                                print(f"       [LIMIT] step {v['step']} (実測から): {n}")
                        rec["vias"][vi].update(target=_fmt6(tgt), notes=notes_now)
                        u2 = check_send_safe(tgt, lo, hi)
                        if u2:
                            unsafe = [f"step {v['step']}: {x}" for x in u2]
                            broke = True
                            break
                        vdelta = tgt - qa          # 送らない判定は実測との差で見る (codex ❌1)
                    final_target = tgt
                    if np.max(np.abs(vdelta)) <= 0.5:
                        if args.via_stride > 0:
                            print(f"       [VIA   ] step {v['step']:2d}  Δ="
                                  + " ".join(f"{d:+5.1f}" for d in vdelta) + "  送らず (0.5° 以下)")
                        continue
                    ok, retried = _send_and_wait_arrival(tgt.tolist(), tag, 3.0)
                    sent_any = True
                    if args.via_stride > 0:
                        rec["vias"][vi].update(called=True, success=bool(ok), retried=bool(retried),
                                               actual_after=_fmt6(read_angles()))
                        print(f"       [VIA   ] step {v['step']:2d}  Δ="
                              + " ".join(f"{d:+5.1f}" for d in vdelta)
                              + ("  着いた" if ok else "  未到達"))
                    if v_last:
                        rec["arrived"] = bool(ok)
                        final_sent = True
                    if not ok:
                        print("       [WARN] 未到達. j4 の発熱などを確認してください")
                        if args.auto:
                            exit_code = 1
                            log_f.write(json.dumps(rec) + "\n")
                            stopped = True
                            broke = True
                            break
                    if v_last:
                        # 残ったずれを同じ目標の送り直しで詰める (LOG359). 止める条件は増やさない.
                        rec["settle"], rec["settle_retries_used"] = settle_target(
                            tgt, f"pi05_chunk{i:03d}", args.settle_tol, args.settle_retries)
                if not broke and args.via_stride > 0 and not final_sent and final_target is not None:
                    # 最後の中継点が「送らない」になった場合も, チャンクの最後の目標について
                    # 到達の記録と settle は必ず行う (codex ❌2: 重複送信を省くことと分ける).
                    qa = read_angles()
                    rec["arrived"] = bool(qa is not None
                                          and float(np.max(np.abs(final_target - qa[:6]))) <= 3.0)
                    rec["settle"], rec["settle_retries_used"] = settle_target(
                        final_target, f"pi05_chunk{i:03d}", args.settle_tol, args.settle_retries)
                if not broke:
                    # 次のチャンクで --state-from-target が使う「直前に送った目標」.
                    # 送らなかった (s / 送信なし / 中断) ときは None に戻して実測を渡す.
                    last_sent_target = (np.asarray(final_target, dtype=float).copy()
                                        if sent_any and final_target is not None else None)
                    if grip_cmd is not None:
                        if grip_cmd == 1:
                            daemon_set_gripper_value(GRIP_VALUE)
                        else:
                            daemon_set_gripper(0)
                        time.sleep(GRIPPER_SLEEP)
                        grip = grip_cmd
                    rec["executed"] = True
            if stopped:
                break
            if unsafe:
                # 計画の検査 または 送る直前のかけ直しで範囲の外になったとき.
                # 送信にもグリッパー操作にも入らず止める.
                # HOME 復帰 (h) だけはこの検査を通さずに送れる (範囲の外にいるアームを戻す手段).
                rec["unsafe"] = unsafe
                rec["envelope"] = {"lo": [round(float(v), 2) for v in lo],
                                   "hi": [round(float(v), 2) for v in hi]}
                for u in unsafe:
                    print(f"       [ABORT] {u}")
                print("[STOP  ] 安全でない目標のため, 送らずに停止します "
                      "(現在角が安全範囲の外にあると, 移動量の制限で範囲の外に戻る)")
                # 記録は入力より前に書いて flush する (codex C2-1: 入力待ちや HOME 復帰中の
                # Ctrl-C でこのチャンクの unsafe / envelope が消えないように).
                log_f.write(json.dumps(rec) + "\n"); log_f.flush()
                exit_code = 1
                if args.execute and not args.auto:
                    ans = input("       h=HOMEに戻して終了 / 他=そのまま終了 > ").strip().lower()
                    if ans == "h":
                        ok_home, _ = _send_and_wait_arrival(HOME, "pi05_home", 2.5)
                        log_f.write(json.dumps({"chunk": i, "type": "home_return", "t": time.time(),
                                                "home_requested": True,
                                                "home_arrived": bool(ok_home)}) + "\n")
                        log_f.flush()
                else:
                    print("         アームを HOME に置き直してからやり直してください")
                break
            log_f.write(json.dumps(rec) + "\n"); log_f.flush()
    except KeyboardInterrupt:
        print("\n[STOP  ] Ctrl-C")
    finally:
        # finally ではアームを動かさない (HOME 復帰もサーボ解放もしない). 止まった姿勢は
        # そのまま保つ: 未知の姿勢から勝手に動かす方が危ない. 戻すときは h で明示的に送る.
        if args.record and rec_sock is not None:
            notify_recorder(rec_sock, {"type": "trial_end", "run_stem": run_stem})
        if not log_f.closed:
            log_f.close()
        if cap is not None:
            cap.release()
        if policy is not None:
            policy.close()
        try:
            close_daemon_socket()
        except Exception:
            pass
        print(f"[DONE  ] 記録: {log_dir}")
    # 終了コードは正常に抜けた経路でだけ表示する (sys.exit で抜ける場合は, その [ABORT] /
    # [ERROR] の文言が出て終了コード 1 になるので, ここで 0 と書くと食い違う).
    if exit_code:
        print(f"[DONE  ] 終了コード {exit_code} (安全停止 / 途中のエラー)")
    return exit_code


if __name__ == "__main__":
    sys.exit(main())
```

上カメラの写り方を確かめる `pi05/camera_align.py` の全文です（コミット b5b093c）。

```python
#!/usr/bin/env python3
"""camera_align.py — 上カメラの写り方をお手本に合わせる画面 (Mac 側・アームは動かさない).

上カメラの iPhone は普段使いのもので, 毎回付け外しする. 付けるたびに写り方が変わり,
2026-10-21 の実機では お手本より下に大きくずれたまま動かしてしまった
(runs/pi05_policy/pi05_20261021_082645 は dy=+37.5. 1 分前のドライランは dy=-7.8 で正常).
iPhone を付けたあと, この画面で写り方を合わせてから実機に進む.

使い方は 2 つ:
  1. 上カメラの写り方を お手本と同じに戻す (dy / dx / response を見る)
  2. 重なったお手本に写っているブロックに実物のブロックを合わせて, お手本と同じ位置に置く
     (--episode でどのお手本を重ねるか選ぶ. ブロックの位置はエピソードごとに違う)

画面:
  ライブ映像に 基準画像 (--episode のエピソードの 1 枚目・HOME の姿勢) を半透明で重ねる.
  --episode を省くと --raw-dir の最初のエピソードになる (従来どおり).
  隅に写り方のずれ (dx, dy) と相関の強さ (response) を出し, 判定を大きく表示する:
    OK       しきい値以内
    ZURE     dx か dy がしきい値の外 (= ずれ)
    NO MATCH 相関が弱く dx/dy が当てにならない (= 測れない)
  q または Esc で終了. **表示だけで, ファイルには何も書かない.**

run_policy_client.py は開始時に この measure_framing / framing_verdict で同じ検査をして,
OK 以外ならアームに何も送らずに終了する (--ignore-framing で続行).

前提:
  - 上カメラ (iPhone 連係) が見えている. アームは HOME に置いておく (基準画像が HOME の姿勢)

Usage:
  RAW=/Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
  python3 pi05/camera_align.py --raw-dir $RAW
  python3 pi05/camera_align.py --raw-dir $RAW --episode run_0001_20261019_192343  # 位置を変える
  python3 pi05/camera_align.py --raw-dir $RAW --episode 192343                    # 部分一致でもよい
  python3 pi05/camera_align.py --raw-dir $RAW --alpha 0.7 --scale 2   # 基準を濃く / 画面を小さく
"""
import argparse
import sys
import time
from pathlib import Path

import cv2
import numpy as np

_HERE = Path(__file__).resolve().parent
_ROOT = _HERE.parent
_PLACE = _ROOT / "dynamic_tracking_limits" / "place" / "place_modules"   # camera_resolver はここ
for p in (_HERE, _ROOT, _PLACE):
    sys.path.insert(0, str(p))

import camera_resolver  # noqa: E402

IMG_LONG = 384            # build_demo_episodes.py / run_policy_client.py と同じ (学習画像の長辺)
FRAMING_MAX_DY = 20.0     # |dy| がこれを超えたら「ずれ」. 下の実測値の間を取った
FRAMING_MAX_DX = 20.0     # |dx| の上限 (codex R2). お手本の dx は +0.00..+7.23 (2026-10-21 実測)
# response (相関の強さ) がこれ未満なら, dx/dy を信用できないので「測れない」として止める (codex R1).
# 2026-10-21 実測: 正しく対応している比較は 0.411..1.000.
# 無関係な画像は ランダム 0.0375 / 真っ黒 0.0000, 10/17 の 222723 の 1 枚目は 0.0505
# (dy=+8.2 / dx=-2.5 なので, 相関を見ないと「OK」で通ってしまう).
FRAMING_MIN_RESPONSE = 0.20
WINDOW = "camera_align (q で終了)"


def to_small_bgr(frame):
    """学習画像と同じ大きさに縮める (run_policy_client.grab_rgb と同じ処理)."""
    h, w = frame.shape[:2]
    s = IMG_LONG / max(h, w)
    return cv2.resize(frame, (round(w * s), round(h * s)), interpolation=cv2.INTER_AREA)


def pick_episode(raw_dir: Path, episode=None):
    """基準にするエピソードのフォルダを決める. episode=None なら最初のエピソード (従来どおり).

    episode は エピソード名 (例 run_0001_20261019_192343). 完全一致が無ければ,
    1 本だけに当てはまる部分一致 (例 192343) も受け付ける.
    """
    eps = sorted(p.parent for p in raw_dir.glob("*/episode.npz"))
    if not eps:
        sys.exit(f"[ERROR] お手本が見つからない (基準画像を決められない): {raw_dir}")
    if episode is None:
        return eps[0]
    exact = [p for p in eps if p.name == episode]
    if exact:
        return exact[0]
    part = [p for p in eps if episode in p.name]
    if len(part) == 1:
        return part[0]
    names = "\n".join(f"           {p.name}" for p in eps)
    if len(part) > 1:
        sys.exit(f"[ERROR] --episode {episode} が {len(part)} 本に当てはまります:\n"
                 + "\n".join(f"           {p.name}" for p in part))
    sys.exit(f"[ERROR] --episode {episode} が見つからない. {raw_dir} にあるのは {len(eps)} 本:\n{names}")


def grasp_j0(ep_dir: Path):
    """つかんだ瞬間 (グリッパーが閉に変わったステップ) の j0 [deg]. 分からなければ None.

    どのブロック位置のお手本かを表示するために使う (check_dataset.py の項目 5 と同じ見方).
    """
    try:
        s = np.load(ep_dir / "episode.npz")["state"]
    except Exception:
        return None
    ch = np.flatnonzero(s[1:, 6] > s[:-1, 6]) + 1
    return float(s[ch[0], 0]) if len(ch) else None


def load_reference(raw_dir: Path, episode=None):
    """基準画像 = エピソードの 1 枚目 (HOME の姿勢). 戻り値: (BGR 画像, パス).

    episode=None (既定) なら --raw-dir の最初のエピソード. run_policy_client.py は
    こちらで呼ぶので, 写り方の検査に使う基準は常に最初のエピソードのまま.
    """
    ep = pick_episode(raw_dir, episode)
    frames = sorted((ep / "frames").glob("*.jpg"))
    if not frames:
        sys.exit(f"[ERROR] お手本の画像が無い: {ep}")
    bgr = cv2.imread(str(frames[0]))
    if bgr is None:
        sys.exit(f"[ERROR] 基準画像を読めない: {frames[0]}")
    return bgr, frames[0]


def measure_framing(ref_bgr, cur_bgr):
    """写り方のずれを測る. 戻り値: (dx, dy, response). cv2.phaseCorrelate + ハニング窓.

    2026-10-21 実測 (基準 = teach_v1 の run_0001_20261019_183454 の 1 枚目):
      お手本 191257   dy= +9.1  / お手本 195120 dy= -6.7   ← ブロックの位置で揺れる範囲
      ドライラン 082512 dy= -7.8                            ← お手本と同じ写り方. 通す
      実機 082645       dy=+37.5                            ← 下にずれた写り方. 止める
    dx はブロックの位置で ±6 ほど動く (お手本どうしで +5.0 / +5.8) ので判定には使わず, 表示だけ.
    """
    a = cv2.cvtColor(ref_bgr, cv2.COLOR_BGR2GRAY).astype(np.float32)
    b = cv2.cvtColor(cur_bgr, cv2.COLOR_BGR2GRAY).astype(np.float32)
    if a.shape != b.shape:
        b = cv2.resize(b, (a.shape[1], a.shape[0]), interpolation=cv2.INTER_AREA)
    win = cv2.createHanningWindow((a.shape[1], a.shape[0]), cv2.CV_32F)
    (dx, dy), response = cv2.phaseCorrelate(a, b, win)
    return float(dx), float(dy), float(response)


def framing_verdict(dx, dy, response):
    """写り方の判定. 戻り値: (verdict, 理由). verdict は "OK" / "ずれ" / "測れない".

    相関が弱い (response が低い) ときは dx/dy 自体が当てにならないので,
    「ずれ」ではなく「測れない」として扱う (既定ではどちらも止める).
    """
    if not all(np.isfinite(v) for v in (dx, dy, response)):
        return "測れない", "dx / dy / response に非有限値"
    if response < FRAMING_MIN_RESPONSE:
        return "測れない", (f"相関が弱く dx/dy が当てにならない "
                            f"(response={response:.3f} < {FRAMING_MIN_RESPONSE:.2f})")
    bad = []
    if abs(dy) > FRAMING_MAX_DY:
        bad.append(f"|dy|={abs(dy):.1f} > {FRAMING_MAX_DY:.0f}")
    if abs(dx) > FRAMING_MAX_DX:
        bad.append(f"|dx|={abs(dx):.1f} > {FRAMING_MAX_DX:.0f}")
    if bad:
        return "ずれ", " / ".join(bad)
    return "OK", (f"|dy|<={FRAMING_MAX_DY:.0f} / |dx|<={FRAMING_MAX_DX:.0f} / "
                  f"response>={FRAMING_MIN_RESPONSE:.2f}")


def open_top_camera():
    cams = camera_resolver.resolve_cameras(require_top=True, require_side=False, verbose=False)
    cap = cv2.VideoCapture(cams["top"])
    if not cap.isOpened():
        sys.exit("[ERROR] 上カメラを開けない")
    t0 = time.time()
    while time.time() - t0 < 8.0:           # 連係カメラは映像が来るまで数秒かかることがある
        ok, f = cap.read()
        if ok and f is not None:
            return cap
        time.sleep(0.2)
    cap.release()
    sys.exit("[ERROR] 上カメラから映像が来ない. iPhone のロック解除・連係カメラの接続を確認 "
             "(Photo Booth の『カメラ』メニューに iPhone が出るか)")


def _put(img, text, org, scale, color, thick):
    """黒で縁取ってから描く. 机の白と マットの黒 のどちらに重なっても読めるように."""
    cv2.putText(img, text, org, cv2.FONT_HERSHEY_SIMPLEX, scale, (0, 0, 0), thick + 3, cv2.LINE_AA)
    cv2.putText(img, text, org, cv2.FONT_HERSHEY_SIMPLEX, scale, color, thick, cv2.LINE_AA)


def draw_overlay(small_bgr, ref_bgr, dx, dy, resp, alpha, scale, ref_label=""):
    ref = ref_bgr
    if ref.shape[:2] != small_bgr.shape[:2]:
        ref = cv2.resize(ref, (small_bgr.shape[1], small_bgr.shape[0]), interpolation=cv2.INTER_AREA)
    view = cv2.addWeighted(small_bgr, 1.0 - alpha, ref, alpha, 0)
    big = cv2.resize(view, None, fx=scale, fy=scale, interpolation=cv2.INTER_NEAREST)
    verdict, _why = framing_verdict(dx, dy, resp)
    # cv2.putText は日本語を出せないので画面はローマ字. 端末には日本語で出す.
    label = {"OK": "OK", "ずれ": "ZURE", "測れない": "NO MATCH"}[verdict]
    color = (0, 200, 0) if verdict == "OK" else (0, 0, 255)
    _put(big, label, (16, 56), 1.8, color, 4)
    _put(big, f"dy={dy:+6.1f}  dx={dx:+6.1f}  (OK: both <= {FRAMING_MAX_DY:.0f})", (16, 92), 0.6, color, 2)
    _put(big, f"resp={resp:.3f}  (OK: >= {FRAMING_MIN_RESPONSE:.2f})   q: quit", (16, 116),
         0.6, (230, 230, 230), 1)
    if ref_label:        # どのお手本を重ねているか (ブロックの位置を合わせるときの目印)
        _put(big, f"ref: {ref_label}", (16, big.shape[0] - 14), 0.6, (230, 230, 230), 1)
    return big


def main():
    ap = argparse.ArgumentParser(description="上カメラの写り方をお手本に合わせる (アームは動かさない・表示だけ)")
    ap.add_argument("--raw-dir", required=True,
                    help="基準画像に使う学習エピソード (必須. 既定は最初の 1 本の 1 枚目を基準にする)")
    ap.add_argument("--episode", default=None,
                    help="基準にするエピソード名 (例 run_0001_20261019_192343. "
                         "1 本だけに当てはまる部分一致 192343 でもよい). "
                         "未指定なら最初のエピソード")
    ap.add_argument("--alpha", type=float, default=0.5, help="基準画像の重ね具合 (0=ライブのみ / 1=基準のみ)")
    ap.add_argument("--scale", type=float, default=3.0, help="画面の拡大倍率")
    args = ap.parse_args()

    ref_bgr, ref_path = load_reference(Path(args.raw_dir), args.episode)
    ep_dir = ref_path.parent.parent
    j0 = grasp_j0(ep_dir)
    pos = "つかんだ瞬間が不明" if j0 is None else f"つかんだ瞬間の j0 = {j0:+.1f}°"
    ref_label = f"{ep_dir.name}" + ("" if j0 is None else f"  j0={j0:+.1f}")
    print(f"[REF   ] 基準画像: {ref_path}")
    print(f"[REF   ] お手本 {ep_dir.name} ({pos})"
          + ("" if args.episode else "  ← --episode 未指定なので最初のエピソード"))
    print("[REF   ] 重なった画像のブロックに実物のブロックを合わせると, お手本と同じ位置に置ける")
    print(f"[ALIGN ] |dy| <= {FRAMING_MAX_DY:.0f} なら OK. アームは HOME に置いた状態で合わせる. "
          "q または Esc で終了 (ファイルには何も書かない)")
    cap = open_top_camera()
    last = None
    try:
        while True:
            for _ in range(2):            # バッファに溜まった古いフレームを捨てる
                cap.grab()
            ok, frame = cap.read()
            if not ok or frame is None:
                if cv2.waitKey(100) & 0xFF in (ord("q"), 27):
                    break
                continue
            small = to_small_bgr(frame)
            dx, dy, resp = measure_framing(ref_bgr, small)
            cv2.imshow(WINDOW, draw_overlay(small, ref_bgr, dx, dy, resp,
                                            args.alpha, args.scale, ref_label))
            if last is None or abs(dy - last) > 1.0:      # 端末は値が動いたときだけ出す
                verdict, why = framing_verdict(dx, dy, resp)
                print(f"[ALIGN ] dy={dy:+6.1f}  dx={dx:+6.1f}  response={resp:.3f}  "
                      f"→ {verdict} ({why})")
                last = dy
            if cv2.waitKey(30) & 0xFF in (ord("q"), 27):
                break
    except KeyboardInterrupt:
        print("\n[STOP  ] Ctrl-C")
    finally:
        cap.release()
        cv2.destroyAllWindows()
        print("[DONE  ] 終了 (何も書いていません)")


if __name__ == "__main__":
    main()
```

コミットごとの変更の大きさです。

```
b5b093c camera_align.py: --episode で重ねるお手本を選べるようにする (LOG359)
 pi05/camera_align.py | 94 ++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 80 insertions(+), 14 deletions(-)
c7e726a 送った目標とのずれを同じ目標の送り直しで詰める (LOG359)
 pi05/run_policy_client.py | 155 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 153 insertions(+), 2 deletions(-)
483a82c モデルに渡す state を直前に送った目標にできるようにする (--state-from-target / LOG359)
 pi05/run_policy_client.py | 260 ++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 215 insertions(+), 45 deletions(-)
```


## 次は、手首 j4 を直してから、位置D・E と 18:26 の回の再現を動画で確かめる

次にやることは3つです。

1. 手首 j4 が +45.87° から動かない原因を調べる。daemon の起動し直しと電源の入れ直しでは戻っていない
2. 位置C で、目標を渡すやり方の回を、横からの動画付きで何回か続けて動かし、箱に入る割合を数える。18:26 の回のように動画がない回を作らない
3. 位置D・E で同じやり方を試す。位置E はブロックが爪の陰に入るので、`camera_align.py` を `--alpha 0.7` で重ねて置く

まだ確かめていないことも残っています。目標を渡すやり方で、つかむ位置がお手本より深くなった（肩 j1 ≈ 80°、お手本は 64°）理由は分かっていません。つかみ損ねた2回が、深くつかもうとしたことと関係があるのかも、切り分けられていません。
