フィジカルAI研究室を作る Log#13 | Physical Intelligence の π0.5 がお手本の3か所すべてで箱に入れた
机の上の小さなロボットアームが、AI の指示だけで赤いブロックをつかみ、白い箱に入れる。この動きを、ブロックの置き場所を変えて試しました。アームの左に置いたとき(位置D)も、アームの前に置いたとき(位置E)も、ブロックは箱に入りました。2日前に試した位置C と合わせて、人がお手本を見せた置き場所のうち、試した3か所すべてで箱に入ったことになります。
使った AI は、米国の Physical Intelligence 社が公開しているロボット用のモデル π0.5(パイレイテンゴ)です。上から見たカメラの画像と、6つの関節の角度を受け取り、次の1秒の関節の角度を返します。人が手でアームを動かして教えた動きを、5か所の置き場所で合わせて19回録り、それを見せて学習させました(模倣学習)。前の回の LOG361 では、位置C で初めてブロックが箱に入りました。ただ、それがその1か所だけのたまたまなのかは、まだ分かっていませんでした。
位置D と位置E は、アームにとって条件がかなり違います。位置D はアームの左にあり、つかんでから箱の上まで、土台を約105°回します。位置E はアームの前の手前側で、上のカメラから見ると、ブロックが爪の真下に隠れて、ほとんど写りません(お手本の最初のコマで、赤く写るのは 7〜18 画素)。AI のモデルも学習も、前の回から何も変えていません。AI の答えをアームに届けるプログラムの設定も、前の回で初めて箱に入ったときと同じです。変えたのは、ブロックを置く場所だけです。
ただ、どちらもぎりぎりでした。位置D では、箱の上で爪を開く直前に、ブロックが爪の先から抜けて落ちました。箱の真上だったので、中に入っています。位置E では、ブロックが箱の手前の縁のすぐ上を通りました。位置E は、1回目は爪がブロックの横で閉じてつかみ損ね、2回目で入っています。
記録を数えると、ブロックを持って運ぶ間の肩は、どちらの位置でもお手本より低いところを通っていて、いちばん高いところの差は位置D で 2.9°、位置E で 4.0° でした。 位置D では、AI が送った目標はお手本とほぼ同じ高さで、足りなかったのは、肩が毎回目標より 1.1〜2.8° 低く止まった分です。位置E では、AI の目標そのものがお手本より 2.0° 低く、そこへ止まるときの不足が重なりました。
やったことの全体は次のとおりです。
| やったこと | なぜ | 結果 |
|---|---|---|
電源を入れ直し、手首 j4 が HOME の姿勢に戻るか確かめた | 前の回の最後に、手首が +45.87° のまま動かなくなっていたため | アームを待ち受けるプログラム(デーモン)を起動し直すと、HOME まで戻った(j4 +1.31°) |
推論用の Pod(時間で借りる GPU マシン)を借り、学習済みのモデルを送ってサーバーを起動した | AI の答えを返す計算をするため | A40 を約1時間、約98円。そのうち約30分は、モデル(6.3GB)を送る待ち時間だった |
位置D のお手本と同じ位置にブロックを置き、AI に動かさせた | 位置C の成功が、置き場所によらないかを確かめるため | 箱に入った。離す直前に、爪の先から抜けて落ちた |
| 位置E で同じことをした | ブロックがカメラにほとんど写らない場所でも動くかを見るため | 1回目はつかみ損ね、2回目で入った。箱の縁のすぐ上を通った |
運ぶ間の肩の角度を、お手本と比べた | ぎりぎりになった理由を数字で見るため | 肩のいちばん高いところが、お手本より D で 2.9°、E で 4.0° 低かった |

