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