メインコンテンツまでスキップ

両腕 SO-ARM トレーニング完全ガイド

はじめに

このガイドでは、LeRobot を用いて両腕 SO-ARM ロボットシステムをトレーニングするための一連の手順を説明します。ハードウェアセットアップ、アームのキャリブレーション、両腕テレオペレーション、データセットの記録と管理、ACT ポリシーのトレーニング、実機ロボットへのデプロイまでをカバーします。これらの手順に従うことで、2 本のリーダーアームと 2 本のフォロワーアームでデモデータを収集し、模倣学習ポリシーを学習させ、実機ロボットにデプロイできます。

まず、以下のように配線を接続します。

役割ポート
左フォロワーアーム/dev/ttyACM0
右フォロワーアーム/dev/ttyACM1
左リーダーアーム/dev/ttyACM2
右リーダーアーム/dev/ttyACM3

フォロワーアームのタイプは so101_follower、リーダーアームのタイプは so101_leader です(LeRobot では、so100_leaderso101_leader は同じ実装を共有します)。


0. 前提条件

0.1 依存関係のインストール

環境構築については、SO-ARM チュートリアルを参照してください:

0.2 USB パーミッション

sudo chmod 666 /dev/ttyACM0 /dev/ttyACM1 /dev/ttyACM2 /dev/ttyACM3

1. キャリブレーション(重要なステップ)

1.1 左フォロワーアームのキャリブレーション

lerobot-calibrate \
--robot.type=so101_follower \
--robot.port=/dev/ttyACM0 \
--robot.id=my_awesome_bimanual_follower_left

1.2 右フォロワーアームのキャリブレーション

lerobot-calibrate \
--robot.type=so101_follower \
--robot.port=/dev/ttyACM1 \
--robot.id=my_awesome_bimanual_follower_right

1.3 左リーダーアームのキャリブレーション

lerobot-calibrate \
--teleop.type=so101_leader \
--teleop.port=/dev/ttyACM2 \
--teleop.id=my_awesome_bimanual_leader_left

1.4 右リーダーアームのキャリブレーション

lerobot-calibrate \
--teleop.type=so101_leader \
--teleop.port=/dev/ttyACM3 \
--teleop.id=my_awesome_bimanual_leader_right

キャリブレーション後、ファイルは次の場所に保存されます:

~/.cache/huggingface/lerobot/calibration/robots/so101_follower/my_awesome_bimanual_follower_left.json
~/.cache/huggingface/lerobot/calibration/robots/so101_follower/my_awesome_bimanual_follower_right.json
~/.cache/huggingface/lerobot/calibration/robots/so101_leader/my_awesome_bimanual_leader_left.json
~/.cache/huggingface/lerobot/calibration/robots/so101_leader/my_awesome_bimanual_leader_right.json

(オプション)以前に別の ID でキャリブレーションしている場合

例えば、以前に my_awesome_follower_arm1my_awesome_follower_arm2 などを使用していた場合は、キャリブレーションファイルをコピーできます:

CAL_DIR=~/.cache/huggingface/lerobot/calibration/robots

cp $CAL_DIR/so101_follower/my_awesome_follower_arm1.json \
$CAL_DIR/so101_follower/my_awesome_bimanual_follower_left.json

cp $CAL_DIR/so101_follower/my_awesome_follower_arm2.json \
$CAL_DIR/so101_follower/my_awesome_bimanual_follower_right.json

cp $CAL_DIR/so101_leader/my_awesome_leader_arm3.json \
$CAL_DIR/so101_leader/my_awesome_bimanual_leader_left.json

cp $CAL_DIR/so101_leader/my_awesome_leader_arm4.json \
$CAL_DIR/so101_leader/my_awesome_bimanual_leader_right.json

2. 両腕テレオペレーション

2.1 カメラなし

