4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ロボット初心者がLeRobot SO-101に挑戦(その2:模倣学習 ※奮闘中)

4
Last updated at Posted at 2025-12-04

この記事はフィジカルAIxロボティクス Advent Calendar 2025 の 5日目の記事です。


「ロボット初心者がLeRobot SO-101に挑戦」シリーズの2回目となります。 模倣学習があと一歩というところで奮闘中なのですが、いったんQiitaで晒します。

前回の記事はこちら


準備

LeRobot は、スマートフォンのカメラ、ノートPC内蔵カメラ、外付けWebカメラなど、複数の映像キャプチャ方法に対応している。
カメラから効率的にフレームを記録するには、OpenCVCamera クラスまたは RealSenseCamera クラスを使用できる。

カメラを見つける方法

カメラを利用するには、まず カメラ識別子(ID) が必要。
自分のPCに接続されているカメラのインデックスを調べるには、次のスクリプトを実行。

lerobot-find-cameras opencv

outputs/captured_images に画像が保存される。

MacとiPhoneのカメラが認識しなかったが、
iPhoneの「設定」>「一般」>「AirPlayとHandoff」>「連係カメラ」をオンにしたら、カメラを認識するようになった。

セッティング

ロボットアームに消しゴムを左側のケースに移動させることを学習させる。

Image from Gyazo

カメラを使ったテレオペレーション(遠隔操作)

模倣学習ではカメラを使ったテレオペレーションをする。
本番前に慣れる前に以下のコマンドを打つ。

※robot.camerasの「index_or_path」に、さきほど調べたカメラのIDを入れる。

lerobot-teleoperate \
    --robot.type=so101_follower \
    --robot.port=/dev/tty.usbmodem5AB90689241 \
    --robot.id=my_awesome_follower_arm \
    --robot.cameras="{ front: {type: opencv, index_or_path: 1, width: 1920, height: 1080, fps: 30}}" \
    --teleop.type=so101_leader \
    --teleop.port=/dev/tty.usbmodem5AB90691591 \
    --teleop.id=my_awesome_leader_arm \
    --display_data=true

Rerunというアプリケーションが立ち上がる。

スクリーンショット 2025-12-04 12.12.45.png

(参考)rerunをデフォルトの画面構成に戻したい場合

Rerun はいろいろ動かしているとビュー配置が崩れたり、カメラが消えたりするので、デフォルト構成に戻す方法は以下。
左側の Blueprint パネルの右上にある「…」(三点メニュー) をクリックし、「Reset to heuristic blueprint」 を選択する。
これで全レイアウト(チャート・画像ビューなど)が初期状態に戻る。


データセットの記録

テレオペレーションに慣れたら、最初のデータセットを記録してみよう。

データセットのアップロードには Hugging Face Hub の機能を使用する。

もし Hub を使うのが初めての場合は、書き込み権限つきのアクセストークンを使って CLI からログインできるようにすること。

このトークンは Hugging Face の設定ページから生成できる。
https://huggingface.co/security-checkup?cookieId=2d182f05-78ef-4a82-a88e-21f4f7869575

Writeタブで設定
スクリーンショット 2025-11-23 19.50.04.png

CLI にトークンを追加するには、次のコマンドを実行。

huggingface-cli login --token ${HUGGINGFACE_TOKEN} --add-to-git-credential

次に、Hugging Face リポジトリ名を変数に保存。

HF_USER=$(hf auth whoami | head -n 1)
echo $HF_USER

これでデータセットを記録できるようになった。

データセットをHubにアップロードするには、以下のコマンドを実行する。
(もちろんロボットのポートなどは、データセットのレポジトリIDなどは自分のに修正すること)

