mechArm 270 Pi 動的追従の限界を探る Log#35 | place が箱に当たる。姿勢を教え直して対応表を取り直す
LOG235R2R2R2026/6/14

mechArm 270 Pi 動的追従の限界を探る Log#35 | place が箱に当たる。姿勢を教え直して対応表を取り直す

赤ブロックを掴んで白箱に入れる。一本通しの Pick&Place は通るようになった。掴む、運ぶ、置く、判定する。ひととおり動く。

ただし置く瞬間に問題が出ていた。爪先が低すぎて、ブロックの底が白箱の縁や底に当たる。当たった勢いで箱を押し、箱ごと動いてしまう。三回通して二回がこれだった。

直すべきは place の高さだけ。ブロックの厚みは約 24mm。余裕を見て 30mm 上げれば、箱の縁の上で離せて当たらない。方針はすぐ決まった。問題は、その 30mm を関節角でどう作るかだった。mechArm に高さの直接指定はない。place の姿勢は六つの関節角で決まる。高さだけ上げるつもりで勘で関節を動かすと、爪先は前後にもずれる。

FK で引こうとして外れ、教示し直し、関節が抜けて何度も止まった。本稿は、姿勢を取り直して対応表を取り切るまでの全ログ。途中で捨てた手も、止まったログも、外部レビューのやりとりも残す。

当たっている現場

まず当たっている状態のログ。run_pick_place.py を一本通したときの出力をそのまま載せる。pick は掴めた、place で外した回。