lerobot-teleoperate \
--robot.type=bi_so_follower \
--robot.left_arm_config.port=/dev/ttyACM0 \
--robot.right_arm_config.port=/dev/ttyACM1 \
--robot.id=my_awesome_bimanual_follower \
--teleop.type=bi_so_leader \
--teleop.left_arm_config.port=/dev/ttyACM2 \
--teleop.right_arm_config.port=/dev/ttyACM3 \
--teleop.id=my_awesome_bimanual_leader \
--display_data=true

2.2 カメラあり

カメラインデックスを確認するには lerobot-find-cameras opencv を使用できます。必要に応じてカメラを追加または削除することもできます。

lerobot-teleoperate \
--robot.type=bi_so_follower \
--robot.left_arm_config.port=/dev/ttyACM0 \
--robot.right_arm_config.port=/dev/ttyACM1 \
--robot.id=my_awesome_bimanual_follower \
--robot.left_arm_config.cameras='{
left_wrist: {"type": "opencv", "index_or_path": 2, "width": 640, "height": 480, "fps": 30}
}' \
--robot.right_arm_config.cameras='{
right_wrist: {"type": "opencv", "index_or_path": 4, "width": 640, "height": 480, "fps": 30}
}' \
--teleop.type=bi_so_leader \
--teleop.left_arm_config.port=/dev/ttyACM2 \
--teleop.right_arm_config.port=/dev/ttyACM3 \
--teleop.id=my_awesome_bimanual_leader \
--display_data=true

安全上の注意

  • フォロワーアーム同士が衝突しないよう、周囲の状況に注意してください。

3. データセットの記録

3.1 ローカルに保存(Hub にはアップロードしない)

--dataset.root--dataset.push_to_hub=false を追加します。

注意:repo_id には / を含める必要があります。ローカルデータセットの場合は、プレースホルダの接頭辞として local/ を使用できますが、実際にはアップロードされません。

lerobot-record \
--robot.type=bi_so_follower \
--robot.left_arm_config.port=/dev/ttyACM0 \
--robot.right_arm_config.port=/dev/ttyACM1 \
--robot.id=my_awesome_bimanual_follower \
--robot.left_arm_config.cameras='{
left_wrist: {"type": "opencv", "index_or_path": 2, "width": 640, "height": 480, "fps": 30}
}' \
--robot.right_arm_config.cameras='{
right_wrist: {"type": "opencv", "index_or_path": 4, "width": 640, "height": 480, "fps": 30}
}' \
--teleop.type=bi_so_leader \
--teleop.left_arm_config.port=/dev/ttyACM2 \
--teleop.right_arm_config.port=/dev/ttyACM3 \
--teleop.id=my_awesome_bimanual_leader \
--dataset.repo_id=seeed/bimanual_so101_task \
--dataset.push_to_hub=false \
--dataset.single_task="Pick the cube with left arm and hand it to right arm" \
--dataset.num_episodes=50 \
--dataset.fps=30 \
--dataset.episode_time_s=30 \
--dataset.reset_time_s=10 \
--dataset.video=true \
--dataset.vcodec=libsvtav1 \
--display_data=true

データは ~/.cache/huggingface/lerobot/seeed/bimanual_so101_task/ に保存され、次のような構造になります:

├── meta/
│ ├── info.json
│ ├── episodes/
│ ├── stats/
│ └── tasks/
├── data/
└── videos/

3.2 Hugging Face Hub へアップロード

自動的にアップロードしたい場合は、HF_USER を残し、rootpush_to_hub=false を削除します:

export HF_USER=your_hf_username