lerobot-record \
  --robot.type=so101_follower \
  --robot.port=/dev/tty.usbmodem5AB90689241 \
  --robot.id=my_awesome_follower_arm \
  --robot.cameras="{ front: {type: opencv, index_or_path: 1, width: 1920, height: 1080, fps: 30}}" \
  --teleop.type=so101_leader \
  --teleop.port=/dev/tty.usbmodem5AB90691591 \
  --teleop.id=my_awesome_leader_arm \
  --display_data=true \
  --dataset.repo_id=tatsuya1970/record-test \
  --dataset.root=./record-test-v3 \
  --dataset.single_task="Grab the eraser" \
  --dataset.num_episodes=20 \
  --dataset.episode_time_s=30 \
  --dataset.reset_time_s=10

コマンド説明

--dataset.episode_time_s=30
各データ収録エピソードの長さを指定する(デフォルトは 60 秒)。
--dataset.num_episodes=20
記録するエピソードの総数を指定する(デフォルトは 50)。
--dataset.reset_time_s=10
次のエピソードまでのインターバル

エラー

こんなエラーが出たら

FileExistsError: [Errno 17] File exists: 'record-test'

既存ファイルを消して取り直し

rm -rf record-test

途中から再開する場合

先ほどのコマンドの一番下に以下をつけて実行

--resume=true

つまり

lerobot-record \
  --robot.type=so101_follower \
  --robot.port=/dev/tty.usbmodem5AB90689241 \
  --robot.id=my_awesome_follower_arm \
  --robot.cameras="{ front: {type: opencv, index_or_path: 1, width: 1920, height: 1080, fps: 30}}" \
  --teleop.type=so101_leader \
  --teleop.port=/dev/tty.usbmodem5AB90691591 \
  --teleop.id=my_awesome_leader_arm \
  --display_data=true \
  --dataset.repo_id=tatsuya1970/record-test-v2 \
  --dataset.root=./record-test \
  --dataset.single_task="Grab the eraser" \
  --dataset.num_episodes=20 \
  --dataset.episode_time_s=30 \
  --dataset.reset_time_s=10 \
  --resume=true

※なお、
dataset.num_episodes は。「今から何回する」ということなので、注意。
例えば当初と同じ20にすると、今から20回記録することになる。

やり直しする場合

別のDataset を作成する。
(Hugging Face に空の Dataset を作る)

Hugging Faceの上部メニューの
「+ New」→「dataset」
Repo name を入力、
Private / Public はどちらでもOK(後で変えらる)
最後に「Create」 を押す。

ターミナルで、先ほどのデータセットを記録するコマンドをうつ。

つまり以下

lerobot-record \
  --robot.type=so101_follower \
  --robot.port=/dev/tty.usbmodem5AB90689241 \
  --robot.id=my_awesome_follower_arm \
  --robot.cameras="{ front: {type: opencv, index_or_path: 1, width: 1920, height: 1080, fps: 30}}" \
  --teleop.type=so101_leader \
  --teleop.port=/dev/tty.usbmodem5AB90691591 \
  --teleop.id=my_awesome_leader_arm \
  --display_data=true \
  --dataset.repo_id=tatsuya1970/record-test \
  --dataset.root=./record-test \
  --dataset.single_task="Grab the eraser" \
  --dataset.num_episodes=20 \
  --dataset.episode_time_s=30 \
  --dataset.reset_time_s=10

もしこんなエラーが出たら

RevisionNotFoundError: Your dataset must be tagged with a codebase version.
Assuming _version_ is the codebase_version value in the info.json, you can run this........

Hugging Face データセットに codebase_version 用のタグがないということなので、以下のコマンド実行してタグをつける。

python - << 'EOF'
from huggingface_hub import HfApi
from lerobot.datasets.lerobot_dataset import CODEBASE_VERSION

repo_id = "tatsuya1970/record-test"

print("CODEBASE_VERSION =", CODEBASE_VERSION)

api = HfApi()
api.create_tag(
    repo_id,
    tag=CODEBASE_VERSION,
    repo_type="dataset",
)

print("Tagged", repo_id, "with", CODEBASE_VERSION)
EOF

データセット

ローカルでは、データセットは次のフォルダに保存される:
~/.cache/huggingface/lerobot/{repo-id}

