フィジカルAI研究室を作る Log#30 | mechArm 270 がブロックを落とす理由は、まさかの電源不足

この記事の素材(コード・ログ・データ 6ファイル・まとめてダウンロードあり)
AIで読む ChatGPT・Claude などで、この記事に質問できます

実物の小型ロボットアーム mechArm 270 が、つかんだブロックを持ち上げる途中で落とす原因は、電源アダプターの容量不足とみられます。本体のラベルは40W を求めているのに、届いたときから使っていたのは外付けディスク用の12V・2A(24W)のアダプターでした。 爪のサーボの電流を記録から見ると、閉じて押している最中に、指令を何も送っていないのに急に0付近まで落ちていました。落ちる瞬間の多くは、アームを動かす指令を送った直後です。新しい12V・5A(60W)のアダプターを注文し、届いたら同じ試し方で確かめます。電源が原因かどうかは、まだ確定していません。

この回でやったことで、次のことが変わりました。

  • 爪が緩む瞬間を、数字で見つけられるようになった:Physical Intelligence の π0.5 に動かさせた20本の記録から、爪の電流が落ちた時刻と、その直前にアームへ送った指令を並べる道具(grip_drop_analysis.py)を作った。目で見て緩んだと感じた所が、どの本でも同じ形(約800から0付近へ一気に落ちる)で記録に残っていた
  • 間違った手当てを1つ避けられた:位置5 の失敗は、はじめは学習の問題(持ち上げが足りない)に見えていた。電源が足りないまま位置5 のお手本を6本撮り足していたら、緩みかけたお手本が学習データに混ざるところだった。撮影は電源が届くまで止めた
  • 爪の閉じる値と締め直しを選べるようになった:Claude Code が依頼箱で56分で入れた(依頼152)。閉じる値を20から25にすると、爪の電流は約900から約700に下がり、止まっている間に持てる時間は11〜19秒から27〜104秒に延びた
  • 費用:GPU(Runpod の A40)を2回借りて、約80円と約238円。新しいアダプターは3,355円

位置1〜5 の5か所にブロックを置いて、π0.5 にブロックを箱へ入れさせました。位置3 は3回とも成功、位置4 は5回中3回、位置5 は9回中2回でした。位置5 の失敗は、ブロックの位置まで届かないのではなく、つかんだあとに落とすものでした。爪のサーボの電流を見ると、閉じてから11〜19秒で、押していた力が急に抜けていました。閉じる値を変えても、アームが動き出すとまた抜けます。最後に、アームの台座のラベルとアダプターのラベルを見比べて、電源が本体の求める量の6割しかないことに気づきました。

アームは2026年3月に届き、箱に AC アダプターが入っていませんでした(LOG113)。サポートに連絡して、あとから別に送られてきたのがこの12V・2A です。送るときに取り違えたのかもしれません。8か月の実機の記録は、すべてこの電源で取っていたことになります。

やったことなぜ結果
位置1〜5 の置き場所を1枚の画像にする
位置3〜5 に正しく置くため
教えた位置を、今のカメラの画像の上に描いた
位置3・4・5 で π0.5 を動かす
位置2 だけが届かないのかを見る
位置3 は3/3、位置4 は3/5、位置5 は2/9
爪の電流と肩の動きを記録から出す
位置5 で落とす理由を探す
閉じて11〜19秒で電流が0付近へ落ちていた。持ち上げもお手本より小さい
閉じる値を選べるようにし、締め直しを直す(依頼152)
押す力を弱めて、抜けないかを見る
値25 で電流は約700。止まっている間は27〜104秒持った
値25 で位置5 を3本力が抜けるかを確かめる
動き出した所でまた抜けた。3本中1本だけ成功(パッドで持ち上げた)
本体とアダプターのラベルを見る
電源の不足を疑う
本体は40W、アダプターは24W
プラグの太さを確かめ、12V・5A を注文
電源を足りる量にする届いてから確かめる

実機と学習の記録は、KIOXIA の lab/Log30/ と runs/pi05_policy/pi05_20261111_* に入れています。

GPU を買うか借りるかの判断は、Runpod で実際に借りて学習させた費用をもとに、別のページにまとめています。

導入比較ガイドロボットAIの学習用GPU、買うか借りるか実際に借りて学習させた費用と、損益分岐の計算機で決められます

作業ログ ― 位置3〜5 を実機で試し、爪が緩む原因を電源まで追うまで

ここから下は作業の記録です。コマンド・出力・コードは全量で載せます。効果を書いた所のうち、数字で書いたものは測った値、「見込み」と書いたものはまだ確かめていない値です。

この回で何度も出てくる言葉を先に言い換えておきます。

  • 位置1〜位置5:赤いブロックを置く5つの場所。お手本はこの5か所で10本ずつ撮った(LOG479 で決めた形)
  • deep1:位置ごとに10本そろえた深いお手本50本で、π0.5 を一から学習したモデル(LOG480)
  • j0〜j5:アームの6つの関節。j0 は根元の回転、j1 は肩、j2 はひじ、j4 は手首。肩 j1 は小さくなるほどアームが起き上がる(持ち上げ)
  • 爪の電流:爪を動かすサーボが使っている電流を、サーボの番地から直接読んだ値(単位のない生の数。LOG461 で記録に足した)。爪がブロックを押しているあいだは大きく、開いているときはマイナス50前後、何も押していないときは0付近になる
  • 閉じる値:爪を閉じるときにサーボへ送る目標の値(0〜100。小さいほど深く閉じようとする)。今までは20 で固定だった
  • 締め直し r:推論の途中で r を押すと、爪を開かずにもう一度閉じる指令を送る
  • 依頼箱:Claude Code への依頼を、Mac の見張り係が順番に渡して報告を書き戻す仕組み。この回の依頼152 はここに入れた
  • Pod:Runpod で借りる GPU のマシン。π0.5 はこの上で動き、Mac から画像と関節の角度を送って次の動きを受け取る

位置1〜5 の置き場所を、今のカメラの画像に描いた

位置3〜5 は、deep1 になってから一度も試していません。置き場所を間違えないように、5か所を1枚の画像にしました。お手本を教えた日(10/19)の、ブロックの中心のマットの上の mm(count_by_position.py の TEACH_REF_MM)を、マットの四隅を手がかりに、昨夜の上カメラの1コマへ写しています。

上カメラの画像に、位置1〜5 の置き場所を四角で描いた。位置5 は HOME の右の爪の真下にあたる

写し方が合っているかは、10/19 の画像に写っていたブロックと比べました。位置3 は写した所が (739, 668)・見つけた赤が (739, 656)、位置4 は (474, 390)・(474, 395) で、どちらも数画素のずれでした。

端末:10/19 の各位置の1コマ目と、昨夜の1コマ目を切り出す

