アーパボー(ARPABLE)
アープらしいエンジニア、それを称賛する言葉・・・アーパボー
ロボット

Behavior Cloningとは?SO-101とLeRobotによる行動ログ採取手順

Behavior Cloningとは?SO-101とLeRobotによる行動ログ採取手順

SO-101アームロボットの組み立てとサーボモータのキャリブレーションが終了し、実世界を動かすための強固な「ハードウェアの土台」が整いました。

ここから、Physical AI(物理実体を持つAI)の開発において最も重要となる「行動ログ(データセット)」を採取する具体的な手順、そしてそれをシミュレーターへ引き渡して「学習可能な仮想世界」を設計するための詳細な定義プロセスまでをステップ・バイ・ステップで解説します。

SO-101の次なるフェーズ:2つの主要作業

ハードウェアが完成した現在のフェーズは、Physical AI開発における「現実世界での観察」から「仮想世界の設計」へ移行する段階です。やるべき作業は大きく分けて以下の2つです。

1. Behavior Cloning(BC:模倣学習)データの収集

まずは現実世界でロボットを動かし、AIの手本となる行動ログを記録します。人間が「リーダーアーム」を動かし、それに追従して動く「フォロワーアーム」に特定のタスク(例:キューブを掴んで箱に入れる)を行わせます。この操作時のカメラ映像、関節状態(角度や速度)、グリッパーの開閉、動作タイミングなどを時系列データとして保存します。

2. Sim2Real環境への「3つの情報」の翻訳

行動ログが取れたら、それを材料にしてシミュレーター(NVIDIA Isaac Simなど)上に「学習可能な仮想世界」を設計します。必要な情報は以下の3つです。

  • 身体情報:SO-101の関節、リンク、可動域、カメラ配置などを仮想空間に再現する。
  • タスク定義:オブジェクトの初期位置や目標位置、作業台、制限時間などの舞台を設定する。
  • 成功基準(Ground Truth):「箱に入ったら成功」「机から落ちたら失敗」といった報酬関数(審判)を定義する。

失敗しないためのUbuntu環境セットアップ手順

SO-101およびNVIDIA Isaac Simを連携させる場合、USBデバイスのパススルーや通信遅延、GPU(CUDA)の挙動トラブルを避けるため、Windows環境(WSL2含む)ではなくUbuntu 22.04 LTS環境(ネイティブ)を強く推奨します。以下に詳細なセットアップ手順をまとめました。

手順1:OSとGPUドライバーの準備

NVIDIAのシミュレーション環境や学習を回すため、適切なGPUドライバーとCUDA環境を導入します。

# NVIDIA公式推奨ドライバーのインストール
sudo ubuntu-drivers install
sudo reboot

# CUDAのパスを通す(~/.bashrcの末尾に追加)
echo 'export PATH=/usr/local/cuda/bin:$PATH' >> ~/.bashrc
echo 'export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH' >> ~/.bashrc
source ~/.bashrc

手順2:USB・シリアル通信の権限付与(最重要)

アームやカメラを接続した際、一般ユーザー権限のままだとアクセス拒否エラー(Permission denied)になります。事前に通信グループへユーザーを追加してください。

# シリアル通信(dialout)権限の付与
sudo usermod -aG dialout $USER

# ビデオカメラ(video)権限の付与
sudo usermod -aG video $USER

⚠️注意:この設定を反映させるため、コマンド実行後は必ず一度PCを再起動(またはログアウト&再ログイン)してください。

手順3:Python仮想環境の構築とLeRobotの導入

Miniconda等を用いて独立したPython環境を作成し、LeRobotと必要な依存パッケージをインストールします。

# Python 3.10環境の作成とアクティベート
conda create -y -n lerobot python=3.10
conda activate lerobot

# LeRobotリポジトリのクローンとインストール
git clone https://github.com/huggingface/lerobot.git
cd lerobot
pip install -e "."
pip install -e ".[opencv,intel]"

実践!行動ログ(データセット)の採取手順

環境が整ったら、いよいよアームを接続して行動ログの記録を開始します。

ステップ1:物理接続とカメラの「超重要」配置

リーダーアームとフォロワーアームをそれぞれPCのUSBポートに接続します。端末(ターミナル)を開き、以下のコマンドでポートが認識されているか確認します。

# シリアルポートの認識確認
ls -l /dev/ttyACM*
# または
ls -l /dev/ttyUSB*

