# 位置D・位置E の実機の回 (LOG363) を, 同じ位置のお手本 (D 5本・E 4本) と比べる # 1) つかんだ姿勢 / 運ぶ間に肩がいちばん上がった所 (j1 の最小) / 離した姿勢 # 2) ブロックを持って肩を上げる指令の, 目標と次のチャンクの実測の差 (+ は目標より低いまま止まった) # 3) 爪先の高さ (FK 表 fk_scan_motion_based_v2.csv の ee_y を (j1,j2,j3,j4) の近い 40 点で局所線形に当てはめる, LOG361 と同じ) # 実機は中継点ごとに「送った目標 (target)」と「着いたあとの実測 (actual_after)」が残っているので, 肩の高さと爪先の高さは両方を出す import os, json import numpy as np, pandas as pd ROOT = os.environ.get("R2R2R_DATA", "/Volumes/KIOXIA/r2r2r-data"); os.chdir(ROOT) RAW = "datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes" DEMO = {"D": ["193404", "193459", "193617", "193825", "193932"], "E": ["194818", "194913", "195023", "195120"]} RUN = {"D": "20261024_190239", "E": "20261024_191603"} 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 p(v, n=6): return " ".join(f"{x:+6.1f}" for x in v[:n]) for pos in ["D", "E"]: print(f"\n######## 位置{pos}") print("== お手本 (閉じた瞬間 / 持っている間の j1 最小 / 開いた瞬間, 角度は j0..j5)") for e in DEMO[pos]: S = np.load(f"{RAW}/run_0001_20261019_{e}/episode.npz")["state"] g = S[:, 6]; c = int(np.argmax(g > 0.5)); o = c + int(np.argmax(g[c:] < 0.5)) held = S[c:o] k = int(np.argmin(held[:, 1])) hs = [h(S[t]) for t in range(c, o + 1, 10)] print(f"demo {e} 閉 [{p(S[c])}] j1最小 {held[k,1]:+.1f} (j0 {held[k,0]:+.1f}) 開 [{p(S[o])}]") print(f" 爪先の高さ mm 閉じた時 {h(S[c]):6.1f} 最高 {max(h(S[t]) for t in range(c, o+1)):6.1f} 1秒ごと " + " ".join(f"{v:5.0f}" for v in hs)) L = [json.loads(l) for l in open(f"runs/pi05_policy/pi05_{RUN[pos]}/log.jsonl")] L = [x for x in L if "chunk" in x] print(f"== 実機 pi05_{RUN[pos]}") close = [x for x in L if x.get("grip_cmd") == 1] opn = [x for x in L if x.get("grip_cmd") == 0] print(f" 閉じる指令のチャンク {[x['chunk'] for x in close]} 開く指令のチャンク {[x['chunk'] for x in opn]}") if close: c = close[0] print(f" 閉じた所 (閉じる指令のチャンクの最後の目標) [{p(c['target'])}]") held = [x for x in L if x["state"][6] == 1] meas = np.array([x.get("measured_state", x["state"])[:6] for x in held]) vias = [v for x in held for v in (x.get("vias") or [])] vt = np.array([v["target"] for v in vias], float) va = np.array([v["actual_after"] for v in vias], float) k = int(np.argmin(meas[:, 1])) print(f" 持っている間 チャンクの頭の実測 j1 最小 {meas[k,1]:+.1f} (チャンク {held[k]['chunk']}, j0 {meas[k,0]:+.1f})") kk = int(np.argmin(vt[:, 1])); ka = int(np.argmin(va[:, 1])) print(f" 持っている間 中継点の目標 j1 最小 {vt[kk,1]:+.1f} (j0 {vt[kk,0]:+.1f}) 中継点の実測 j1 最小 {va[ka,1]:+.1f} (j0 {va[ka,0]:+.1f})") print(f" 中継点の目標と実測の j1 の差 (+ は低いまま) 平均 {np.mean(va[:,1]-vt[:,1]):+.2f} 最小 {np.min(va[:,1]-vt[:,1]):+.2f} 最大 {np.max(va[:,1]-vt[:,1]):+.2f} ({len(va)} 点)") print(" 中継点ごと (j0 目標 / j1 目標 → 実測 / 爪先の高さ mm 目標 → 実測)") for v in vias: t = v["target"]; a = v["actual_after"] print(f" j0 {t[0]:+6.1f} j1 {t[1]:+6.1f} → {a[1]:+6.1f} 高さ {h(t):5.0f} → {h(a):5.0f}") print(f" 爪先の高さの最高 (中継点の実測) {max(h(a) for a in va):.1f} mm (中継点の目標) {max(h(t) for t in vt):.1f} mm") if opn: o = opn[0] print(f" 離した所 (開く指令のチャンクの最後の目標) [{p(o['target'])}]") print(" 爪先の高さ mm (持っている間のチャンクの頭の実測) " + " ".join(f"{h(s):5.0f}" for s in meas) + f" 最高 {max(h(s) for s in meas):.1f}") print(" 肩 j1: 目標 (チャンクの最後) と 次のチャンクの頭の実測 (+ は目標より低いまま止まった)") 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]) print(f" {a['chunk']:02d} 爪 {int(a['state'][6])} 指令 {t[1]-s[1]:+6.1f} 目標 {t[1]:+6.1f} 実測 {n[1]:+6.1f} ずれ {n[1]-t[1]:+5.2f}")