← 返回

LeRobot&SO101 (Ubuntu)

LeRobot&SO101

一、安装 Miniconda

在控制台中输入

curl -O https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh

等待脚本下载

% Total    % Received % Xferd  Average Speed  Time    Time    Time   Current
                                 Dload  Upload  Total   Spent   Left   Speed
 70 188.1M  70 132.3M   0      0  4.11M      0   00:45   00:32   00:13  3.80M

执行安装脚本

bash ~/Miniconda3-latest-Linux-x86_64.sh

设置全部默认,无脑 yes 下一步即可。

完成后输入 conda --version 可以查看到版本号就代表安装成功了,如果提示找不到 conda 命令,尝试重启 wsl 控制台。

(base) shawn@pc:~$ conda --version
conda 26.5.3

三、安装 LeRobot

更多信息可以查看 LeRobot中文文档

1.下载、安装 miniforge

wget "https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-$(uname)-$(uname -m).sh"
bash Miniforge3-$(uname)-$(uname -m).sh

完成后重启终端,创建一个名为 lerobot 的 Python 3.12 虚拟环境

conda create -y -n lerobot python=3.12

看见如下输出即为成功

Downloading and Extracting Packages:

Preparing transaction: done
Verifying transaction: done
Executing transaction: done
#
# To activate this environment, use
#
#     $ conda activate lerobot
#
# To deactivate an active environment, use
#
#     $ conda deactivate

使用 conda activate lerobot 命令进入刚刚创建的虚拟环境,使用 conda deactivate 退出虚拟环境。

(base) shawn@114514yyds:~$
(base) shawn@114514yyds:~$ conda activate lerobot
(lerobot) shawn@114514yyds:~$ conda deactivate
(base) shawn@114514yyds:~$

2.安装 ffmpeg

conda install ffmpeg -c conda-forge

3.安装 LeRobot

克隆并进入项目目录

git clone https://github.com/huggingface/lerobot.git
cd lerobot

以可编辑模式安装库,安装时确保网络通畅。

pip install -e .

安装电机控制组件

pip install -e ".[feetech]"

四、驱动机械臂

3.确定机械臂的端口

执行 lerobot-find-port ,看到如下输出

Finding all available ports for the MotorsBus.
Ports before disconnecting: ['/dev/ttyACM1', '/dev/ttyACM0', '/dev/ttyS7', '/dev/ttyS6', '/dev/ttyS5', '/dev/ttyS4', '/dev/ttyS3', '/dev/ttyS2', '/dev/ttyS1', '/dev/ttyS0', '/dev/tty63', '/dev/tty62', '/dev/tty61', '/dev/tty60', '/dev/tty59', '/dev/tty58', '/dev/tty57', '/dev/tty56', '/dev/tty55', '/dev/tty54', '/dev/tty53', '/dev/tty52', '/dev/tty51', '/dev/tty50', '/dev/tty49', '/dev/tty48', '/dev/tty47', '/dev/tty46', '/dev/tty45', '/dev/tty44', '/dev/tty43', '/dev/tty42', '/dev/tty41', '/dev/tty40', '/dev/tty39', '/dev/tty38', '/dev/tty37', '/dev/tty36', '/dev/tty35', '/dev/tty34', '/dev/tty33', '/dev/tty32', '/dev/tty31', '/dev/tty30', '/dev/tty29', '/dev/tty28', '/dev/tty27', '/dev/tty26', '/dev/tty25', '/dev/tty24', '/dev/tty23', '/dev/tty22', '/dev/tty21', '/dev/tty20', '/dev/tty19', '/dev/tty18', '/dev/tty17', '/dev/tty16', '/dev/tty15', '/dev/tty14', '/dev/tty13', '/dev/tty12', '/dev/tty11', '/dev/tty10', '/dev/tty9', '/dev/tty8', '/dev/tty7', '/dev/tty6', '/dev/tty5', '/dev/tty4', '/dev/tty3', '/dev/tty2', '/dev/tty1', '/dev/tty0', '/dev/tty']
Remove the USB cable from your MotorsBus and press Enter when done.

断开主臂,按下回车