cd $HOME/mnt/KIOXIA/r2r2r-data/runs/run_pick_place; O=$HOME/mnt/PixelstoMotors/デジタルツイン学習R2R2R/フィジカルAI研究室を作る/position_guide; mkdir -p "$O"; i=1; for t in 183454 191541 192438 193459 194913; do ffmpeg -loglevel error -y -i run_0001_20261019_$t/recording/top.mp4 -frames:v 1 "$O/pos${i}_raw.jpg"; i=$((i+1)); done; ls -la "$O"
cd $HOME/mnt/KIOXIA/r2r2r-data/runs/pi05_policy; O=$HOME/mnt/PixelstoMotors/デジタルツイン学習R2R2R/フィジカルAI研究室を作る/position_guide; for r in pi05_20261110_193431 pi05_20261110_192201; do ffmpeg -loglevel error -y -i $r/recording/top.mp4 -frames:v 1 "$O/now_raw.jpg" && echo ok $r && break; done

map_positions.py(教えた位置の mm を、マットの四隅から画像の画素へ写す。Mac 連携の shell で $O は position_guide のフォルダ)

cd $HOME/mnt/r2r2r-scripts; O=$HOME/mnt/PixelstoMotors/デジタルツイン学習R2R2R/フィジカルAI研究室を作る/position_guide; python3 - <<E
import sys,cv2,numpy as np
sys.path.insert(0,'pi05'); sys.path.insert(0,'.')
import count_by_position as c
for f in ['now_raw','pos2_raw','pos3_raw']:
    im=cv2.imread('$O/'+f+'.jpg'); co=c.detect_corners(im); print(f,co)
    if co is None: continue
    H=cv2.getPerspectiveTransform(np.array(c.MAT_CORNERS_MM,np.float32),np.array(co,np.float32))
    for k,v in c.TEACH_REF_MM.items():
        p=cv2.perspectiveTransform(np.array([[v]],np.float32),H)[0][0]; print(' ',k,[round(x) for x in p])
E

map_positions.py の出力

now_raw [[ 294    0]
 [1678    0]
 [1703  925]
 [ 296  952]]
  1 [589, 580]
  2 [514, 694]
  3 [725, 678]
  4 [454, 397]
  5 [1116, 695]
pos2_raw [[ 321    0]
 [1691    0]
 [1718  924]
 [ 314  937]]
  1 [605, 571]
  2 [531, 684]
  3 [739, 668]
  4 [474, 390]
  5 [1128, 688]
pos3_raw [[ 321    0]
 [1691    0]
 [1717  924]
 [ 314  936]]
  1 [605, 571]
  2 [531, 683]
  3 [739, 668]
  4 [474, 390]
  5 [1127, 688]

draw_positions.py(昨夜の画像に、5か所の四角と番号を描く)

import cv2
from PIL import Image,ImageDraw,ImageFont
img=Image.open('now_raw.jpg').convert('RGBA')
P={1:(589,580),2:(514,694),3:(725,678),4:(454,397),5:(1116,695)}
res={1:"3回とも成功",2:"届かない",3:"今回",4:"今回",5:"今回"}
off={1:(0,-1),2:(-1,0),3:(1,0),4:(0,-1),5:(1,0)}
ov=Image.new('RGBA',img.size,(0,0,0,0)); d=ImageDraw.Draw(ov)
F=lambda s:ImageFont.truetype('/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc',s)
s=36
for k,(x,y) in P.items():
    on=k in(3,4,5); col=(255,70,70,255) if on else (200,200,200,255)
    d.rectangle([x-s,y-s,x+s,y+s],outline=col,width=6)
    ox,oy=off[k]; bx,by=x+ox*(s+52),y+oy*(s+52)
    if k==5: bx,by=x+s+130,y   # 爪の外へ
    d.ellipse([bx-34,by-34,bx+34,by+34],fill=col)
    t=str(k); w=d.textlength(t,font=F(48)); d.text((bx-w/2,by-35),t,font=F(48),fill=(255,255,255,255) if on else (30,30,30,255))
    lab=res[k]; tw=d.textlength(lab,font=F(28))
    lx,ly=bx-tw/2,by+40
    d.rounded_rectangle([lx-10,ly,lx+tw+10,ly+42],8,fill=(0,0,0,200)); d.text((lx,ly+2),lab,font=F(28),fill="white")
d.line([P[5][0]+s,P[5][1],P[5][0]+s+96,P[5][1]],fill=(255,70,70,255),width=5)
img=Image.alpha_composite(img,ov); d=ImageDraw.Draw(img)
d.rounded_rectangle([20,20,820,190],12,fill=(0,0,0,205))
d.text((40,28),"ブロックの置き場所 位置1〜5",font=F(44),fill="white")
d.text((40,90),"四角=ブロックの中心に置く場所(約3cm角)",font=F(28),fill="white")
d.text((40,132),"赤=今回試す位置3〜5 灰=試した位置1・2",font=F(28),fill=(255,190,190))
d.rounded_rectangle([1240,800,1890,900],12,fill=(0,0,0,205))
d.text((1260,808),"位置5は HOME の右の爪の真下",font=F(28),fill="white")
d.text((1260,850),"写っている赤いブロックは位置2",font=F(28),fill=(220,220,220))
img.convert('RGB').save('/mnt/user-data/outputs/block_positions_1to5.jpg',quality=92)

起動と位置合わせ(09:44・Log30)

この記事のコード・ログ・データは、1ファイルずつ下に置いています。全文はリンク先にあります。

ファイルの一覧(6本)

01_sec03.txt ― 端末:lab_start_20261111_094411.txt(Pod の準備から、位置3 の3本まで)・80,422字

02_sec05.txt ― 端末:lab_start_20261111_100129.txt(つなぎ直しから、位置4 の5本と位置5 の9本まで)・253,116字

03_grip_drop_analysis.py.txt ― grip_drop_analysis.py(爪を閉じている間に、電流が急に落ちる所を探す)・5,630字

04_sec08.md ― Claude Code の報告(結果/20261111_152)・3,599字

05_sec08.txt ― commit d6f5823 の差分(依頼152)・55,251字

06_sec09.txt ― 端末:lab_start_20261111_160103.txt(閉じる値25 で位置5 の3本)・66,796字

前の回(LOG486)で入れた2つの直しが、この起動から効いています。上カメラの傾きはソフトが学習データの向きへ回してそろえ(−2.05° を +1.43° 回して −0.61° に)、ゲームパッドの読み取りは推論と別のプロセスです。

位置合わせの画面を q で閉じたあと、ターミナルが止まって見えましたが、推論の入力待ちに進んでいただけでした。記録のファイルはターミナルより遅れて書かれるので、記録だけ見ると止まっているように見えます。

端末:lab_start_20261111_094411.txt(Pod の準備から、位置3 の3本まで)

01_sec03.txt80,422字・1,310行・text
[RANGE ] 安全範囲 (学習データ ±10°) は /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_deep_even10_v1/raw_episodes から (--model deep1)
[FRAME ] 写り方の確かめの基準画像は /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes の最初のエピソードから (位置合わせと同じ trim2. 依頼 137)
[TILT  ] 上カメラの傾きのお手本 (各エピソードの 1 枚目の中央値) は /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_deep_even10_v1/raw_episodes から (安全範囲と同じ. 差だけ画像を回して AI に渡す. 依頼 144)
[LAB   ] 2026-11-11 09:44:11  GPU=NVIDIA A40  episode=run_0001_20261019_194818  log=/Volumes/KIOXIA/r2r2r-data/lab/Log30  
[MODEL ] --model deep1: π0.5 base から deep_even10_v1 で新しく学習した 2999 (依頼 133. decay_steps 5000)
         PixelstoMotors/pi05-mecharm-deep-even10-lora-v1 → /workspace/ckpt/deep_v1_2999  設定 pi05_mecharm_deep_even10_lora  assets local/mecharm_redblock_box_deep_even10_v1