この回の作業も、Claude(この記事の手順と分析を一緒に組み立てた AI)と進めました。手順・分析・記録の集計は Claude が行い、アームの操作と、目で見た判断・止める判断はこちらで行っています。プログラムの変更はしていません。ここから下は、使ったコマンド・コード・出力を全量で載せた作業ログです。ログの中の Pod の IP アドレスとポート番号は、<POD_IP> と <SSH_PORT> に置き換えています。費用の円は 1ドル=158円 で計算しています。結果と効果の数字は、どれも記録から数えた値です。見込みのものは、見込みと書いています。
作業ログ ― 手首 j4 は、デーモンを起動し直すと HOME の姿勢に戻った
前の回の最後に、手首 j4 が +45.87° のまま動かなくなり、HOME の姿勢(全関節がほぼ 0°)に戻せなくなっていました。この回は、アームの電源を入れ直してから始めています。
電源を入れ直したあと、HOME に戻すスクリプトを動かすと、まず Connection refused で止まりました。アームの中の Raspberry Pi で、角度の指令を受け取って関節へ送るプログラム(デーモン、5555番で待ち受ける)は、電源を入れ直すと止まります。それを起動し直してから、もう一度 HOME に戻しました。
Last login: Sat Oct 24 10:23:26 on ttys003
(base) shimazueiichi@shimadzueiichinoMacBook-Pro ~ % cd ~/r2r2r-scripts
python3 dynamic_tracking_limits/place/place_modules/08_home_from_anywhere.py
[INIT] daemon 接続中...
Traceback (most recent call last):
File "/Users/shimazueiichi/r2r2r-scripts/dynamic_tracking_limits/place/place_modules/08_home_from_anywhere.py", line 97, in <module>
main()
File "/Users/shimazueiichi/r2r2r-scripts/dynamic_tracking_limits/place/place_modules/08_home_from_anywhere.py", line 37, in main
get_daemon_socket()
File "/Users/shimazueiichi/r2r2r-scripts/visual_servo_pick.py", line 528, in get_daemon_socket
s.connect((DAEMON_HOST, DAEMON_PORT))
ConnectionRefusedError: [Errno 61] Connection refused
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % ssh -i ~/.ssh/id_rsa_pi ubuntu@192.168.2.1 "setsid nohup python3 /home/ubuntu/mecharm_daemon.py </dev/null >>/home/ubuntu/daemon.log 2>&1 &"; sleep 8; ssh -i ~/.ssh/id_rsa_pi ubuntu@192.168.2.1 'tail -3 ~/daemon.log; ss -ltn | grep 5555'
[DAEMON 14:42:21] ✓ MyCobot 初期化完了
[DAEMON 14:42:21] startup_warmup angles=[1.66, 92.81, 0.61, 0.35, -95.27, -29.44]
[DAEMON 14:42:21] ポート 5555 で待ち受け中...
LISTEN 0 1 0.0.0.0:5555 0.0.0.0:*
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % python3 dynamic_tracking_limits/place/place_modules/08_home_from_anywhere.py
[INIT] daemon 接続中...
[WARN] fresh_mode切替不可: daemon error: set_fresh_mode is not available in this pymycobot environment
[INIT] fresh_mode=1
[PRE] 現在姿勢: [1.66, 92.81, 0.61, 0.35, -95.27, -29.44]
[SEND] HOME へ移動指令
[WAIT] t=2.1s max_err=11.33°
[WAIT] t=2.6s max_err=1.40°
[DONE] HOME 到達 max_err=1.40°
[POST] 最終姿勢: [0.17, 1.31, 1.40, 0.26, 1.31, -29.53]
[WARN] fresh_mode切替不可: daemon error: set_fresh_mode is not available in this pymycobot environment
[EXIT] fresh_mode=0, socket close
デーモンが起動したときの姿勢は [1.66, 92.81, 0.61, 0.35, -95.27, -29.44] で、電源が切れている間に、肩 j1 と手首 j4 が重さで大きく倒れていました。HOME の指令を送ると 2.6 秒で着き、手首 j4 は +1.31° になりました。前の回の +45.87° のずれは、残っていません。
推論用の Pod を借り、モデル 6.3GB を約30分かけて送った
推論は、Runpod で借りた Pod(時間で借りる GPU マシン)で動かしました。GPU は A40 を1枚、料金は1時間 0.62ドル(約98円)です。前の回(LOG361)の夕方と同じ手順で、Mac から、mechArm 用のスクリプト一式・学習設定の追加スクリプト・学習済みのモデル(KIOXIA の checkpoints/pi05_mecharm_trim_lora_v1/3999/、32ファイル・6,340,573,809 バイト)を送りました。
Mac のターミナルで打ったコマンドです。
P=<SSH_PORT>; IP=<POD_IP>; K=~/.ssh/id_ed25519
ssh -p $P -i $K root@$IP "mkdir -p /workspace/r2r2r /workspace/logs"
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/
cd /Volumes/KIOXIA/r2r2r-data/checkpoints/pi05_mecharm_trim_lora_v1/3999
find . -type d | ssh -p $P -i $K root@$IP "mkdir -p /workspace/ckpt/3999 && cd /workspace/ckpt/3999 && xargs mkdir -p"
find . -type f -exec stat -f '%z %N' {} + | sort -rn | cut -d' ' -f2- | xargs -P 4 -I{} scp -q -P $P -i $K {} root@$IP:/workspace/ckpt/3999/{}
ssh -p $P -i $K root@$IP "cd /workspace/ckpt/3999 && find . -type f -printf '%s %p\n'" > /tmp/remote_ck.txt
find . -type f | while read f; do s=$(stat -f %z "$f"); grep -qx "$s $f" /tmp/remote_ck.txt || echo "不一致: $f"; done; echo "確認おわり"
そのときの出力です。モデルは -q(進み具合を出さない)で送っているので、スクリプトを送った行のあとは、送り終わるまで何も出ません。
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % P=<SSH_PORT>; IP=<POD_IP>; K=~/.ssh/id_ed25519
ssh -p $P -i $K root@$IP "mkdir -p /workspace/r2r2r /workspace/logs"
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/
cd /Volumes/KIOXIA/r2r2r-data/checkpoints/pi05_mecharm_trim_lora_v1/3999
find . -type d | ssh -p $P -i $K root@$IP "mkdir -p /workspace/ckpt/3999 && cd /workspace/ckpt/3999 && xargs mkdir -p"
find . -type f -exec stat -f '%z %N' {} + | sort -rn | cut -d' ' -f2- | xargs -P 4 -I{} scp -q -P $P -i $K {} root@$IP:/workspace/ckpt/3999/{}
ssh -p $P -i $K root@$IP "cd /workspace/ckpt/3999 && find . -type f -printf '%s %p\n'" > /tmp/remote_ck.txt
find . -type f | while read f; do s=$(stat -f %z "$f"); grep -qx "$s $f" /tmp/remote_ck.txt || echo "不一致: $f"; done; echo "確認おわり"
The authenticity of host '[<POD_IP>]:<SSH_PORT> ([<POD_IP>]:<SSH_PORT>)' can't be established.
ED25519 key fingerprint is: SHA256:biMgaaE6vvD2BAFaeXtdrn1BUngh5/6qiskLLrvkkOE
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[<POD_IP>]:<SSH_PORT>' (ED25519) to the list of known hosts.
eval_policy_offline.py 100% 9921 35.6KB/s 00:00
convert_to_lerobot.py 100% 2873 10.4KB/s 00:00
run_policy_client.py 100% 44KB 71.0KB/s 00:00
check_dataset.py 100% 14KB 52.1KB/s 00:00
build_demo_episodes.py.bak_pre_LOG352_2026101 100% 11KB 40.5KB/s 00:00
RUNPOD_TRAIN.md 100% 15KB 53.1KB/s 00:00
install_addon.py 100% 4786 13.1KB/s 00:00
mecharm_policy.py 100% 2321 8.5KB/s 00:00
eval_policy_offline.cpython-312.pyc 100% 15KB 56.7KB/s 00:00
build_demo_episodes.cpython-310.pyc 100% 11KB 39.5KB/s 00:00
build_demo_episodes.cpython-312.pyc 100% 29KB 105.9KB/s 00:00
check_dataset.cpython-312.pyc 100% 25KB 93.6KB/s 00:00
policy_ws.cpython-312.pyc 100% 4580 16.6KB/s 00:00
camera_align.cpython-312.pyc 100% 18KB 67.5KB/s 00:00
run_policy_client.cpython-312.pyc 100% 49KB 168.3KB/s 00:00
build_demo_episodes.py 100% 24KB 89.1KB/s 00:00
policy_ws.py 100% 2778 10.1KB/s 00:00
camera_align.py 100% 13KB 48.5KB/s 00:00
add_trim_config.py 100% 1966 6.8KB/s 00:00
送っている間に、Pod に入って tmux(接続が切れても作業が続く画面)を開き、その中で openpi(π0.5 を動かすための公開コード)を前の回と同じ版(コミット 215abfb)で取り直しました。
tmux new -s p
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
Pod の画面に残っていた、uv sync の最後の部分です。
root@cda8d55e10f9:/# tmux new -s p
+ transformers==4.53.2
+ treescope==0.1.9
+ triton==3.3.1
+ 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
+ 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@cda8d55e10f9:/workspace/openpi#
[p] 0:uv* "cda8d55e10f9" 09:26 24-Oct-26
モデルを送り始めてから15分ほどたったところで、Pod 側に届いた量を見ました。
root@cda8d55e10f9:/workspace/openpi# du -sb /workspace/ckpt/3999
3491538720 /workspace/ckpt/3999
root@cda8d55e10f9:/workspace/openpi#
全体 6,340,573,809 バイトのうち 3,491,538,720 バイト(約55%)で、送る速さは1秒あたり約 3.9MB でした。確認おわり が出たのは送り始めてから約30分後で、不一致 の行は出ていません。Pod を借りていた約1時間のうち、半分はこの送る待ち時間でした。
送り終わったあと、Pod の tmux の中でサーバーを起動しました。前の回と同じコマンドです。
python3 /workspace/r2r2r/pi05/openpi_addon/install_addon.py /workspace/openpi
python3 /workspace/r2r2r/add_trim_config.py /workspace/openpi
cd /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/Log13/serve.log)
Pod を消す前に持ち帰ったサーバーのログです。時刻は Pod の時計(世界標準時)です。Loaded norm stats from …/mecharm_redblock_box_teach_v1_trim2 の2行で、学習に使ったお手本(trim2)から計算した正規化の値を読んだことが分かります。connection open と closed の組は、Mac のクライアントが1回つなぐたびに出る行で、3組あります(位置D の回、位置E の1回目、位置E の2回目)。
INFO:root:Loading model...
INFO:2026-10-24 09:57:33,134: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-24 09:57:33,136: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 0x70592001c490>
INFO:absl:Restoring checkpoint from /workspace/ckpt/3999/params.
INFO:absl:[thread=MainThread] Failed to get flag value for EXPERIMENTAL_ORBAX_USE_DISTRIBUTED_PROCESS_ID.
INFO:absl:[process=0] /jax/checkpoint/read/bytes_per_sec: 1.3 GiB/s (total bytes: 6.3 GiB) (time elapsed: 5 seconds) (per-host)
INFO:absl:Finished restoring checkpoint in 5.02 seconds from /workspace/ckpt/3999/params.
INFO:openpi.shared.download:Downloading gs://big_vision/paligemma_tokenizer.model to /root/.cache/openpi/big_vision/paligemma_tokenizer.model
INFO:tqdm_loggable.tqdm_logging:Progress on: -/4264023 rate:- remaining:? elapsed:00:00 postfix:-
INFO:tqdm_loggable.tqdm_logging:Progress on: 4.07MiB/4.07MiB rate:4,261,478.9iB/s remaining:00:00 elapsed:00:01 postfix:-
INFO:root:Loaded norm stats from /workspace/openpi/assets/pi05_mecharm_trim_lora/local/mecharm_redblock_box_teach_v1_trim2
INFO:root:Loaded norm stats from /workspace/ckpt/3999/assets/local/mecharm_redblock_box_teach_v1_trim2
INFO:root:Creating server (host: cda8d55e10f9, ip: 172.28.0.2)
INFO:websockets.server:server listening on 0.0.0.0:8000
INFO:websockets.server:connection open
INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 58928) opened
INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 58928) closed
INFO:websockets.server:connection open
INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 60202) opened
INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 60202) closed
INFO:websockets.server:connection open
INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 48308) opened
INFO:openpi.serving.websocket_policy_server:Connection from ('127.0.0.1', 48308) closed
位置D:お手本と同じ位置にブロックを置き、AI に動かさせた
この記事のコード・ログ・データは、1ファイルずつ下に置いています。全文はリンク先にあります。
ファイルの一覧(5本)
01_sec03.txt ― 位置D の回(19:02・pi05_20261024_190239)のターミナルの出力・22,286字
02_sec04.txt ― 2回目(19:16・pi05_20261024_191603)のターミナルの出力・18,159字
03_de_vs_demo.py.txt ― お手本と比べたスクリプト de_vs_demo.py・4,071字
04_out_de_vs_demo.txt ― 出力 out_de_vs_demo.txt・7,096字
05_out_run_chunk_tables.txt ― 出力 out_run_chunk_tables.txt・9,307字
位置D は、アームの左側です。お手本は5本あり、どれもつかんだときの土台 j0 は −61.5〜−61.7° です。ブロックを置くときは、前の回に作った camera_align.py の --episode で、上のカメラのライブ映像に、お手本(run_0001_20261019_193404)の最初のコマを重ね、写っているブロックに実物のブロックを合わせました。
cd ~/r2r2r-scripts
RAW=/Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
python3 pi05/camera_align.py --raw-dir $RAW --episode run_0001_20261019_193404 --scale 5
この画面の出力は、最後の数行しか残っていません。
nse>=0.20)
^C
[STOP ] Ctrl-C
[DONE ] 終了 (何も書いていません)
横からの動画を撮り始めてから、前の回の 18:16 の回(π0.5 が初めて箱に入れた回)と同じオプションでアームを動かしました。--via-stride 3 は、1秒分の答えのうち途中の姿勢も3ステップおきに送るもの、--state-from-target は、AI に渡すいまの関節の角度を、直前にアームへ送った目標の角度にするものです(どちらも LOG361 で足したもの)。
位置D の回(19:02・pi05_20261024_190239)のターミナルの出力
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % python3 pi05/run_policy_client.py --raw-dir $RAW --steps-per-chunk 10 --via-stride 3 --settle-retries 0 --state-from-target --execute
[SAFE ] 安全範囲 (学習 19 本 ±10°): j0[-72,+55] j1[-9,+88] j2[-46,+41] j3[-18,+27] j4[-90,+10] j5[-51,-14]
[SAFE ] 肩 j1 の上限は J1_SAFE_MAX=88° で切った (これを超える指令はアームが黙って捨てる / LOG352) 元データ: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
[MODE ] EXECUTE steps/chunk=10 max_move=20.0° log=/Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261024_190239
[CAMERA] 写り方 dy=+0.3 dx=+1.4 response=0.574 → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[CAMERA] 基準: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes/run_0001_20261019_183454/frames/000000.jpg
[POLICY] 接続 ws://localhost:8000 metadata={}
[GRIP ] 開始時のグリッパー開放は, 最初の目標が検査を通ってから行います (爪が閉じていたら手で開けておく)チャンク(1回の問い合わせで返る1秒分の動き)04 で爪を閉じ、05〜06 でその場で肩を上げ、07〜10 で土台を −58° から +42° まで回して箱の上へ運び、11 で肩を下げて爪を開きました。12〜15 で HOME の姿勢に戻り、16 でまたつかみに行こうとしたところを h で止めています。
横から撮った動画では、箱の上で、離す前にブロックが落ちた