Finding all available ports for the MotorsBus.
Ports before disconnecting: ['/dev/ttyACM1', '/dev/ttyACM0', '/dev/ttyS7', '/dev/ttyS6', '/dev/ttyS5', '/dev/ttyS4', '/dev/ttyS3', '/dev/ttyS2', '/dev/ttyS1', '/dev/ttyS0', '/dev/tty63', '/dev/tty62', '/dev/tty61', '/dev/tty60', '/dev/tty59', '/dev/tty58', '/dev/tty57', '/dev/tty56', '/dev/tty55', '/dev/tty54', '/dev/tty53', '/dev/tty52', '/dev/tty51', '/dev/tty50', '/dev/tty49', '/dev/tty48', '/dev/tty47', '/dev/tty46', '/dev/tty45', '/dev/tty44', '/dev/tty43', '/dev/tty42', '/dev/tty41', '/dev/tty40', '/dev/tty39', '/dev/tty38', '/dev/tty37', '/dev/tty36', '/dev/tty35', '/dev/tty34', '/dev/tty33', '/dev/tty32', '/dev/tty31', '/dev/tty30', '/dev/tty29', '/dev/tty28', '/dev/tty27', '/dev/tty26', '/dev/tty25', '/dev/tty24', '/dev/tty23', '/dev/tty22', '/dev/tty21', '/dev/tty20', '/dev/tty19', '/dev/tty18', '/dev/tty17', '/dev/tty16', '/dev/tty15', '/dev/tty14', '/dev/tty13', '/dev/tty12', '/dev/tty11', '/dev/tty10', '/dev/tty9', '/dev/tty8', '/dev/tty7', '/dev/tty6', '/dev/tty5', '/dev/tty4', '/dev/tty3', '/dev/tty2', '/dev/tty1', '/dev/tty0', '/dev/tty']
Remove the USB cable from your MotorsBus and press Enter when done.

The port of this MotorsBus is '/dev/ttyACM0'
Reconnect the USB cable.

可知主臂对应 ttyACM0 ,同样的操作确认从臂对应 ttyACM1

4.机械臂校准

主臂校准

lerobot-calibrate \
    --teleop.type=so101_leader \
    --teleop.port=/dev/ttyACM0 \
    --teleop.id=R07260541

从臂校准

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

port 是端口由上一步获得,id 是名称可以任取但不要重复

错误处理:

  • PermissionError: [Errno 13] Permission denied: '/dev/ttyACM0'

    权限不足,执行 sudo chmod 666 /dev/ttyACM0

成功示例

INFO 2026-07-09 14:43:57 calibrate.py:89 {'robot': None,
 'teleop': {'calibration_dir': None,
            'id': 'R07260541',
            'port': '/dev/ttyACM0',
            'use_degrees': True}}
INFO 2026-07-09 14:43:57 so_leader.py:78 R07260541 SOLeader connected.
INFO 2026-07-09 14:43:57 so_leader.py:95
Running calibration of R07260541 SOLeader
Move R07260541 SOLeader to the middle of its range of motion and press ENTER....
Move all joints except 'wrist_roll' sequentially through their entire ranges of motion.
Recording positions. Press ENTER to stop...

-------------------------------------------
-------------------------------------------
NAME            |    MIN |    POS |    MAX
shoulder_pan    |    849 |   1925 |   3270
shoulder_lift   |    790 |    807 |   2089
elbow_flex      |   1024 |   3224 |   3228
wrist_flex      |    659 |   2201 |   2990
gripper         |   2037 |   2048 |   3272
Calibration saved to /home/shawn/.cache/huggingface/lerobot/calibration/teleoperators/so_leader/R07260541.json
INFO 2026-07-09 14:44:35 o_leader.py:163 R07260541 SOLeader disconnected.

查看校准文件

(lerobot) shawn@pc:~/lerobot$ cat /home/shawn/.cache/huggingface/lerobot/calibration/robots/so_follower/R12260541.json
{
    "shoulder_pan": {
        "id": 1,
        "drive_mode": 0,
        "homing_offset": -1305,
        "range_min": 908,
        "range_max": 3311
    },
    "shoulder_lift": {
        "id": 2,
        "drive_mode": 0,
        "homing_offset": 2033,
        "range_min": 835,
        "range_max": 3207
    },
    "elbow_flex": {
        "id": 3,
        "drive_mode": 0,
        "homing_offset": 1988,
        "range_min": 848,
        "range_max": 2993
    },
    "wrist_flex": {
        "id": 4,
        "drive_mode": 0,
        "homing_offset": -1949,
        "range_min": 961,
        "range_max": 3279
    },
    "wrist_roll": {
        "id": 5,
        "drive_mode": 0,
        "homing_offset": -338,
        "range_min": 0,
        "range_max": 4095
    },
    "gripper": {
        "id": 6,
        "drive_mode": 0,
        "homing_offset": 861,
        "range_min": 2047,
        "range_max": 3489
    }
}
(lerobot) shawn@114514yyds:~/lerobot$ cat /home/shawn/.cache/huggingface/lerobot/calibration/teleoperators/so_leader/R07260541.json
{
    "shoulder_pan": {
        "id": 1,
        "drive_mode": 0,
        "homing_offset": -1588,
        "range_min": 849,
        "range_max": 3270
    },
    "shoulder_lift": {
        "id": 2,
        "drive_mode": 0,
        "homing_offset": 1867,
        "range_min": 790,
        "range_max": 2089
    },
    "elbow_flex": {
        "id": 3,
        "drive_mode": 0,
        "homing_offset": -1205,
        "range_min": 1024,
        "range_max": 3228
    },
    "wrist_flex": {
        "id": 4,
        "drive_mode": 0,
        "homing_offset": 1495,
        "range_min": 659,
        "range_max": 2990
    },
    "wrist_roll": {
        "id": 5,
        "drive_mode": 0,
        "homing_offset": -350,
        "range_min": 0,
        "range_max": 4095
    },
    "gripper": {
        "id": 6,
        "drive_mode": 0,
        "homing_offset": 1874,
        "range_min": 2037,
        "range_max": 3272
    }
}

