mechArm 270 Pi 動的追従の限界を探る Log#3 | TIP検出ノイズの正体を特定して初めて赤ブロックを掴んだ
視覚サーボのループは「CONVERGED」と表示されていた。なのにアームは赤ブロックを掴めなかった。今日はその原因を1日かけて特定した。
💡 Key Takeaway
青シール3点をY座標降順でwrist/claw_a/claw_bに割り当てていたロジックが、姿勢によってY座標の順序が入れ替わることで37mmのジャンプを生んでいた。3点間の最短辺で爪先2点を特定する幾何学的アルゴリズムに変更し、TIP検出 stdev を19.42mmから0.08mmへ改善。グリッパー制御を実装し、Trial 3・6で赤ブロックの把持に初成功した。
発生した問題 | 現場判断 | 結果 |
|---|---|---|
noise_test で赤ブロックが全10回 None を返し続けた |
| 赤ブロック検出が正常動作。red_x_mm stdev=0.00mm、range=0.01mmを確認 |
TIP検出が10回中8回同一値(247.42mm)を返し続けた | Y座標降順ソートによる青シール識別ロジックの不安定が原因。3点間の最短辺で爪先を特定する幾何学ベースのアルゴリズムに変更 | TIP stdev 19.42mm → 0.08mm。2値間ジャンプ現象が消滅 |
ループCONVERGEDなのに物理最終位置が最大52mmズレた | APPROACH_PICK姿勢でj0を合わせてから降下するとj1・j4の変化でTIP_Xが連鎖的にズレることが原因。視覚サーボをPICK姿勢(降下後)で実行するよう再設計 | Trial 3(diff=+7.5mm)・Trial 6(diff=-0.8mm)で赤ブロックの把持に成功 |
問いの設定
Log#1・Log#2では視覚サーボの制御周期と振幅の問題を扱った。今回のテーマは「なぜ視覚サーボはCONVERGEDと報告しているのに、アームが赤ブロックを掴めないのか」だ。
前回テストのCSVデータにはすでに奇妙な数字があった。
# 前回テストCSV(視覚サーボ改版)の一部
trial,converged,loop_count,final_tip_x_mm,final_diff_x_mm
1,True,3,174.7,-19.3
4,True,2,-147.2,-7.4
5,True,1,245.8,14.9
6,True,2,202.3,-52.2Trial 6はループ最終diff=-3.3mmでCONVERGEDと判定しているのに、物理最終位置が-52.2mmズレている。「収束した」と「実際に合った」は別の話だ。
デバッグの入り口として、まず検出系そのものが正常かどうかを確かめることにした。
検出系の切り分け:noise_test
アームを手動で把持姿勢に固定し、10回連続でTIPと赤ブロックの位置を取得する detection_noise_test.py を実行した。
第1回:全10回がNone
# noise_test_20260502_130707.csv(全データ)
i,tip_x_mm,tip_z_mm,red_x_mm,red_z_mm,fixed_angles
1,,,,,"[-35.77, 99.05, -38.75, 0.43, -59.94, -31.46]"
2,,,,,"[-35.77, 99.05, -38.75, 0.43, -59.94, -31.46]"
3,,,,,"[-35.77, 99.05, -38.75, 0.43, -59.94, -31.46]"
4,,,,,"[-35.77, 99.05, -38.75, 0.43, -59.94, -31.46]"
5,,,,,"[-35.77, 99.05, -38.75, 0.43, -59.94, -31.46]"
6,,,,,"[-35.77, 99.05, -38.75, 0.43, -59.94, -31.46]"
7,,,,,"[-35.77, 99.05, -38.75, 0.43, -59.94, -31.46]"
8,,,,,"[-35.77, 99.05, -38.75, 0.43, -59.94, -31.46]"
9,,,,,"[-35.77, 99.05, -38.75, 0.43, -59.94, -31.46]"
10,,,,,"[-35.77, 99.05, -38.75, 0.43, -59.94, -31.46]"全部Noneだった。スクリプトにデバッグ画像保存を追加した。
# detection_noise_test.py への追加(1回目のフレームで保存)
if i == 0:
cv2.imwrite(f"{DEBUG_DIR}/raw_frame.png", frame)
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
lower1 = (0, 100, 50); upper1 = (10, 255, 255)
lower2 = (160, 100, 50); upper2 = (180, 255, 255)
m1 = cv2.inRange(hsv, lower1, upper1)
m2 = cv2.inRange(hsv, lower2, upper2)
red_mask = cv2.bitwise_or(m1, m2)
cv2.imwrite(f"{DEBUG_DIR}/red_mask.png", red_mask)生フレームには赤ブロックがはっきり映っていた。赤マスクには赤ブロックの位置に白い塊が光っていた。つまりHSV閾値は正常。それでもNoneが返ってくる。
detect_red_block() のコードを確認した。
# visual_servo_pick.py(マット範囲チェック箇所)
if _mat_px_range is not None:
min_x, max_x, min_y, max_y = _mat_px_range
if not (min_x <= cx <= max_x and min_y <= cy <= max_y):
continue # ここで弾かれていたターミナルのログには マット範囲: X=[994, 1594] と出ていた。正常時は X=[585, 1863] 程度になるはずで、今回は右半分だけの異常な範囲になっている。マット四隅検出が破綻し、homographyも誤っていた。赤ブロックは画像のX=400〜500ピクセル付近にあったため、この範囲チェックで全部弾かれていた。
検出ノイズを計測するというテストの目的に限り、範囲チェックを無効化した。
# detection_noise_test.py に追加(setup後)
vsp._mat_px_range = None
print("[DEBUG] マット範囲チェック無効化(全画面で検出する)")第2回:TIPが2値の間をジャンプ
# ターミナル出力(noise_test 第2回)
[検出開始] 10 回測定(間隔 0.5s)
[ 1/10] TIP=(218.43, 259.732) RED=(215.442, 257.54) red_px=(515, 785)
[ 2/10] TIP=(218.43, 259.732) RED=(215.442, 257.54) red_px=(515, 785)
[ 3/10] TIP=(180.831, 230.411) RED=(215.442, 257.54) red_px=(515, 785)
[ 4/10] TIP=(180.831, 230.411) RED=(215.442, 257.54) red_px=(515, 785)
[ 5/10] TIP=(180.831, 230.411) RED=(215.442, 257.54) red_px=(515, 785)
[ 6/10] TIP=(180.831, 230.411) RED=(215.442, 257.54) red_px=(515, 785)
[ 7/10] TIP=(180.831, 230.411) RED=(215.442, 257.54) red_px=(515, 785)
[ 8/10] TIP=(180.831, 230.411) RED=(215.442, 257.54) red_px=(515, 785)
[ 9/10] TIP=(218.43, 259.732) RED=(215.442, 257.54) red_px=(515, 785)
[10/10] TIP=(218.43, 259.732) RED=(215.442, 257.54) red_px=(515, 785)
統計サマリー (mm単位) 固定姿勢: [-38.23, 101.16, -45.26, -1.93, -55.81, -29.26]
tip_x_mm: n=10 mean=+195.87 stdev=19.42 range=37.60 (+180.83 〜 +218.43)
tip_z_mm: n=10 mean=+242.14 stdev=15.14 range=29.32 (+230.41 〜 +259.73)
red_x_mm: n=10 mean=+215.44 stdev= 0.00 range= 0.00 (+215.44 〜 +215.44)
red_z_mm: n=10 mean=+257.54 stdev= 0.00 range= 0.00 (+257.54 〜 +257.54)赤ブロックはstdev 0.00mmで完全に安定している。TIPだけが大きく揺れている。
10回の内訳を見ると、2つの値の間を行き来していた。
[1, 2, 9, 10] : TIP=(218.43, 259.732) ← 4回
[3〜8] : TIP=(180.831, 230.411) ← 6回ランダムなノイズではなく、離散的な2値間のジャンプだった。37.60mmというrangeはまさに2つのTIP値の差そのものだ。
原因特定:青シール識別ロジックの脆弱性
2値間ジャンプが起きているということは、「どのシールをwrist/claw_a/claw_bに割り当てるか」がフレームごとに入れ替わっていることを意味する。
現状の identify_blue_markers はY座標降順でソートしていた。
# 旧実装(visual_servo_pick.py L269-280)
def identify_blue_markers(blue_points, homography):
sorted_by_y = sorted(blue_points, key=lambda p: p[1], reverse=True)
claw_a_px = sorted_by_y[0] # Y座標が最大
claw_b_px = sorted_by_y[1] # Y座標が2番目
wrist_px = sorted_by_y[2] # Y座標が最小
...今回の姿勢でwristに近い2点のY座標が拮抗していた。撮影タイミングのわずかなノイズで順序が入れ替わる。wristとclawが混ざるとTIPの計算結果(claw_aとclaw_bの中点)が大きく動く。37mmのジャンプはwristとclawが入れ替わったときのTIP移動距離と一致していた。
修正:幾何学ベースの割り当てに変更
claw_aとclaw_bは物理的に爪先で近接している。wristは離れた位置にある。この構造は姿勢に関係なく成立する。3点間の最短辺の両端をclaw_a/claw_b、残りをwristと割り当てる。
# 新実装(DAY184改 visual_servo_pick.py L268-310)
def identify_blue_markers(blue_points, homography):
"""
3点を wrist/claw_a/claw_b に割り当てる。
3点間の最短辺で爪先2点を特定。X座標で claw_a/claw_b を区別。
"""
import math
p0, p1, p2 = blue_points
d01 = math.hypot(p0[0] - p1[0], p0[1] - p1[1])
d02 = math.hypot(p0[0] - p2[0], p0[1] - p2[1])
d12 = math.hypot(p1[0] - p2[0], p1[1] - p2[1])
if d01 <= d02 and d01 <= d12:
wrist_px = p2; claw_pts = [p0, p1]
elif d02 <= d01 and d02 <= d12:
wrist_px = p1; claw_pts = [p0, p2]
else:
wrist_px = p0; claw_pts = [p1, p2]
claw_pts.sort(key=lambda p: p[0])
claw_a_px = claw_pts[0]
claw_b_px = claw_pts[1]
def to_unity(px, py):
pt = np.array([[[float(px), float(py)]]], dtype=np.float32)
r = cv2.perspectiveTransform(pt, homography)
return float(r[0][0][0]) * 0.001, float(r[0][0][1]) * 0.001
wrist_ux, wrist_uz = to_unity(*wrist_px)
claw_a_ux, claw_a_uz = to_unity(*claw_a_px)
claw_b_ux, claw_b_uz = to_unity(*claw_b_px)
return {
"wrist": (wrist_px[0], wrist_px[1], wrist_ux, wrist_uz),
"claw_a": (claw_a_px[0], claw_a_px[1], claw_a_ux, claw_a_uz),
"claw_b": (claw_b_px[0], claw_b_px[1], claw_b_ux, claw_b_uz),
}修正後のnoise_test結果(第3回)
# ターミナル出力(noise_test 第3回 / 新ロジック適用後)
[ 1/10] TIP=(265.481, 195.972) RED=(258.277, 192.764) red_px=(421, 665)
[ 2/10] TIP=(265.481, 195.972) RED=(258.277, 192.764) red_px=(421, 665)
[ 3/10] TIP=(265.737, 195.477) RED=(258.277, 192.269) red_px=(421, 664)
[ 4/10] TIP=(265.481, 195.972) RED=(258.277, 192.764) red_px=(421, 665)
[ 5/10] TIP=(265.481, 195.972) RED=(258.277, 192.764) red_px=(421, 665)
[ 6/10] TIP=(265.481, 195.972) RED=(264.069, 201.798) red_px=(410, 683)
[ 7/10] TIP=(265.481, 195.972) RED=(264.069, 201.798) red_px=(410, 683)
[ 8/10] TIP=(265.481, 195.972) RED=(264.069, 201.798) red_px=(410, 683)
[ 9/10] TIP=(265.481, 195.972) RED=(264.069, 201.798) red_px=(410, 683)
[10/10] TIP=(265.481, 195.972) RED=(264.069, 201.798) red_px=(410, 683)
統計サマリー (mm単位) 固定姿勢: [-52.55, 96.15, -34.27, -4.57, -60.55, -28.38]
tip_x_mm: n=10 mean=+265.51 stdev= 0.08 range= 0.26 (+265.48 〜 +265.74)
tip_z_mm: n=10 mean=+195.92 stdev= 0.51 range= 1.50 (+195.48 〜 +195.97)
red_x_mm: n=10 mean=+258.27 stdev= 0.00 range= 0.01 (+258.27 〜 +258.28)
red_z_mm: n=10 mean=+192.71 stdev= 0.16 range= 0.50 (+192.27 〜 +192.76)
diff_x (TIP-RED): mean=+7.24 stdev=0.08 range=0.25
diff_z (TIP-RED): mean=+3.21 stdev=0.00 range=0.00全項目stdev < 0.2mm。2値間ジャンプが消えた。
「見えているのに合わせられない」の構造
検出系が安定した状態で本番の視覚サーボを再テストした。ループ収束率は5/6まで改善した(前回3/6)。しかし「ループはCONVERGEDなのに物理最終位置がズレる」問題は残っていた。
カメラはマット平面(XZ)を真上から見ている。赤ブロックのX座標もTIPのX座標も見える。しかし6軸アームは、同じTIP位置(X, Z)に対して無数の関節角度の組み合わせを持つ。視覚サーボはAPPROACH_PICK姿勢でj0だけを調整してTIP_Xを目標に合わせる。その後PICK姿勢に降りるとき、j1とj4が変化することでTIP_Xも連鎖的に動いてしまう。
実際のテストデータで確認できる。
# DAY184改テスト(APPROACH_PICK姿勢でサーボ実行)
Trial 3:
ループ最終: TIP_X=+150.1mm Target=+155.4mm diff=+5.3mm [CONVERGED]
物理最終: TIP_X=+174.7mm 目標との差=-19.3mm 乖離=24.6mm
Trial 6:
ループ最終: TIP_X=+153.4mm Target=+150.1mm diff=-3.3mm [CONVERGED]
物理最終: TIP_X=+202.3mm 目標との差=-52.2mm 乖離=48.9mm「APPROACH姿勢でのTIP_X」と「PICK姿勢でのTIP_X」は別物だった。
動作シーケンスの再設計
視覚サーボの実行タイミングをPICK姿勢(降下後)に変えた。同時にグリッパー制御とLIFT動作を追加して動作シーケンスを確定した。
# 動作シーケンス(DAY184改で確定)
1. HOME
HOME = [0, 0, 0, 0, 0, -30]
2. GRIPPER OPEN
mc.set_gripper_state(0, 100) # state=0: 開く
3. APPROACH_PICK へ移動
approach_angles = [j0_lookup, 87.74, -38.33, 3.6, -70.11, -30.0]
4. DESCEND(j0はAPPROACH時のまま・j1を固定値で降下)
PICK_J1_FIXED = 90.87
descend_angles = [j0_lookup, PICK_J1_FIXED, j2_lookup, j3_lookup, j4_lookup, j5_lookup]
5. PICK_VISUAL_SERVO(PICK姿勢のままj0だけ微調整)
CONVERGE_THRESHOLD_MM = 10
MAX_DELTA_DEG = 5.0
J0_RELATIVE_LIMIT = 15.0
6. 最終TIP測定(GRIP前・評価用)
7. GRIP
mc.set_gripper_state(1, 100) # state=1: 閉じる
8. LIFT(APPROACH_PICK姿勢に戻る・j0は視覚サーボの最終値)
lift_angles = [final_j0, 87.74, -38.33, 3.6, -70.11, -30.0]
9. HOME復帰(爪は閉じたまま・赤ブロックを保持)j1を90.87°に固定したのは、赤ブロックが常にマット平面に置かれているためだ。lookupで決まるj1が90.61〜90.96°でバラつくより固定値の方が安定する。LIFT動作はPICK失敗時でも必ず実行する設計にした。グリッパーを閉じたままHOMEに戻ると、赤ブロックをマット上で引きずってしまうためだ。
グリッパー制御関数を実装した。
# visual_servo_pick.py に追加(L373-403)
def ssh_set_gripper(state, speed=100, wait=2):
"""
グリッパー開閉制御。
state=0: 開く / state=1: 閉じる
DAY175既知問題: result=-1 は動作の成否と無関係。連続送信時は2秒以上sleep。
"""
cmd = (
f"python3 -c \""
f"from pymycobot.mycobot import MyCobot; import time; "
f"mc = MyCobot('/dev/ttyAMA0', 1000000); time.sleep(2); "
f"result = mc.set_gripper_state({state}, {speed}); "
f"time.sleep({wait}); "
f"print('GRIPPER:', 'OPEN' if {state} == 0 else 'CLOSE', 'result=', result)\""
)
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(SSH_HOST, username=SSH_USER, key_filename=SSH_KEY_PATH)
stdin, stdout, stderr = client.exec_command(cmd)
output = stdout.read().decode("utf-8", errors="ignore").strip()
error = stderr.read().decode("utf-8", errors="ignore").strip()
client.close()
if output:
print(f" [Pi] {output}")
if error and "no longer maintained" not in error:
print(f" [Pi stderr] {error}")本番テスト結果(7 trial)
新しいシーケンスとグリッパー制御を実装して7 trialを実行した。
# visual_servo_20260502_181427.csv(全データ)
trial,pick_x_mm,pick_z_mm,initial_j0,final_j0,converged,loop_count,final_tip_x_mm,final_diff_x_mm
1, 227.68,243.51,-50.0,-35.077,True, 6, 247.42,-19.74
2, 156.52,256.12,-32.0,-17.0, False,4, 219.45,-62.94
3,-191.83,256.36, 41.0, 41.0, True, 1,-199.37, 7.54 ← 把持成功
4, 265.7, 152.83,-45.0,-57.499,False,5, 244.73, 20.97
5,-257.79,148.14, 72.0, 72.0, False,2, ,
6, 18.81,306.11, 3.0, 3.0, True, 1, 19.59, -0.78 ← 把持成功
7, 157.01,255.62,-32.0,-17.0, False,4, 219.45,-62.44Trial 3とTrial 6で赤ブロックの把持に成功した。Trial 6はdiff=-0.8mm、loops=1。1ループで収束し、0.8mmの誤差でグリッパーが閉じた。
一方、Trial 1・2・4・7ではループが回っているのにTIP_Xが動かない現象があった。
# Trial 1のhistory(CSVのhistoryカラムより)
loop 1: tip_x=247.67 diff=-19.99 j0=-50.00
loop 2: tip_x=247.42 diff=-19.74 j0=-46.985 ← j0が3°変わってもTIPが動かない
loop 3: tip_x=247.42 diff=-19.74 j0=-44.008 ← さらに3°変えてもTIP変わらず
loop 4: tip_x=247.42 diff=-19.74 j0=-41.031
loop 5: tip_x=247.42 diff=-19.74 j0=-38.054
loop 6: tip_x=229.83 diff=-2.15 j0=-35.077 ← 最後だけ動いたj0を15°変えているのにTIP_Xがほぼ変わっていない。
j0送信の切り分けテスト
j0_send_test.py でAPPROACH姿勢(j1=87.74)でのj0動作を確認した。
# j0_send_test.py 結果サマリー
send_j0 | measured_j0 | diff
---------+-------------+--------
-30.00 | -29.79 | +0.21 ✓
-25.00 | -24.60 | +0.40 ✓
-20.00 | -19.59 | +0.41 ✓
-15.00 | -14.76 | +0.24 ✓
-10.00 | -9.93 | +0.07 ✓
-5.00 | -4.92 | +0.08 ✓
+0.00 | +0.00 | +0.00 ✓全送信値±0.41°以内で一致。APPROACH姿勢では ssh_send_angles は正常動作している。
次に visual_servo_loop 内にデバッグprintを追加してPICK姿勢でのj0を確認した。
# visual_servo_pick.py のvisual_servo_loop内に追加
ssh_send_angles(angles_to_send, wait=LOOP_WAIT_SEC)
measured_angles = ssh_get_angles()
if measured_angles is not None:
print(f" [DEBUG] 送信j0={angles_to_send[0]:+.2f} → 実測j0={measured_angles[0]:+.2f}")
tip_unity, markers, frame = detect_gripper_tip_auto(cap, trial=None)
if tip_unity is not None:
print(f" [DEBUG] TIP検出 raw_unity=({tip_unity[0]:.4f}, {tip_unity[1]:.4f})")# デバッグログ出力(Trial 1・2)
=== 視覚サーボループ開始 (PICK姿勢) ===
Target X: +156.8mm 初期 j0: -32.00
[DEBUG] TIP検出 raw_unity=(0.2171, 0.2556)
[Loop 1] TIP_X=+217.1mm Target_X=+156.8mm diff=-60.3mm j0=-32.00
[DEBUG] 送信j0=-27.00 → 実測j0=-31.55 ← ★ アームが動いていない
[DEBUG] TIP検出 raw_unity=(0.2151, 0.2571)
[Loop 2] TIP_X=+215.1mm Target_X=+156.8mm diff=-58.3mm j0=-27.00
[DEBUG] 送信j0=-22.00 → 実測j0=-31.55 ← ★ 同じ値のまま
[DEBUG] TIP検出 raw_unity=(0.2151, 0.2571)
[Loop 3] TIP_X=+215.1mm Target_X=+156.8mm diff=-58.3mm j0=-22.00
[DEBUG] 送信j0=-17.00 → 実測j0=-31.55 ← ★ 同じ値のまま
[DEBUG] TIP検出 raw_unity=(0.2151, 0.2571)
[Loop 4] TIP_X=+215.1mm Target_X=+156.8mm diff=-58.3mm j0=-17.00
[ABORT] j0=-12.00 が 初期j0=-32.00から +/-15.0度を超過。視覚サーボ中断。
=== 視覚サーボループ開始 (PICK姿勢) ===
Target X: -151.8mm 初期 j0: +45.00
[DEBUG] TIP検出 raw_unity=(-0.2076, 0.2707)
[Loop 1] TIP_X=-207.6mm Target_X=-151.8mm diff=+55.8mm j0=+45.00
[DEBUG] 送信j0=+40.00 → 実測j0=+44.64 ← ★ アームが動いていない
[DEBUG] TIP検出 raw_unity=(-0.2083, 0.2700)
[Loop 2] TIP_X=-208.3mm Target_X=-151.8mm diff=+56.5mm j0=+40.00
[DEBUG] 送信j0=+35.00 → 実測j0=+44.64 ← ★ 同じ値のまま
[DEBUG] TIP検出 raw_unity=(-0.2083, 0.2700)
[Loop 3] TIP_X=-208.1mm Target_X=-151.8mm diff=+56.3mm j0=+35.00
[DEBUG] 送信j0=+30.00 → 実測j0=+44.64 ← ★ 同じ値のまま
[DEBUG] TIP検出 raw_unity=(-0.2081, 0.2700)
[ABORT] j0=+25.00 が 初期j0=+45.00から +/-15.0度を超過。視覚サーボ中断。送信j0は変化しているのに、実測j0がPICK降下後の値から動かない。APPROACH姿勢(j1=87.74)では問題なく動くが、PICK姿勢(j1=90.87)では固まる。原因の特定は次のセッションへ持ち越した。
判断ログ
迷った点: 視覚サーボをAPPROACH姿勢で実行するか、PICK姿勢で実行するか。
選んだ: PICK姿勢(降下後)で実行する。
理由: APPROACH姿勢でTIP_Xを合わせても、降下動作でj1・j4が変化すると連鎖的にTIP_Xが動く。「見えている位置に合わせた」と「実際に掴む位置に合わせた」が一致しない。視覚サーボはできる限り最終動作に近い姿勢で実行すべきだ。
迷った点: j1固定値をlookupの平均値にするか、実測で安定していた90.87にするか。
選んだ: 90.87固定。
理由: LOG184初回テストでCONVERGEDだったTrialの実測j1が90.87と90.96で安定していた。lookupの平均より実績値を優先した。
今日の原則
「CONVERGED」と「物理的に位置が合った」は異なる検証レイヤーだ。ループが収束したことと、実際に物体を掴める位置に到達したことは別の問いとして検証しなければならない。
分類: #workflow
→ principles.md にP009として転記すること
メタ情報
Phase: #phase/PICK Tool: #tool/Python #tool/mechArm #tool/iPhone
ハンドオフ
パイプライン状態
Layer | Status | Last Confirmed DAY |
|---|---|---|
Camera detection | ✅ | LOG184 |
Blue marker identification | ✅ | LOG184 |
Red block detection | ✅ | LOG184 |
PICK lookup | ✅ | LOG184 |
Visual servo convergence | ✅ | LOG184 |
j0 execution in servo loop | ❌ | LOG184 |
PICK physical motion | ⚠️ 2/5 (lookup成功trial中) | LOG184 |
Gripper open/close | ✅ | LOG184 |
LIFT motion | ✅ | LOG184 |
今日達成されたこと
青シール識別ロジックを幾何学ベースに変更(TIP stdev 19.42mm → 0.08mm)
動作シーケンス確定(APPROACH → DESCEND → PICK_VISUAL_SERVO → GRIP → LIFT → HOME)
PICK_J1_FIXED = 90.87 確定
グリッパー制御実装(state=0:開く / state=1:閉じる)
Trial 3・6で赤ブロック把持に成功
arm_kinematics.md 作成・ローカルGitとClaudeプロジェクト知識に両所配置
今日達成されなかったこと
PICK姿勢でのj0送信問題の原因特定(DEBUGログで現象は確認済み)
視覚サーボの安定した収束率(現状2/5、lookup成功trial中)
未検証の前提
PICK姿勢(j1=90.87)でj0が動かない原因(原因特定が未完)
PICK_J1_FIXED=90.87がマット全域の位置で通用するか
次にやること
PICK姿勢でj0が動かない問題の原因特定
原因特定後、収束率の安定化