lerobot-record \
--robot.type=bi_so_follower \
--robot.left_arm_config.port=/dev/ttyACM1 \
--robot.right_arm_config.port=/dev/ttyACM2 \
--robot.id=my_awesome_bimanual_follower \
--robot.left_arm_config.cameras='{
left_wrist: {"type": "opencv", "index_or_path": 0, "width": 640, "height": 480, "fps": 30}
}' \
--robot.right_arm_config.cameras='{
right_wrist: {"type": "opencv", "index_or_path": 1, "width": 640, "height": 480, "fps": 30}
}' \
--teleop.type=bi_so_leader \
--teleop.left_arm_config.port=/dev/ttyACM3 \
--teleop.right_arm_config.port=/dev/ttyACM4 \
--teleop.id=my_awesome_bimanual_leader \
--dataset.repo_id=${HF_USER}/bimanual_so101_task \
--dataset.single_task="Pick the cube with left arm and hand it to right arm" \
--dataset.num_episodes=50 \
--dataset.fps=30 \
--dataset.episode_time_s=30 \
--dataset.reset_time_s=10 \
--dataset.video=true \
--dataset.vcodec=libsvtav1 \
--display_data=true

3.3 記録の継続(再開)

記録が予期せず終了した場合(例えば、リセットフェーズ中に右ボタンを押して終了した場合)や、複数回に分けて収集を完了したい場合は、--resume を使用して同じデータセットにエピソードを追加し続けることができます。

注意事項

  • 必ず --resume=true を追加してください。そうしないと、ディレクトリがすでに存在するために LeRobotDataset.create() がエラーを報告します。
  • --dataset.num_episodes今回記録するエピソード数を指し、目標の合計数ではありません。例えば、すでに 15 エピソードを記録済みで、50 まで増やしたい場合は 35 に設定します。
  • できるだけエピソード記録中、または自然な終了後に終了するようにし、「Reset the environment」フェーズ中の終了は避けてください(空のエピソード保存失敗を引き起こす可能性があります)。
lerobot-record \
--resume=true \
--robot.type=bi_so_follower \
--robot.left_arm_config.port=/dev/ttyACM0 \
--robot.right_arm_config.port=/dev/ttyACM1 \
--robot.id=my_awesome_bimanual_follower \
--robot.left_arm_config.cameras='{
left_wrist: {"type": "opencv", "index_or_path": 2, "width": 640, "height": 480, "fps": 30}
}' \
--robot.right_arm_config.cameras='{
right_wrist: {"type": "opencv", "index_or_path": 4, "width": 640, "height": 480, "fps": 30}
}' \
--teleop.type=bi_so_leader \
--teleop.left_arm_config.port=/dev/ttyACM2 \
--teleop.right_arm_config.port=/dev/ttyACM3 \
--teleop.id=my_awesome_bimanual_leader \
--dataset.repo_id=seeed/bimanual_so101_task \
--dataset.push_to_hub=false \
--dataset.single_task="Pick the cube with left arm and hand it to right arm" \
--dataset.num_episodes=35 \
--dataset.fps=30 \
--dataset.episode_time_s=30 \
--dataset.reset_time_s=10 \
--dataset.video=true \
--dataset.vcodec=libsvtav1 \
--display_data=true

3.4 エピソードの再生と削除

特定のエピソードを再生

lerobot-replay \
--robot.type=bi_so_follower \
--robot.left_arm_config.port=/dev/ttyACM0 \
--robot.right_arm_config.port=/dev/ttyACM1 \
--robot.id=my_awesome_bimanual_follower \
--dataset.repo_id=seeed/bimanual_so101_task \
--dataset.episode=24

episode は 0 始まりのインデックスなので、24 は 25 番目のエピソードを意味します。

特定のエピソードを削除

python -m lerobot.scripts.lerobot_edit_dataset \
--repo_id=seeed/bimanual_so101_task \
--operation.type=delete_episodes \
--operation.episode_indices="[24]"

削除後、データセットはその場で書き換えられ、元のデータは ~/.cache/huggingface/lerobot/seeed/bimanual_so101_task_old/ にバックアップされます。新しいデータセットが正しいことを確認したら、バックアップを手動で削除できます:

rm -rf ~/.cache/huggingface/lerobot/seeed/bimanual_so101_task_old

データセット全体を削除する

rm -rf ~/.cache/huggingface/lerobot/seeed/bimanual_so101_task_old

4. ACT の学習

4.1 ローカルデータセットから学習する

