LeRobot&SO101
此文档以 Windiws + WSL(Ubuntu) 为开发环境,如果你直接使用 Ubuntu系统可以跳过部分步骤。
一、安装 WSL
在管理员模式下打开 PowerShell 运行以下命令,然后重启电脑。
wsl --install
使用
wsl.exe --list --online
查看可用 Linux 发行版列表。
❯ wsl.exe --list --online 以下是可安装的有效分发的列表。 使用“wsl.exe --install <Distro>”安装。 NAME FRIENDLY NAME AlmaLinux-8 AlmaLinux OS 8 AlmaLinux-9 AlmaLinux OS 9 AlmaLinux-Kitten-10 AlmaLinux OS Kitten 10 AlmaLinux-10 AlmaLinux OS 10 Debian Debian GNU/Linux FedoraLinux-44 Fedora Linux 44 FedoraLinux-43 Fedora Linux 43 SUSE-Linux-Enterprise-15-SP7 SUSE Linux Enterprise 15 SP7 SUSE-Linux-Enterprise-16.0 SUSE Linux Enterprise 16.0 Ubuntu Ubuntu Ubuntu-26.04 Ubuntu 26.04 LTS Ubuntu-24.04 Ubuntu 24.04 LTS Ubuntu-22.04 Ubuntu 22.04 LTS archlinux Arch Linux eLxr eLxr 12.12.0.0 GNU/Linux kali-linux Kali Linux Rolling openSUSE-Tumbleweed openSUSE Tumbleweed openSUSE-Leap-16.0 openSUSE Leap 16.0 OracleLinux_7_9 Oracle Linux 7.9 OracleLinux_8_10 Oracle Linux 8.10 OracleLinux_9_5 Oracle Linux 9.5 SUSE-Linux-Enterprise-15-SP6 SUSE Linux Enterprise 15 SP6
输入
wsl.exe --install -d Ubuntu-24.04
安装 Ubuntu-24.04,你也可以使用 Ubuntu 的其他版本。
在开始菜单搜索 Ubuntu,单击即可打开命令行终端。


