フィジカルAI研究室を作る Log#14 | π0.5 を回数で測ったら、苦手な置き場所が見えた
この記事の素材(コード・ログ・データ 7ファイル・まとめてダウンロードあり)arrow_downwardPhysical Intelligence の π0.5 で動かす小型ロボットアーム mechArm 270 は、実機で、3か所に5回ずつ置いた赤いブロックを15回中9回、白い箱に入れました。置き場所ごとに分けると、アームの左前の位置C は5回中5回、手前の位置E は5回中3回、アームの左で腕を伸ばしきる位置D は5回中1回でした。
π0.5(パイレイテンゴ)は、米国の Physical Intelligence 社が公開しているロボット用の AI のモデルです。上から見たカメラの画像と6つの関節の角度を受け取り、次の1秒ぶんの関節の角度を返します。人が手でアームを動かして教えた19回の動き(お手本)を見せて学習させてあり、学習も推論(AI に答えを出させる計算)も、Runpod で時間単位に借りた GPU で動かしています。
前の回(LOG363)では、お手本を録った置き場所のうち3か所で、それぞれ1回ずつ箱に入るところまで確かめました。ただ、1回入っただけでは、その置き場所でどのくらいの割合で入るのかは分かりません。そこで、モデルもプログラムの設定も変えずに、3か所で5回ずつ数えました。
数えてみると、置き場所によってはっきり差が出ました。腕を伸ばしきる位置D では、AI が送った目標の姿勢はお手本とほぼ同じなのに、ブロックを爪の先でしかつかめず、持ち上げた瞬間に落とす回が続きました。 位置E の失敗は2回とも、爪がブロックの奥側に下りてつかみ損ねたものです。位置C は5回とも入りました。
もう1つ変えたのは、学習済みのモデル(6.3GB)の置き場所です。前の回までは、GPU を借りるたびに自宅の Mac から送り直していて、借りた時間の半分(約30分)がその待ちでした。モデルを Hugging Face(AI のモデルを置いて配るサービス)の非公開の置き場に一度だけ上げておき、借りた GPU のほうから取りに行く形にしたところ、取ってくるのにかかった時間は13秒でした。
やったことの全体は次のとおりです。
| やったこと | なぜ | 結果 |
|---|---|---|
学習済みのモデルを Hugging Face の非公開リポジトリに上げた | GPU を借りるたびに Mac から 6.3GB を送る待ち(約30分)をなくすため | Mac から上げるのは1回だけで6分5秒。借りた GPU で取ってくるのは13.19秒 |
Runpod で A40 を借り、モデルを取ってきてサーバーを起動した | AI の答えを返す計算をするため | モデルの読み込み 5.41 秒。休憩を入れて約4時間38分、2.87ドル(約453円) |
位置C・D・E に5回ずつブロックを置き、AI に動かさせた | 1回入っただけでは分からない、置き場所ごとの入る割合を数えるため | C 5/5・D 1/5・E 3/5。合わせて15回中9回 |
失敗した回を、ログと横からの動画で見た | どこで、なぜ入らなかったかを分けるため | D は爪の先でつかんで持ち上げた瞬間に落ちる回が2回、つかみ損ねが2回。E はつかみ損ねが2回 |
つかむところの関節の角度を、お手本と比べた | AI の狙いがお手本からずれていないかを見るため | 爪を閉じる直前の目標は、D でもお手本とほぼ同じ(肩 j1 で 62.2〜63.5°、お手本は 62.3〜62.5°) |