通常、/dev/ttyACM0/dev/ttyACM1 のように2つ認識されます。どちらがリーダーでどちらがフォロワーかは、のちのテストで判別します。

次に、USBカメラを作業スペースに向けて設置します。ここで最大の肝となるのがカメラの画角です。

💡画角の超重要注意点
カメラには「フォロワーアーム」と「操作対象(キューブ等)」だけが映るように固定してください。操作する「リーダーアーム」や「人間の手・影」が絶対に映り込まないようにします。人間の手が映ると、AIはアームの動かし方ではなく「人間の手の動き」を学習してしまい、自動駆動時に全く動かなくなります。

ステップ2:Hugging Face Hubへのログインとカメラ確認

採取したデータをクラウドで管理するため、あらかじめ書き込み権限(Write)付きで作成したトークンを使いログインします。

export HF_TOKEN="ご自身のトークン"
hf auth login --token $HF_TOKEN --add-to-git-credential

# カメラのインデックス番号と画角の確認
lerobot-find-cameras opencv

※ コマンドを実行すると、~/lerobot/outputs/captured_images にテスト撮影された画像が保存されます。画像を確認し、アームが綺麗に収まっているか、カメラのインデックス番号(0 や 1 など)が何番になっているかをメモしておきます。

ステップ3:記録コマンドの実行

以下のコマンド(LeRobot標準のレコードスクリプト)をカスタマイズして実行します。ポート番号やカメラのインデックスはご自身の環境に合わせて書き換えてください。

lerobot-record \
  --robot.type=so101_follower \
  --robot.port=/dev/ttyACM0 \
  --robot.id=my_follower_arm \
  --teleop.type=so101_leader \
  --teleop.port=/dev/ttyACM1 \
  --teleop.id=my_leader_arm \
  --robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}}" \
  --display_data=true \
  --dataset.repo_id=${HF_USER}/so101-cube-task \
  --dataset.single_task="Grab the cube and put it in the box" \
  --dataset.num_episodes=20 \
  --dataset.episode_time_s=30

💡 引数(パラメーター)の解説:ここだけ書き換えればOK!

  • --robot.port / --teleop.port : ステップ1で確認したポート(ACM0やACM1)を指定します。もし動かしてみて「リーダーとフォロワーの挙動が逆」だったら、この2つの記述を入れ替えてください。
  • index_or_path: 0 : ステップ2で確認したカメラのインデックス番号を入れます。
  • --dataset.num_episodes=20 : 何回分の成功データを取るか(エピソード数)です。最初はテスト用に 2 程度にして動作確認し、本番は 20〜50 程度を目標にします。
  • --dataset.episode_time_s=30 : 1回の操作(掴んで箱に入れるまで)の制限時間(秒)です。余裕を持った時間を設定します。

ステップ4:実際の記録ワークフロー(人間の操作手順)

コマンドを実行すると、システムが起動し、画面に案内(プロンプト)が表示されます。ここからは「人間がロボットを動かして手本を見せる」時間です。

  1. 開始前の初期配置:フォロワーアームの前に、タスクの対象物(キューブ等)を置きます。
  2. エピソード(1回目)の開始:ターミナル画面に Press Enter to start recording... などの指示が出るので、キーボードの「Enter」キーを押すと、ログの録画・録音がスタートします。
  3. 人間による実演(テレオペ):リーダーアームを優しく掴み、フォロワーアームを動かって「キューブを掴む ➔ 箱に入れる」という一連の動作をスムーズに行います。
  4. エピソードの終了:無事に箱に入り、タスクが成功したら、制限時間を待つか、指定のキー(EscapeやEnterなど画面に表示されるキー)を押してそのエピソードの記録を終了します。
  5. ★ここが最重要:配置を「ランダムに」変えて繰り返す:次のエピソード(2回目)を開始する前に、キューブの初期位置や箱の位置を、毎回数センチずつわざとズラして配置してください。

💡 なぜ?
毎回全く同じ場所からスタートすると、AIは「その絶対座標に手を伸ばすこと」しか学べず、少しでもズレると対応できない応用力のないAIになってしまいます。シミュレーター(Sim2Real)に渡した時に「位置のバリエーション」を認識させるため、意図的に毎回バラバラな位置から成功させてください。

  • 保存とアップロード:指定した回数(例:20回)を繰り返し終えると、記録が自動でストップします。データは自動的に「LeRobotDataset形式」としてローカルに保存され、Hugging Face Hubのリポジトリへ自動でアップロード(プッシュ)されます。