二、安装 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
完成后重启 wsl 控制台。
创建一个名为 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.安装 evdev
conda activate lerobot conda install evdev -c conda-forge
3.安装 ffmpeg
conda install ffmpeg -c conda-forge
4.安装 LeRobot
克隆并进入项目目录
git clone https://github.com/huggingface/lerobot.git cd lerobot
以可编辑模式安装库,安装时确保网络通畅。
pip install -e .
安装电机控制组件
pip install -e ".[feetech]"
四、驱动机械臂
1.安装 usbipd
打开一个 Windows 终端
winget install usbipd
查看当前的 usb 设备
usbipd list
Connected: BUSID VID:PID DEVICE STATE 1-6 0461:5b4a USB 输入设备 Not shared 1-11 048d:5702 USB 输入设备 Not shared 1-13 17ef:6099 USB 输入设备 Not shared 1-14 8087:0033 英特尔(R) 无线 Bluetooth(R) Not shared 2-3 1bcf:2281 JYU2C-2083 Shared 2-4 1bcf:2281 JYU2C-2083 Shared Persisted: GUID DEVICE 01e5c160-1ccb-406b-8fc1-0e7d7242cf4f USB-Enhanced-SERIAL CH343 (COM8) 3a2ecc41-718f-4683-9678-54b1953fd5ac icspring camera 6ae2504b-b1ee-4cee-842b-baea9d48d3f5 icspring camera 737fc7db-e7e2-4b51-b1c2-918f1aa4e3ef icspring camera 7dd49518-1480-4653-bb07-0ab347fa75f2 icspring camera b10ae574-cb8f-4154-9ae8-a62ad8ddb2f0 USB-Enhanced-SERIAL CH343 (COM10) ed0cf675-f16f-4bf7-a612-e8509cff0509 USB-Enhanced-SERIAL CH343 (COM9) f508f19f-a548-41e2-97ad-8b79a4236ad8 icspring camera
插上机械臂数据线后
Connected: BUSID VID:PID DEVICE STATE 1-6 0461:5b4a USB 输入设备 Not shared 1-11 048d:5702 USB 输入设备 Not shared 1-13 17ef:6099 USB 输入设备 Not shared 1-14 8087:0033 英特尔(R) 无线 Bluetooth(R) Not shared 2-3 1bcf:2281 JYU2C-2083 Shared 2-4 1bcf:2281 JYU2C-2083 Shared 4-1 1a86:55d3 USB-Enhanced-SERIAL CH343 (COM10) Shared 4-2 1a86:55d3 USB-Enhanced-SERIAL CH343 (COM9) Shared Persisted: GUID DEVICE 01e5c160-1ccb-406b-8fc1-0e7d7242cf4f USB-Enhanced-SERIAL CH343 (COM8) 3a2ecc41-718f-4683-9678-54b1953fd5ac icspring camera 6ae2504b-b1ee-4cee-842b-baea9d48d3f5 icspring camera 737fc7db-e7e2-4b51-b1c2-918f1aa4e3ef icspring camera 7dd49518-1480-4653-bb07-0ab347fa75f2 icspring camera f508f19f-a548-41e2-97ad-8b79a4236ad8 icspring camera
对比发现
4-1 1a86:55d3 USB-Enhanced-SERIAL CH343 (COM10) Shared 4-2 1a86:55d3 USB-Enhanced-SERIAL CH343 (COM9) Shared
两个新增设备。
补充关于 usbipd 的说明
STATE 这一列表示每个 USB 设备当前在 usbipd-win 里的共享/连接状态。它反映设备是否已经被"绑定"以便通过 USB/IP 转发给远程主机(比如 WSL2 或另一台机器)。
常见的 STATE 取值
┌─────────────────┬──────────────────────────────────────────────────────────────────────────────────────┐
│ STATE │ 含义 │
├─────────────────┼──────────────────────────────────────────────────────────────────────────────────────┤
│ Not shared │ 设备未绑定,不能被远程连接。这是默认状态。 │
├─────────────────┼──────────────────────────────────────────────────────────────────────────────────────┤
│ Shared │ 设备已通过 usbipd bind 绑定,可以被远程客户端(如 WSL)attach 使用,但当前还没有被连接。 │
├─────────────────┼──────────────────────────────────────────────────────────────────────────────────────┤
│ Shared (forced) │ 用 --force 强制绑定,会替换掉原本的 Windows 驱动,连一些"顽固"设备也能共享。 │
├─────────────────┼──────────────────────────────────────────────────────────────────────────────────────┤
│ Attached │ 设备已经被某个远程客户端连接并正在使用(比如已经 attach 到 WSL 里)。 │
└─────────────────┴──────────────────────────────────────────────────────────────────────────────────────┘
对应你的输出
- 1-6、1-11、1-13、1-14 → Not shared:这些(键盘鼠标、蓝牙等本机输入设备)没有共享,仍由 Windows 本地使用。
- 2-3、2-4(JYU2C-2083)→ Shared:这两个设备已经绑定,处于"可被远程 attach"的待命状态,但目前还没有被 attach。
状态流转关系
Not shared --(usbipd bind)--> Shared --(usbipd attach)--> Attached
^ | |
+------(usbipd unbind)--------+------(usbipd detach)---------+
如果你想让 2-3 真正在 WSL 里用起来,下一步是在管理员权限下执行:
usbipd attach --wsl --busid 2-3
attach 成功后,那一行的 STATE 就会变成 Attached。
---
顺便说明:下面的 Persisted 区块是另一回事——那是曾经绑定过、即使设备当前没插着也会"记住"绑定信息的设备列表(按 GUID 记录),插上后会自动恢复共享状态。
在 Windows 中打开一个管理员权限的终端
usbipd bind --busid=4-1 usbipd attach --wsl --busid 4-1
2.使用 WSL Dashboard
前往下载安装 WSL Dashboard
完成后打开即可看到已经安装的虚拟机实例,同时也可以管理 USB 设备
3.确定机械臂的端口
将刚刚确定的 4-1 和 4-2 两个设备连接到虚拟机,例子中 4-1 是主臂 4-2 是从臂。
在虚拟机中执行 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.
断开主臂(4-1)
回到虚拟机中按下回车
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.
可知主臂(4-1)对应 ttyACM0 ,同样的操作确认从臂(4-2)对应 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