(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-content % python3 ~/r2r2r-scripts/dynamic_tracking_limits/place/place_modules/run_pick_place.py
======================================================================
[RUN] run_pick_place.py  dry_run=False  log=run_0001_20260614_192238.json
======================================================================
  [Pi] fresh_mode=1
[INIT  ] fresh_mode=1
[STAGE 1] HOME 復帰 + グリッパー開
[SEND] stage1_to_home: send_angles (single) [  +0.00,   +0.00,   +0.00,   +0.00,   +0.00,  -30.00]  speed=20 wait=1.0s  (pre max|Δ|=1.58°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.58° (tol 2.5°)
[MOVE  ] stage1_to_home  arrived=True retried=False post_max|Δ|=1.580°
[GRIP  ] stage1_grip_open  action=open  sleep=2.0s  dry_run=False
  [Pi] GRIPPER: OPEN result= None
[STAGE 2] 赤ブロック + 白箱 同時検出(block と box は同回・同 homography)
[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=[348, 1562] Y=[59, 931]
[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]
[テンプレ] 計 8 枚 (day165=8, auto=0)
[06f] DETECT: center=(1406,483) score=0.667 angle=0° scale=0.85 size=(158x158) template=white_box_20260520_163923_012.png (eval 4.19s)
[DETECT][1/3] box Unity=(-0.232,+0.129) score=0.6671843528747559
  赤ブロック pixel=(521, 655) → Unity=(0.2277, 0.2222)
[DETECT][1/3] block Unity=(+0.228,+0.222) score=null
[06f] DETECT: center=(1406,483) score=0.667 angle=0° scale=0.85 size=(158x158) template=white_box_20260520_163923_012.png (eval 4.21s)
[DETECT][2/3] box Unity=(-0.232,+0.129) score=0.6674215197563171
  赤ブロック pixel=(522, 655) → Unity=(0.2272, 0.2222)
[DETECT][2/3] block Unity=(+0.227,+0.222) score=null
[06f] DETECT: center=(1406,483) score=0.668 angle=0° scale=0.85 size=(158x158) template=white_box_20260520_163923_012.png (eval 4.25s)
[DETECT][3/3] box Unity=(-0.232,+0.129) score=0.6675243377685547
  赤ブロック pixel=(522, 655) → Unity=(0.2272, 0.2222)
[DETECT][3/3] block Unity=(+0.227,+0.222) score=null
[DETECT] block_xz=[0.2271919860839844, 0.22219218444824218] block_score=None
[DETECT] box_xz=[-0.23168214416503907, 0.12901483154296875] box_score=0.6674215197563171
[LOOKUP] stage3_approach_pick  phase=approach_pick  target_xz=(+0.2272,+0.2222)  → j0=-35.617°  method=interp  x_resid=0.00000m  z_resid=0.02939m  joint_ok=True
[SEND] stage3_approach_pick: send_angles (single) [ -35.62,  +87.74,  -38.33,   +3.60,  -70.11,  -30.00]  speed=20 wait=1.0s  (pre max|Δ|=86.16°, post-send timeout 14.9s)
[SEND] arrival OK: max|Δ|=1.29° (tol 2.0°)
[MOVE  ] stage3_approach_pick  arrived=True retried=False post_max|Δ|=1.290°
[LOOKUP] stage4_pick  phase=pick  target_xz=(+0.2272,+0.2222)  → j0=-44.257°  method=interp  x_resid=0.00000m  z_resid=0.01590m  joint_ok=True
[SEND] stage4_pick: send_angles (single) [ -44.26,  +88.00,  -21.44,   +1.40,  -70.48,  -32.87]  speed=20 wait=1.0s  (pre max|Δ|=15.64°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.03° (tol 3.0°)
[MOVE  ] stage4_pick  arrived=True retried=False post_max|Δ|=1.030°
[GRIP  ] stage5_grip_close  action=close  sleep=2.0s  dry_run=False
  [Pi] GRIPPER: CLOSE result= None
[SEND] stage6_lift: send_angles (single) [ -35.62,  +87.74,  -38.33,   +3.60,  -70.11,  -30.00]  speed=20 wait=1.0s  (pre max|Δ|=17.50°, post-send timeout 8.0s)
[SEND] arrival OK: max|Δ|=1.38° (tol 2.0°)
[MOVE  ] stage6_lift  arrived=True retried=False post_max|Δ|=1.380°
[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
[CAP-VLM] pick 保存: /Users/shimazueiichi/r2r2r-scripts/dynamic_tracking_limits/logs/run_pick_place/run_0001_20260614_192238_frames/pick.jpg
[JUDGE ] pick: verdict=yes confidence=0.85 reason=爪の先端部分に赤い四角いブロックが挟まれており、グリッパーの指が両側からブロックを保持している様子が確認できる
[LOOKUP] stage7_approach_place  phase=approach_place  target_xz=(-0.2317,+0.1290)  → j0=+42.435°  method=interp  x_resid=0.00000m  z_resid=0.14234m  joint_ok=True
[INFO  ] stage7_approach_place z_residual_m=0.1423m (情報のみ・ABORT しない。工程跨ぎや弧高さ差で構造的に大きいことがある)
[SEND] stage7_approach_place: send_angles (single) [ +42.43,  +87.74,  -38.33,   +3.60,  -70.11,  -30.00]  speed=20 wait=1.0s  (pre max|Δ|=78.28°, post-send timeout 13.7s)
[SEND] arrival OK: max|Δ|=1.38° (tol 2.0°)
[MOVE  ] stage7_approach_place  arrived=True retried=False post_max|Δ|=1.380°
[LOOKUP] stage8_place  phase=place_withblock  target_xz=(-0.2317,+0.1290)  → j0=+52.200°  method=interp  x_resid=0.00000m  z_resid=0.06017m  joint_ok=True
[INFO  ] stage8_place z_residual_m=0.0602m (情報のみ・ABORT しない。工程跨ぎや弧高さ差で構造的に大きいことがある)
[SEND] stage8_place: send_angles (single) [ +52.20,  +68.50,   +7.47,   +2.37,  -81.73,  -33.04]  speed=20 wait=1.0s  (pre max|Δ|=44.64°, post-send timeout 8.7s)
[SEND] arrival OK: max|Δ|=2.25° (tol 3.0°)
[MOVE  ] stage8_place  arrived=True retried=False post_max|Δ|=2.250°
[GRIP  ] stage9_release  action=open  sleep=2.0s  dry_run=False
  [Pi] GRIPPER: OPEN result= None
[SEND] stage9b_swept_retreat: send_angles (single) [ +85.00,  +87.74,  -38.33,   +3.60,  -70.11,  -30.00]  speed=20 wait=1.0s  (pre max|Δ|=45.71°, post-send timeout 8.9s)
[SEND] arrival OK: max|Δ|=1.07° (tol 2.0°)
[MOVE  ] stage9b_swept_retreat  arrived=True retried=False post_max|Δ|=1.070°
[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
[CAP-VLM] place 保存: /Users/shimazueiichi/r2r2r-scripts/dynamic_tracking_limits/logs/run_pick_place/run_0001_20260614_192238_frames/place.jpg
[JUDGE ] place: verdict=no confidence=0.95 reason=赤いブロックは白い箱の外側(箱の右下付近)に置かれており、箱の中には入っていない
[SEND] stage10_lift_back: send_angles (single) [ +42.43,  +87.74,  -38.33,   +3.60,  -70.11,  -30.00]  speed=20 wait=1.0s  (pre max|Δ|=42.56°, post-send timeout 8.4s)
[SEND] arrival OK: max|Δ|=1.20° (tol 2.0°)
[MOVE  ] stage10_lift_back  arrived=True retried=False post_max|Δ|=1.200°
[SEND] stage10_to_home: send_angles (single) [  +0.00,   +0.00,   +0.00,   +0.00,   +0.00,  -30.00]  speed=20 wait=1.0s  (pre max|Δ|=88.94°, post-send timeout 15.3s)
[SEND] arrival OK: max|Δ|=1.49° (tol 2.5°)
[MOVE  ] stage10_to_home  arrived=True retried=False post_max|Δ|=1.490°
[RESULT] 完走
  [Pi] fresh_mode=0
[LOG   ] /Users/shimazueiichi/r2r2r-scripts/dynamic_tracking_limits/logs/run_pick_place/run_0001_20260614_192238.json

注目する行は二つ。pick の判定はカメラ越しに「掴めた」と出ている。

[JUDGE ] pick: verdict=yes confidence=0.85 reason=爪の先端部分に赤い四角いブロックが挟まれており、グリッパーの指が両側からブロックを保持している様子が確認できる

place の判定は「外」と出た。

[JUDGE ] place: verdict=no confidence=0.95 reason=赤いブロックは白い箱の外側(箱の右下付近)に置かれており、箱の中には入っていない

判定はVLM(Anthropic API のビジョン)。人の目を介さず成否を返す。掴みは捉え、置きの失敗も捉えた。成否を可視化する仕組みは機能している。問題は、place の爪先が箱に当たる高さそのものだ。

この回の box 検出は z=+0.129、つまり箱がいつもより手前にあった。place の降下姿勢 [_, 68.5, 7.47, 2.37, -81.73, -33.04] は箱の位置によらず固定で、箱が手前に来るほど縁に当たりやすくなる。低すぎる降下と箱の位置が重なって、箱を押した。

FK テーブルには、欲しい姿勢がなかった

高さだけ 30mm 上げた関節角がほしい。最初に試したのは FK テーブルから引く方法だった。fk_scan_motion_based_v2.csv(710,704 点)は関節角と Unity 座標(爪先位置)の対応表で、現 place 姿勢の ee 座標を出して、そこから上方向に +30mm ずれた近傍姿勢を引けば、高さだけ上げた角度が出るはずだった。読み取りと計算だけで、実機は動かさない。

approach_place は素直に解けた。

approach_place(j0=+4.5 箱中心向き)— FK 適合良好
現姿勢 FK 最近傍 joint L2 = 2.87°(小・FK テーブルに密に含まれる)
現 ee = (-0.0063, +0.1264, +0.3240) m(爪先高さ 126mm)
目標 ee_y = +0.1564 m = 156mm(+30mm)

候補2(最小 Δj): y_err=+0.38mm、水平ズレ Δx=+0.5mm/Δz=+4.7mm、Δj=[0, +4, -16, 0, +4, 0]
joints = [+3.0, +90.74, -55.33, +3.60, -68.11, -30.0]

approach 側は j2 を 16度浅くするだけで、水平ズレ 0.5mm でほぼ垂直に 30mm 上がる解が出た。問題は place 側だった。

place_withblock(j0=+4.5・採用 j1=68.5)— FK 適合悪い
現姿勢 FK 最近傍 joint L2 = 19.65°(大・FK テーブルがこの姿勢を密に含まない)
現 ee = (-0.0721, +0.1269, +0.2897) m(爪先高さ 127mm)

最近傍 FK 行 [+8, +67, -5, -12, -81, -30] vs target [+4.5, +68.5, +7.47, +2.37, -81.73, -33.04] で j2 差 +12°、j3 差 +14°

place の基準姿勢は FK テーブルから L2=19.65度も離れていた。この姿勢は手で教示したもので、j2=+7.47 や j5=-33.04 が FK サンプルの密な領域の外にある。だから「現姿勢を素直に上げた」解が無く、五軸を大きく動かす別解しか出てこない。

ここで分かったことがある。place の基準姿勢を、これまで正確には測れていなかった。手で教えた姿勢のまま固定していて、実際の爪先高さが FK で裏取りされていなかった。机上で +30mm を計算しても、その姿勢自体がサンプル外なら計算の信頼性が低い。計算より先に、動かす方が早い。FK で引くのは諦めて、実機で教え直すことにした。

教え直す ― ドラッグティーチング

place は「ブロックを持って箱に置く」動作だから、咥えた状態で教える。空の爪で「箱の縁の上」に持っていっても、その先にぶら下がるブロックの厚み(24mm)の分だけ低くなって、結局当たる。咥えた状態なら、ブロックの底が箱の縁に当たらない高さを直接見ながら教えられる。

教示には既存の drag_teach_v2.py を使った。脱力(damping mode)させて手でアームを動かし、要所でマーカーを打つ方式。脱力は release_all_servos() を serial 直結で呼ぶため、daemon を止めて Pi 上で直接実行する。daemon と直結は同じ /dev/ttyAMA0 を奪い合うので両立しない。

最初の教示は空 Enter を先に押してしまい、マーカーが入らず止まった。

[V2.TEACH] 記録開始。アームを手で動かしてください。終わったら 空Enter で停止

[V2.TEACH] 空Enter 検出 → 記録停止
[V2.TEACH] power_on() 完了 result=None
[V2.TEACH] 記録停止。163 姿勢 / 経過 19.05s
[V2.TEACH] [WARN] 押されなかった工程キー: ['APPROACH_PICK', 'PICK', 'APPROACH_PLACE', 'PLACE']

マーカーは数字を打ってから Enter。3 で APPROACH_PLACE、4 で PLACE。何も打たない Enter は停止になる。二回目で正しくマークが入った。

[V2.TEACH] 記録開始。アームを手で動かしてください。終わったら 空Enter で停止
3
[V2.TEACH] PHASE mark: APPROACH_PLACE idx=91 rt=10.72s
4
[V2.TEACH] PHASE mark: PLACE idx=167 rt=19.62s

[V2.TEACH] 空Enter 検出 → 記録停止
[V2.TEACH] power_on() 完了 result=None
[V2.TEACH] 記録停止。231 姿勢 / 経過 27.03s
[V2.TEACH] 保存: drag_v2_20221013_161431.json

このスクリプトは軌道全体を連続記録して、phases にマークの位置を残す。保存ファイル名の日付が 20221013 になっているのは Pi の時計がずれているためで、中身には影響しない。マーク位置の関節角を取り出すと、こうなっていた。

=== APPROACH_PLACE idx 91
  91 [40.6, 40.95, 12.83, -0.35, -64.42, -27.94]
=== PLACE idx 167
  167 [40.6, 59.15, 12.83, -1.4,  -78.04, -29.53]

place の j1 が、旧姿勢の 68.5 から 59.15 に下がった。j1 が浅くなって前傾が緩み、爪先が上がった。狙い通り、咥えたブロックが箱に当たらない高さに上がっている。approach と place は j0 が同じ 40.6 で、j1 だけ大きく違う。place の真上に approach がある関係になっている。

place の対応表を取り直す

教示で取れたのは、箱がその位置にあったときの一点だけ。箱は左右に動くから、j1〜j5 を固定して j0 をスイープした対応表にしないと位置に追従できない。place の新姿勢を base にして、j0 を -85 から +85 まで 20 点振る。咥えたまま赤ブロックを検出する。

place 側は一度 8 点目で沈黙して止まったが、再実行で抜けて完走した。20 点すべて検出成功、保持軸の j4 も全点 -78 前後で安定していた。

[SWEEP] 完了: 検出成功 20/20, 失敗 0
[EXIT] JSON   : /Users/shimazueiichi/r2r2r-scripts/dynamic_tracking_limits/logs/j0_sweep/j0_sweep_place_12.json

place の取り直しはこれで済んだ。問題は approach_place の方だった。

関節が抜ける

approach_place を、教示値 [40.6, 40.95, 12.83, -0.35, -64.42, -27.94] を base にして同じく j0 スイープすると、途中で止まった。

--- [ 5/20] j0_cmd=-49.21° target=[ -49.21,  +40.95,  +12.83,   -0.35,  -64.42,  -27.94] ---
[SEND] [ 5/20] j0=-49.21: send_angles (single) [ -49.21,  +40.95,  +12.83,   -0.35,  -64.42,  -27.94]  speed=20 wait=1.0s  (pre max|Δ|=27.95°, post-send timeout 8.0s)
[SEND] [TIMEOUT] 8.0s 内に未到達: max|Δ|=40.34° actual=[ -49.39,  +41.92,  +13.44,   -0.17,  -24.08,  -27.77]
[SEND] リトライしません: j0以外の保持軸が 12.39° > tol 2.0° 動いたため (姿勢崩れ疑い)
[ABORT] [ 5/20] 到達確認タイムアウト。これまでの記録を保存して終了

j4 が抜けた。目標は j4=-64.42 のはずが、実機は -24.08。40度もずれている。一つ前の 4 点目で既に -43.41 と崩れ始めていて、5 点目で完全に落ちた。スクリプトは「j0 以外の保持軸が大きく動いた」のを検知して止めた。崩れた姿勢のまま次へ進まない、正しい挙動だった。

j0 が切り替わる瞬間に、ブロックを握り直すような動きをする。実機を横で見ているとそう見えた。そのタイミングで j4 が抜ける。

base の j1 を変えて、抜ける点が動くかを試した。

approach base の j1

抜けた点

40.95(寝ている)

5 点目

48

10 点目

57.39(立て気味・別teach)

4 点目(-側)

place の 59.15(参考・別姿勢)

抜けず 20 点完走

表のとおり、j1 を変えると抜ける点はずれた。ただし j1=57.39 は j1=48 より立てているのに 4 点目で抜けていて、立てるほど単純に粘るわけではなかった。j1 を上げすぎると、この姿勢では逆にアームが下がって白箱より低くなった。j1 と高さの関係は姿勢の形によって変わり、単純な比例ではない。

教示をやり直して、手で「箱の上・j4 が抜けない」を探した姿勢がこれだった。

=== APPROACH_PLACE idx 324
  324 [38.4, 57.39, 17.49, 0.08, -89.2, -29.44]

j1 を 57.39 に立て、j4 を -89.2 と深めに取った。手で動かして抜けないと感じた姿勢だった。ところがこれでもフルレンジのスイープでは 4 点目で抜けた。

[ 4/20] j0=-58.16 target=[-58.16, +57.39, +17.49, +0.08, -89.20, -29.44]
[SEND] [TIMEOUT] max|Δ|=28.65° actual=[-58.27, +58.35, +17.40, -0.08, -60.55, -29.61]
[SEND] リトライしません: j0以外の保持軸が 29.27° > tol 2.0° 動いた (姿勢崩れ疑い)

外部レビューに機序を確かめる

関節制御で繰り返し止まる事象は、自分の仮説だけで進めず外部レビューを通す。codex に、根本原因・送信方式・安全性・そもそも全点必要かを問うた。返ってきた要点を引く。

機序について。j0 はヨー(鉛直軸の回転)なので、回しても静的な重力トルクは変わらない。マイナス側で悪化するのを「重力が逆に効く」と説明したのは誤りで、配線の引き回し、摩擦、手首のガタ、加減速の方向依存などを見るべきだ、と正された。主因は j1 が寝ていることより、j4=-89 付近の保持余裕の小ささにある、という指摘もあった。place が j4=-78 で完走していることがその傍証になる。

送信方式について、四つの案が評価された。

案

評価

A. speed を下げる

有効。回転の角加速度が下がり慣性トルクが減る。切り替え瞬間の抜けに効く

B. j0 を分割送信

慣性は下げられるが送信回数が増え沈黙リスク。最後の手段

C. base の j4 を保持しやすい値に

最も本質的。-75〜-82度側に戻し、j1/j2 で高さを稼ぐ

D. スイープ範囲を実用域に限定

強く推奨。approach は箱上空の中継なので -側を取る必要が薄い

推奨は D + C + A の組み合わせ、B の分割は使わない、というものだった。安全面では、保持軸のずれで ABORT する現状の設計は正しい、ただし到達タイムアウトを待たずポーリング中に早期検知する方が望ましい、と添えられた。

範囲を絞り、もう一度フルレンジで取る

まず実用域だけ取ってみた。箱が実際に来るのはプラス側なので、--j0-min 0 --j0-max 85 で +側だけ 20 点。j4 は教示値の -89.2 のまま。これは 10 点目まで進んで j4 が全点健全だった。マイナス側を捨てれば、教示した高さを変えずに抜けを避けられる見込みが立った。

そのうえでフルレンジに戻した。このときの開始時の現在姿勢は base とほぼ一致していた(max|Δ|=0.96度)。前回まで抜けたときは、遠い姿勢から base へ移動してからスイープに入っていた。今回は base に居る状態から各点 8〜9度ずつ刻んで、抜けずに完走した。何が違って完走したのかは、この一回からは断定できない。違っていたのは開始姿勢の近さと、直前に実用域だけを通していたことだった。

フルレンジ -85 から +85、20 点を完走した。

[SWEEP] 完了: 検出成功 20/20, 失敗 0
[MOVE] 基準姿勢へ復帰 ...
[SEND] arrival OK: max|Δ|=0.96° (tol 2.0°)
  [Pi] fresh_mode=0
[EXIT] JSON   : /Users/shimazueiichi/r2r2r-scripts/dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_place_23.json
[EXIT] frames : /Users/shimazueiichi/r2r2r-scripts/dynamic_tracking_limits/logs/j0_sweep/j0_sweep_approach_place_23_frames (20 files)

JSON を検算すると、保持軸が 20 点とも一定だった。j1=58.35、j2=17.57、j4=-89.38、j5=-29.61 が全点で同じ値。j4 は一点も抜けていない。検出座標は j0 -85→+85 で x が +0.317→-0.323 と素直に動き、x=0 を跨ぐのが j0≒+4.5 で、箱中心を向く角度と一致した。

sweep[0]  j0=-85.0  angles_actual=[-84.9, 58.35, 17.57, 0.26, -89.38, -29.61]  xz=(+0.317, -0.019)
sweep[10] j0=+4.47  angles_actual=[4.04, 58.35, 17.57, -0.17, -89.38, -29.61]  xz=(-0.011, +0.292)
sweep[19] j0=+85.0  angles_actual=[84.63, 58.35, 17.57, 0.17, -89.38, -29.61]  xz=(-0.323, +0.013)

codex は j4 を -78 に下げろと推奨したが、手で教示した j4=-89.2 を変えずに 20 点取れた。下げる前に完走したので、推奨は試さずに済んだ。

取り直しの結果

当たり問題を直すための対応表が二つそろった。

対応表

base 姿勢

状態

place_withblock

[40.6, 59.15, 12.83, -1.4, -78.04, -29.53]

20/20・高さ 30mm 上げ

approach_place

[38.4, 57.39, 17.49, 0.08, -89.2, -29.44]

20/20・j4 抜けなし

どちらも箱に当たらない高さへ上げた新版で、旧版(低くて当たる)は置き換えになる。j0_lookup が読む先を新採用版に切り替えれば、コードのロジックは変えずに高さだけ入れ替わる。次の一本通しで、箱に当たらず入るかを確かめる段階に来た。

approach_place の 20 点を上から撮った連番を見ると、全点でブロックが床から浮き、爪先の赤ブロックがマット上を弧を描いて左右に移動している。approach は降りる前の中継だから、この高さで箱の上空を横切れていればいい。狙いに対しては素直なデータが取れた。

今回の作業は、当たりを直すという一点に対して、FK で引く・教示し直す・関節抜けで止まる・範囲を変えて取り直す、と手を変え続けた記録になった。机上で +30mm を計算する道は、place の姿勢が FK サンプルの外にあって塞がっていた。教えて、振って、抜けて、また振った。最後にフルレンジで 20 点が取れたが、何が決定的だったのかはこの一回では言い切れない。place と approach_place の対応表は、当たらない高さへ上げた状態でそろった。次は一本通して、箱に当たらず入るかを見る。

※ プロジェクト名「R2R2R」は、UC Berkeley・Toyota Research Instituteの研究「Real2Render2Real」(Yu, Fu et al., 2025)の概念に触発されています。現実空間をデジタルツイン化し、仮想空間での試行から得た知見を実世界のモーター駆動へ還元する——その設計と実装過程を毎日記録しています。技術アプローチおよび目的は独自のものです。