=== 1. Pod を作る
別のタブで開く保存

位置3 は3回とも箱まで運べた

位置3 の3本(095426・095717・095917)は、どれも π0.5 だけでブロックをつかみ、箱に入れました。つかみはやや浅めでした。1本目は、推論4 で一度閉じたあと、推論17 でもう一度閉じています。2本目は途中で関節の角度の読み取りに3回失敗しましたが、最後まで動きました。

位置4 は5回中3回、位置5 は9回中2回

続けて同じ Pod で、位置4 を5本、位置5 を9本動かしました。位置5 の成功2本は、どちらも人が手を貸した本です(101720 はゲームパッドで直し、102516 は締め直し r を押した)。

試行位置結果人の手
1006594成功なし
1008574成功なし
1011024失敗なし
1012174失敗なし
1013294成功r を3回
1015575失敗r を2回
1017205成功ゲームパッド
1019185失敗ゲームパッド
1020435失敗r を1回
1022135失敗ゲームパッド
1023535失敗なし
1025165成功r を1回
1027205失敗ゲームパッド
1028515失敗r を1回

試行ごとの位置は、上カメラの録画からブロックの位置を mm で出して確かめました。どの本も、教えた位置から17mm 以内に置けています。

端末:lab_start_20261111_100129.txt(つなぎ直しから、位置4 の5本と位置5 の9本まで)

02_sec05.txt253,116字・3,193行・text
[RANGE ] 安全範囲 (学習データ ±10°) は /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_deep_even10_v1/raw_episodes から (--model deep1)
[FRAME ] 写り方の確かめの基準画像は /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes の最初のエピソードから (位置合わせと同じ trim2. 依頼 137)
[TILT  ] 上カメラの傾きのお手本 (各エピソードの 1 枚目の中央値) は /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_deep_even10_v1/raw_episodes から (安全範囲と同じ. 差だけ画像を回して AI に渡す. 依頼 144)
[LAB   ] 2026-11-11 10:01:29  GPU=NVIDIA A40  episode=run_0001_20261019_194818  log=/Volumes/KIOXIA/r2r2r-data/lab/Log30  
[MODEL ] --model deep1: π0.5 base から deep_even10_v1 で新しく学習した 2999 (依頼 133. decay_steps 5000)
         PixelstoMotors/pi05-mecharm-deep-even10-lora-v1 → /workspace/ckpt/deep_v1_2999  設定 pi05_mecharm_deep_even10_lora  assets local/mecharm_redblock_box_deep_even10_v1

=== 1. Pod を作る
別のタブで開く保存

positions_today.py(この日の試行で、ブロックを置いた位置を録画から出す)

#!/usr/bin/env python3
"""positions_today.py — 2026-11-11 の実機推論(runs/pi05_policy/pi05_20261111_*)で、ブロックを置いた位置を上カメラの録画から出す(Log30・LOG487)。
count_by_position.py の block_mm(マットの四隅 → mm、閉じる前のコマでいちばん大きい赤)と nearest_position(教えた位置 1〜5 で最も近いもの・30mm 以内)を使う。
読むだけ(記録には何も書かない)。
使い方: python3 positions_today.py   (r2r2r-scripts の直下で)
"""
import sys
from pathlib import Path
sys.path[:0] = ['pi05', '.']
import count_by_position as c

R = Path('/Volumes/KIOXIA/r2r2r-data/runs/pi05_policy')
if not R.exists():
    R = Path.home() / 'mnt/KIOXIA/r2r2r-data/runs/pi05_policy'
print('run_stem, 位置, 教えた位置からの離れ_mm, ブロックの中心_mm')
for d in sorted(R.glob('pi05_20261111_*')):
    try:
        b, why = c.block_mm(d)
    except Exception as e:
        print(d.name, 'ERR', e); continue
    if b is None:
        print(d.name, '見つからない', why); continue
    pos, near, dist = c.nearest_position(b['mm'])
    print(f"{d.name}, {pos}, {dist}, ({b['mm'][0]:.0f}, {b['mm'][1]:.0f})")

positions_today.py の出力

run_stem, 位置, 教えた位置からの離れ_mm, ブロックの中心_mm
pi05_20261111_095426, 3, 13.3, (134, 244)
pi05_20261111_095717, 3, 8.4, (131, 239)
pi05_20261111_095917, 3, 12.2, (134, 242)
pi05_20261111_100659, 4, 10.9, (244, 112)
pi05_20261111_100857, 4, 11.4, (250, 108)
pi05_20261111_101102, 4, 7.2, (248, 104)
pi05_20261111_101217, 4, 10.8, (240, 112)
pi05_20261111_101329, 4, 12.9, (241, 114)
pi05_20261111_101557, 5, 7.6, (-41, 248)
pi05_20261111_101720, 5, 11.5, (-42, 256)
pi05_20261111_101918, 5, 1.5, (-50, 248)
pi05_20261111_102043, 5, 4.4, (-46, 250)
pi05_20261111_102213, 5, 8.2, (-43, 252)
pi05_20261111_102353, 5, 3.4, (-47, 249)
pi05_20261111_102516, 5, 4.8, (-44, 246)
pi05_20261111_102720, 5, 6.4, (-46, 252)
pi05_20261111_102851, 5, 6.5, (-42, 246)
pi05_20261111_160851, 5, 16.6, (-65, 242)
pi05_20261111_161402, 5, 8.3, (-56, 250)
pi05_20261111_161743, 5, 8.4, (-56, 250)

位置5 の失敗は、つかんだあとに爪の力が抜けて落としていた

位置5 で何が起きているのかを、動いているときに見て次のように感じました。

5の位置でブロック持った後に爪が緩みやすいのと、爪の握り直しが効いてないね。あとブロック持った後の持ち上げの高さが足りないね。

爪の電流を、閉じた時刻を0秒にして並べると、閉じた直後は約900あり、そのまま約800で押し続けます。それが閉じてから11〜19秒たったところで、一気に0付近まで落ちていました。爪を開いたとき(マイナス50前後)とは違う値なので、爪が開いたのではなく、サーボが押すのをやめた状態です。値20 で閉じた17本のうち12本で起き、落ちなかったのは、位置3 の3本と位置4 の2本だけでした。

締め直し r は、同じ値20 をもう一度送るだけでした。落ちたあとに押した5回のうち、101329 と 102516 の2回は電流が約820 に戻り、101557・102043・102851 の3回は戻りませんでした。戻らなかった3回は、持ち上げ始めた所で力が抜け、ブロックがもう爪から外れていたとみられます。

