0
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?

SO-101 コマンド覚書

Last updated at Posted at 2026-01-07

a.ローカル(mac)でSO-101を動作させる

a-1.Motors Busの検出とUSBポート番号の確認

コマンド

$ lerobot-find-port

結果

['/dev/ttyw4', '/dev/ttyw5', '/dev/ttyw6', '/dev/ttyw7', '/dev/ttyw8', '/dev/ttyw9', '/dev/ttywa', '/dev/ttywb', '/dev/ttywc', '/dev/ttywd', '/dev/ttywe', '/dev/ttywf', '/dev/tty.debug-console', '/dev/tty.Bluetooth-Incoming-Port', '/dev/ttys000', '/dev/ttys001', '/dev/ttys002', '/dev/ttys003', '/dev/tty.usbmodem5AB90676501', '/dev/tty.usbmodem5AB90669021']

> '/dev/tty.usbmodem5AB90676501' leader
> '/dev/tty.usbmodem5AB90669021' follow

a-2.リーダーのモーター初期化、設定

コマンド

$ lerobot-setup-motors --teleop.type=so101_leader --teleop.port=/dev/tty.usbmodem5AB90676501

結果。番号が表示される順番にモーターを接続してエンターを押す。
(組み立て順とは異なって、グリッパー側の6番から番号が割り振られることに注意)

% lerobot-setup-motors --teleop.type=so101_leader --teleop.port=/dev/tty.usbmodem5AB90676501
Connect the controller board to the 'gripper' motor only and press enter.
'gripper' motor id set to 6
Connect the controller board to the 'wrist_roll' motor only and press enter.
'wrist_roll' motor id set to 5
Connect the controller board to the 'wrist_flex' motor only and press enter.
'wrist_flex' motor id set to 4
Connect the controller board to the 'elbow_flex' motor only and press enter.
'elbow_flex' motor id set to 3
Connect the controller board to the 'shoulder_lift' motor only and press enter.
'shoulder_lift' motor id set to 2
Connect the controller board to the 'shoulder_pan' motor only and press enter.
'shoulder_pan' motor id set to 1

a-3.フォロワーのモーター初期化、設定

コマンド

$ lerobot-setup-motors --robot.type=so101_follower --robot.port=/dev/tty.usbmodem5AB90669021

結果。番号が表示される順番にモーターを接続してエンターを押す。
(組み立て順とは異なって、グリッパー側の6番から番号が割り振られることに注意)

% lerobot-setup-motors --robot.type=so101_follower --robot.port=/dev/tty.usbmodem5AB90669021
Connect the controller board to the 'gripper' motor only and press enter.
'gripper' motor id set to 6
Connect the controller board to the 'wrist_roll' motor only and press enter.
'wrist_roll' motor id set to 5
Connect the controller board to the 'wrist_flex' motor only and press enter.
'wrist_flex' motor id set to 4
Connect the controller board to the 'elbow_flex' motor only and press enter.
'elbow_flex' motor id set to 3
Connect the controller board to the 'shoulder_lift' motor only and press enter.
'shoulder_lift' motor id set to 2
Connect the controller board to the 'shoulder_pan' motor only and press enter.
'shoulder_pan' motor id set to 1

a-4.キャリブレーション(リーダー)

コマンド

$ lerobot-calibrate --teleop.type=so101_leader --teleop.port=/dev/tty.usbmodem5AB90676501 --teleop.id=so101_leader

結果
各モーターの可動範囲を一つずつ動かしていく。

% lerobot-calibrate --teleop.type=so101_leader --teleop.port=/dev/tty.usbmodem5AB90676501 --teleop.id=so101_leader
INFO 2025-12-19 09:31:47 calibrate.py:76 {'robot': None,
 'teleop': {'calibration_dir': None,
            'id': 'so101_leader',
            'port': '/dev/tty.usbmodem5AB90676501',
            'use_degrees': False}}
INFO 2025-12-19 09:31:48 01_leader.py:82 so101_leader SO101Leader connected.
INFO 2025-12-19 09:31:48 01_leader.py:99 
Running calibration of so101_leader SO101Leader
Move so101_leader SO101Leader to the middle of its range of motion and press ENTER....
Move all joints sequentially through their entire ranges of motion.
Recording positions. Press ENTER to stop...

