こんにちは! ABEJAでエンジニアをしている宇留嶋です。 ついに今年もこの季節がやってきました、ABEJAアドベントカレンダー2025、開幕です! 今年も25日間、ABEJAメンバーが総力を挙げてテックブログを毎日お届けします。
2025年のABEJAを象徴する濃厚な技術記事を怒涛の勢いで公開していきますのでよろしくお願いします! そしてこの記事は、
ABEJAアドベントカレンダー2025
記念すべき1日目の記事です。 ロボットアームによる物体操作タスクでは、環境の変化や対象物の多様性に対して柔軟に適応できるモデルが求められています。単純な反復作業にとどまらず、位置のずれ・カメラ視点の揺らぎ・背景の変化といった実世界特有のノイズに強く、かつ人間が自然言語で記述する指示に従って操作を生成できる能力が不可欠になっています。 今回使用する π0.5は、こうした課題に向けて設計された Vision-Language-Action(VLA)モデルであり、多様なロボットデータ・Webデータ・高レベルサブタスク推論データを統合した大規模な事前学習により、実環境での高い汎化性能を実現しています。モデルは単にカメラ画像を入力してロボットの動作を予測するだけでなく、環境の意味理解、状況に応じたサブタスク判断、連続値のアクション生成までを一貫して処理できる点が特徴です。 本記事では、このπ0.5 を SO-101 アームに適用し、実際の物体操作タスクを実行した際のセットアップ、挙動の評価について紹介します。 π0.5の一つ前のモデルにあたるπ0については、以前以下ブログを公開しましたので是非ご覧ください。
tech-blog.abeja.asia π0.5は、多様な実世界データを統合して学習されたVision-Language-Actionモデルです。家庭環境で収集された約400時間の操作データだけでなく、異なるロボット構成で撮影されたクロスエンボディメントデータやWeb由来の画像・言語データを併せて学習しており、未知環境でも柔軟に動作できる汎化能力を持ちます。モデル内部では高レベル指示から意味的サブタスクを推定し、それを基に手先の軌道を連続値で生成する二段構成を採用しています。また、学習時の効率化のために離散トークン化したアクション表現を用い、実行時にはflow matchingで連続アクションを生成する仕組みにより、計算負荷と実機制御の滑らかさを両立している点も特徴です。 今回は以下の実験をします。 π0.5をゼロショットで動かしてみる 追加学習を全くしないでSO-101アームをどのくらい動かせるか実験します。 追加学習して動かしてみる データ収集を行い追加学習しどのくらいタスクを成功できるか実験します。 データ収集とは違う環境で動かしてみる 照明の強さが違う環境でどれくらいタスクが成功するか実験します。 Real-Time Action Chunkingの検証 最近LerobotにReal-Time Action Chunkingがマージされたので、おまけとして動かしてみます。 カメラはEMEET Webカメラを3台を使用し、トップ(真上から)、サイド、SO101アームのリストに設置しました。 以下のようなアルミフレームを使った環境で、カメラ、SO-101アームを固定し、実験を行いました。 タスクはpick&placeにして、1エピソード20秒、30fpsでデータ収集しました。 実際にデータセット作成に使用したコマンドは以下です。 50件データを取得しました。キューブの位置はランダムにしました。 インストラクションは以下を設定しました。 ベースモデル lerobot/pi05_baseを起点として、作成したデータセットでファインチューニングしました。 主要パラメータは以下のとおりです。 学習はGoogle Colab A100 で行いました。 コマンドは以下になります。 Colab Pro+プランだとGPU RAMは40.0 GBの上限があり、設定できるbatch_sizeは最大でも8でした。 ファインチューニングには約5時間かかり、スパイクはあるもののLossは下がっていました。 Mac Studio(Apple M3 Ultra, mps)上でπ0.5モデルを動作させて実施しました。 まずは追加学習をしていないベースモデルでpick&placeをしてみました。 lerobotのGithubにある以下のコードを今回は使って動かしました。 https://github.com/huggingface/lerobot/blob/main/examples/tutorial/pi0/using_pi0_example.py 結果は上記のようになりミドルポジションに一気に移動し、タスクを行うことすらできませんでした。 次に追加学習したモデルでpick&placeさせました。
以下π0.5モデルを使ってSO-101アームを動かすコマンドになります。 上記動画の様にタスクは成功し、20/25で成功しました。
失敗した場合ではエンドエフェクタはキューブに向いているのにもかかわらず、後少しの所で掴めないケースが多かったです。 次にデータ収集とは違う環境でpick&placeができるか評価しました。 照明がやや暗く、机の色が違う環境で動かしてみました。 上記の通り、pick&placeすることができで13/25成功することができました。
50%ですが、環境が変わっても一定タスクを行うことができ、π0.5の環境差異への強さが確認できます。 Real-Time Action ChunkingとはVLAモデルをリアルタイムで滑らかに動かすための、推論アルゴリズムのことです。 前チャンクの実行済み / 実行予定部分を見ながら、次チャンクを補完して滑らかに繋ぐことができ、推論遅延が起きても成功率が保てたり、同期推論より早くタスクを完了できたり、外的変化に強いというメリットがあります。 今回はReal-Time Action Chunkingをπ0.5で動かすために以下のLerobotのコードを用いました。 https://github.com/huggingface/lerobot/blob/main/examples/rtc/eval_with_real_robot.py コマンドとしては以下を実行しました。 上記動画の通り、通常の推論実行に比べて、推論が停止してロボットが動かなくなるタイミングはなくなるのですが、カクつきが多く、タスク実行に時間がかかる挙動となりました。タスクは19/25で成功しました。 今回の検証を通じて、π0.5はSO-101アームに対し少量の実データだけでも高い適応性を示し、環境差異に対して十分な汎化性能を発揮することが確認できました。一方でReal-Time Action Chunkingは推論停止がなくなる利点がある一方、滑らかさや動作速度に課題が残りました。今後も新たなVLAモデルの登場に合わせて、環境変化への強さ・リアルタイム性といった観点で継続的な検証を進め、実運用に耐えるロボット制御手法を探求していきたいと思います。 ABEJAは、テクノロジーの社会実装に取り組んでいます。 技術はもちろん、技術をどのようにして社会やビジネスに組み込んでいくかを考えるのが好きな方は、下記採用ページからエントリーください! (新卒の方やインターンシップのエントリーもお待ちしております!)
careers.abejainc.com 特に下記ポジションの募集を強化しています!ぜひ御覧ください!
はじめに
π0.5とは
実験計画