データ記録が終わると、データセットは自分の Hugging Face ページにアップロードされる
(例: https://huggingface.co/datasets/${HF_USER}/record-test )。

その URL は次のコマンドを実行することで取得できる。

echo https://huggingface.co/datasets/${HF_USER}/record-test

アップロードが済んだあとのエラー

アップロード済んだ後にエラーが出たら、
以下のプログラムで手動アップロード

python upload_dataset.py
upload_dataset.py
from huggingface_hub import HfApi, create_repo

repo_id = "tatsuya1970/record-test"
folder_path = "./record-test"

api = HfApi()

# まだリポジトリがなければ作成(あっても OK)
create_repo(repo_id, repo_type="dataset", exist_ok=True)

api.upload_folder(
    folder_path=folder_path,
    repo_id=repo_id,
    repo_type="dataset",
)

学習(Google Colab)

まず、学習中PCがスリープしないようにPCの設定をする。


いよいよ、収集したデータを模倣学習にて学習する。

私はGoogle Colab Pro(A100 GPU)を使用して学習を行った。

なお、Hagging Face上のチュートリアルのリンク先
https://colab.research.google.com/github/huggingface/notebooks/blob/main/lerobot/training-act.ipynb

は古いらしく、以下からは、ChatGPTに聞きながらやった。

Google Colab

Google Colabを開き、
まず、GPUの設定

Colab メニューから
「ランタイム」→「ランタイムのタイプを変更」
ハードウェア アクセラレータGPU「A100 GPU」を選択する。


Lerobot をインストールする。
!git clone https://github.com/huggingface/lerobot.git
%cd lerobot
!pip install -e .

依存関係の最新版を更新。

!pip install torch torchvision --upgrade

huggingface-hubをインストール(バージョン指定、Lerobot 0.4.x は 0.34〜1.0 未満しか対応していないため)

!pip install "huggingface-hub>=0.34.0,<1.0.0" --force-reinstall

Hugging Face にログイン

from huggingface_hub import login
login()

Hugging Face のアクセストークン(Write 以上、前に作ったもの)を貼り付けて Enter

スクリーンショット 2025-11-24 8.45.01.png

学習

以下のコマンドを実行。
stepsはデフォルトで10万、今回は5万でやってみた。

!lerobot-train \
  --dataset.repo_id=tatsuya1970/record-test \
  --dataset.video_backend=pyav \
  --batch_size=2 \
  --num_workers=0 \
  --policy.type=act \
  --policy.device=cuda \
  --steps=50000 \
  --output_dir=/content/lerobot/outputs/train/fast_run0 \
  --policy.repo_id=tatsuya1970/lerobot-fast-policy \
  --policy.push_to_hub=true \
  --wandb.enable=false

エラー

以下のエラーが出たら、

RevisionNotFoundError: Your dataset must be tagged with a codebase version.

LeRobot はローカルのデータセットのフォルダ内のmeta/info.json の "codebase_version" と同じ名前の タグ が、Hugging Face 上のデータセットに付いていないと、学習を始めてくれない。
例えば、"codebase_version": "v3.0"と記載の場合、Google Colabで以下のコマンドを打つ。

from huggingface_hub import HfApi

api = HfApi()
api.create_tag(
    repo_id="tatsuya1970/record-test",  # データセット名
    tag="v3.0",                         # info.json の codebase_version と同じ
    repo_type="dataset",
)

学習中のログ(例)

INFO 2025-11-30 04:57:50 ot_train.py:354 step:20K smpl:41K ep:137 epch:68.57 loss:0.120 grdn:26.451 lr:1.0e-05 updt_s:0.078 data_s:0.093
INFO 2025-11-30 04:58:24 ot_train.py:354 step:21K smpl:41K ep:138 epch:69.24 loss:0.114 grdn:25.154 lr:1.0e-05 updt_s:0.078 data_s:0.092
INFO 2025-11-30 04:58:59 ot_train.py:354 step:21K smpl:42K ep:140 epch:69.92 loss:0.112 grdn:24.538 lr:1.0e-05 updt_s:0.080 data_s:0.094

step — 学習ステップ数(反復回数)
smpl — 観測サンプル(フレーム)の累計数
ep — 擬似エピソードカウント
epch — エポック数(=何周したか)
loss — 損失(訓練誤差)
grdn — 勾配ノルム(gradient norm)
lr — 学習率(learning rate)
updt_s — 学習(モデル更新)にかかる時間 / step
data_s — データロードにかかる時間 / step


学習終了 (約3時間30分)

NFO 2025-12-04 08:21:18 ot_train.py:357 step:50K smpl:100K ep:111 epch:5.57 loss:0.122 grdn:12.082 lr:1.0e-05 updt_s:0.087 data_s:0.151
INFO 2025-12-04 08:21:18 ot_train.py:367 Checkpoint policy after step 50000
INFO 2025-12-04 08:21:19 ot_train.py:438 End of training
Processing Files (0 / 0)      : |          |  0.00B /  0.00B            
New Data Upload               : |          |  0.00B /  0.00B            

PCのスリープ設定をもとに戻す。


推論実行・ポリシー評価(ロボット制御)

改めてlerobot 環境を作る(Python 3.10)

conda deactivate   # いったん抜ける(今 lerobot 環境の中なら)
conda env remove -n lerobot

conda create -n lerobot python=3.10 -y
conda activate lerobot

lerobotをインストール

pip install "lerobot[teleop]"

インストール確認

python -c "import lerobot, inspect; print('lerobot', lerobot.__version__); "

サーボモーターのSDKをインストール

pip install feetech-servo-sdk

古いデータセットのローカルフォルダやキャッシュが残っていると、LeRobot がデータを読み込む際にエラーになる場合があるので、以下を削除する。

rm -rf eval_fast_policy_so101
rm -rf ~/.cache/huggingface/lerobot/tatsuya1970/eval_fast_policy_so101

カメラをPCに接続し、以下のコマンドを実行

※robot.camerasの「index_or_path」には冒頭調べたカメラのIDを入れる。

lerobot-record \
  --robot.type=so101_follower \
  --robot.port=/dev/tty.usbmodem5AB90689241 \
  --robot.id=my_awesome_follower_arm \
  --robot.cameras='{front: {type: opencv, index_or_path: 1, width: 1920, height: 1080, fps: 30}}' \
  --dataset.repo_id=tatsuya1970/eval_fast_policy_so101 \
  --dataset.single_task="Grab the eraser" \
  --dataset.num_episodes=5 \
  --dataset.episode_time_s=30 \
  --dataset.reset_time_s=0 \   #ゼロ超だと不具合になる
  --dataset.push_to_hub=false \
  --policy.path=tatsuya1970/lerobot-fast-policy \
  --policy.device=mps

動いた!!

けど、あまり、うまく行かなかった。

データセットが少ない(20セット)のか、学習量が少ない(5万steps)のか、カメラの位置が悪いのか?
引き続き、試行錯誤します。




P.S.モーターが機能してるか調べるには

モータが機能してるか疑義がある場合、以下のコードをそのままターミナルへコピペしてエンター。

python - << 'EOF'
from scservo_sdk import *
import time

port = "/dev/tty.usbmodem5AB90689241"
baud = 1000000

portHandler = PortHandler(port)
packetHandler = PacketHandler(2.0)

portHandler.openPort()
portHandler.setBaudRate(baud)

print("Scanning for motors...")
for i in range(1, 20):
    dxl_model, dxl_comm_result, dxl_error = packetHandler.ping(portHandler, i)
    if dxl_comm_result == COMM_SUCCESS:
        print(f"Found motor ID={i}, model={dxl_model}")
    time.sleep(0.05)

portHandler.closePort()
EOF

これが以下の結果ならモーターは正常。

Found motor ID=1, model=2307
Found motor ID=2, model=2307
Found motor ID=3, model=2307
Found motor ID=4, model=2307
Found motor ID=5, model=2307
Found motor ID=6, model=2307

違ってたら、モーターIDを再度セットする。
セット方法はこちら

以上



4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?