仮想世界の設計:Sim2Real環境へ「3つの情報」を定義・翻訳する

実機でのデータ採取が終わったら、次はいよいよ本番である仮想世界の設計(Sim2Real環境の構築)です。採取した行動ログ(BCデータ)を単にシミュレーターに流し込むのではなく、シミュレーター(NVIDIA Isaac Sim / Isaac Lab)の中に「ロボットが自ら試行錯誤して学習できる仮想世界」として再構築する必要があります。なぜこれらの情報を定義しなければならないのか、その背景と具体的なシステム内部の仕組みを詳細に解説します。

1. 身体情報の定義:ロボットの身体を仮想空間に再現する

シミュレーター内でロボットを現実と同様に動かすためには、単なる「3Dの見た目(ビジュアル)」だけでなく、「質量」「慣性」「関節の特性」といった物理特性(ダイナミクス)を正確に再現する必要があります。

① URDFからUSDへの変換

URDF(Unified Robot Description Format)は、ロボットのどの部品(リンク)と部品がどのような関節(ジョイント)で繋がっているか、可動域や重量、3Dモデルのファイルパスが記述されたXML形式のファイルです。これをNVIDIA OmniverseやIsaac Simの基盤フォーマットである「USD(Universal Scene Description)」に変換することで、シミュレーター内の物理エンジン(PhysX)が、SO-101の「重さ」や「重心」「関節のつながり」を物理演算の対象として認識できるようになります。

② BCデータをパラメーターにどう反映させるか?

現実のサーボモータには、電気的な遅延、ギアのバックラッシュ(遊び)、摩擦、命令に対する応答のズレ(追従性の限界)が存在します。シミュレーター上の関節(Joint Drive)には、これらの特性を合わせるために剛性(Stiffness / Kpゲイン)減衰(Damping / Kdゲイン)を設定します。剛性を上げると命令通りにカチッと動き、下げると現実のロボットのように「負荷がかかると少ししなる(追従が遅れる)」ようになります。

人間がリーダーアームを急に動かした時、フォロワーアームの関節角度が「どれくらいの遅れ(ミリ秒)」で、かつ「どれくらい目標値をオーバーシュートして追従したか」を行動ログから分析し、この実機の癖とシミュレーターの挙動が一致するように値をチューニングします。これがズレていると、シミュレーションで学習したAIを実機に戻した際、モーターの出力不足や過剰反応でアームが激しく発振(ガタガタ震える)原因になります。

# Isaac Sim Python APIによる関節パラメーターの設定例
from omni.isaac.core.robots import Robot

# ステージ上のSO-101を読み込み
my_so101 = Robot(prim_path="/World/SO101_Follower", name="so101")
my_so101.initialize()

# 各関節のサーボゲイン(剛性と減衰)を実機に合わせてチューニング
for joint_name in my_so101.dof_names:
    joint_idx = my_so101.get_dof_index(joint_name)
    # 実機の応答速度や保持力に合わせて数値を調整
    my_so101.get_joint_driving_properties(joint_idx).stiffness = 400.0
    my_so101.get_joint_driving_properties(joint_idx).damping = 40.0

2. タスク定義:作業の舞台を作る

ロボットの身体ができたら、次は「何をどこからどこへ動かすか」という環境(舞台)のルール化を行います。

① 3D配置と物理属性の設定

Isaac Simの3D空間に、作業台(Table)、操作対象(Cube)、箱(Box)のUSDモデルを配置します。重要なのは「衝突属性(Colliders)」と「摩擦(Friction)」の設定です。もし衝突属性を設定し忘れると、ロボットの手先がキューブや机をすり抜けてしまいます。また、現実のグリッパー(指先)の滑り止め素材とキューブの間の「摩擦係数」を現実の物理特性に合わせて設定します。これが適切でないと、シミュレーター内では簡単に掴めたのに、現実ではツルツル滑って落とすというシミュレーションギャップが発生します。

② BCデータから「初期位置の範囲」や「制約」を定義する

人間が行動ログを取る際、キューブの位置を毎回わざと数センチずつズラして記録した「ズラした範囲の最大値・最小値(例:X軸にプラスマイナス5cmなど)」をログから割り出し、シミュレーターが新しい学習(エピソード)を始める際、その範囲内のランダムな座標にキューブを自動発生させるようにプログラムします。