GPU を買うか借りるかの判断は、Runpod で実際に借りて学習させた費用をもとに、別のページにまとめています。
導入比較ガイドロボットAIの学習用GPU、買うか借りるか実際に借りて学習させた費用と、損益分岐の計算機で決められますarrow_forwardこの回の作業も、Claude(手順と分析を一緒に組み立てた AI)と進めました。手順・分析・記録の集計は Claude が行い、アームの操作と、目で見た判断・止める判断はこちらで行っています。アームを動かすプログラムは変えていません。ここから下は、使ったコマンド・コード・出力を全量で載せた作業ログです。ログの中の Pod の IP アドレスとポート番号は、<POD_IP> と <SSH_PORT> に置き換えています。Hugging Face の鍵(アクセストークン)は、どこにも載せていません。費用の円は 1ドル=158円 で計算しています。結果と効果の数字は、どれも記録から数えた値です。見込みのものは、見込みと書いています。
作業ログ ― 学習済みのモデルを Hugging Face の非公開リポジトリに置いた
前の回までは、Pod(Runpod で時間単位に借りる GPU つきの計算機)を借りるたびに、Mac の外付け SSD(KIOXIA)にある学習済みのモデル(checkpoints/pi05_mecharm_trim_lora_v1/3999/、32ファイル)を scp で送っていました。家の回線では1秒あたり約 3.9MB で、送り終わるまで約30分かかります。Pod は借りている間ずっと料金がかかるので、借りた時間の約半分が、この待ちに払っていた分でした。
Hugging Face は、AI のモデルとデータを置いて配るサービス
Hugging Face(ハギングフェイス)は、米国の Hugging Face 社が運営している、AI のモデルやデータセットを置いて配るためのサービスです。プログラムのコードを置く GitHub の、AI のモデル版と考えると近いです。世界中の会社や研究者が、作ったモデルをここに置いて公開しています。ロボットの学習の道具 LeRobot も Hugging Face が作っていて、ロボットのお手本のデータもここで多く配られています。
この記事で使う言葉は、次のとおりです。
| 言葉 | 意味 |
|---|---|
| リポジトリ | モデル1つ分の置き場。この記事では PixelstoMotors/pi05-mecharm-trim-lora-v1 という名前で1つ作った |
| 公開・非公開 | 公開はだれでも取ってこられる。非公開は持ち主と、持ち主が鍵を渡した相手だけが取ってこられる。無料のアカウントでも、非公開で 100GB まで置ける(Hugging Face の容量の決まり) |
| 鍵(アクセストークン) | 非公開のリポジトリを読み書きするための、 hf_ で始まる37文字の文字列。人に見られると、その鍵でリポジトリを操作されてしまう |
| hf | Hugging Face を操作するコマンド。 pip install huggingface_hub で入る。上げるのは hf upload、取ってくるのは hf download |
| Xet | Hugging Face の、大きなファイルの置き方。ファイルを細かく分け、前に送った部分と同じ中身は送り直さない(Hugging Face の紹介記事) |
このプロジェクトでの使い方は、学習済みのモデルを Mac から1回だけ上げておき、借りた GPU(Pod)のほうから取りに行く、というものです。GPU を借りるデータセンターは毎回変わることがありますが、Hugging Face はどこからでも同じ手順で取ってこられます。
置き場所の候補は3つあった
置き場所の候補は3つありました。
| 置き場所 | 月の費用 | 借りられる GPU |
|---|---|---|
Hugging Face の非公開リポジトリ | 0円(無料のアカウントで非公開 100GB まで) | どのデータセンターの、どの GPU でも |
1GB あたり月 0.07ドル(Runpod の料金)。約30GB で月約330円 | 置いたデータセンターにある GPU だけ | |
| 料金は未公開(試用版) | どのデータセンターでも |
Hugging Face にしました。月の費用がかからず、借りる GPU の種類も場所も選べるからです。置き場所を「公開」に切り替えれば、ほかの人も同じモデルを取ってきて試せます。公開するかどうかは、まだ決めていません。
置き場所を増やすので、先にプロジェクトの決まり(MASTER)の保存先の表に1行足しました。
| フィジカルAI研究室の学習済みモデル(Pod が取りに行く写し。原本は KIOXIA の `checkpoints/`) | Hugging Face の非公開リポジトリ(モデルごとに1つ。名前は checkpoints/ のフォルダ名に合わせる。例 `pi05-mecharm-trim-lora-v1`) |
- 2026-10-29: 保存先テーブルにフィジカルAI研究室の学習済みモデルの行を追加(Hugging Face の非公開リポジトリ。原本は KIOXIA の checkpoints/ のまま)。Pod を借りるたびに Mac からモデル 6.3GB を送っていて、借りた時間の約半分がその待ちだったため。
Hugging Face のアカウントと鍵を2つ作った
アカウントの名前は、GitHub と同じ PixelstoMotors にしました。鍵(アクセストークン)は2つ作っています。Mac から上げる用の書き込める鍵(mac-upload)と、Pod で取ってくる用の読むだけの鍵(runpod-read)です。Pod は借りている計算機なので、書き込める鍵は置かないようにしました。
mac-upload は、作るときに種類が Fine-grained(権限を1つずつ選ぶ種類)になりました。権限の画面で、Repositories の欄の次の2つにチェックが入っていることを確かめてから保存しています。
- Create repos and read/write/manage repos created by this token
- Write contents/settings of your repos
Mac では hf auth login を使いました。新しい版の huggingface_hub(2.3.0)では、鍵を貼る代わりにブラウザでログインする形になっていて、表示されたコードをブラウザで入力して許可しています。
Mac でログインしたときの出力
Installing collected packages: pyyaml, idna, httpcore2, hf-xet, fsspec, filelock, click, httpx2, huggingface_hub
Attempting uninstall: idna
Found existing installation: idna 3.11
Uninstalling idna-3.11:
Successfully uninstalled idna-3.11
Attempting uninstall: click
Found existing installation: click 8.4.1
Uninstalling click-8.4.1:
Successfully uninstalled click-8.4.1
Successfully installed click-8.5.0 filelock-4.2.4 fsspec-2026.9.0 hf-xet-1.7.1 httpcore2-2.16.0 httpx2-2.16.0 huggingface_hub-2.3.0 idna-3.20 pyyaml-6.0.3
Hint: The `hf-cli` skill is not installed. Run `hf skills add -g` to teach your AI agents how to use the `hf` CLI.
? How would you like to log in? Log in with your browser
Open this URL in your browser:
https://hf.co/oauth/device
And enter the code: AGAM-FAEF
Waiting for authorization..
And enter the code: AGAM-FAEF
Waiting for authorization.......................
Token is valid.
The token `oauth-PixelstoMotors` has been saved to /Users/shimazueiichi/.cache/huggingface/stored_tokens
Your token has been saved to /Users/shimazueiichi/.cache/huggingface/token
Login successful.
The current active token is: `oauth-PixelstoMotors`
Note: This token will be refreshed automatically when it expires.
(base) shimazueiichi@shimadzueiichinoMacBook-Pro ~ %
表示されたコード(AGAM-FAEF)は、ブラウザでの許可が済んだ時点で使えなくなる、1回きりのものです。
Mac からモデルを1回だけ上げた(6分5秒)
上げるときに打ったコマンドです。
hf auth whoami
hf repo create PixelstoMotors/pi05-mecharm-trim-lora-v1 --repo-type model --private
time hf upload PixelstoMotors/pi05-mecharm-trim-lora-v1 /Volumes/KIOXIA/r2r2r-data/checkpoints/pi05_mecharm_trim_lora_v1/3999 . --repo-type model
hf upload-large-folder(途中で切れても続きから上げられる命令)は使っていません。この命令は、上げる元のフォルダの中に作業用のファイルを作るので、KIOXIA の原本のフォルダに書き込んでしまうからです。測定データとモデルは、上書き・移動・削除をしない決まりにしています。
Run 'hf --help' for full details. Did you mean 'repos'?
Found 32 files to upload
Preparing ████████████████████ 32 / 32 ✓
Uploading ████████████████████ 20 / 20 files 1.79GB · 67.6kB/s ✓
Validating ████████████████████ 100%
Committing ████████████████████ 32 / 32 ✓
✓ Uploaded
url: https://huggingface.co/PixelstoMotors/pi05-mecharm-trim-lora-v1/commit/8ce882b68e8d5383c857c176ec26c0dd7c838b11
hf upload PixelstoMotors/pi05-mecharm-trim-lora-v1 . --repo-type model 16.69s user 11.09s system 7% cpu 6:05.42 total
(base) shimazueiichi@shimadzueiichinoMacBook-Pro ~ %
上げ終わるまで 6分5秒 でした。見込んでいた30分より短かったのは、回線を通ったのが 6.3GB のうち 1.79GB だけだったからです。Hugging Face の置き方(Xet)は、ファイルを細かく分け、同じ中身の部分を1回しか送りません。
出力の最初の行 Did you mean 'repos'? は、hf repo create がこの版では hf repos create に名前が変わっていて、リポジトリを作る前にエラーで止まっていたことを示しています。そのあとの hf upload が、リポジトリがないので自動で作っていました。
自動で作られたリポジトリは公開になっていた(約9分)
hf upload が自動で作ったリポジトリは、公開の設定でした。外から Hugging Face の API に問い合わせて確かめた結果です。
$ curl -sS -m 20 https://huggingface.co/api/models/PixelstoMotors/pi05-mecharm-trim-lora-v1 | head -c 600
{"_id":"6ae2abc1e413a206073b106d","id":"PixelstoMotors/pi05-mecharm-trim-lora-v1","private":false,"tags":["region:us"],"downloads":0,"likes":0,"modelId":"PixelstoMotors/pi05-mecharm-trim-lora-v1","author":"PixelstoMotors","sha":"8ce882b68e8d5383c857c176ec26c0dd7c838b11","lastModified":"2026-10-29T02:19:24.000Z","gated":false,"disabled":false,"config":{},"siblings":[{"rfilename":".gitattributes"},{"rfilename":"_CHECKPOINT_METADATA"},{"rfilename":"assets/local/mecharm_redblock_box_teach_v1_trim2/norm_stats.json"},{"rfilename":"params/_METADATA"},{"rfilename":"params/_sharding"},{"rfilename":"par
リポジトリの Settings の Model Access control で、Public を Private に切り替えました。切り替えのときに確認の画面は出ませんでした。切り替えたあとに同じ問い合わせをすると、見る権限がないという応答(401)に変わっています。
$ curl -sS -m 20 -o /dev/null -w '%{http_code}\n' https://huggingface.co/api/models/PixelstoMotors/pi05-mecharm-trim-lora-v1
401
公開になっていたのは、上げ終わった 11:19 から切り替えた 11:28 までの約9分です。その間のダウンロード数は 0 でした(Settings の Total downloads)。次に別のモデルを置くときは、先に hf repos create … --private で非公開のリポジトリを作ってから上げます。
上げたファイルは、32ファイルとも原本と同じ大きさだった
Mac の KIOXIA にある原本と、Hugging Face に上がったファイルの一覧を、1ファイルずつ大きさで比べました。原本の一覧は Mac につないだ作業環境で、上がった側の一覧は Hugging Face の API で出しています(このときはまだ公開だったので、鍵なしで読めました)。
local files sum 6335855217 32
426 _CHECKPOINT_METADATA
1766 assets/local/mecharm_redblock_box_teach_v1_trim2/norm_stats.json
33052 params/_METADATA
17773 params/_sharding
12891 params/array_metadatas/process_0
2861 params/d/5135b7cda491aae169dd0001cb558427
118 params/manifest.ocdbt
29598904 params/ocdbt.process_0/d/015b3153da5204ea859de42455bbb66f
1258 params/ocdbt.process_0/d/064d53822e61a8449ad46a1bf1cbb357
945626246 params/ocdbt.process_0/d/0f74cbd20e735395c7d7995803245d70
235537011 params/ocdbt.process_0/d/1e373b40e2d78b11f1a46c1c3451e63f
945879588 params/ocdbt.process_0/d/2105d39052b427b1c8a576587d2ea70e
497034603 params/ocdbt.process_0/d/2701bbdc45d3cd25d60aface67c14298
497190748 params/ocdbt.process_0/d/2a99d4f0a467bcf84d77d1fbafdfdf5d
234403 params/ocdbt.process_0/d/334da8956d4358be340387e33c84dffc
132946559 params/ocdbt.process_0/d/34bae0b3baaf174e9041ecf109784d1d
58980373 params/ocdbt.process_0/d/37a68386c19e90ee7de121f1b66e0c6a
1107 params/ocdbt.process_0/d/7441dbd0e616dc943ff1ecd59ffda518
17463306 params/ocdbt.process_0/d/74cf06263b61569cf71b1e85c27b0af2
14719239 params/ocdbt.process_0/d/81fc104abd9310a7a173df6e58f01ac2
41477813 params/ocdbt.process_0/d/875b5c7933edbbcbe9aa30f0478ff975
828933461 params/ocdbt.process_0/d/89a9e8779f70eea2f5ddd4ea3486e0cf
118290936 params/ocdbt.process_0/d/956498ee1dbc961c03bb714835709f7f
90308271 params/ocdbt.process_0/d/a55fd069f835d8b221ea9a562b8e952d
236602677 params/ocdbt.process_0/d/b215c8aff42c77082723a0f0ea72bda5
945630533 params/ocdbt.process_0/d/b64f43979583f0ca922ba0a109be8c9b
488768410 params/ocdbt.process_0/d/c8502eef036907a2a72bd6c4ab846e29
1376 params/ocdbt.process_0/d/c9d1b9901f0e9ecb4a8a8a5c1521bca1
151449744 params/ocdbt.process_0/d/dc471644a511839d37da75e3b5338edf
59109038 params/ocdbt.process_0/d/e7b4ef0b9d72d9cd35c5b7487098b0c7
213 params/ocdbt.process_0/d/f441d5a43fd08f99c163955edd12e309
513 params/ocdbt.process_0/manifest.ocdbt
remote files sum 6335858616 33
3399 .gitattributes
426 _CHECKPOINT_METADATA
1766 assets/local/mecharm_redblock_box_teach_v1_trim2/norm_stats.json
33052 params/_METADATA
17773 params/_sharding
12891 params/array_metadatas/process_0
2861 params/d/5135b7cda491aae169dd0001cb558427
118 params/manifest.ocdbt
29598904 params/ocdbt.process_0/d/015b3153da5204ea859de42455bbb66f
1258 params/ocdbt.process_0/d/064d53822e61a8449ad46a1bf1cbb357
945626246 params/ocdbt.process_0/d/0f74cbd20e735395c7d7995803245d70
235537011 params/ocdbt.process_0/d/1e373b40e2d78b11f1a46c1c3451e63f
945879588 params/ocdbt.process_0/d/2105d39052b427b1c8a576587d2ea70e
497034603 params/ocdbt.process_0/d/2701bbdc45d3cd25d60aface67c14298
497190748 params/ocdbt.process_0/d/2a99d4f0a467bcf84d77d1fbafdfdf5d
234403 params/ocdbt.process_0/d/334da8956d4358be340387e33c84dffc
132946559 params/ocdbt.process_0/d/34bae0b3baaf174e9041ecf109784d1d
58980373 params/ocdbt.process_0/d/37a68386c19e90ee7de121f1b66e0c6a
1107 params/ocdbt.process_0/d/7441dbd0e616dc943ff1ecd59ffda518
17463306 params/ocdbt.process_0/d/74cf06263b61569cf71b1e85c27b0af2
14719239 params/ocdbt.process_0/d/81fc104abd9310a7a173df6e58f01ac2
41477813 params/ocdbt.process_0/d/875b5c7933edbbcbe9aa30f0478ff975
828933461 params/ocdbt.process_0/d/89a9e8779f70eea2f5ddd4ea3486e0cf
118290936 params/ocdbt.process_0/d/956498ee1dbc961c03bb714835709f7f
90308271 params/ocdbt.process_0/d/a55fd069f835d8b221ea9a562b8e952d
236602677 params/ocdbt.process_0/d/b215c8aff42c77082723a0f0ea72bda5
945630533 params/ocdbt.process_0/d/b64f43979583f0ca922ba0a109be8c9b
488768410 params/ocdbt.process_0/d/c8502eef036907a2a72bd6c4ab846e29
1376 params/ocdbt.process_0/d/c9d1b9901f0e9ecb4a8a8a5c1521bca1
151449744 params/ocdbt.process_0/d/dc471644a511839d37da75e3b5338edf
59109038 params/ocdbt.process_0/d/e7b4ef0b9d72d9cd35c5b7487098b0c7
213 params/ocdbt.process_0/d/f441d5a43fd08f99c163955edd12e309
513 params/ocdbt.process_0/manifest.ocdbt
32ファイルとも大きさが一致しています。Hugging Face 側には、自動で作られる .gitattributes(3,399 バイト)が1つ増えています。前の回の記事に書いた 6,340,573,809 バイトは du -sb の値で、フォルダそのものの大きさも数えに入っています。ファイルの中身だけを足すと 6,335,855,217 バイトです。
A40 の Pod を借り、モデルを Hugging Face から13秒で取ってきた
この記事のコード・ログ・データは、1ファイルずつ下に置いています。全文はリンク先にあります。
ファイルの一覧(7本)
01_serve.log.txt ― サーバーのログ serve.log(KIOXIA の lab/Log14/serve.log)・5,731字
02_run_summary.py.txt ― 回ごとの1行の表を作るスクリプト run_summary.py・3,379字
03_out_run_summary.txt ― run_summary.py の出力 out_run_summary.txt・3,751字
04_out_approach_vs_demo.txt ― approach_vs_demo.py の出力 out_approach_vs_demo.txt・25,457字
05_out_run_chunk_tables.txt ― run_chunk_tables.py の出力 out_run_chunk_tables.txt・51,635字
06_terminal_c_d.txt ― ターミナルの出力 terminal_c_d.txt(11:39〜12:57・位置C と位置D)・207,050字
07_terminal_e.txt ― ターミナルの出力 terminal_e.txt(14:49〜15:12・位置E)・87,512字
Pod は前の回と同じく、Runpod の A40(GPU のメモリ 48GB)を1枚、テンプレートは Runpod Pytorch 2.8.0、コンテナのディスクは 200GB で借りました。料金は1時間 0.62ドル(約98円)です。最初に Deploy Pod を押したときは「This machine does not have the resources to deploy your pod. Please try a different machine」と出て借りられず、押し直すと借りられました。選んだ機械が、押すまでの間に別の人に借りられていたと見ています(見込み)。LOG355 でディスクを小さくしても同じ表示が変わらなかったので、ディスクの大きさはそのままにしました。
Mac から Pod へ送ったのは、アームを動かすスクリプト一式(pi05/)と、学習の設定を足すスクリプト(add_trim_config.py)だけです。
P=<SSH_PORT>; IP=<POD_IP>; K=~/.ssh/id_ed25519
ssh -p $P -i $K root@$IP "mkdir -p /workspace/r2r2r /workspace/logs /workspace/ckpt"
scp -P $P -i $K -r ~/r2r2r-scripts/pi05 root@$IP:/workspace/r2r2r/
scp -P $P -i $K /Volumes/KIOXIA/r2r2r-data/lab/Log11/pod/add_trim_config.py root@$IP:/workspace/r2r2r/
run_policy_client.py 100% 44KB 118.0KB/s 00:00
check_dataset.py 100% 14KB 74.7KB/s 00:00
build_demo_episodes.py.bak_pre_LOG352_2026101 100% 11KB 57.8KB/s 00:00
RUNPOD_TRAIN.md 100% 15KB 73.9KB/s 00:00
install_addon.py 100% 4786 25.0KB/s 00:00
mecharm_policy.py 100% 2321 12.1KB/s 00:00
eval_policy_offline.cpython-312.pyc 100% 15KB 81.4KB/s 00:00
build_demo_episodes.cpython-310.pyc 100% 11KB 40.2KB/s 00:00
build_demo_episodes.cpython-312.pyc 100% 29KB 152.9KB/s 00:00
check_dataset.cpython-312.pyc 100% 25KB 96.5KB/s 00:00
policy_ws.cpython-312.pyc 100% 4580 23.8KB/s 00:00
camera_align.cpython-312.pyc 100% 18KB 70.5KB/s 00:00
run_policy_client.cpython-312.pyc 100% 49KB 258.1KB/s 00:00
build_demo_episodes.py 100% 24KB 127.9KB/s 00:00
policy_ws.py 100% 2778 14.3KB/s 00:00
camera_align.py 100% 13KB 69.8KB/s 00:00
add_trim_config.py 100% 1966 10.2KB/s 00:00
(base) shimazueiichi@shimadzueiichinoMacBook-Pro ~ %
Pod では hf のコマンドが入らず、鍵の貼り付けも1回まちがえた
Pod に入って tmux(接続が切れても作業が続く画面)を開き、pip install -U huggingface_hub を打つと、そのあとの hf download が hf: command not found で止まりました。このテンプレートの Ubuntu 24.04 は、何も付けないと pip でのインストールを断ることがあります。--break-system-packages を付けて入れ直しました。
root@f2787ffca4f4:/# time hf download PixelstoMotors/pi05-mecharm-trim-lora-v1 --local-dir /workspace/ckpt/3999
find /workspace/ckpt/3999 -type f -not -path '*/.cache/*' -printf '%s\n' | awk '{s+=$1} END{print s, NR}'
-bash: hf: command not found
real 0m0.001s
user 0m0.000s
sys 0m0.001s
find: ‘/workspace/ckpt/3999’: No such file or directory
0
root@f2787ffca4f4:/#
pip install -U --break-system-packages huggingface_hub
hash -r
which hf
Downloading truststore-0.10.5-py3-none-any.whl.metadata (4.5 kB)
Requirement already satisfied: h11>=0.16 in /usr/local/lib/python3.12/dist-packages (from httpcore2==2.16.0->httpx2<3,>=2.0.0->huggingface_hub) (0.16.0)
Downloading huggingface_hub-2.3.0-py3-none-any.whl (855 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 855.2/855.2 kB 16.1 MB/s 0:00:00
Downloading click-8.5.0-py3-none-any.whl (125 kB)
Downloading hf_xet-1.7.1-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (4.2 MB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4.2/4.2 MB 80.7 MB/s 0:00:00
Downloading httpx2-2.16.0-py3-none-any.whl (97 kB)
Downloading httpcore2-2.16.0-py3-none-any.whl (85 kB)
Downloading tqdm-4.70.1-py3-none-any.whl (80 kB)
Downloading truststore-0.10.5-py3-none-any.whl (19 kB)
Installing collected packages: truststore, tqdm, hf-xet, click, httpcore2, httpx2, huggingface_hub
Successfully installed click-8.5.0 hf-xet-1.7.1 httpcore2-2.16.0 httpx2-2.16.0 huggingface_hub-2.3.0 tqdm-4.70.1 truststore-0.10.5
/usr/local/bin/hf
root@f2787ffca4f4:/#
Pod では、鍵を read -s HF_TOKEN && export HF_TOKEN で入れています。read -s は打った文字を画面に出さず、コマンドの履歴にも残しません。1回目は、鍵とは違う文字列を貼り付けていました(Hugging Face の鍵は hf_ で始まる37文字ですが、50文字ありました)。文字数だけを出して確かめ、貼り直しています。
[ -n "$HF_TOKEN" ] && echo 鍵あり || echo 鍵なし
鍵なし
root@f2787ffca4f4:/# read -s HF_TOKEN && export HF_TOKEN
root@f2787ffca4f4:/# time hf download PixelstoMotors/pi05-mecharm-trim-lora-v1 --local-dir /workspace/ckpt/3999
find /workspace/ckpt/3999 -type f -not -path '*/.cache/*' -printf '%s\n' | awk '{s+=$1} END{print s, NR}'
Hint: The `hf-cli` skill is not installed. Run `hf skills add -g` to teach your AI agents how to use the `hf` CLI.
Error: Model 'PixelstoMotors/pi05-mecharm-trim-lora-v1' not found.
If the repo is private, make sure you are authenticated and your token has the required permissions.
If the repo does not exist, create it with: hf repos create PixelstoMotors/pi05-mecharm-trim-lora-v1
Hint: set HF_DEBUG=1 as environment variable for full traceback.
real 0m0.540s
user 0m0.383s
sys 0m0.057s
find: ‘/workspace/ckpt/3999’: No such file or directory
0
root@f2787ffca4f4:/#
echo ${#HF_TOKEN}
hf auth whoami
hf auth whoami
50
Error: Invalid user token. The token from HF_TOKEN environment variable is invalid. Note that HF_TOKEN takes precedence over `hf auth login`.
Hint: set HF_DEBUG=1 as environment variable for full traceback.
root@f2787ffca4f4:/# echo ${#HF_TOKEN}
hf auth whoami
50
Error: Invalid user token. The token from HF_TOKEN environment variable is invalid. Note that HF_TOKEN takes precedence over `hf auth login`.
Hint: set HF_DEBUG=1 as environm
hf auth whoami
37
✓ Logged in
user: PixelstoMotors
root@f2787ffca4f4:/#
Pod でモデルを取ってくるのにかかった時間は13.19秒だった
user: PixelstoMotors
root@f2787ffca4f4:/# time hf download PixelstoMotors/pi05-mecharm-trim-lora-v1 --local-dir /workspace/ckpt/3999
find /workspace/ckpt/3999 -type f -not -path '*/.cache/*' -printf '%s\n' | awk '{s+=$1} END{print s, NR}'
Fetching 33 files: 100%|███████████████████████| 33/33 [00:12<00:00, 2.61it/s]
Download complete: ████████████████████████████████████████| 6.34GB, 57.6MB/s ✓
Downloadedion complete: 100%|████████████████████| 6.34GB / 6.34GB, 539MB/s
path: /workspace/ckpt/3999
Download complete: ████████████████████████████████████████| 6.34GB, 57.6MB/s
Reconstruction complete: 100%|████████████████████| 6.34GB / 6.34GB, 539MB/s
real 0m13.190s
user 0m11.067s
sys 0m19.014s
6335858616 33
root@f2787ffca4f4:/#
取ってきたファイルは33個・合わせて 6,335,858,616 バイトで、Hugging Face 側の一覧と同じです。
- ねらい:Pod を借りている時間の約半分を占めていた、モデルを送る待ちをなくす
- 変わったこと:Mac から Pod へ
scpで送る形から、Hugging Face の非公開リポジトリに1回だけ上げ、Pod から取りに行く形にした - 見込める効果:Pod にモデルを置くまでの時間が、約30分(LOG363)から 13.19 秒になった(どちらも記録の値)。A40 の料金で、1回借りるごとに約0.3ドル(約49円)の待ちがなくなる。借りるデータセンターや GPU の種類にも縛られない
そのあとの openpi(π0.5 を動かすための公開コード)の取り直しとサーバーの起動は、前の回と同じコマンドです。コミット 215abfb の版を使っています。
cd /workspace
git clone --recurse-submodules https://github.com/Physical-Intelligence/openpi.git
cd openpi && git checkout 215abfb
curl -LsSf https://astral.sh/uv/install.sh | sh
source $HOME/.local/bin/env
GIT_LFS_SKIP_SMUDGE=1 uv sync
+ typeguard==4.4.2
+ typing-extensions==4.13.2
+ typing-inspect==0.9.0
+ typing-inspection==0.4.1
+ tyro==0.9.22
+ tzdata==2025.2
+ urllib3==2.4.0
+ virtualenv==20.31.2
+ wadler-lindig==0.1.6
+ wandb==0.19.11
+ wcwidth==0.2.13
+ websockets==15.0.1
+ werkzeug==3.1.3
+ widgetsnbextension==4.0.14
+ wrapt==1.14.1
+ xxhash==3.5.0
+ yarl==1.20.0
+ zarr==3.0.8
+ zipp==3.22.0
root@f2787ffca4f4:/workspace/openpi#
python3 /workspace/r2r2r/pi05/openpi_addon/install_addon.py /workspace/openpi
python3 /workspace/r2r2r/add_trim_config.py /workspace/openpi
mkdir -p assets/pi05_mecharm_trim_lora/local && cp -r /workspace/ckpt/3999/assets/local/mecharm_redblock_box_teach_v1_trim2 assets/pi05_mecharm_trim_lora/local/
uv run scripts/serve_policy.py policy:checkpoint --policy.config=pi05_mecharm_trim_lora --policy.dir=/workspace/ckpt/3999 2>&1 | tee /workspace/logs/serve.log
Mac からは、Pod の 8000 番を手元の 8000 番へつなぐ SSH のトンネルを張りました。アームを動かすクライアントは ws://localhost:8000 に問い合わせます。
ssh -N -L 8000:localhost:8000 -p <SSH_PORT> -i ~/.ssh/id_ed25519 root@<POD_IP>
サーバーのログ serve.log(KIOXIA の lab/Log14/serve.log)
モデルの読み込みは 5.41 秒でした。Connection from … opened が、クライアントを1回起動するごとに1組出ています。
INFO:root:Loading model...
INFO:2026-10-29 02:51:41,645:jax._src.xla_bridge:925: Unable to initialize backend 'rocm': module 'jaxlib.xla_extension' has no attribute 'GpuAllocatorConfig'
INFO:jax._src.xla_bridge:Unable to initialize backend 'rocm': module 'jaxlib.xla_extension' has no attribute 'GpuAllocatorConfig'
INFO:2026-10-29 02:51:41,648:jax._src.xla_bridge:925: Unable to initialize backend 'tpu': INTERNAL: Failed to open libtpu.so: libtpu.so: cannot open shared object file: No such file or directory
INFO:jax._src.xla_bridge:Unable to initialize backend 'tpu': INTERNAL: Failed to open libtpu.so: libtpu.so: cannot open shared object file: No such file or directory
INFO:absl:orbax-checkpoint version: 0.11.13
INFO:absl:Created BasePyTreeCheckpointHandler: use_ocdbt=True, use_zarr3=False, pytree_metadata_options=PyTreeMetadataOptions(support_rich_types=False), array_metadata_store=<orbax.checkpoint._src.metadata.array_metadata_store.Store object at 0x7f981f8068d0>
INFO:absl:Restoring checkpoint from /workspace/ckpt/3999/params.位置C:5回とも箱に入った
アームは、電源を入れてデーモン(アームの中の Raspberry Pi で、角度の指令を受け取って関節へ送るプログラム。5555番で待ち受ける)を起動し、HOME の姿勢(全関節がほぼ 0°)に戻してから始めました。手首 j4 は −0.17° で、前の回の最後に起きた手首のずれは残っていません。
AI は、1回問い合わせるごとに、次の1秒分の関節の角度を10ステップぶん返します。この1回分の答えを、この記事ではチャンクと呼びます。チャンク04 なら、5回目の問い合わせの答えです(00 から数えます)。
1回ごとの流れは次のとおりです。爪を開き、上のカメラの映像にお手本の最初のコマを重ねる camera_align.py でブロックをお手本と同じ位置に置き、横からの動画を撮り始めてから、AI に動かさせます。オプションは前の回と同じです。
cd ~/r2r2r-scripts
RAW=/Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
python3 dynamic_tracking_limits/place/place_modules/08_home_from_anywhere.py
python3 -c "from visual_servo_pick import get_daemon_socket, daemon_set_gripper, close_daemon_socket; get_daemon_socket(); daemon_set_gripper(0); close_daemon_socket()"
python3 pi05/camera_align.py --raw-dir $RAW --episode run_0001_20261019_192343 --scale 5 --alpha 0.7
python3 pi05/run_policy_client.py --raw-dir $RAW --steps-per-chunk 10 --via-stride 3 --settle-retries 0 --state-from-target --execute
--via-stride 3 は、1秒分の答えのうち途中の姿勢も3ステップおきに送るもの、--state-from-target は、AI に渡すいまの関節の角度を、直前にアームへ送った目標の角度にするものです(どちらも LOG361 で足したもの)。AI が答えを1回返すたびに、ターミナルで Enter を押して送っています。箱に入れて HOME 近くまで戻ったら、h(HOME に戻して終了)で終えます。
上カメラの写り方の確認で、12回止まった
クライアントは、動かし始める前に、上カメラのいまの映像を、お手本を撮った日の1枚(10/19 18:34 のお手本の最初のコマ)と比べます。似かたの強さ(response)が 0.2 を下回ると「測れない」として、アームに何も送らずに止まります。C の1回目に入る前と2回目の前で、この確認で合わせて12回止まりました(アームは動いていません。回ごとの値は後ろの「回ごとの集計」の表)。
止まった理由は2つありました。
1つ目は、上カメラの左下の角に、横のカメラの台か椅子の脚のような黒いものが写っていたことです。お手本の日の映像にはありません。これをよけてから、camera_align.py の画面では response が 0.38〜0.46 に上がりました。

2つ目は、比べている基準のコマが1枚だけだったことです。camera_align.py は位置C のお手本と比べて 0.46 でしたが、クライアントはどの位置でも同じ1枚(ブロックが別の場所にあるお手本)と比べていて、0.17〜0.21 を行ったり来たりしていました。ずれ(dy −8.3・dx +3.3)は毎回ほぼ同じで、カメラが動いたのではありません。また、camera_align.py を閉じた直後にクライアントを動かすと、カメラの最初のコマが整っていないようで、response が 0.003 や 0.035 になることがありました。
camera_align.py で位置ごとのお手本と比べて OK を見たうえで、C の2回目からは、クライアントの確認を外すオプション --ignore-framing を付けました。付けても、写り方の値は記録(log.jsonl)に残ります。
- ねらい:写り方は合っているのに、基準のコマの違いで止まり続けるのを避ける
- 変わったこと:位置ごとのお手本で
camera_align.pyの OK を見てから、クライアントの確認を外して動かした - 見込める効果:付ける前は、写り方の確認で12回止まり、動いたのは1回だった。付けたあとに動かした回は、写り方では1回も止まっていない(記録から数えた値)。カメラの最初のコマを数枚捨ててから確認する直しと、位置ごとの基準で比べる直しは、まだしていない
位置C の5回の結果
| 回 | 記録 | 写り方の response | 閉じたチャンク | 離したチャンク | 結果 |
|---|---|---|---|---|---|
| 1 | pi05_20261029_115823 | 0.212 | 04 | 10 | 入った。持ち上げて箱の上で離した |
| 2 | pi05_20261029_120644 | 0.183(外した) | 04 | 10 | 入った。離す前に爪から抜け、箱の中に落ちた |
| 3 | pi05_20261029_121202 | 0.049(外した) | 03 | 08 | 入った |
| 4 | pi05_20261029_121650 | 0.051(外した) | 04 | 10 | 入った |
| 5 | pi05_20261029_122156 | 0.212(外した) | 04 | 11 | 入った。つかむときブロックが爪に引っかかった |
5回とも、爪を閉じたのはチャンク03〜04、離したのはチャンク08〜11でした。3回目と4回目は、クライアントの確認の response が 0.05 前後でしたが(camera_align.py を閉じた直後の最初のコマ)、そのまま箱に入っています。
位置D:5回中1回。爪の先でつかみ、持ち上げた瞬間に落ちた
位置D はアームの左で、つかむとき土台 j0 を約 −61° まで回し、腕を低く長く伸ばします。お手本は5本あり、C(4本)より多い置き場所です。
| 回 | 記録 | 閉じたチャンク | 離したチャンク | 結果 |
|---|---|---|---|---|
| 1 | pi05_20261029_122909 | 04 | なし | 入らなかった。爪がブロックの手前で閉じた |
| 2 | pi05_20261029_123158 | 04 | なし | 入らなかった。爪の先でつかみ、持ち上げた瞬間に手先が跳ね上がって落とした |
| 3 | pi05_20261029_124104 | 04 | なし | 入らなかった。2回目と同じ落ち方 |
| 4 | pi05_20261029_124830 | 04 | 11 | 入った |
| 5 | pi05_20261029_125314 | 04 | なし | 入らなかった。つかみ損ね |
| (6) | pi05_20261029_125528 | 02 | なし | 5回の外なので数に入れない。手首 j4 が目標より 36.7° 手前で止まり、ブロックの上に来る前に閉じたので止めた |
1回目は、爪がブロックの手前で閉じた
上カメラのコマでは、爪はブロックのすぐ手前で閉じ、ブロックは爪の先の外に残っています。最初のコマを比べると、ブロックはお手本より少し左(アームから遠い側)にあり、マットの幅から計算するとおよそ 1cm です。camera_align.py の画像は横 384 画素で、1画素がマットの上でおよそ 2mm にあたり、1cm のずれは画面のぼやけに隠れます。

2回目からは、重ねた画像の中のマットの方眼の線も目印にして、ブロックの左の端と手前の端を、お手本と同じ線に揃えて置きました。
2回目と3回目は、持ち上げた瞬間に手先が跳ね上がって落ちた
横からの動画では、どちらの回も同じ順に進んでいます。爪の先でブロックをつかみ、爪の先がマットに押しつけられたまま数十秒止まり、持ち上げる指令で手先が跳ね上がるように一気に上がり、その勢いでブロックが爪の先から抜けて、つかんだ場所の近くに落ちました。そのあと、空の爪のまま箱の方へ回っています。


2回目の作業中には、ログの 未到達. j4 の発熱などを確認してください を見て、手首が熱で緩んで落としたと見ていました。動画を見ると、落ちたのは持ち上げた瞬間で、手首の 15.4° の未到達が出たのは、そのあと空の爪で箱の方へ回っていたときでした。2回とも同じ所で同じ落ち方をしているので、熱で緩んだのではないと見ています。
AI が送った目標は、お手本とほぼ同じ姿勢だった
作業中は、AI がお手本より低い所を狙っていて、爪の先がマットに当たるのではないかと考えていました。そこで、爪を閉じるまでに送った目標の関節の角度を、お手本と1つずつ並べました(スクリプトと全部の出力は、後ろの「回ごとの集計」の節)。
| 肩 j1 | ひじ j2 | 手首 j4 | |
|---|---|---|---|
| お手本5本の、閉じた瞬間 | +62.3〜+62.5 | +13.9〜+14.8 | −60.8〜−58.0 |
実機5回の、閉じる直前に送った目標 | +62.2〜+63.5 | +12.6〜+14.5 | −61.1〜−57.2 |
お手本5本の、閉じる前に手首をいちばん下へ曲げた所 | +55.3 | +22.5〜+22.6 | −76.6〜−76.2 |
目標は、お手本からほとんど外れていません。違いが出たのは、目標まで動けたかどうかです。3回目と5回目は、閉じる直前のチャンク03で、手首 j4 が目標まで動けずに止まっています。
| 回 | 中継点 | 送った目標の j4 | 着いたあとの j4 | 差 |
|---|---|---|---|---|
| 3(落とした) | チャンク03 の5ステップ目 | −71.5 | −60.1 | 11.4° 上で止まった |
| 4(入った) | チャンク03 の5ステップ目 | −74.2 | −75.8 | 目標まで動けた |
| 5(つかみ損ね) | チャンク03 の2ステップ目 | −76.4 | −69.0 | 7.4° 上で止まった |
手首を下へ曲げきれずに上で止まったのは、爪の先がマットかブロックに当たって押し返されたからだと見ています(見込み。3回目の動画では、このとき爪の先がマットに当たっています)。2回目は、ログでは手首が目標まで動けていますが、動画では爪の先がマットに押しつけられていました。
位置D は、お手本でも爪の先でつかんでいる場所です(LOG363)。腕を伸ばしきった低い姿勢なので、ブロックの置き方が 1cm ずれるだけで、爪の奥まで入らずに先だけがかかり、爪の先がマットに当たります。肩・ひじ・手首の角度がお手本と同じでも、つかみ方に余裕がない、というのが記録から言えることです。
5回のあとに1回足した回では、手首が 36.7° 手前で止まった
5回目のあと、もう1回だけ動かしました(5回の数には入れていません)。チャンク01(まだブロックへ向かっている途中)で、手首 j4 が目標 −49.8° に対して −13.1° で止まり、そのあとブロックの上に来る前に爪を閉じたので止めました。マットに当たる高さではないので、手首そのものが動かなくなっています。12:33 に 15.4°、12:55 に 36.7° と、アームを続けて動かすうちに手首の止まり方が大きくなっていたので、ここで休ませました。
休ませたのは約1時間50分です。アームの電源は入れたまま HOME に置き、Pod はつけたままにしました(借り直すと openpi を入れ直すのに10分ほどかかるため)。
再開の前に、デーモンとトンネルを確かめた
再開するとき、デーモンを起動するコマンドは Address already in use で止まりました。電源を入れたままだったので、デーモンはすでに動いていました。HOME には 2.0 秒で着いています。
_server_sock.bind((DAEMON_HOST, DAEMON_PORT))
OSError: [Errno 98] Address already in use
LISTEN 0 1 0.0.0.0:5555 0.0.0.0:*
[INIT] daemon 接続中...
[WARN] fresh_mode切替不可: daemon error: set_fresh_mode is not available in this pymycobot environment
[INIT] fresh_mode=1
[PRE] 現在姿勢: [-0.17, 1.31, 1.75, 0.26, -0.26, -30.23]
[SEND] HOME へ移動指令
[WAIT] t=2.0s max_err=1.75°
[DONE] HOME 到達 max_err=1.75°
[POST] 最終姿勢: [-0.17, 1.31, 1.75, 0.26, -0.26, -30.23]
[WARN] fresh_mode切替不可: daemon error: set_fresh_mode is not available in this pymycobot environment
[EXIT] fresh_mode=0, socket close
トンネルは、張り直そうとすると 8000 番がまだ使われていました。前に張ったトンネルが、8000 番を押さえたまま、中身の接続だけ切れていた状態です。クライアントが サーバー待ち のまま進まなかったので、古いトンネルを止めてから張り直しました。
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % ssh -N -L 8000:localhost:8000 -p <SSH_PORT> -i ~/.ssh/id_ed25519 root@<POD_IP>
bind [::1]:8000: Address already in use
channel_setup_fwd_listener_tcpip: cannot listen to port: 8000
Could not request local forwarding.
pkill -f "ssh -N -L 8000"
ssh -N -L 8000:localhost:8000 -p <SSH_PORT> -i ~/.ssh/id_ed25519 root@<POD_IP>
位置E:5回中3回。失敗の2回は爪がブロックの奥側に下りた
位置E はアームの前の手前側で、上のカメラから見ると、ブロックが爪の真下に隠れます。camera_align.py では、重ねた画像の爪のすき間から見える赤い部分を目印に置きました。
| 回 | 記録 | 写り方の response | 閉じたチャンク | 離したチャンク | 結果 |
|---|---|---|---|---|---|
| 1 | pi05_20261029_145207 | 0.547 | 04 | 09 | 入った |
| 2 | pi05_20261029_145641 | 0.558 | 04 | なし | 入らなかった。爪がブロックの奥側に下りて閉じ、ブロックは爪の手前に残った |
| 3 | pi05_20261029_145851 | 0.566 | 04 | 09 | 入った |
| 4 | pi05_20261029_150534 | 0.550 | 04 | 09 | 入った |
| 5 | pi05_20261029_150950 | 0.543 | 04 | なし | 入らなかった。2回目と同じ |
4回目は、動かしていたときには入らなかったと見ていましたが、横からの動画で、箱の上で離して箱の中に入っているのを確かめ、入ったに数えています。位置E の失敗の2回は、どちらもつかむところで外れていて、持ったあとに落とした回はありません。前の回で心配した、箱の手前の縁にぶつかる回もありませんでした。


15回のまとめ:C 5/5・D 1/5・E 3/5、合わせて15回中9回
| 位置 | お手本の本数 | LOG363 で動かした回 | LOG363 で入った回 | この回に動かした回 | この回に入った回 |
|---|---|---|---|---|---|
| C | 4本 | 7回 | 1回 | 5回 | 5回 |
| D | 5本 | 1回 | 1回 | 5回 | 1回 |
| E | 4本 | 2回 | 1回 | 5回 | 3回 |
LOG363 の位置C の7回のうち、3回は途中で手で止め、1回は動画がなく入ったか分からず、2回がつかみ損ねでした。この回の C の5回は、どれも最後まで動かしています。止め方が違うので、7回中1回と5回中5回を、そのまま比べることはしていません。
お手本の本数は、D がいちばん多い5本です。それでも D がいちばん入りませんでした。19本と少ないお手本の中では、置き場所ごとの本数の差よりも、その場所がアームにとってどれだけ余裕のない姿勢かのほうが効いていると見ています(見込み)。5回ずつでは割合の数字としてはまだ粗く、回数を増やせば多少は動きます。
AI に問い合わせてから答えが返るまで(推論)の時間は、195回の問い合わせの中央値が 632ミリ秒、いちばん短いのが 417ミリ秒、いちばん長いのが 2,344ミリ秒で、1秒を超えたのは53回でした(A40・Pod から Mac までの往復を含む)。
Pod の費用は2.87ドル(約453円)で、そのうち約1.1ドルは休憩の待ちだった
| 項目 | 値 |
|---|---|
| GPU | A40 × 1(Runpod) |
| 料金 | 1時間 0.62ドル(約98円) |
| 残高 | 借りる前 3.82ドル(LOG363 の終わりの値。その後 Runpod は使っていない)、途中で 10ドル足して、消したあと 10.95ドル |
| 費用 | 2.87ドル(約453円) |
| 借りた時間 | 費用を料金で割ると約4時間38分(11:37 ごろ〜16:15 ごろ) |
| そのうち休憩の待ち | 約1時間50分(約1.1ドル・約180円) |
| モデルを取ってくる時間 | 13.19 秒 |
| サーバーの起動 | モデルの読み込み 5.41 秒 |
| 実機の回 | 位置C 5回・D 5回(ほかに数に入れない1回)・E 5回 |
Pod を消す前に、サーバーのログを Mac の KIOXIA へ持ち帰りました。
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % mkdir -p /Volumes/KIOXIA/r2r2r-data/lab/Log14
scp -P <SSH_PORT> -i ~/.ssh/id_ed25519 root@<POD_IP>:/workspace/logs/serve.log /Volumes/KIOXIA/r2r2r-data/lab/Log14/serve.log
serve.log 100% 5732 11.8KB/s 00:00
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts %
そのあと、Runpod の画面で Stop → Terminate を押して Pod を消しました。ターミナルの出力・serve.log・横からの動画7本は KIOXIA の lab/Log14/ に、上カメラのコマと log.jsonl は runs/pi05_policy/ に置いています。
次は位置D のつかみ方と、上カメラの確認の直し方を決める
この回で、置き場所によって入る割合が大きく違うことが分かりました。次に考えていることは3つです。
- 位置D のお手本を、ブロックを爪の奥までつかむ形で撮り直すか。撮り直すと学習のやり直しになるので、費用と合わせて決める
- 上カメラの写り方の確認を、位置ごとのお手本と比べる形にし、カメラを開いた直後の数コマを捨ててから確かめる形にする(アームを動かすプログラムの直しなので、Claude Code に頼む)
- 照明を変えたときに入るかどうか。お手本の19本は、すべて 10/19 の夕方に同じ部屋の明かりで撮ったものです。この回は昼の12時台と15時台で、C は5回とも入っています。照明を変えて試すのは、この回の結果を基準にして、1つずつ変える別の回にします
回ごとの集計と、すべてのチャンクの記録
この回の数字は、すべて KIOXIA の runs/pi05_policy/pi05_20261029_*/log.jsonl から次の3つのスクリプトで出しています。どれも読むだけで、ファイルには何も書きません。Mac につないだ作業環境で R2R2R_DATA を KIOXIA の場所にして動かしました。
回ごとの1行の表を作るスクリプト run_summary.py
結果(入った・入らなかった)は、目で見た結果と横からの動画を、スクリプトの中に書き写しています。
"""LOG401: 2026-10-29 の π0.5 実機の回をすべて 1 行ずつの表にする (読むだけ).
runs/pi05_policy/pi05_20261029_*/log.jsonl を読み, 回ごとに
写り方の確認 (response と, 確認を外したか) / 動かしたチャンク数 / 閉じる指令・開く指令のチャンク /
推論時間 (中央値・最大) / 中継点の未到達 (8 秒以内に着かなかった数) /
閉じる前と閉じたあとの, 手首 j4 の目標と実測の差の最大
を出す. 結果 (入った・入らなかった) は, 目で見た結果をここに書き写したもの.
"""
import json, glob, osrun_summary.py の出力 out_run_summary.txt
run 位置 回 結果 写り方(resp/外した) chunk 閉 開 推論ms(中央/最大) 未到達 j4差(閉じる前/後) ひとこと
115543 - - - 0.035/- 0 - - -/ - 0 0.0/ 0.0 写り方の確認で止まった (アームは動いていない)
115631 - - - 0.317/- 0 - - -/ - 0 0.0/ 0.0 最初のチャンクを送る前に止めた (アームは動いていない)
115718 - - - 0.199/- 0 - - -/ - 0 0.0/ 0.0 写り方の確認で止まった (アームは動いていない)
115733 - - - 0.194/- 0 - - -/ - 0 0.0/ 0.0 写り方の確認で止まった (アームは動いていない)
115823 C 1 入った 0.212/- 15 4 10 609/ 1730 0 1.3/ 1.6 持ち上げて箱の上で離した
120216 - - - 0.176/- 0 - - -/ - 0 0.0/ 0.0 写り方の確認で止まった (アームは動いていない)
120221 - - - 0.094/- 0 - - -/ - 0 0.0/ 0.0 写り方の確認で止まった (アームは動いていない)つかむまでをお手本と比べるスクリプト approach_vs_demo.py
"""LOG401: ブロックへ下りていくところ (爪を閉じるまで) を, お手本と 2026-10-29 の実機の回で比べる (読むだけ).
お手本 (10Hz): 爪を閉じるまでの手首 j4 の最小 (いちばん下へ曲げた所) と, そのときの j0 j1 j2. 閉じた瞬間の関節角
実機: 閉じる指令のチャンクまでの中継点ごとに, 送った目標 (target) と 着いたあとの実測 (actual_after).
手首 j4 の 目標−実測 (− は目標まで曲がりきらずに止まった) と, 8 秒以内に着いたか
"""
import os, json
import numpy as np
ROOT = os.environ.get("R2R2R_DATA", "/Volumes/KIOXIA/r2r2r-data"); os.chdir(ROOT)
RAW = "datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes"
DEMO = {"C": ["192343", "192438", "192539", "192633"],
"D": ["193404", "193459", "193617", "193825", "193932"],
"E": ["194818", "194913", "195023", "195120"]}
RUNS = {"C": [("115823", "入った"), ("120644", "入った"), ("121202", "入った"), ("121650", "入った"), ("122156", "入った")],
"D": [("122909", "入らなかった"), ("123158", "入らなかった"), ("124104", "入らなかった"), ("124830", "入った"), ("125314", "入らなかった"), ("125528", "数に入れない")],
"E": [("145207", "入った"), ("145641", "入らなかった"), ("145851", "入った"), ("150534", "入った"), ("150950", "入らなかった")]}
def p(v, n=6):
return " ".join(f"{x:+6.1f}" for x in v[:n])
for pos in "CDE":
print(f"\n######## 位置{pos}")
print("== お手本: 閉じるまでの j4 の最小 / 閉じた瞬間 (j0..j5)")
for e in DEMO[pos]:
S = np.load(f"{RAW}/run_0001_20261019_{e}/episode.npz")["state"]
c = int(np.argmax(S[:, 6] > 0.5))
k = int(np.argmin(S[:c + 1, 4]))
print(f" demo {e} j4最小 {S[k,4]:+6.1f} (閉じる {(c-k)/10:.1f} 秒前, j0 {S[k,0]:+6.1f} j1 {S[k,1]:+6.1f} j2 {S[k,2]:+6.1f}) 閉じた瞬間 [{p(S[c])}]")
print("== 実機: 閉じるまでの中継点 (チャンク.ステップ 目標 j0 j1 j2 j3 j4 j5 | 実測 j4 | j4 目標−実測 | 着いた)")
for stem, res in RUNS[pos]:
L = [json.loads(l) for l in open(f"runs/pi05_policy/pi05_20261029_{stem}/log.jsonl")]
ch = [x for x in L if "chunk" in x and x.get("executed")]
cl = [x["chunk"] for x in ch if x.get("grip_cmd") == 1]
c0 = cl[0] if cl else ch[-1]["chunk"]
print(f" -- {stem} {res} 閉じる指令 チャンク{c0:02d}")
for x in ch:
if x["chunk"] > c0:
break
for v in x.get("vias") or []:
if not v.get("called"):
continue
t, a = v["target"], v["actual_after"]
mark = "" if v.get("success") else " ← 未到達"
print(f" {x['chunk']:02d}.{v['step']} [{p(t)}] | {a[4]:+6.1f} | {t[4]-a[4]:+6.1f} | {v.get('success')}{mark}")
approach_vs_demo.py の出力 out_approach_vs_demo.txt
######## 位置C
== お手本: 閉じるまでの j4 の最小 / 閉じた瞬間 (j0..j5)
demo 192343 j4最小 -70.3 (閉じる 1.4 秒前, j0 -27.6 j1 +58.1 j2 +19.7) 閉じた瞬間 [ -27.7 +63.7 +14.1 -7.6 -61.2 -27.9]
demo 192438 j4最小 -70.6 (閉じる 1.4 秒前, j0 -27.8 j1 +58.1 j2 +19.6) 閉じた瞬間 [ -27.8 +63.7 +14.1 -7.7 -61.4 -27.3]
demo 192539 j4最小 -70.3 (閉じる 1.4 秒前, j0 -28.4 j1 +58.1 j2 +19.7) 閉じた瞬間 [ -27.2 +63.7 +14.1 -7.7 -61.4 -27.3]
demo 192633 j4最小 -70.4 (閉じる 1.4 秒前, j0 -28.2 j1 +58.1 j2 +19.7) 閉じた瞬間 [ -27.4 +63.7 +14.1 -7.6 -61.4 -27.2]
== 実機: 閉じるまでの中継点 (チャンク.ステップ 目標 j0 j1 j2 j3 j4 j5 | 実測 j4 | j4 目標−実測 | 着いた)すべてのチャンクの表を作るスクリプト run_chunk_tables.py
"""LOG401: 2026-10-29 の π0.5 実機の回 (C・D・E) を, チャンクごとの表にする (読むだけ).
runs/pi05_policy/pi05_20261029_*/log.jsonl を読み, 1 行 = 1 チャンクで
推論時間 / 使ったステップ / モデルに渡した state / 送った目標 / グリッパー /
送ったか / 着いたか / state の出どころ / 中継点の数と未到達の数 を出す (LOG363 の run_chunk_tables.py と同じ形).
アームが動いていない回 (写り方の確認で止まった回など) は, 写り方の 1 行だけを出す.
"""
import json, glob, os
ROOT = os.environ.get("R2R2R_DATA", "/Volumes/KIOXIA/r2r2r-data") + "/runs/pi05_policy"
def f6(v):
return "[" + " ".join(f"{x:+6.1f}" for x in v[:6]) + "]" if v else "-"
for d in sorted(glob.glob(ROOT + "/pi05_20261029_*")):
L = [json.loads(l) for l in open(d + "/log.jsonl")]
fr = [l for l in L if l.get("type") == "framing"]
ch = [l for l in L if "chunk" in l]
print(f"== {os.path.basename(d)} チャンク {len(ch)}")
for f in fr:
print(f" framing dy={f['dy']} dx={f['dx']} response={f['response']} -> {f['verdict']} ignored={f.get('ignored')}")
for c in ch:
src = c.get("state_source", "measured")
vs = [v for v in (c.get("vias") or []) if v.get("called")]
miss = sum(1 for v in vs if not v.get("success"))
print(f" {c['chunk']:02d} {c['latency_s']*1000:6.0f}ms used={c.get('used_step')} "
f"state={f6(c['state'])} grip_state={c['state'][6]:.0f} src={src:8s} target={f6(c.get('target'))} "
f"grip={c.get('grip_cmd')} exec={c.get('executed')} arrived={c.get('arrived')} vias={len(vs)} miss={miss}"
+ (" HOME" if c.get("home_requested") else ""))
if src == "target" and c.get("measured_state"):
print(f" measured={f6(c['measured_state'])}")
run_chunk_tables.py の出力 out_run_chunk_tables.txt
== pi05_20261029_115543 チャンク 0
framing dy=-19.0 dx=11.96 response=0.035 -> 測れない ignored=False
== pi05_20261029_115631 チャンク 0
framing dy=-7.05 dx=4.23 response=0.317 -> OK ignored=False
== pi05_20261029_115718 チャンク 0
framing dy=-8.06 dx=4.89 response=0.199 -> 測れない ignored=False
== pi05_20261029_115733 チャンク 0
framing dy=-8.04 dx=4.97 response=0.194 -> 測れない ignored=FalseMac のターミナルの出力
アームを動かした Mac のターミナルの出力を、そのまま載せます。11:39〜12:57 は位置C と位置D、14:49〜15:12 は位置E です。
ターミナルの出力 terminal_c_d.txt(11:39〜12:57・位置C と位置D)
Last login: Thu Oct 29 11:39:05 on ttys007
(base) shimazueiichi@shimadzueiichinoMacBook-Pro ~ % cd ~/r2r2r-scripts
ssh -i ~/.ssh/id_rsa_pi ubuntu@192.168.2.1 'pgrep -f mecharm_daemon.py >/dev/null && echo デーモン動いてる || (setsid nohup python3 /home/ubuntu/mecharm_daemon.py </dev/null >>/home/ubuntu/daemon.log 2>&1 &); sleep 8; tail -3 ~/daemon.log; ss -ltn | grep 5555'
python3 dynamic_tracking_limits/place/place_modules/08_home_from_anywhere.py
デーモン動いてる
[DAEMON 14:37:47] cmd received: get_angles
[DAEMON 14:37:47] cmd received: set_fresh_mode
[DAEMON 14:37:47] 切断: ('192.168.2.2', 60628)ターミナルの出力 terminal_e.txt(14:49〜15:12・位置E)
Last login: Thu Oct 29 11:53:13 on ttys008
(base) shimazueiichi@shimadzueiichinoMacBook-Pro ~ % python3 -c "from visual_servo_pick import get_daemon_socket, daemon_set_gripper, close_daemon_socket; get_daemon_socket(); daemon_set_gripper(0); close_daemon_socket()"
python3 pi05/camera_align.py --raw-dir $RAW --episode run_0001_20261019_194818 --scale 5 --alpha 0.7
python3 pi05/run_policy_client.py --raw-dir $RAW --steps-per-chunk 10 --via-stride 3 --settle-retries 0 --state-from-target --execute --ignore-framing
Traceback (most recent call last):
File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'visual_servo_pick'
python3: can't open file '/Users/shimazueiichi/pi05/camera_align.py': [Errno 2] No such file or directory