持ち上げの大きさも比べました。位置5 のお手本のうち、教えた動きの再生で撮った4本は、閉じてから肩 j1 が約14°戻り(60°→46°)、ひじ j2 は約31°まで上がります。π0.5 の位置5 は、肩の戻りが −4〜−12° の本がほとんどでした。位置5 のお手本10本のうち6本は補正入りで、肩の戻りが −9〜−50° と本ごとにばらばらです。持ち上げ方が定まらないのは、このばらつきが一因かもしれません。

ねらい:落とす理由を、学習の問題と、爪のハードの問題に分けて見る。 変わったこと:試行ごとに、爪の電流が落ちた時刻・直前の指令からの秒数・肩の動きを1行で出せるようになった(grip_drop_analysis.py)。 見込める効果:電源を替えたあとに同じスクリプトを回せば、落ちる所が消えたかを数字で比べられる(見込み)。

grip_drop_analysis.py(爪を閉じている間に、電流が急に落ちる所を探す)

この回の会話の中で何度かに分けて確かめたこと(閉じて1秒の電流・落ちた時刻・r の前後・肩の持ち上げ)を、1本のスクリプトにまとめ直して KIOXIA に置いたものです。

03_grip_drop_analysis.py.txt5,630字・116行・python
#!/usr/bin/env python3
"""grip_drop_analysis.py — 爪を閉じている間に、爪の電流(gripper_current)が急に 0 付近へ落ちる所を探す(Log30・LOG487)。

入力: runs/pi05_policy/pi05_20261111_*/recording/states.csv・currents.csv・log.jsonl(読むだけ)
見ること(試行ごと)
- 閉じた指令(gripper_cmd の gripper_state=1)の時刻。1 回目を 0 秒にする
- 閉じて 0.8〜1.5 秒の電流の中央値
- 「落ちた」所: 1 つ前の行が 400 を超え, 次の行が 150 を下回った所(爪が閉じている間だけ)
別のタブで開く保存

grip_drop_analysis.py の出力(午後の値25 の3本まで含めて、最後にもう一度回した)

run, 閉じる値, 閉じて1秒の電流, 閉じた時刻(秒), 落ちた所(秒・直前の送りから・前1秒の動き), 締め直し r(秒・値), 開いた, 肩j1の持ち上げ(°)
095426, 20, 905.0, [0.0], -, -, True, -20.0
095717, 20, 722.0, [0.0], -, -, True, -16.0
095917, 20, 874.0, [0.0], -, -, True, -16.2
100659, 20, 924.0, [0.0], -, -, True, -13.1
100857, 20, 874.0, [0.0], -, -, True, -14.9
101102, 20, 849.0, [0.0], 19.2s(送り0.3s・1.4°), -, False, -6.2
101217, 20, 846.0, [0.0], 12.1s(送り0.4s・1.6°), -, False, -5.2
101329, 20, 897.0, [0.0, 5.9, 16.2, 29.4], 19.0s(送り0.2s・2.0°) / 38.7s(送り0.4s・1.1°), 5.9s(None) / 16.2s(None) / 29.4s(None), True, -18.0
101557, 20, 905.0, [0.0, 9.5, 15.9], 11.7s(送り0.4s・2.9°), 9.5s(None) / 15.9s(None), False, -3.5
101720, 20, 895.0, [0.0], 19.0s(送り8.6s・0.0°), -, True, -27.3
101918, 20, 850.0, [0.0], 14.9s(送り5.1s・0.0°), -, False, -25.3
102043, 20, 896.0, [0.0, 17.2], 14.3s(送り3.5s・0.2°), 17.2s(None), False, -7.8
102213, 20, 897.0, [0.0, 23.3], 16.9s(送り12.1s・0.1°), -, False, -20.3
102353, 20, 849.0, [0.0], 11.3s(送り1.6s・0.0°), -, True, -7.7
102516, 20, 901.0, [0.0, 27.3], 13.3s(送り1.7s・0.0°) / 36.9s(送り0.8s・3.6°), 27.3s(None), True, -11.1
102720, 20, 899.0, [0.0], 16.4s(送り6.0s・0.0°), -, False, -11.6
102851, 20, 892.0, [0.0, 16.7], 12.7s(送り0.2s・0.4°), 16.7s(None), False, -4.8
160851, 25, 754.0, [0.0], 104.5s(送り17.7s・11.2°), -, True, -32.2
161402, 25, 774.0, [0.0, 89.3, 95.1, 115.5, 128.2, 133.4, 146.3, 149.5], 72.8s(送り1.9s・0.0°) / 121.5s(送り35.4s・1.0°) / 143.1s(送り57.1s・0.0°), 89.3s(22) / 95.1s(25), True, -7.6
161743, 25, 706.0, [0.0], 27.5s(送り18.6s・0.0°), -, False, -30.9
書き出し /sessions/rcw-01levexwtongyyuqavpffdk7/mnt/KIOXIA/r2r2r-data/lab/Log30/analysis/grip_drop_summary.csv /sessions/rcw-01levexwtongyyuqavpffdk7/mnt/KIOXIA/r2r2r-data/lab/Log30/analysis/grip_drop_series.json

lift.py(お手本の位置4・位置5 で、閉じてから肩 j1 がいちばん上がった所を出す)

import sys,json,csv,numpy as np; sys.path[:0]=['pi05','.']
import count_by_position as c
from pathlib import Path
K=Path.home()/'mnt/KIOXIA/r2r2r-data'
ds=K/'datasets/mecharm_redblock_box_deep_even10_v1/raw_episodes'
def lift(S,g):
    ci=np.where(g>0.5)[0]
    if len(ci)==0: return None
    a=ci[0]; oi=np.where(g[a:]<0.5)[0]; b=a+oi[0] if len(oi) else len(g)
    seg=S[a:b]; k=np.argmin(seg[:,1])
    return f"close j1={S[a,1]:6.1f} j2={S[a,2]:6.1f} | peak j1={seg[k,1]:6.1f} j2={seg[k,2]:6.1f} j4={seg[k,4]:6.1f} | dj1={seg[k,1]-S[a,1]:6.1f}"
print("== demos")
for e in sorted(ds.iterdir()):
    m=json.load(open(e/'meta.json')); p=c.classify(e.name,m,K/'runs')['position']
    if p not in (4,5): continue
    d=np.load(e/'episode.npz'); S=d['state']
    print(p,e.name[:24],lift(S,S[:,6]))

lift.py の出力

== demos
5 pi05_20261031_175527 close j1=  61.6 j2=  18.5 | peak j1=  49.5 j2=  30.6 j4= -63.6 | dj1= -12.1
5 pi05_20261031_180435 close j1=  61.4 j2=  20.0 | peak j1=  51.5 j2=   4.6 j4= -62.0 | dj1=  -9.9
5 pi05_20261031_184016 close j1=  60.0 j2=  22.1 | peak j1=  50.8 j2=  -2.3 j4= -59.1 | dj1=  -9.2
5 pi05_20261101_190347 close j1=  61.5 j2=  19.4 | peak j1=  50.8 j2=  29.7 j4= -64.4 | dj1= -10.7
5 pi05_20261106_183926 close j1=  61.3 j2=  21.0 | peak j1=  28.6 j2=  10.9 j4= -53.0 | dj1= -32.8
5 pi05_20261106_184650 close j1=  61.1 j2=  21.1 | peak j1=  10.7 j2=  30.8 j4= -65.2 | dj1= -50.4
4 run_0001_20261019_193404 close j1=  62.5 j2=  14.8 | peak j1=  45.9 j2=  10.1 j4= -62.8 | dj1= -16.6
4 run_0001_20261019_193459 close j1=  62.4 j2=  14.8 | peak j1=  45.9 j2=  10.0 j4= -62.4 | dj1= -16.5
4 run_0001_20261019_193617 close j1=  62.4 j2=  14.8 | peak j1=  45.9 j2=   9.7 j4= -62.3 | dj1= -16.5
4 run_0001_20261019_193825 close j1=  62.3 j2=  13.9 | peak j1=  45.9 j2=   9.7 j4= -62.5 | dj1= -16.4
4 run_0001_20261019_193932 close j1=  62.5 j2=  14.8 | peak j1=  45.9 j2=   9.9 j4= -62.4 | dj1= -16.5
5 run_0001_20261019_194818 close j1=  60.0 j2=  19.5 | peak j1=  46.3 j2=  31.4 j4= -64.2 | dj1= -13.7
5 run_0001_20261019_194913 close j1=  60.0 j2=  19.4 | peak j1=  46.3 j2=  31.4 j4= -64.2 | dj1= -13.7
5 run_0001_20261019_195023 close j1=  60.0 j2=  19.4 | peak j1=  46.4 j2=  31.3 j4= -64.1 | dj1= -13.6
5 run_0001_20261019_195120 close j1=  60.0 j2=  19.4 | peak j1=  46.4 j2=  31.2 j4= -64.1 | dj1= -13.6
4 run_0001_20261109_130542 close j1=  62.7 j2=   9.9 | peak j1=  43.8 j2=   9.8 j4= -53.5 | dj1= -18.8
4 run_0001_20261109_130723 close j1=  62.6 j2=  10.0 | peak j1=  43.9 j2=   9.8 j4= -53.1 | dj1= -18.7
4 run_0001_20261109_130824 close j1=  62.7 j2=  10.0 | peak j1=  43.9 j2=   9.8 j4= -52.9 | dj1= -18.8
4 run_0001_20261109_130929 close j1=  62.6 j2=   9.9 | peak j1=  43.9 j2=   9.8 j4= -53.1 | dj1= -18.7
4 run_0001_20261109_131103 close j1=  62.7 j2=  10.0 | peak j1=  43.9 j2=   9.7 j4= -53.2 | dj1= -18.8

Pod を消した(51分・約80円)

端末:lab_stop_20261111_103519.txt

[STOP  ] Log30 の Pod: id t3fnpcsccc95vo  GPU=NVIDIA A40  作った時刻 2026-11-11 09:44:14
[LOG   ] serve.log を持ち帰った → /Volumes/KIOXIA/r2r2r-data/lab/Log30/serve.log (69 行)
[STOP  ] Terminate を送った (10:35:29)
[STOP  ] Pod (id t3fnpcsccc95vo) が消えたことを API で確かめた
[COST  ] 借りていた時間 51 分 15 秒 (0.85 時間) × 1時間 0.59 ドル = 約 0.50 ドル (約 80 円. 1ドル=158円)
[TUNNEL] 8000 番のトンネルは残っていません

依頼152:爪の閉じる値を選べるようにし、締め直しは前と違う値を送る

直し方の案を3つ出し、次のように決めました。

深いお手本に入れ替え、1,2はおすすめで進めて

1つ目は、閉じる値をブロックの幅に近い値(25〜30)にして、押し続ける力を弱めること。2つ目は、締め直し r で、開かずに前と違う値を送ること。同じ目標の値をもう一度送っても、サーボが動かないことがあるためです。3つ目は、位置5 の補正入りのお手本6本を、教えた動きの再生で撮る深いお手本に入れ替えることです。3つ目は、データを撮る前の準備(外す6本の表と手順書)までを入れました。

Claude Code は10:38 に始め、11:34 に終えました(56分)。codex(外部のコードの見直し役)に2回見てもらい、1回目の指摘3件を直しています。

ねらい:爪がブロックに当たって閉じきれず、約800の電流で押し続けている状態を弱める。 変わったこと:起動の1行で閉じる値を選べる(--grip-value)。r は 22→25→22 のように値を交互に送る。 見込める効果:押す力が弱まれば、サーボが力を抜くまでの時間が延びる(見込み。下の値25 の試しで、止まっている間は延びたことを確かめた)。

依頼文(依頼箱 20261111_152)

---
作業フォルダ: /Users/shimazueiichi/r2r2r-scripts
上限時間: 120
---
# 依頼152:爪の閉じる値を変えられるようにする・締め直し (r) を効くようにする・位置5 のお手本を入れ替える準備

実機は動かさない(実装・テスト・レビューまで)。エイイチは見ていない。Log30。
(依頼151 は別の案で番号だけ取ってあるので飛ばしている)

## 何が起きたか(2026-11-11 午前・KIOXIA lab/Log30・runs/pi05_policy/pi05_20261111_*)
deep1 で位置3〜5 を実機推論した。位置3 は 3/3、位置4 は 3/5、位置5 は 2/9(2 本とも手で助けた)。
位置5 の失敗はつかんだあとに落とすもの。recording/currents.csv の gripper_current を見ると:
- 閉じた直後は約 900、そのあと約 800 で押し続け、閉じてから 11〜19 秒で指令なしに急に 0 付近へ落ちる
  (101557 は 11.7 秒・102043 は 14.3 秒(待っている間)・101329 は 19.0 秒・102516 は約 14 秒)。
  落ちる瞬間に read の no_reply が重なることが多い。750 前後だった 100659 は 36 秒持って落ちなかった
- 見立て(未確認):GRIP_VALUE=20 はブロックに当たって閉じきれず、約 800 の電流で押し続け、サーボが力を抜く
- r(締め直し)は同じ値 20 をもう一度送るだけ。落ちたあとに押した 4 回のうち 2 回(101329・102516)は約 820 に戻り、
  2 回(101557・102043)は戻らなかった

## エイイチの決め(2026-11-11)
1. 爪の閉じる値を、ブロックの幅に近い値(25〜30 あたり)に変えて、押し続ける力を弱める。実機でまず 1 本試す
2. r は、開かずに、今と違う値を送って閉じ直す形にする(同じ目標だとサーボが動かないことがあるため)
3. 位置5 の補正入りのお手本 6 本を、教えた動きの再生で撮る深いお手本に入れ替える(持ち上げをそろえるため)

## やること
### A. 閉じる値を選べるようにする
1. pi05/run_policy_client.py に --grip-value を足す(既定は今の 20 のまま)。閉じる指令(推論の gripper_cmd・補正の g・r・R・巻き戻し)はすべてこの値を使う。
   tools/gamepad_teleop.py が rpc.GRIP_VALUE を読んでいる所も同じ値になるようにする(--pad-io の別プロセスにも渡す)
2. lab_start.sh に --grip-value を足し、run_policy_client.py に渡す。起動時に [GRIP  ] で使う値を 1 行出す
3. log.jsonl の頭(model の行)に grip_value を残す
4. 閉じてから 1 秒後の爪の電流(currents.csv の gripper_current の中央値)を、推論の終わりに 1 行で出す(記録には何も足さない。表示だけ)
5. dynamic_tracking_limits/drag_teaching/record_teach_demo.py にも --grip-value を足す(既定は今の値のまま)。meta に残す

### B. r(締め直し)を効くようにする
6. r は開かずに、前に送った閉じる値と違う値を送る:1 回目は (閉じる値 − 3)、次の r は閉じる値、と交互にする(0 より下にはしない)。
   補正の外の r と補正の中の r の両方。log.jsonl の regrip_tighten に送った値を残す
7. R(開いて閉じ直す)は今のまま

### C. 位置5 のお手本を入れ替える準備(データはまだ撮っていない)
8. pi05/excludes/deep_even10_v2.json を作る:deep_even10_v1 の 50 本から、位置5 の補正入り 6 本
   (pi05_20261031_175527・pi05_20261031_180435・pi05_20261031_184016・pi05_20261101_190347・pi05_20261106_183926・pi05_20261106_184650)を
   理由(位置5 の持ち上げをそろえるため、教えた動きの再生に入れ替える。エイイチの決め 2026-11-11)と一緒に外す。
   位置5 かどうかは count_by_position.py で確かめて、6 本が位置5 の補正入りであることを報告に書く
9. pi05/DEEP_DEMOS.md に「位置5 を撮り足す(6 本)」の節を足す:教えた記録は drag_v2_20221013_233323.json、
   撮る前に測る(measure)・ドライラン・--execute(--grip-value を付ける)、1 本目で深さ(grasp_depth.py)を見てから続ける、
   撮り終えたら deep_even10_v1 の残り 44 本と新しい 6 本から mecharm_redblock_box_deep_even10_v2 を作るコマンド、
   count_by_position.py で位置ごとに 10 本になったことを確かめるコマンドまで。学習は lab_train.sh の新しい --model を足す形でよいが、
   この依頼では学習の設定は作らなくてよい(データができてから)
10. 実機で試す手順を報告の最後に書く:lab_start.sh --model deep1 --grip-value 25 で位置5 を 1 本。閉じて 1 秒後の電流と、力が抜けるかを見る。
   抜けたら 30、ブロックが滑るなら 22 を試す

## 守ること
- 既定の動き(--grip-value を付けないとき)は今と同じ
- テストを足して通す(--grip-value がすべての閉じる指令に渡ること・r が値を交互に送ること・excludes の 6 本)。既存のテスト(pi05/ のもの・test_gamepad_teleop.py・test_lab_start.sh など)も通す
- codex で差分を見てもらう。指摘を直して通るまで
- 変えたファイルだけを指定して git add・commit(git add . と git clean は使わない)
- 報告には、変えたこと・テストの結果・codex の指摘と直したこと・実機で試す手順を書く

Claude Code の報告(結果/20261111_152)

04_sec08.md3,599字・81行・markdown
# 結果:20261111_152_爪の閉じる値を変えられるようにし締め直しを効くようにし位置5のお手本を入れ替える準備

- 状態:完了
- 始めた時刻:2026-11-11 10:38
- 終わった時刻:2026-11-11 11:34(56分)
- 作業フォルダ:/Users/shimazueiichi/r2r2r-scripts
- この続きを Claude Code で話すとき:作業フォルダで `claude --resume 1e6767bd-0d76-4d4e-99c0-82a4df934aa2`
別のタブで開く保存

commit d6f5823 の差分(依頼152)

05_sec08.txt55,251字・1,053行・diff
commit d6f5823896197ca1a924069988015a2a50fc487e
Author: Eiichi Shimazu <studio@adaptdesign.jp>
Date:   Wed Nov 11 11:34:03 2026 +0900

    爪の閉じる値を変えられるようにし, 締め直し (r) を前に送った値と違う値にし, 位置5 のお手本を入れ替える準備をする (依頼 152・Log30). run_policy_client.py に --grip-value (0〜100. 既定 20 のまま) を足し, 推論の閉じる指令・補正の g / r / R・巻き戻し・補正の取り消し・ゲームパッドの補正の閉じる指令をすべてこの値にする. log.jsonl の頭 (type=model) に grip_value. 推論の終わりに閉じて 1〜2 秒の爪の電流の中央値を閉じた命令ごとに 1 行で出す (grip_current.after_close. 表示だけ). r は開かずに (閉じる値 − 3) と閉じる値を交互に送る (補正の中と外. 0 より下にしない. regrip_tighten に grip_value_sent・prev_close_value). R は今のまま. gamepad_teleop.py を単独で動かすときも --grip-value. lab_start.sh に --grip-value N を足しクライアントに渡す ([GRIP  ] で使う値を出す). pi05/excludes/deep_even10_v2.json (deep_even10_v1 から位置5 の補正入り 6 本を外す. count_by_position.py で位置5・補正入りを確かめた) と DEEP_DEMOS.md の 5 節 (位置5 を教えた動きの再生で 6 本撮り, deep_even10_v2 を作る手順). テストを足す (test_rewind_correct 81・test_pad_correction 24・test_gamepad_teleop 93・test_teach_currents 27・lab_start 197). record_teach_demo.py の run --grip-value は git の外 (依頼 152. codex 2 回)
    
    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
別のタブで開く保存

record_teach_demo.py の差分(git の外にあるファイル。変える前の写しとの比べ)

--- dynamic_tracking_limits/drag_teaching/record_teach_demo.py.bak_pre_req152_20261111	2026-11-11 02:08:19.773579112 +0000
+++ dynamic_tracking_limits/drag_teaching/record_teach_demo.py	2026-11-11 01:43:09.380349088 +0000
@@ -152,6 +152,9 @@
 # _do_gripper は set_gripper_value の直後に time.sleep(GRIPPER_SLEEP) する。
 GRIPPER_DWELL_SEC = rpp.GRIPPER_SLEEP              # 2.0
 GRIP_VALUE = wpsr.GRIP_VALUE                       # 20(close の押し込み保持目標値)
+# run --grip-value N で上の値を置き換える(依頼 152。付けなければ 20 のまま)。試行 JSON の grip_value と
+# constants.GRIP_VALUE に残す
+GRIP_VALUE_RANGE = (0, 100)
 STREAM_INTERVAL_SEC = wpsr.STREAM_INTERVAL_SEC     # 0.1
 STEP_DEG_PER_TICK = wpsr.STEP_DEG_PER_TICK         # 2.0
 ARRIVAL_POLL_SLEEP = jss.POLL_SLEEP                # 0.3(本線と同値)
@@ -3709,8 +3712,19 @@
 
 
 def cmd_run(args):
+    global GRIP_VALUE
     _note_tol_source()
 
+    # 依頼 152: 爪の閉じる値(計画の表示・再生の閉じる指令・試行 JSON がすべてこの値を使う)
+    if getattr(args, "grip_value", None) is not None:
+        if not (GRIP_VALUE_RANGE[0] <= args.grip_value <= GRIP_VALUE_RANGE[1]):
+            _abort_msg("--grip-value は {}〜{} の整数で指定してください(指定: {})".format(
+                GRIP_VALUE_RANGE[0], GRIP_VALUE_RANGE[1], args.grip_value))
+            sys.exit(2)
+        GRIP_VALUE = int(args.grip_value)
+    _log("爪の閉じる値: {}{}".format(
+        GRIP_VALUE, "(--grip-value)" if getattr(args, "grip_value", None) is not None else "(既定)"))
+
     if args.teach_local and args.execute:
         _abort_msg("--teach-local は ドライラン専用です(--execute とは併用できません)。"
                    "実機では Pi から取得した教えた記録だけを再生します")
@@ -4018,6 +4032,8 @@
             "run_dir": str(run_dir),
             "started_at": datetime.now().isoformat(),
             "recording_enabled": recording_enabled,
+            # 依頼 152: 爪の閉じる値(--grip-value。付けなければ 20)
+            "grip_value": GRIP_VALUE,
             # 肩が上限を超えた姿勢の置き換え(計画段階で決まったもの)
             "shoulder_fix": shoulder_fix_payload,
             "teach": {
@@ -4315,6 +4331,8 @@
                            "電流の読み取りを一切せず、依頼 121 の前と同じ動きになる")
     ap_r.add_argument("--measure", default=None,
                       help="使う measure JSON を明示する(既定は直近を自動で探す)")
+    ap_r.add_argument("--grip-value", type=int, default=None,
+                      help="爪の閉じる値(既定 {}。試行 JSON の grip_value に残す。依頼 152)".format(GRIP_VALUE))
     ap_r.add_argument("--repeat", type=int, default=MEASURE_REPEAT_DEFAULT,
                       help="再生直前の検出回数(既定 {})".format(MEASURE_REPEAT_DEFAULT))
     ap_r.add_argument("--interval", type=float, default=MEASURE_INTERVAL_DEFAULT,

閉じる値25 にすると電流は約700に下がり、止まっている間は持った

16:01 に Pod を立て直し、閉じる値25 で位置5 を3本動かしました。つかんだら、すぐには進めず20秒ほど待ちます。値20 では11〜19秒で力が抜けていたので、その時間を越えて持つかを見るためです。

起動の [GRIP ] の行は、位置合わせの画面ではなくターミナルの起動の直後(4行目)に出ます。位置合わせの画面の途中に「測れない」と傾き −8° 前後の行が並んでいるのは、ブロックを置く手が写った間の値です。

位置合わせの画面。ずれは dy +0.3・dx +1.3 で OK。傾きはソフトが −1.15° 回してそろえている。右の爪の下に、位置5 のブロックの赤が少し見える
位置合わせ中のターミナル。手が写った間は「測れない」と傾き −8° 前後が出て、手を離すと OK に戻る
試行閉じて1秒の電流力が抜けた所結果
160851754
104.5秒(パッドで持ち上げを始めた所)
成功(持ち上げはパッド)
161402774
72.8秒・121.5秒・143.1秒
失敗
16174370627.5秒(止まったまま)失敗

電流は約900から約700に下がり、止まっている間に持った時間は、1本目104秒、2本目72秒、3本目27秒でした。値20 の11〜19秒より延びています。

端末:lab_start_20261111_160103.txt(閉じる値25 で位置5 の3本)

06_sec09.txt66,796字・1,153行・text
[RANGE ] 安全範囲 (学習データ ±10°) は /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_deep_even10_v1/raw_episodes から (--model deep1)
[FRAME ] 写り方の確かめの基準画像は /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes の最初のエピソードから (位置合わせと同じ trim2. 依頼 137)
[TILT  ] 上カメラの傾きのお手本 (各エピソードの 1 枚目の中央値) は /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_deep_even10_v1/raw_episodes から (安全範囲と同じ. 差だけ画像を回して AI に渡す. 依頼 144)
[GRIP  ] 爪の閉じる値は 25 (--grip-value). 締め直し r はこの値−3 とこの値を交互に送る (依頼 152)
[LAB   ] 2026-11-11 16:01:03  GPU=NVIDIA A40  episode=run_0001_20261019_194818  log=/Volumes/KIOXIA/r2r2r-data/lab/Log30  
[MODEL ] --model deep1: π0.5 base から deep_even10_v1 で新しく学習した 2999 (依頼 133. decay_steps 5000)
         PixelstoMotors/pi05-mecharm-deep-even10-lora-v1 → /workspace/ckpt/deep_v1_2999  設定 pi05_mecharm_deep_even10_lora  assets local/mecharm_redblock_box_deep_even10_v1
別のタブで開く保存

値25 でも、アームが動き出すと力が抜けた

1本目と2本目で力が抜けたのは、ゲームパッドで持ち上げを始めた直後でした。動いているときに見た様子も同じです。

持ち上げる時に緩むみたいだね。爪の掴み直しも効いていない

2本目(161402)では r を2回押し、電流は約790 と約630 に戻りました。r は値を変えて送るようになったので、サーボはまた押し始めています。ただ、次にアームを動かすと、また抜けました。1度緩んだ時点でブロックの位置がずれているので、締め直してもうまく持てません。

20本をまとめて見ると、力が抜けた所は、推論がアームへ次の目標を送った0.2〜0.4秒後か、ゲームパッドで動かしている最中がほとんどでした(grip_drop_analysis.py の出力の「送り」が小さい行と、ゲームパッドで直した本)。止まったまま抜けた本もあります(161743 の27.5秒)。

閉じる値を25 にしても動き出しで抜けるので、押す力の強さが主な原因ではなさそうです。 肩とひじのサーボが動き出す瞬間に大きな電流を使い、電源の電圧が下がって、爪のサーボが押すのをやめている、という見立てに変えました。まだ電圧は測っていないので、推測です。

mechArm 270 の電源は40W、つないでいたアダプターは24W だった

電源の電圧と電流を、台座のラベルとアダプターのラベルで確かめました。

mechArm 270-Pi の台座のラベル。電源は DC 7〜14V・40W
つないでいたアダプターのラベル。LaCie の外付けディスク用(Asian Power Devices WA-24E12)で、出力は12V・2A
電圧電流電力
台座のラベル7〜14V―40W
8.4V5A42W
つないでいたアダプター12V2A24W

アダプターは、本体が求める40W の6割しかありません。中のラズベリーパイ(Raspberry Pi)もこの電源で動いているので、アームのサーボに回る分はさらに少なくなります。午前の値20 で、止まったまま力が抜けた本があったのも、爪だけで約900の電流を使い続けていたためと考えると説明がつきます。

アームは2026年3月に届いたとき、箱に AC アダプターが入っておらず、サポートに連絡しました(LOG113)。このアダプターは、あとから別に送られてきたものです。

アームが届いた時に電源アダプタが入ってなくて、別で送られてきたんだよね。その時に送るの間違えたんだろうね。

説明書の電源と電圧も電流も違うので、送るときに取り違えた可能性があります(確かめてはいません)。8か月分の実機の記録は、すべてこの電源で取っていました。前から出ていた、関節の角度の読み取りの失敗(get_angles returned empty/invalid)も、電源が足りないことと関係しているかもしれません。電源を替えたあとに、読み取りの失敗の数も比べます。

プラグの太さを確かめて、12V・5A のアダプターを注文した

新しいアダプターは、台座のラベルの範囲(7〜14V)に入る12V で、電流に余裕のある5A(60W)にしました。電圧の8.4V で探すと、電池の充電用のアダプター(電流を一定にする作り)が多く出てくるので避けました。

プラグの太さは、説明書には外径6.5mm・内径2.0mm と書かれています。今のプラグは、ものさしで外径5mm くらいで、差し込むとしっかり止まりました。差し込み口の中の芯は細く見えます。そこで、一般的な外径5.5mm・内径2.1mm の、スイッチサイエンスの ACアダプター 12V/5A を選びました。ケーブルも、今の細い線(22AWG と読める)から、16AWG の太い線になります。

今のアダプターのプラグ。外径は約5mm で、一般的な5.5mm の太さに見える
mechArm 270-Pi の台座の電源の差し込み口。中の芯は細い
注文したスイッチサイエンスの ACアダプター 12V/5A。プラグは内径2.1mm・外径5.5mm・センタープラス

Pod を消した(153分・約238円)

午後の Pod は、3本目の結果を入れる所でスクリプトが止まったまま、2時間ほど残っていました。結果を入れてスクリプトを終え、消しています。

端末:lab_stop_20261111_183401.txt

[STOP  ] Log30 の Pod: id 1zx0vdv9xasenp  GPU=NVIDIA A40  作った時刻 2026-11-11 16:01:07
[LOG   ] serve.log を持ち帰った → /Volumes/KIOXIA/r2r2r-data/lab/Log30/serve_20261111_183402.log (27 行)
[STOP  ] Terminate を送った (18:34:11)
[STOP  ] Pod (id 1zx0vdv9xasenp) が消えたことを API で確かめた
[COST  ] 借りていた時間 153 分 4 秒 (2.55 時間) × 1時間 0.59 ドル = 約 1.51 ドル (約 238 円. 1ドル=158円)
[TUNNEL] 8000 番のトンネルは残っていません

新しい電源が届いたら、値25 で位置5 を3本動かして確かめる

位置5 のお手本6本の撮影と、学習のやり直しは、電源で確かめたあとにします。足りない電源のまま撮ると、持ち上げで緩みかけたお手本が混ざるおそれがあるためです。

  1. アダプターを差し替えて、ラズベリーパイが立ち上がることを確かめる
  2. 閉じる値25 で位置5 を3本。つかんで20秒待ち、持ち上げで力が抜けないかを grip_drop_analysis.py で見る
  3. 抜けなければ、電源が原因だったと決め、同じ値25 で位置5 のお手本6本を撮る(DEEP_DEMOS.md の5節)
  4. deep_even10_v2 を作って、学習し直す

サムネイルの作り方

フィジカルAI研究室のサムネイルは、その回の実データを線で描きます。この回は、爪の電流を6本重ねました。赤は閉じて押している間、青は指令なしに0付近へ落ちたあとです。

lab_thumb.py の差分(LOG487 の1回分と、電流を描く drop_draw を足した)

diff --git a/tools/lab_thumbs/lab_thumb.py b/tools/lab_thumbs/lab_thumb.py
index ce418e8..1611730 100644
--- a/tools/lab_thumbs/lab_thumb.py
+++ b/tools/lab_thumbs/lab_thumb.py
@@ -332,6 +332,28 @@ def time_draw(runs, t_lo, t_hi, v_lo, v_hi, w=4):
     return f
 
 
+def drop_draw(runs, t_hi, thresh=300, w=4):
+    """爪の電流を何本か重ねる(横は閉じた時刻を0にした秒、縦は電流)。つかんで押している間(しきい値を超えた所)は赤、
+    力が抜けて0付近に落ちたあとは主役の青。本ごとに縦に少しずらして重なりを分ける"""
+    def f(box, pal):
+        x0, y0, x1, y1 = box
+        n = len(runs); band = (y1 - y0) / (n + 0.4)
+        out = []
+        for i, r in enumerate(runs):
+            base_y = y0 + band * (i + 1.2)
+            X = lambda t: x0 + (t + 2) / (t_hi + 2) * (x1 - x0)
+            Y = lambda v: base_y - max(-60, min(1000, v)) / 1000 * band * 0.8
+            pts = [(X(t), Y(v), v > thresh) for t, v in r if t <= t_hi]
+            seg, cur = [pts[0][:2]], pts[0][2]
+            for x, y, on in pts[1:]:
+                seg.append((x, y))
+                if on != cur:
+                    out.append(poly(seg, RED if cur else pal['m'][0], '1', w=w)); seg = [(x, y)]; cur = on
+            out.append(poly(seg, RED if cur else pal['m'][0], '1', w=w))
+        return '\n'.join(out)
+    return f
+
+
 def both(*fs):
     return lambda box, pal: '\n'.join(f(box, pal) for f in fs)
 
@@ -339,7 +361,7 @@ def both(*fs):
 # ---------- 記事ごとの指定 ----------
 # 一覧の並び(LOG番号の大きい順)と構図。隣どうしで同じ構図にしない
 ORDER = """