また、人間の操作ログを見ることで、「これ以上高くアームを上げたらカメラの画角から外れてしまう」「この領域はアームのケーブルが引っかかるので通ってはいけない」という現実の制約(ワークスペースの限界)を割り出し、シミュレーター内にもシステム的な制約(境界クランプ)をかけます。

# 毎エピソード開始時にオブジェクトの位置をランダム化するロジック(Isaac Lab風の記述例)
import numpy as np

def reset_target_position():
    # 行動ログから算出した「人間が置く範囲」の最小・最大値(単位:メートル)
    x_range = [0.2, 0.4]  # ロボットの前方20cm〜40cm
    y_range = [-0.1, 0.1] # 左右に10cmの幅
    z_fixed = 0.02        # 机の上の高さ(固定)

    # 範囲内でランダムな座標を生成
    random_x = np.random.uniform(x_range[0], x_range



)
    random_y = np.random.uniform(y_range[0], y_range



)
    
    return [random_x, random_y, z_fixed]

3. 成功基準 / Ground Truth:学習の審判(報酬関数)を作る

強化学習(Reinforcement Learning)やAIの評価において、最も難易度が高く、アルゴリズムの性能を左右するのがこの「審判の設計」ステップです。

① Ground Truth(グラウンド・トゥルース:真値)とは?

現実世界では、ロボットは「カメラに映った映像のピクセルデータ」や「サーボの不正確なセンサー値」からしかキューブの位置を推測できません。しかし、シミュレーターの内部(仮想世界)では、キューブの中心座標や、グリッパーの内側に何ニュートンの力がかかっているかという「絶対的な正解データ(Ground Truth)」をリアルタイム(1コマごと)に取得できます。このGround Truthを使って、ロボットの行動を採点するプログラム(報酬関数)を書きます。

② 判定項目と報酬関数の詳細設計

強化学習では、ただ「箱に入ったら100点、それ以外は0点」というような極端な採点(Sparse Reward:疎な報酬)にすると、ロボットは偶然成功するまで何万回もアームをデタラメに振り回すことになり、学習が全く進みません。そのため、以下のようにステップごとのご褒美(Dense Reward:密な報酬)を設計します。

判定項目 シミュレーターへの実装内容(報酬関数) 終了条件(Terminations)
成功条件 キューブのGround Truth座標($P_{cube}$)が、箱の目標座標領域($P_{goal}$)の中に完全に含まれた瞬間、エピソードを「成功」と判定し、大きなプラス報酬を与えてその回の学習を終了(リセット)します。 タスク達成としてエピソード終了
中間評価
(Dense Reward)
接近報酬: グリッパーの先端座標とキューブの距離を計算し、近づくほど毎フレーム加点(距離の逆数)されるようにします。これによりAIはまず「キューブに手を伸ばすこと」を覚えます。
把持報酬: グリッパー内側の接触センサー値を監視し、キューブに対して一定以上の力がかかったら「上手く掴めている」として加点します。
運搬報酬: キューブを掴んだ状態のまま、キューブと箱(ゴール)の距離が縮まるほど追加で加点します。
継続(次のステップへ)
失敗・危険条件 落下ペナルティ: キューブのZ座標(高さ)が机より下になった(床に落とした)と判定し、マイナス減点します。
関節限界ペナルティ: モーターの可動域限界までアームを無理に曲げようとした場合、実機なら過負荷で壊れるリスクがあるため、限界に達した瞬間に減点します。
即座に失敗としてエピソード終了(強制リセット)
制限時間切れ 1エピソード(例:30秒=900ステップ)以内に成功しなかった場合、追加の報酬なしで終了。アームが虚空を彷徨い続ける無駄な計算時間を省きます。 時間切れとしてリセット
# 報酬関数(Reward Function)の実装サンプル(Gym / Isaac Lab環境のインライン例)
import math

