只有机械臂没有底盘时候,使用so100配置。
1. 标定
# 下载源码
git clone git@github.com:huggingface/lerobot.git
1.1 查看端口
# 1. 主从机械臂通过TypeC-USB线连接电脑主机
# 2. 进入主机源码目录
cd lerobot
# 3. 依次查看机械臂总线伺服适配器的端口
python lerobot/scripts/find_motors_bus_port.py
# 4. 得到串口号:从臂COM6,主臂COM5
1.2 更新配置
@RobotConfig.register_subclass("so100")
@dataclass
class So100RobotConfig(ManipulatorRobotConfig):
calibration_dir: str = ".cache/calibration/so100"
max_relative_target: int | None = None
leader_arms: dict[str, MotorsBusConfig] = field(
default_factory=lambda: {
"main": FeetechMotorsBusConfig(
port="COM5",
motors={
# name: (index, model)
"shoulder_pan": [1, "sts3215"],
"shoulder_lift": [2, "sts3215"],
"elbow_flex": [3, "sts3215"],
"wrist_flex": [4, "sts3215"],
"wrist_roll": [5, "sts3215"],
"gripper": [6, "sts3215"],
},
),
}
)
follower_arms: dict[str, MotorsBusConfig] = field(
default_factory=lambda: {
"main": FeetechMotorsBusConfig(
port="COM6",
motors={
# name: (index, model)
"shoulder_pan": [1, "sts3215"],
"shoulder_lift": [2, "sts3215"],
"elbow_flex": [3, "sts3215"],
"wrist_flex": [4, "sts3215"],
"wrist_roll": [5, "sts3215"],
"gripper": [6, "sts3215"],
},
),
}
)
1.3 执行标定
# 先进行从臂(main follower),后进行主臂(main leader),按照提示依次执行
python lerobot/scripts/control_robot.py --robot.type=so100 --robot.cameras={} --control.type=calibrate
#标定结果位于:lerobot/.cache/calibration/so100
# 主臂
{"homing_offset": [-2059, 3043, -1062, -1948, 2050, -2138], "drive_mode": [0, 1, 0, 0, 1, 0], "start_pos": [2058, 2994, 1174, 2041, 2048, 2048], "end_pos": [3083, -2019, 2086, 2972, -1026, 3162], "calib_mode": ["DEGREE", "DEGREE", "DEGREE", "DEGREE", "DEGREE", "LINEAR"], "motor_names": ["shoulder_pan", "shoulder_lift", "elbow_flex", "wrist_flex", "wrist_roll", "gripper"]}
# 从臂
{"homing_offset": [-2044, 3038, -1068, -1907, 1885, -2457], "drive_mode": [0, 1, 0, 0, 1, 0], "start_pos": [2054, 3030, 1083, 2047, 2046, 2048], "end_pos": [3068, -2014, 2092, 2931, -861, 3481], "calib_mode": ["DEGREE", "DEGREE", "DEGREE", "DEGREE", "DEGREE", "LINEAR"], "motor_names": ["shoulder_pan", "shoulder_lift", "elbow_flex", "wrist_flex", "wrist_roll", "gripper"]}
-
从臂中间位置(new middle position)
-
从臂零位( zero position)
-
从臂旋转位(rotated target position)
-
从臂就绪等待位(rest position)
-
主臂中间位(new middle position)
-
主臂零位(zero position)
-
主臂旋转位(rotated target position)
-
主臂就绪等待位(rest position)
2. 遥控
python lerobot/scripts/control_robot.py --robot.type=so100 --robot.cameras={} --control.type=teleoperate
lerobot 机械臂跟随操控
3. 数据录制
有个录制10次训练的文章:【https://blog.csdn.net/suoxd123/article/details/148322591】
3.1 打开摄像头权限
3.2 验证摄像头可用
# 修改查找最大序号(默认60):MAX_OPENCV_INDEX = 2
# 默认打开摄像头采集图像4秒(USB口延时1秒有点高)
# parser.add_argument(
# "--record-time-s",
# type=float,
# default=4.0,
# help="Set the number of seconds used to record the frames. By default, 2 seconds.",
# )
python lerobot/common/robot_devices/cameras/opencv.py
3.3 执行动作录制
# 进行两轮录制:control.num_episodes=2
# 单次录制30s时间:control.episode_time_s=30
python lerobot/scripts/control_robot.py --robot.type=so100 --control.type=record --control.fps=30 --control.single_task="Grasp a sealant on left and put it to the right." --control.repo_id="%HF_USER%/so100_test" --control.tags=[\"so100\",\"tutorial\"] --control.warmup_time_s=5 --control.episode_time_s=30 --control.reset_time_s=30 --control.num_episodes=2 --control.push_to_hub=true
图片是中间状态,是用来编码为视频的(使用av库),最终生成视频后,图片会被自动删除
3.4 本地查看录制的数据集
# 管理员权限:查看当前数据集
python lerobot/scripts/visualize_dataset_html.py --repo-id "%HF_USER%/so100_test"
3.5 在线平台查看数据集
huggingface官网-> datasets -> 搜索:suoxd123
3.7 本地回放动作
# 从臂回放第一次动作(episode=0)
python lerobot/scripts/control_robot.py --robot.type=so100 --control.type=replay --control.fps=30 --control.repo_id="%HF_USER%/so100_test" --control.episode=0
动作回放
4. 训练
# 当前用4090显卡,2个30秒训练视频,完成训练要2个小时左右
python lerobot/scripts/train.py --dataset.repo_id=suoxd123/so100_test --policy.type=act --output_dir=outputs/train/act_so100_test --job_name=act_so100_test --policy.device=cuda --wandb.enable=false
5. 训练源码概述
程序支持混合精度训练、梯度裁剪、检查点保存和恢复、WandB集成、定期评估、性能指标跟踪、自定义数据集和策略模型等,基本训练流程如下:
5.1 初始化配置
5.2 设置基础组件:
初始化WandB日志记录器(可选)
设置随机种子
配置CUDA设备和性能选项
5.3 创建训练所需对象
# 创建数据集
dataset = make_dataset(cfg)
# 创建评估环境(可选)
if cfg.eval_freq > 0 and cfg.env is not None:
eval_env = make_env(cfg.env)
# 创建策略模型
policy = make_policy(cfg=cfg.policy, ds_meta=dataset.meta)
# 创建优化器和学习率调度器
optimizer, lr_scheduler = make_optimizer_and_scheduler(cfg, policy)
5.4 创建数据加载器
dataloader = torch.utils.data.DataLoader(
dataset,
num_workers=cfg.num_workers,
batch_size=cfg.batch_size,
shuffle=shuffle,
sampler=sampler
)
5.5 训练循环: 主循环包含以下步骤
for _ in range(step, cfg.steps):
# 获取批次数据
batch = next(dl_iter)
# 更新策略
train_tracker, output_dict = update_policy(
train_tracker,
policy,
batch,
optimizer,
cfg.optimizer.grad_clip_norm,
grad_scaler,
lr_scheduler,
use_amp=cfg.policy.use_amp
)
# 定期执行:
# - 日志记录 (每 cfg.log_freq 步)
# - 保存检查点 (每 cfg.save_freq 步)
# - 评估模型 (每 cfg.eval_freq 步)
5.6 更新策略
def update_policy():
# 1. 前向传播计算损失
loss, output_dict = policy.forward(batch)
# 2. 反向传播
grad_scaler.scale(loss).backward()
# 3. 梯度裁剪
grad_norm = torch.nn.utils.clip_grad_norm_(...)
# 4. 优化器更新
grad_scaler.step(optimizer)
# 5. 重置梯度
optimizer.zero_grad()
# 6. 更新学习率
if lr_scheduler is not None:
lr_scheduler.step()
5.7 指标跟踪:
loss: 损失值
grad_norm: 梯度范数
lr: 学习率
update_s: 更新时间
dataloading_s: 数据加载时间
6. 异常记录
6.1 无法使用libsvtav1编码器
# 查看版本
import av
print(av.library_versions)
ffmpeg -version
# 重新安装 av
pip uninstall av
conda install -c conda-forge pyav ffmpeg
故障:
查看版本不一致,说明 PyAV 使用的是其自带的 FFmpeg(而非系统的),此时需要强制 PyAV 使用系统 FFmpeg
6.2 训练未启动GPU
# 查看CUDA版本
python --version
python -c "import torch; print(torch.__version__); print(torch.cuda.is_available())"
python -c "import torch; print(torch.version.cuda);print(torch.backends.cudnn.version())"
# 重装支持GPU的Pytorch
pip uninstall torch
pip uninstall torchvision torchaudio
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu128
6.3 终端编码错误
默认终端是gbk编码,改为UTF-8即可
# 回放时候因编码报错
# 在命令行中临时设置(仅当前会话有效)
set PYTHONIOENCODING=UTF-8
# 或者永久设置(管理员权限运行)
setx PYTHONIOENCODING UTF-8 /M
6.4 客户端没权限
查看本地数据集以及训练时候,默认是在C盘,所以默认终端没权限,需要使用管理员权限打开终端后执行即可。
具身开源套件部分课程如下,欢迎联系合作采购(全套开源)