5.开始遥操

lerobot-teleoperate \
    --robot.type=so101_follower \
    --robot.port=/dev/ttyACM1 \
    --robot.id=R12260541 \
    --teleop.type=so101_leader \
    --teleop.port=/dev/ttyACM0 \
    --teleop.id=R07260541

五、连接摄像头

lerobot-find-cameras opencv
--- Detected Cameras ---
Camera #0:
  Name: OpenCV Camera @ /dev/video0
  Type: OpenCV
  Id: /dev/video0
  Backend api: V4L2
  Default stream profile:
    Format: 0.0
    Fourcc: YUYV
    Width: 640
    Height: 480
    Fps: 30.0
--------------------
Camera #1:
  Name: OpenCV Camera @ /dev/video2
  Type: OpenCV
  Id: /dev/video2
  Backend api: V4L2
  Default stream profile:
    Format: 0.0
    Fourcc: YUYV
    Width: 640
    Height: 480
    Fps: 30.0
--------------------

Finalizing image saving...
Image capture finished. Images saved to outputs/captured_images
lerobot-teleoperate \
    --teleop.type=so101_leader \
    --teleop.port=/dev/ttyACM0 \
    --robot.type=so101_follower \
    --teleop.id=R07260541 \
    --robot.port=/dev/ttyACM1 \
    --robot.id=R12260541 \
    --robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30, fourcc: "MJPG"}, side: {type: opencv, index_or_path: 2, width: 640, height: 480, fps: 30, fourcc: "MJPG"}}" \
    --display_data=true

六、数据采集

lerobot-record \
    --teleop.type=so101_leader \
    --teleop.port=/dev/ttyACM0 \
    --teleop.id=R07260541 \
    --robot.type=so101_follower \
    --robot.port=/dev/ttyACM1 \
    --robot.id=R12260541  \
    --robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30, fourcc: MJPG}, side: {type: opencv, index_or_path: 2, width: 640, height: 480, fps: 30, fourcc: MJPG}}" \
    --display_data=true \
    --dataset.repo_id=local/grab_oranges \
    --dataset.num_episodes=40 \
    --dataset.single_task="Grab Oranges" \
    --dataset.push_to_hub=false \
    --dataset.episode_time_s=10 \
    --dataset.reset_time_s=5

参数说明

  • --dataset.repo_id
    • 数据集保存的地址
  • --dataset.num_episodes=40
    • 总共录制 40 段演示
  • --dataset.single_task="Grab Oranges"
    • 任务描述/标签为”抓橙子”,会作为语言指令存入数据集
  • --dataset.push_to_hub=false
    • 录制完成后不上传到 Hugging Face Hub
  • --dataset.episode_time_s=10
    • 每段演示录制 10 秒
  • --dataset.reset_time_s=5
    • 每段之间留 2 秒用于重置场景(把物体摆回原位)

数据集保存路径为 /home/shawn/lerobot/outputs/train/act_so101_grab_black_box

七、ACT模型训练

lerobot-train \
    --dataset.repo_id=local/grab_black_box \
    --policy.type=act \
    --output_dir=outputs/train/act_so101_grab_black_box \
    --job_name=act_so101_grab_black_box \
    --policy.device=cuda \
    --wandb.enable=false \
    --policy.repo_id=local/grab_black_box \
    --policy.push_to_hub=false \
    --batch_size=8 \
    --steps=30000 \
    --save_freq=5000

八、真机部署

lerobot-rollout \
    --strategy.type=episodic \
    --policy.path=/home/shawn/lerobot/outputs/train/act_so101_grab_black_box/checkpoints/last/pretrained_model \
    --robot.type=so101_follower \
    --robot.port=/dev/ttyACM1 \
    --robot.id=R12260542 \
    --robot.cameras="{ front: {type: opencv, index_or_path: 2, width: 640, height: 480, fps: 30, fourcc: MJPG}, side: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30, fourcc: MJPG}}" \
    --task="grab the black box" \
    --dataset.repo_id=local/rollout_grab_black_box \
    --dataset.num_episodes=10