-486 paper   484 split   480 dark    479 split   463 dark    461 paper   460 split   450 dark    446 paper   436 dark    422 photo_l 419 photo_r 417 dark
+487 dark    486 paper   484 split   480 dark    479 split   463 dark    461 paper   460 split   450 dark    446 paper   436 dark    422 photo_l 419 photo_r 417 dark
 407 split   403 dark    401 paper   363 split   361 paper   358 dark    355 paper   352 split
 349 dark    348 paper   345 split   341 dark    337 split   327 paper   326 dark    277 paper
 234 dark    225 paper
@@ -349,6 +371,10 @@ ORDER = """
 def build(log, d, img_dir):
     n = int(log[3:])
     # GPU ラックの写真(public/site/gbr/reverse.webp)はここでは使わない(2026-11-08 エイイチ「GPUラックの写真は作っちゃダメ」)
+    if n == 487:
+        # 爪の電流(閉じた時刻を0秒)を6本重ねる。赤=閉じて押している間、青=指令なしに0付近へ落ちたあと。
+        # 上の3本は閉じる値20(11〜19秒で落ちる)、下の3本は値25と、落ちなかった1本(100659)。電源が足りないとみた回
+        return dark('GRIPPER CURRENT', '24 W', drop_draw(d['LOG487'], 150, w=4.5))
     if n == 486:
         # 位置2 で π0.5 が出した行き先(log.jsonl の actions を、最初の人の操作の手前までつないだもの)のひじ j2。
         # 薄い線は午前の4回(上カメラが右下がり約 +0.7°。位置1 寄りの -10° 前後で平らになる)、青は夜の4回(右上がり約 -0.8〜-1.0° に直したあと。