-------------------------------------------
-------------------------------------------
NAME            |    MIN |    POS |    MAX
shoulder_pan    |   1177 |   2187 |   3093
shoulder_lift   |    859 |    865 |   3243
elbow_flex      |    847 |   3058 |   3063
wrist_flex      |    908 |   1890 |   3072
wrist_roll      |     67 |   1966 |   3677
gripper         |   1906 |   1922 |   3146
Calibration saved to /Users/oggata/.cache/huggingface/lerobot/calibration/teleoperators/so101_leader/so101_leader.json
INFO 2025-12-19 09:32:33 1_leader.py:156 so101_leader SO101Leader disconnected.

a-5.キャリブレーション(フォロワー)

$ lerobot-calibrate --robot.type=so101_follower --robot.port=/dev/tty.usbmodem5AB90669021 --robot.id=so101_follower
% lerobot-calibrate --robot.type=so101_follower --robot.port=/dev/tty.usbmodem5AB90669021 --robot.id=so101_follower
INFO 2025-12-19 09:08:15 calibrate.py:76 {'robot': {'calibration_dir': None,
           'cameras': {},
           'disable_torque_on_disconnect': True,
           'id': 'so101_follower',
           'max_relative_target': None,
           'port': '/dev/tty.usbmodem5AB90669021',
           'use_degrees': False},
 'teleop': None}
INFO 2025-12-19 09:08:15 follower.py:104 so101_follower SO101Follower connected.
INFO 2025-12-19 09:08:15 follower.py:121 
Running calibration of so101_follower SO101Follower
Move so101_follower SO101Follower to the middle of its range of motion and press ENTER....
Move all joints sequentially through their entire ranges of motion.
Recording positions. Press ENTER to stop...

-------------------------------------------
-------------------------------------------
NAME            |    MIN |    POS |    MAX
shoulder_pan    |   1127 |   2087 |   2975
shoulder_lift   |    914 |   3107 |   3107
elbow_flex      |    898 |   1249 |   2951
wrist_flex      |    944 |   1423 |   3182
wrist_roll      |   2046 |   2055 |   2057
gripper         |   2010 |   2015 |   3385
Calibration saved to /Users/oggata/.cache/huggingface/lerobot/calibration/robots/so101_follower/so101_follower.json

a-6.カメラの検出

コマンド

$ lerobot-find-cameras

a-7.テレオペレーション

コマンド

//カメラ無し
$ lerobot-teleoperate \
    --robot.type=so101_follower \
    --robot.port=/dev/tty.usbmodem5AB90669021 \
    --robot.id=so101_follower \
    --teleop.type=so101_leader \
    --teleop.port=/dev/tty.usbmodem5AB90676501 \
    --teleop.id=so101_leader
    --display_data=true


//テレオペレーション-カメラx1
$ lerobot-teleoperate \
    --robot.type=so101_follower \
    --robot.port=/dev/tty.usbmodem5AB90669021 \
    --robot.id=so101_follower \
    --teleop.type=so101_leader \
    --teleop.port=/dev/tty.usbmodem5AB90676501 \
    --teleop.id=so101_leader \
    --robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}}" \
    --display_data=true

//テレオペレーション-カメラx2
$ lerobot-teleoperate \
    --robot.type=so101_follower \
    --robot.port=/dev/tty.usbmodem5AB90669021 \
    --robot.id=so101_follower \
    --teleop.type=so101_leader \
    --teleop.port=/dev/tty.usbmodem5AB90676501 \
    --teleop.id=so101_leader \
    --robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30},second: {type: opencv, index_or_path: 1, width: 640, height: 480, fps: 20}}" \
    --display_data=true

スクリーンショット 2025-12-21 13.07.40.png

a-8.記録の準備

hugging faceでcredintialの作成
https://huggingface.co/settings/tokens

hugging faceでスペースの作成
https://huggingface.co/settings/tokens

コンソールでcredientialを使ってログインする

# ログイン
pip install huggingface_hub
export HUGGINGFACE_TOKEN=""
huggingface-cli login --token ${HUGGINGFACE_TOKEN} --add-to-git-credential
hf auth whoami
$ lerobot-find-port
$ lerobot-find-cameras
$ rm -rf ./record-gab-cookie-demo

a-9.記録スタート