lerobot-train \
--dataset.repo_id=seeed/bimanual_so101_task \
--policy.type=act \
--policy.device=cuda \
--steps=60000 \
--output_dir=outputs/train/act_bimanual_so101 \
--wandb.enable=false \
--policy.push_to_hub=false

4.2 Hugging Face Hub から学習する

export HF_USER=your_hf_username

lerobot-train \
--dataset.repo_id=${HF_USER}/bimanual_so101_task \
--policy.type=act \
--policy.device=cuda \
--steps=100000 \
--output_dir=outputs/train/act_bimanual_so101 \
--wandb.enable=false \
--policy.push_to_hub=false

上記は ACT のデフォルトパラメータ(chunk_size=100dim_model=512 など)を使用しています。

5. 実機ロボットへのデプロイ

5.1 評価データをローカルに保存する

lerobot-record \
--robot.type=bi_so_follower \
--robot.left_arm_config.port=/dev/ttyACM0 \
--robot.right_arm_config.port=/dev/ttyACM1 \
--robot.id=my_awesome_bimanual_follower \
--robot.left_arm_config.cameras='{
left_wrist: {"type": "opencv", "index_or_path": 2, "width": 640, "height": 480, "fps": 30}
}' \
--robot.right_arm_config.cameras='{
right_wrist: {"type": "opencv", "index_or_path": 4, "width": 640, "height": 480, "fps": 30}
}' \
--dataset.root=seeed_eval/eval_bimanual_so101_task8 \
--dataset.push_to_hub=false \
--dataset.num_episodes=10 \
--dataset.single_task="Pick the cube with left arm and hand it to right arm" \
--dataset.fps=30 \
--dataset.video=true \
--policy.path=outputs/train/act_bimanual_so101/checkpoints/last/pretrained_model \
--display_data=true

5.2 Hugging Face Hub へアップロードする

export HF_USER=your_hf_username

lerobot-record \
--robot.type=bi_so_follower \
--robot.left_arm_config.port=/dev/ttyACM1 \
--robot.right_arm_config.port=/dev/ttyACM2 \
--robot.id=my_awesome_bimanual_follower \
--robot.left_arm_config.cameras='{
left_wrist: {"type": "opencv", "index_or_path": 0, "width": 640, "height": 480, "fps": 30}
}' \
--robot.right_arm_config.cameras='{
right_wrist: {"type": "opencv", "index_or_path": 1, "width": 640, "height": 480, "fps": 30}
}' \
--dataset.repo_id=${HF_USER}/eval_bimanual_so101_task \
--dataset.num_episodes=10 \
--dataset.single_task="Pick the cube with left arm and hand it to right arm" \
--dataset.fps=30 \
--dataset.video=true \
--policy.path=outputs/train/act_bimanual_so101/checkpoints/last/pretrained_model \
--display_data=true

6. FAQ

問題原因解決策
テレオペレーションで再キャリブレーションを求められるbi_so_follower_left / _right サフィックス付きのキャリブレーションファイルを見つけられない_left / _right を含む ID で再キャリブレーションするか、既存のキャリブレーションファイルをコピーする
リーダーアームを手で動かせないリーダーのトルクが無効化されていない再キャリブレーションするか、モーターを確認する
記録を継続するときに "Directory already exists" と表示される--resume=true が追加されていないlerobot-record コマンドに --resume=true を追加する
左右のアームが入れ替わっているポート設定の誤りleft_arm_config.portright_arm_config.port を入れ替える
学習中にデータセットが見つからないローカルデータセットの root が指定されていない学習時に --dataset.root=./datasets/xxx を追加する
データセットが自動的にアップロードされるpush_to_hub=false が設定されていない記録時に --dataset.push_to_hub=false を追加する
You must add one or several frames before calling add_episode で終了するリセットフェーズ中に終了したため、現在のエピソードにフレームがない既に記録済みのデータには影響しません。--resume=true を付けて記録を続行してください。現在のコードではこの状況は修正されており、空のエピソードは自動的にスキップされます
Loading Comments...