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)。今の未到達(手動)はグリ ッパーまで進みますが、腕の位置が読めず目標にも着いていない状態で爪を動かすのは 危ないと判断しています。従来どおり爪を動かす方がよければ直します。