def compute_reward(ee_pos, cube_pos, goal_pos, is_contacted):
    reward = 0.0
    
    # 1. 距離ベース of 報酬:手先(End Effector)とキューブの距離を縮める
    dist_ee_to_cube = math.dist(ee_pos, cube_pos)
    reward += 1.0 / (1.0 + dist_ee_to_cube) # 近づくほど最大+1.0の報酬
    
    # 2. 把持成功報酬:接触センサーが反応していれば追加加算
    if is_contacted:
        reward += 2.0
        # 3. ゴールアプローチ報酬:掴んだ状態でキューブを箱に近づける
        dist_cube_to_goal = math.dist(cube_pos, goal_pos)
        reward += 2.0 / (1.0 + dist_cube_to_goal)
        
    # 4. 完全成功報酬(大ボーナス)
    if math.dist(cube_pos, goal_pos) < 0.05: # 箱の5cm以内にキューブが入った
        reward += 100.0
        
    return reward

まとめ:よくある誤解と次のステップ

Sim2Real(シミュレーションから現実への移行)を進める上で、最も陥りやすい失敗パターンをまとめました。

失敗パターン 原因 正しいアプローチ
BCログをそのまま再生しようとする シミュレーターを単なる「学習器(再生機)」と誤解している BCログから身体・タスク・成功基準を抽出し、仮想世界として再定義する
ロボットの見た目だけ作って学習が進まない タスク定義や成功・失敗の判定条件(報酬関数)が不足している 対象物の座標、終了条件、中間評価をシミュレーターに教え込む

無事に行動ログが採取できたら、まずは「LeRobot Dataset Visualizer」などで、アームの関節角度グラフとカメラ映像が完全に同期して記録されているかチェックしましょう。

問題がなければ、このデータをインプット(翻訳の材料)として、今回詳細に定義したシミュレーター(NVIDIA Isaac Sim / Isaac Lab)上の仮想空間に「SO-101が自律的に学習できる世界」を構築するフェーズへと進むことができます。

この3つの情報の定義がコードとして実装されることで、ロボットはコンピューターの中で「自分で動いてみる ➔ 審判に採点される ➔ 失敗してリセットされる」というサイクルを現実の100倍以上の超高速で回し、自律的に賢くなっていくことが可能になります。

Physical AIの核心的な設計パターンを、ぜひ手元の実機とシミュレーターで体験していきましょう!

参考サイト

  • Hugging Face LeRobot 公式GitHubリポジトリ
    SO-101アームロボットを制御するためのソースコードの管理や、最新のアップデート、トラブルシューティング(Issues)を確認できる最重要の一次ソースです。
    huggingface/lerobot – GitHub
  • Hugging Face LeRobot 公式ドキュメント
    Behavior Cloning(模倣学習)のチュートリアルや、lerobot-recordコマンドをはじめとする各種データセット採取ツールの詳細な使い方が体系的にまとめられている公式マニュアルです。
    LeRobot Documentation – Hugging Face
  • NVIDIA Isaac Sim 公式ドキュメント
    身体情報のインポート(URDFからUSDへの変換手順)や、物理エンジンの設定、仮想空間内へのオブジェクト配置など、シミュレーターを動かすための基本操作を網羅した公式リファレンスです。
    What Is Isaac Sim? — Isaac Sim Documentation
  • NVIDIA Isaac Lab 公式ドキュメント
    シミュレーター内にタスク環境を定義し、報酬関数(Reward Function)の記述や終了条件をプログラムして強化学習を回すための、ロボット学習専用フレームワークの公式ドキュメントです。
    Isaac Lab Documentation
  • Hugging Face Hub LeRobotコミュニティページ
    世界中のエンジニアが公開しているロボット学習用のデータセットや、事前学習済みモデルがホストされているリポジトリです。自身で採取したSO-101の行動ログの管理や、他ユーザーのデータ構造を参考にする際に必須となります。
    LeRobot Organization – Hugging Face Hub

合わせて読みたい

変更履歴

  • 2026年5月26日:初稿アップ
ABOUT ME
ケニー 狩野
ケニー狩野(Kenny Kano)は、AI社会実装・技術経営・ITコンサルティングを専門とする経営者・監修者。株式会社ベーネテック代表、株式会社アープ取締役、一般社団法人Society 5.0振興協会 AI社会実装推進委員長。早稲田大学大学院理工学研究科修了後、キヤノンで国内外の開発や中国・インド・オーストラリアを含むオフショア案件を牽引。独立後はAI社会実装支援に従事し、Arpableで人工知能・先端技術分野の記事を約2年間で約300本監修。中小企業診断士、PMP、ITコーディネータ。著書『リアル・イノベーション・マインド』。実務と経営を橋渡しする。