動画を見て、こう返しました。
入ったけど、所定の位置で離す前に落ちちゃった。
動画の 137.5〜140.5 秒を、0.5秒ずつ並べました。139.5 秒で、ブロックが爪の先から斜めに抜けて、箱の中へ落ちています。

ログと合わせると、落ちたのはチャンク10 の途中です。チャンク10 は、土台を +28.6° から +42.4° へ回して止め、同時に肩を下げ始める(目標の j1 が 46.1° から 52.6° へ)動きでした。爪を開く指令は、その次のチャンク11 で出ています。
上のカメラで見ると、ブロックは爪の先のほうでつかまれていた
アームを動かすクライアントは、問い合わせのたびに上のカメラのコマを残しています。チャンク10 の頭ではまだ爪の中にあり、チャンク11 の頭ではもうありません。運んでいる間のコマでは、ブロックが爪の奥ではなく、先のほうに挟まっているように見えます。

つかんだ姿勢はお手本とほぼ同じですが、土台 j0 が 2.0° ずれていました(お手本 −61.6°、この回 −59.6°)。上のカメラで測ると、ブロックを置いた位置も、お手本より、左の端からも下の端からも 8〜9mm 離れていました(このあとの節)。浅くつかんだことが、この 2° や置いた位置のずれから来たのかは、まだ確かめていません。
位置E:1回目は爪がブロックの横で閉じ、2回目で箱に入った
位置E は、アームの前の手前側です。お手本は4本で、つかんだときの土台 j0 は +12.8〜+13.2° です。HOME の姿勢の爪のほぼ真下にあるので、上のカメラでは、ブロックが爪の陰に隠れます。ブロックを置くときは、重ねた画像が見えるように --alpha 0.7 を付けました。
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_194818 --scale 5 --alpha 0.7
1回目(19:13)は爪がブロックの横で閉じ、19:14 の回は上のカメラの確認で止まった
位置E では、成功した回の前に2回動かしていました。この2回のターミナルの出力は残していないので、クライアントが KIOXIA に残した記録(runs/pi05_policy/ の log.jsonl と上カメラのコマ)から書きます。全チャンクの表は、記事の最後の節に載せています。
| 記録 | 何が起きたか |
|---|---|
pi05_20261024_191309(19:13) | 上カメラの写り方は OK(dy −2.36・dx +3.39・response 0.577)。チャンク04 で爪を閉じたが、上カメラのコマでは、ブロックは爪の外の右下にあった。チャンク05 は送らずに h で HOME に戻して止めた |
pi05_20261024_191455(19:14) | 上カメラの写り方の確認で、判定が 測れない になり(dy +4.26・dx +13.98・response −0.012)、アームには何も送らずに終わった |
19:13 の回の最初のコマでは、赤く写るブロックが 89 画素ありました。お手本4本の最初のコマは 7〜18 画素(LOG361 で測った値)で、成功した 19:16 の回は 37 画素です。爪の陰から外れて見えていた分だけ、ブロックがお手本の位置からずれていたことになります。
2回目(19:16・pi05_20261024_191603)のターミナルの出力
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % python3 pi05/run_policy_client.py --raw-dir $RAW --steps-per-chunk 10 --via-stride 3 --settle-retries 0 --state-from-target --execute
[SAFE ] 安全範囲 (学習 19 本 ±10°): j0[-72,+55] j1[-9,+88] j2[-46,+41] j3[-18,+27] j4[-90,+10] j5[-51,-14]
[SAFE ] 肩 j1 の上限は J1_SAFE_MAX=88° で切った (これを超える指令はアームが黙って捨てる / LOG352) 元データ: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes
[MODE ] EXECUTE steps/chunk=10 max_move=20.0° log=/Volumes/KIOXIA/r2r2r-data/runs/pi05_policy/pi05_20261024_191603
[CAMERA] 写り方 dy=-4.7 dx=+6.9 response=0.585 → OK (|dy|<=20 / |dx|<=20 / response>=0.20)
[CAMERA] 基準: /Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes/run_0001_20261019_183454/frames/000000.jpg
[POLICY] 接続 ws://localhost:8000 metadata={}
[GRIP ] 開始時のグリッパー開放は, 最初の目標が検査を通ってから行います (爪が閉じていたら手で開けておく)チャンク04 で爪を閉じ、05 でその場で肩を上げ、06〜07 で土台を +12° から +43° まで回して箱の上へ運び、08 で肩を下げて爪を開きました。09〜12 で HOME の姿勢に戻り、13 は q で止めています。最初の問い合わせが 877ms で返っているのは、19:13 の回でサーバー側のコンパイルが済んでいたためです(位置D の最初の問い合わせは 56,893ms)。
横から撮った動画では、ブロックが箱の手前の縁のすぐ上を通った
動画を見て、こう返しました。
超難関のE入るのすごいわ(ちょっとギリギリだったけど)
96〜104 秒を並べると、爪につかんだブロックの下の面が、箱の手前の縁とほぼ同じ高さを通っています。