# 1カメラ
$ lerobot-record \
    --robot.type=so101_follower \
    --robot.port=/dev/tty.usbmodem5AB90669021 \
    --robot.id=so101_follower \
    --teleop.type=so101_leader \
    --teleop.port=/dev/tty.usbmodem5AB90676501 \
    --teleop.id=so101_leader \
    --robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}}" \
    --display_data=true \
    --dataset.repo_id=oggata/record-gab-cookie-demo \
    --dataset.root=/Volumes/so101/lerobot_datasets/record-gab-cookie-demo/ \
    --dataset.single_task="Pickup the rice crackers and put them in the basket." \
    --dataset.num_episodes=30 \
    --dataset.episode_time_s=30 \
    --dataset.reset_time_s=5 \
    --resume=true

## 2カメラ
$ lerobot-record \
    --robot.type=so101_follower \
    --robot.port=/dev/tty.usbmodem5AB90669021 \
    --robot.id=so101_follower \
    --teleop.type=so101_leader \
    --teleop.port=/dev/tty.usbmodem5AB90676501 \
    --teleop.id=so101_leader \
    --dataset.root=/Volumes/so101/lerobot_datasets/record-gab-cookie-demo/ \
    --robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30},second: {type: opencv, index_or_path: 1, width: 640, height: 480, fps: 30}}" \
    --display_data=true \
    --dataset.repo_id=oggata/record-gab-cookie-demo \
    --dataset.root=./record-gab-cookie-demo \
    --dataset.single_task="Pickup the rice crackers and put them in the basket." \
    --dataset.num_episodes=7 \
    --dataset.episode_time_s=20 \
    --dataset.reset_time_s=10 \
    --resume=true
## 外付けハードディスクに保存する
$ lerobot-record \
    --robot.type=so101_follower \
    --robot.port=/dev/tty.usbmodem5AB90669021 \
    --robot.id=so101_follower \
    --teleop.type=so101_leader \
    --teleop.port=/dev/tty.usbmodem5AB90676501 \
    --teleop.id=so101_leader \
    --robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30},second: {type: opencv, index_or_path: 1, width: 640, height: 480, fps: 30}}" \
    --display_data=true \
    --dataset.repo_id=oggata/record-gab-cookie-demo \
    ----dataset.root=/Volumes/so101/lerobot_datasets/record-gab-cookie-demo/ \
    --dataset.single_task="Pickup the rice crackers and put them in the basket." \
    --dataset.num_episodes=7 \
    --dataset.episode_time_s=20 \
    --dataset.reset_time_s=10 \
    --resume=true

b. GoogleColabでレコードデータをもとに学習を行う

b-1.準備

from google.colab import drive
drive.mount('/content/drive')
!pip install -q condacolab
import condacolab
condacolab.install()
import os
os.chdir('/content/')  # ディレクトリを移動
print(os.getcwd())

!git clone https://github.com/huggingface/lerobot.git
!conda install ffmpeg=7.1.1 -c conda-forge
!cd lerobot && pip install -q -e .
import os

# LeRobot リポジトリをクローン
!git clone https://github.com/huggingface/lerobot.git /content/lerobot

# ディレクトリ移動して確認
os.chdir('/content/lerobot')
print(os.getcwd())
!ls -la src/lerobot/scripts/

# 必要な依存関係をインストール
!pip install -e .
from google.colab import userdata
import os

# シークレットから取得(strip()で前後の空白を削除)
hf_token = userdata.get('HF_TOKEN').strip()
wandb_key = userdata.get('WANDB_API_KEY').strip()

# 環境変数に設定
os.environ['HF_TOKEN'] = hf_token
os.environ['WANDB_API_KEY'] = wandb_key

# git credential helper を設定
!git config --global credential.helper store

# 新しいコマンドでログイン
!hf auth login --token {hf_token} --add-to-git-credential

# wandb ログイン
!wandb login {wandb_key}

b-2.パスの設定

hugging faceのデータディレクトリはこのパスによって変更すること。
https://huggingface.co/datasets/oggata/record-gab-cookie-demo
ルールとして、polycyにはact_という接頭語をつけている。

os.makedirs('/root/.cache/huggingface/lerobot/oggata', exist_ok=True)
os.chdir('/root/.cache/huggingface/lerobot/oggata')
print(os.getcwd())
!git clone https://huggingface.co/datasets/oggata/record-gab-cookie-demo
exp_name = "record-gab-cookie-demo"
dir_name = "oggata"
DATASET_REPO_ID = f"{dir_name}/{exp_name}"
POLICY_REPO_ID = f"{dir_name}/act_{exp_name}"
JOB_NAME = f"act_{exp_name}"
OUTPUT_DIR = f"/content/drive/MyDrive/Colab\ Notebooks/act_{exp_name}"

b-3.実行