データセット作成
uv run lerobot-record \
--robot.type=so101_follower \
--robot.port=/dev/tty.usbmodem5A7A0161521 \
--robot.id=main_follower \
--robot.cameras="{ top: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}, side: {type: opencv, index_or_path: 1, width: 640, height: 480, fps: 30}, wrist: {type: opencv, index_or_path: 2, width: 640, height: 480, fps: 30}}" \
--teleop.type=so101_leader \
--teleop.port=/dev/tty.usbmodem5AA90178971 \
--teleop.id=main_leader \
--display_data=true \
--play_sounds=true \
--dataset.repo_id="dataset repo id" \
--dataset.single_task="Move the red cube into the black square area." \ # タスク指示文
--dataset.num_episodes=10 \
--dataset.episode_time_s=20 \
--dataset.reset_time_s=4 \
--dataset.fps=30 \
--dataset.video=true \
--dataset.push_to_hub=true
Move the red cube into the black square area.
π0.5のファインチューニング
uv run lerobot-train \
--dataset.repo_id="dataset repo id" \
--dataset.revision=main \
--dataset.video_backend=pyav \
--policy.type=pi05 \
--output_dir="output dir" \
--policy.repo_id="policy repo id" \
--policy.pretrained_path=lerobot/pi05_base \
--policy.compile_model=true \
--policy.gradient_checkpointing=true \
--policy.dtype=bfloat16 \
--policy.push_to_hub=true \
--policy.private=true \
--steps=10000 \
--policy.scheduler_decay_steps=10000 \
--policy.device=cuda \
--batch_size=8 \
--num_workers=2 \
--wandb.enable=true \
--job_name="job name"
評価
追加学習なしの評価
追加学習ありの評価
uv run lerobot-record \
--robot.type=so101_follower \
--robot.port="/dev/tty.usbmodem5A7A0161521" \
--robot.cameras="{ top: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}, side: {type: opencv, index_or_path: 1, width: 640, height: 480, fps: 30}, wrist: {type: opencv, index_or_path: 2, width: 640, height: 480, fps: 30}}" \
--robot.id=main_follower \
--dataset.repo_id="dataset repo id" \
--dataset.single_task="Move the red cube into the black square area." \
--dataset.num_episodes=1 \
--dataset.episode_time_s=300 \
--dataset.reset_time_s=5 \
--dataset.fps=30 \
--dataset.push_to_hub=false \
--policy.path="policy path" \
--policy.device=mps \
--display_data=true
データ収集とは違う環境での評価
Real-Time Action Chunkingの評価
uv run python lerobot/examples/rtc/eval_with_real_robot.py
--robot.type=so101_follower
--robot.port="/dev/tty.usbmodem5A7A0161521"
--robot.cameras="{ top: {type: opencv, index_or_path: 2, width: 640, height: 480, fps: 30}, side: {type: opencv, index_or_path: 1, width: 640, height: 480, fps: 30}, wrist: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}}"
--robot.id=main_follower
--policy.path="policy path"
--rtc.execution_horizon=10 # 1回で何ステップ分のアクションをまとめて出すか
--rtc.max_guidance_weight=1.0 # RTCのガイダンスの強さ
--rtc.enabled=true
--device=mps
--task="Move the red cube into the black square area."
--duration=120
結果まとめ
タスク
検証回数
成功回数
成功率
追加学習なし
25
0
0%
追加学習あり
25
20
80%
データ収集とは別環境
25
13
52%
Real-Time Action Chunking
25
19
76%
考察とまとめ
We Are Hiring!