ブロックを置いた位置は、お手本と 1cm 以内で合っていた
上のカメラの最初のコマで、赤いブロックの中心がマット(620mm × 450mm)の端から何 mm にあるかを測りました。LOG361 の block_position_mm.py に、この回の3つの回を足したものです。

ブロックの位置を測るスクリプト block_position_mm.py
# お手本と実機の回 (LOG363) の最初のコマで、赤いブロックの中心をマットの端からの距離 (mm) にする
# LOG361 の block_position_mm.py に、2026-10-24 の実機の回 (位置D・位置E) の最初のコマを足したもの
# マットの横幅 620mm を画像の左右の端の間の画素数で割って 1 画素の大きさを出す
import os
import cv2, numpy as np
ROOT = os.environ.get("R2R2R_DATA", "/Volumes/KIOXIA/r2r2r-data"); os.chdir(ROOT)
R = "datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes"
def mat_edges(im):
g = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY); dark = g < 90
L, Rr = [], []
for y in range(120, 180):
xs = np.where(dark[y])[0]; L.append(xs.min()); Rr.append(xs.max())
yb = np.median([np.where(dark[:, x])[0].max() for x in range(70, 110)])
return np.median(L), np.median(Rr), yb
def block(im, s_min, v_min):
hsv = cv2.cvtColor(im, cv2.COLOR_BGR2HSV)
m = (((hsv[..., 0] < 10) | (hsv[..., 0] > 165)) & (hsv[..., 1] > s_min) & (hsv[..., 2] > v_min)).astype(np.uint8)
m[:60] = 0
n, lab, st, cen = cv2.connectedComponentsWithStats(m); k = 1 + np.argmax(st[1:, 4])
pts = np.column_stack(np.where(lab == k))[:, ::-1].astype(np.float32)
(_, _), (bw, bh), ang = cv2.minAreaRect(pts)
return cen[k], st[k, 4], ang, bw, bh
RUNS = "runs/pi05_policy"
for name, path, s_min, v_min in [("D お手本", f"{R}/run_0001_20261019_193404/frames/000000.jpg", 70, 50),
("D お手本", f"{R}/run_0001_20261019_193932/frames/000000.jpg", 70, 50),
("D 実機 190239", f"{RUNS}/pi05_20261024_190239/frames/0000.jpg", 70, 50),
("E お手本", f"{R}/run_0001_20261019_194818/frames/000000.jpg", 120, 80),
("E お手本", f"{R}/run_0001_20261019_195120/frames/000000.jpg", 120, 80),
("E 実機 191309", f"{RUNS}/pi05_20261024_191309/frames/0000.jpg", 120, 80),
("E 実機 191603", f"{RUNS}/pi05_20261024_191603/frames/0000.jpg", 120, 80)]:
im = cv2.imread(path)
xl, xr, yb = mat_edges(im); mm = 620 / (xr - xl)
(cx, cy), area, ang, bw, bh = block(im, s_min, v_min)
print(f"{name:14s} 1画素 {mm:.2f}mm 画素数 {area:3d} 左の端から {(cx-xl)*mm:4.0f}mm 下の端から {(yb-cy)*mm:4.0f}mm 向き {ang:5.0f}° {bw*mm:.0f}x{bh*mm:.0f}mm")
出力 out_block_position_mm.txt
D お手本 1画素 2.23mm 画素数 253 左の端から 63mm 下の端から 244mm 向き -22° 37x38mm
D お手本 1画素 2.24mm 画素数 253 左の端から 62mm 下の端から 243mm 向き -31° 37x39mm
D 実機 190239 1画素 2.24mm 画素数 251 左の端から 71mm 下の端から 252mm 向き -23° 37x39mm
E お手本 1画素 2.23mm 画素数 18 左の端から 378mm 下の端から 103mm 向き -90° 11x7mm
E お手本 1画素 2.24mm 画素数 14 左の端から 373mm 下の端から 99mm 向き -76° 11x7mm
E 実機 191309 1画素 2.24mm 画素数 89 左の端から 383mm 下の端から 113mm 向き -11° 21x28mm
E 実機 191603 1画素 2.23mm 画素数 37 左の端から 379mm 下の端から 113mm 向き -63° 20x11mm
位置D は、お手本より左の端から 8〜9mm、下の端から 8〜9mm 離れた位置に置いていました(マットの下の端は、カメラで見てアームと反対の側)。位置E は、ブロックがほとんど爪の陰に隠れていて、見えている部分の中心しか測れないので、この数字は位置の目安になりません。
運ぶ間の肩は、お手本より位置D で 2.9°、位置E で 4.0° 低かった
どちらの回もぎりぎりだったので、ブロックを持っている間の動きを、同じ位置のお手本と比べました。アームを動かすクライアントは、中継点(1秒分の答えの途中の姿勢)ごとに、送った目標と、着いたあとに測った角度を残しています。肩 j1 は、数字が小さいほど腕が上がります。
| お手本の肩の最高 | AI が送った目標の最高 | 着いたあとの実測の最高 | 目標と実測の差(持っている間の中継点) | |
|---|---|---|---|---|
| 位置D | 45.9°(5本とも) | 46.1°(+0.2°) | 48.8°(+2.9°) | 28点、+1.08〜+2.78°、平均 +2.07° |
| 位置E | 46.3〜46.4°(4本) | 48.3°(+2.0°) | 50.3°(+4.0°) | 16点、+0.59〜+2.06°、平均 +1.24° |
位置D では、AI の目標はお手本とほとんど同じ高さを通っていて、足りなかったのは、ブロックを持った肩が目標より毎回低く止まった分です。前の回で、ブロックを持って肩を上げる指令43回が43回とも目標より低く止まっていたのと、同じ傾向です。位置E では、AI の目標そのものがお手本より 2.0° 低いところまでしか上がらず、そこへ止まるときの不足が重なりました。
爪先の高さも、関節の角度から見積もりました(FK 表 fk_scan_motion_based_v2.csv の近い 40 点からの当てはめで、LOG361 と同じ方法)。1点ずつは揺れがありますが、持っている間の最高は、位置D がお手本 135〜137mm に対して 116.5mm、位置E がお手本 115〜120mm に対して 90.8mm でした。位置E は、お手本より 24〜29mm 低いところを通ったことになり、動画で縁すれすれだったことと合っています。
お手本と比べたスクリプト de_vs_demo.py
# 位置D・位置E の実機の回 (LOG363) を, 同じ位置のお手本 (D 5本・E 4本) と比べる
# 1) つかんだ姿勢 / 運ぶ間に肩がいちばん上がった所 (j1 の最小) / 離した姿勢
# 2) ブロックを持って肩を上げる指令の, 目標と次のチャンクの実測の差 (+ は目標より低いまま止まった)
# 3) 爪先の高さ (FK 表 fk_scan_motion_based_v2.csv の ee_y を (j1,j2,j3,j4) の近い 40 点で局所線形に当てはめる, LOG361 と同じ)
# 実機は中継点ごとに「送った目標 (target)」と「着いたあとの実測 (actual_after)」が残っているので, 肩の高さと爪先の高さは両方を出す
import os, json
import numpy as np, pandas as pd
ROOT = os.environ.get("R2R2R_DATA", "/Volumes/KIOXIA/r2r2r-data"); os.chdir(ROOT)出力 out_de_vs_demo.txt
######## 位置D
== お手本 (閉じた瞬間 / 持っている間の j1 最小 / 開いた瞬間, 角度は j0..j5)
demo 193404 閉 [ -61.6 +62.5 +14.8 +1.5 -60.7 -32.4] j1最小 +45.9 (j0 +19.3) 開 [ +43.8 +63.4 -3.3 +7.4 -61.7 -35.7]
爪先の高さ mm 閉じた時 31.7 最高 135.3 1秒ごと 32 43 51 30 71 132 95 89
demo 193459 閉 [ -61.6 +62.4 +14.8 +1.1 -60.8 -31.7] j1最小 +45.9 (j0 +20.5) 開 [ +43.7 +63.4 -3.3 +7.4 -62.0 -35.8]
爪先の高さ mm 閉じた時 32.5 最高 135.6 1秒ごと 32 44 13 95 122 64 109 88
demo 193617 閉 [ -61.7 +62.4 +14.8 +1.1 -60.8 -31.7] j1最小 +45.9 (j0 +20.8) 開 [ +43.8 +63.5 -3.3 +7.5 -61.7 -35.8]位置C・D・E の3か所とも、1回以上ブロックが箱に入った
前の回の位置C と合わせて、AI に渡す角度を直前の目標にするやり方(--state-from-target)と中継点(--via-stride 3)で動かした回をまとめます。
| 位置 | お手本の本数 | 動かした回 | 箱に入った回 | 入り方 |
|---|---|---|---|---|
| C(LOG361) | 4本 | 7回(18:13〜18:32) | 1回(18:16) | 持ち上げて箱の上で離した。ほかの6回は、18:13・18:24・18:25 を途中で止め、18:26 は箱の位置で離したが動画がなく入ったかは分からず、18:30・18:32 はつかみ損ねて止めた |
| D | 5本 | 1回(19:02) | 1回 | 離す直前に爪の先から抜け、箱の中に落ちた |
| E | 4本 | 2回(19:13・19:16)と、写り方の確認で止まった1回(19:14) | 1回(19:16) | 箱の手前の縁のすぐ上を通って、箱の上で離した |
- ねらい:位置C で入ったのが、その置き場所だけのたまたまかを確かめる
- 変わったこと:モデル・学習・クライアントの設定は前の回のまま、ブロックの置き場所だけを D と E に変えた
- 見込める効果:お手本のある3か所すべてで、1回以上箱に入った(入った回/動かした回は C 1/7・D 1/1・E 1/2。記録から数えた値)。置き場所によらず入る、という見込みが立ったので、次は1か所あたりの回数を増やして、入る割合を数えられる
ただ、入った3回のうち2回(D と E)はぎりぎりでした。今の割合のまま回数を増やすと、同じ理由で落ちたり縁に当たったりする回が出ると見ています(見込み)。
Pod を消す前に、サーバーのログを持ち帰った
位置E のあと、この回のテストを終えました。Pod を消すと中身がなくなるので、先にサーバーのログを Mac の KIOXIA へ持ち帰っています。
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % mkdir -p /Volumes/KIOXIA/r2r2r-data/lab/Log13
scp -P <SSH_PORT> -i ~/.ssh/id_ed25519 root@<POD_IP>:/workspace/logs/serve.log /Volumes/KIOXIA/r2r2r-data/lab/Log13/serve.log
serve.log 100% 2721 4.9KB/s 00:00
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts %
そのあと、Runpod の画面で Stop → Terminate を押して、Pod を消しました。
| 項目 | 値 |
|---|---|
| GPU | A40 × 1(Runpod) |
| 料金 | 1時間 0.62ドル(約98円) |
| 借りた時間 | 約1時間(Pod の画面の残高が 4.44ドル → 3.82ドル) |
| 費用 | 0.62ドル(約98円) |
| そのうちモデルを送る待ち | 約30分(6,340,573,809 バイト、1秒あたり約 3.9MB) |
| サーバーの起動 | モデルの読み込み 5.02 秒 |
| 実機の回 | 4回(位置D 1回、位置E 3回。うち1回は写り方の確認で止まった) |
次は C・D・E を何回かずつ動かして、箱に入る割合を数える
ここまでで、どの置き場所でも1回は入ることが分かりました。次は、同じやり方のまま、C・D・E を何回かずつ動かして、入る割合を数えます。そのときに見ておくことは次の3つです。
- 運ぶ間の肩の高さ。位置E のように、お手本より 4° 低いと箱の縁すれすれになる。ブロックを持っている間の肩の止まり方(目標より約 1〜3° 低い)が、毎回どのくらい出るか
- つかみの深さ。位置D のように爪の先でつかむと、回転を止めたときに抜ける。置いた位置のずれ(1cm 弱)と関係があるか
- 位置E のつかみ損ね。ブロックが爪の陰に隠れる場所で、置いた位置のずれがどこまで許されるか
Pod を借りるたびにモデル 6.3GB を送り直していて、借りた時間の半分がその待ちでした。何回も試すなら、モデルを Pod 側に置いたままにしておける方法(Runpod のネットワークボリュームなど)を、先に調べておくのがよさそうです(見込み)。
実機の回すべてのチャンクの記録
この回に動かした4回(位置D 1回、位置E 3回)の log.jsonl を、1行 = 1チャンクの表にしました。state は AI に渡した角度、measured はそのとき測った角度、target はそのチャンクの最後に送った目標です。
表を作ったスクリプト run_chunk_tables.py
"""LOG363: 2026-10-24 の π0.5 実機の回 (位置D・位置E) を, チャンクごとの表にする (読むだけ).
runs/pi05_policy/pi05_20261024_*/log.jsonl を読み, 1 行 = 1 チャンクで
推論時間 / 使ったステップ / モデルに渡した state / 送った目標 / グリッパー /
送ったか / 着いたか / state の出どころ / 中継点の数 を出す.
"""
import json, glob, os
ROOT = os.environ.get("PI05_RUNS", "/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_20261024_*")):
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']}")
for c in ch:
src = c.get("state_source", "measured")
vias = len(c.get("vias") or [])
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={vias}")
if src == "target" and c.get("measured_state"):
print(f" measured={f6(c['measured_state'])}")
出力 out_run_chunk_tables.txt
== pi05_20261024_190239 チャンク 17
framing dy=0.26 dx=1.41 response=0.574 -> OK
00 56893ms used=9 state=[ -0.1 +1.2 +1.5 +0.3 -0.3 -29.7] grip_state=0 src=measured target=[ -20.0 +19.8 +7.1 +1.0 -26.2 -31.4] grip=None exec=True arrived=True vias=4
01 815ms used=9 state=[ -20.0 +19.8 +7.1 +1.0 -26.2 -31.4] grip_state=0 src=target target=[ -41.4 +40.4 +14.4 +1.4 -54.5 -31.7] grip=None exec=True arrived=True vias=4
measured=[ -20.2 +20.8 +7.9 +0.7 -26.2 -31.1]
02 2178ms used=9 state=[ -41.4 +40.4 +14.4 +1.4 -54.5 -31.7] grip_state=0 src=target target=[ -57.5 +54.2 +20.8 +2.0 -74.2 -31.8] grip=None exec=True arrived=True vias=4
measured=[ -41.7 +41.4 +14.9 +1.8 -55.1 -31.4]
03 1036ms used=9 state=[ -57.5 +54.2 +20.8 +2.0 -74.2 -31.8] grip_state=0 src=target target=[ -59.0 +58.2 +18.3 +1.7 -67.1 -31.9] grip=None exec=True arrived=True vias=4図解の数字を作ったスクリプト figure_data.py
図解に入れた、ブロックを持っている間の土台 j0 と肩 j1 の組を作ったスクリプトと、その出力です。
# 図解 LOG363_shoulder_path.html に入れる数字を作る (LOG363)
# ブロックを持っている間の「土台 j0 (箱へ回った角度)」と「肩 j1 (小さいほど腕が上がっている)」の組
# お手本: 位置D 193404 / 位置E 194818 (10Hz の全ステップ)
# 実機: 位置D 190239 / 位置E 191603 の中継点ごとの目標 (target) と着いたあとの実測 (actual_after)
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"
out = {}
for pos, demo, run in [("D", "193404", "20261024_190239"), ("E", "194818", "20261024_191603")]:
S = np.load(f"{RAW}/run_0001_20261019_{demo}/episode.npz")["state"]
g = S[:, 6]; c = int(np.argmax(g > 0.5)); o = c + int(np.argmax(g[c:] < 0.5))
dm = [[round(float(s[0]), 1), round(float(s[1]), 1)] for s in S[c:o + 1]]
L = [json.loads(l) for l in open(f"runs/pi05_policy/pi05_{run}/log.jsonl")]
L = [x for x in L if "chunk" in x and x["state"][6] == 1]
tg, ac = [], []
for x in L:
for v in x.get("vias") or []:
tg.append([round(v["target"][0], 1), round(v["target"][1], 1)])
ac.append([round(v["actual_after"][0], 1), round(v["actual_after"][1], 1)])
out[pos] = {"demo": dm, "target": tg, "actual": ac}
print(json.dumps(out, ensure_ascii=False))
出力 out_figure_data.json
{"D": {"demo": [[-61.6, 62.5], [-61.6, 62.5], [-61.6, 62.5], [-61.6, 62.5], [-61.6, 62.5], [-61.6, 62.5], [-61.6, 62.5], [-61.6, 62.4], [-61.5, 61.8], [-61.3, 61.3], [-61.2, 60.7], [-61.1, 60.1], [-61.0, 59.6], [-60.8, 59.0], [-60.7, 58.5], [-60.6, 57.9], [-60.4, 57.4], [-60.3, 56.8], [-60.3, 56.7], [-60.3, 56.7], [-60.3, 56.7], [-59.8, 56.6], [-57.1, 56.2], [-54.3, 55.8], [-51.6, 55.4], [-48.9, 55.0], [-46.1, 54.6], [-43.4, 54.2], [-40.6, 53.9], [-37.9, 53.5], [-35.1, 53.1], [-32.4, 52.7], [-29.3, 52.2], [-26.1, 51.8], [-22.9, 51.3], [-19.7, 50.8], [-16.6, 50.4], [-13.6, 50.0], [-10.6, 49.6], [-7.8, 49.1], [-5.0, 48.6], [-2.2, 48.1], [0.7, 47.7], [3.7, 47.3], [6.6, 46.9], [9.7, 46.6], [12.9, 46.3], [16.1, 46.0], [19.3, 45.9], [22.4, 45.9], [25.5, 45.9], [28.6, 45.9], [31.5, 45.9], [34.5, 45.9], [37.2, 45.9], [39.2, 45.9], [41.2, 45.9], [43.2, 45.9], [43.3, 46.9], [43.3, 48.5], [43.4, 50.2], [43.4, 51.9], [43.5, 53.5], [43.5, 55.2], [43.6, 56.9], [43.6, 58.6], [43.7, 60.2], [43.7, 61.9], [43.8, 63.4], [43.8, 63.4], [43.8, 63.4], [43.8, 63.4]], "target": [[-59.4, 61.0], [-59.1, 60.1], [-59.4, 58.6], [-59.5, 58.4], [-59.6, 57.4], [-59.6, 56.7], [-59.1, 56.6], [-57.7, 56.4], [-49.7, 55.6], [-41.1, 54.5], [-32.6, 53.5], [-29.8, 53.2], [-20.6, 51.7], [-12.1, 50.4], [-3.3, 49.2], [-1.2, 49.3], [7.5, 48.0], [16.9, 47.0], [26.7, 46.5], [28.6, 46.6], [37.1, 46.1], [42.0, 46.6], [42.6, 51.0], [42.4, 52.6], [42.6, 57.8], [42.6, 61.9], [43.1, 63.0], [43.1, 63.0]], "actual": [[-59.0, 62.6], [-59.0, 62.0], [-59.1, 60.8], [-59.1, 60.8], [-59.1, 59.5], [-59.1, 59.2], [-59.1, 59.2], [-57.7, 58.9], [-50.1, 57.7], [-41.3, 56.9], [-32.9, 55.5], [-30.2, 55.5], [-20.8, 54.1], [-12.3, 52.6], [-3.5, 51.7], [-1.3, 51.7], [7.3, 50.5], [16.7, 49.7], [26.4, 48.8], [28.6, 48.8], [37.0, 48.8], [42.1, 48.8], [42.5, 52.2], [42.5, 53.8], [42.5, 58.9], [42.5, 63.1], [42.5, 64.1], [42.5, 64.1]]}, "E": {"demo": [[13.2, 60.0], [13.2, 60.0], [12.9, 60.0], [12.9, 60.0], [12.7, 60.0], [12.7, 58.9], [12.8, 57.6], [12.8, 56.4], [12.8, 55.1], [12.8, 53.8], [12.8, 52.6], [12.8, 51.3], [12.8, 50.0], [12.8, 48.8], [12.8, 47.5], [12.8, 46.3], [14.8, 46.6], [17.1, 46.9], [19.4, 47.2], [21.7, 47.5], [23.9, 47.8], [26.2, 48.1], [28.5, 48.4], [30.8, 48.8], [33.0, 49.1], [35.3, 49.4], [37.5, 49.7], [39.6, 50.2], [41.7, 50.7], [43.4, 51.1], [43.4, 52.6], [43.3, 54.1], [43.3, 55.6], [43.2, 57.1], [43.2, 58.6], [43.2, 60.1], [43.1, 61.5], [43.1, 63.0], [43.0, 64.5], [43.0, 66.0], [43.0, 66.9], [43.0, 66.9], [42.9, 66.9], [42.9, 66.9]], "target": [[12.0, 59.3], [12.1, 56.0], [12.0, 52.5], [12.1, 51.5], [11.8, 48.3], [16.7, 48.7], [23.3, 49.3], [25.0, 49.5], [31.5, 50.6], [38.4, 52.6], [42.4, 55.0], [42.7, 56.4], [42.8, 60.9], [42.9, 64.5], [42.9, 65.8], [42.9, 65.8]], "actual": [[11.9, 60.8], [11.9, 57.6], [11.9, 54.5], [11.9, 53.6], [11.9, 50.3], [16.6, 50.3], [23.3, 50.3], [25.0, 50.5], [31.6, 51.7], [38.3, 53.6], [42.3, 56.2], [42.4, 57.6], [43.0, 61.8], [43.0, 65.2], [43.0, 66.3], [43.0, 66.3]]}}
スクリプトは、Mac 連携の作業環境から、データの場所を環境変数で渡して動かしました(Mac で動かすときは、何も渡さなければ /Volumes/KIOXIA/r2r2r-data を読みます)。
export R2R2R_DATA=$HOME/mnt/KIOXIA/r2r2r-data PI05_RUNS=$HOME/mnt/KIOXIA/r2r2r-data/runs/pi05_policy
python3 run_chunk_tables.py > out_run_chunk_tables.txt
python3 de_vs_demo.py > out_de_vs_demo.txt
python3 block_position_mm.py > out_block_position_mm.txt
python3 figure_data.py > out_figure_data.json