途中から再開する場合は、--resume=trueをコメントアウトして使う。
中身よるが、batch_sizeは8、stepsは40000前後を指定。

import os
import shutil

# 既存ディレクトリを削除
output_dir = "/content/drive/MyDrive/Colab Notebooks/act_record-gab-cookie-demo4"
if os.path.exists(output_dir):
   # shutil.rmtree(output_dir)
    print(f"Deleted: {output_dir}")

!cd /content/lerobot/ && python src/lerobot/scripts/lerobot_train.py \
  --dataset.repo_id=$DATASET_REPO_ID \
  --policy.type=act \
  --policy.repo_id=$POLICY_REPO_ID \
  --output_dir=$OUTPUT_DIR \
  --job_name=$JOB_NAME \
  --policy.device=cuda \
  --wandb.enable=true \
  --batch_size=8  \
  --save_freq=5000  \
  --steps=40000 #\
  # --resume=true


b-4. wandb.aiで確認する

スクリーンショット 2026-01-05 17.43.29.png

b-4.再開

チェックポイントから再開する場合は下記のコードに習う。

import os

# 設定
OUTPUT_DIR = "/content/drive/MyDrive/Colab Notebooks/act_record-gab-cookie-demo"
CONFIG_PATH = f"{OUTPUT_DIR}/checkpoints/010000/pretrained_model/train_config.json"

# 再開
# L4でbatch_size=8 A100でbatch_size=32程度
print(f"Resuming training from: {OUTPUT_DIR}")
!cd /content/lerobot/ && python src/lerobot/scripts/lerobot_train.py \
  --config_path="{CONFIG_PATH}" \
  --policy.device=cuda \
  --wandb.enable=true \
  --batch_size=4 \
  --save_freq=2000 \
  --steps=40000 \
  --resume=true

b-5.手動でデータをアップロードする

from lerobot.common.policies.act.modeling_act import ACTPolicy
from huggingface_hub import login

# ログイン
login(token="your_hf_token_here")

# モデルをロード
policy = ACTPolicy.from_pretrained(
    "/content/drive/MyDrive/Colab Notebooks/act_record-gab-cookie-demo/checkpoints/040000"
)

# Hubにアップロード
policy.push_to_hub(
    repo_id="oggata/act_policy_gab_cookie",
    private=False
)

c.ローカル(mac)で学習データを元にSO-101を実行させる

c-1.アームの自動実行(学習データを利用して実行する)

$ lerobot-find-port
$ lerobot-find-cameras

$ rm -rf ./Volumes/so101/lerobot_datasets/eval_record-gab-cookie-demo/
$ lerobot-record \
    --robot.type=so101_follower \
    --robot.port=/dev/tty.usbmodem5AB90669021 \
    --robot.id=so101_follower \
    --robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30},second: {type: opencv, index_or_path: 1, width: 640, height: 480, fps: 30}}" \
    --display_data=true \
    --dataset.repo_id=oggata/eval_record-stack-blocks \
    --dataset.root=/Volumes/so101/lerobot_datasets/eval_record-stack-blocks/ \
    --dataset.single_task="StackWoodenBlocks." \
    --dataset.push_to_hub=false \
    --policy.path=/Volumes/so101/lerobot_datasets/record-stack-blocks/checkpoints/080000/pretrained_model

記録データの視聴

DecodingError(path, f"The fields {formatted_keys} are not valid for {stringify_type(cls)}")
draccus.utils.DecodingError: The fields use_peft are not valid for ACTConfig

# バックアップを作成
cp /Users/oggata/Documents/act_record-dungeons-1/checkpoints/040000/pretrained_model/config.json \
   /Users/oggata/Documents/act_record-dungeons-1/checkpoints/040000/pretrained_model/config.json.bak

# use_peftを削除
python3 << 'EOF'
import json

config_path = '/Users/oggata/Documents/act_record-dungeons-1/checkpoints/040000/pretrained_model/config.json'

with open(config_path, 'r') as f:
    config = json.load(f)

# use_peftを削除
if 'use_peft' in config:
    del config['use_peft']
    print("✓ use_peftを削除しました")

# pretrained_pathも更新(Colab用のパスなので)
if 'pretrained_path' in config and '/content/drive/' in config['pretrained_path']:
    config['pretrained_path'] = None
    print("✓ pretrained_pathをNullに設定しました")

with open(config_path, 'w') as f:
    json.dump(config, f, indent=4)

print("✓ 設定ファイルを更新しました")
EOF
0
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
0
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?