lerobot搭建
- Ai
- 9天前
- 87热度
- 0评论
设备查询
本文是记录ubuntu系统lerobot试验的快捷命令,方便开始负责执行设备,不会介绍为什么?
python -m lerobot.find_port
python -m lerobot.find_cameras
机器标定
从臂标定
python -m lerobot.calibrate \
--robot.type=so101_follower \
--robot.port=/dev/ttyACM0 \
--robot.id=R12252801
主臂标定
python -m lerobot.calibrate \
--teleop.type=so101_leader \
--teleop.port=/dev/ttyACM1 \
--teleop.id=R07252608
标定的文件路径默认存储在/home/laumy/.cache/huggingface/lerobot/calibration。如果要更改路径。
--robot.calibration_dir=/home/laumy/lerobot/calibrations
--teleop.calibration_dir=/home/laumy/lerobot/calibrations
如果指定了路径,后续的代码都需要指定。
示教
python -m lerobot.teleoperate \
--robot.type=so101_follower \
--robot.port=/dev/ttyACM0 \
--robot.id=R12252801 \
--teleop.type=so101_leader \
--teleop.port=/dev/ttyACM1 \
--teleop.id=R07252608
数据采集
python -m lerobot.record \
--robot.disable_torque_on_disconnect=true \
--robot.type=so101_follower \
--robot.port=/dev/ttyACM0 \
--robot.id=R12252801 \
--robot.cameras="{ handeye: {type: opencv, index_or_path: 6, width: 640, height: 480, fps: 30}, fixed: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}}" \
--teleop.type=so101_leader \
--teleop.port=/dev/ttyACM1 \
--teleop.id=R07252608 \
--dataset.repo_id=laumy/record-07271148\
--dataset.num_episodes=10 \
--dataset.reset_time_s=5 \
--dataset.push_to_hub=false \
--dataset.single_task="Grab the cube" \
--display_data=true
repo_id必现为"用户名/数据集名"格式,代码中会检测是否有"/"。
数据存储默认的路径为/home/laumy/.cache/huggingface/lerobot/laumy/record-07271148如果要修改路径的话,加上下面参数。
--dataset.root=/home/laumy/lerobot/data/record_07271148
如果要继续上一次的录制,可以添加在上面命令基础上加上: --resume=true
如果数据采集过程中,突然异常终止,无法恢复报错如下时。
Traceback (most recent call last):
File "/home/laumy/lerobot/./src/lerobot/scripts/train.py", line 291, in <module>
train()
File "/home/laumy/lerobot/src/lerobot/configs/parser.py", line 226, in wrapper_inner
response = fn(cfg, *args, **kwargs)
File "/home/laumy/lerobot/./src/lerobot/scripts/train.py", line 128, in train
dataset = make_dataset(cfg)
File "/home/laumy/lerobot/src/lerobot/datasets/factory.py", line 90, in make_dataset
dataset = LeRobotDataset(
File "/home/laumy/lerobot/src/lerobot/datasets/lerobot_dataset.py", line 489, in __init__
check_timestamps_sync(timestamps, episode_indices, ep_data_index_np, self.fps, self.tolerance_s)
File "/home/laumy/lerobot/src/lerobot/datasets/utils.py", line 585, in check_timestamps_sync
raise ValueError(
ValueError: One or several timestamps unexpectedly violate the tolerance inside episode range.
This might be due to synchronization issues during data collection.
[{'diff': np.float32(-15.966666),
'episode_index': 90,
'timestamps': [np.float32(15.966666), np.float32(0.0)]}]
解决办法就是到数据集路径下~/.cache/huggingface/lerobot/laumy/record-07261516/检查数据,一般就是数据集不匹配了,打开data和videos下面的数据,看看数量是否和meta里面的jsonl对齐了,因为程序采集过程中异常终止,可能只写了data目录或videos目录,但是meta目录下没来得及写就崩溃退出,把最新的一组数据删除了并把meta下面的所有文件数量对齐就可以了。
需要注意的时,info.json中的数据要特别进行修改,下面是需要修改info.json的地方。
{
"codebase_version": "v2.1",
"robot_type": "so101_follower",
"total_episodes": 54, ------采集的周期
"total_frames": 21243, ------采集的总长度,是episodes.jsonl的总和,这个可以通过后面的脚步来计算确认
"total_tasks": 1,
"total_videos": 108, -----总的视频数量,一般是episodes * 2
"total_chunks": 1,
"chunks_size": 1000,
"fps": 30,
"splits": {
"train": "0:54" -----用于划分给训练集的数据,后面的数据一般要和total_episodes一致。
},
如果meta/info.json中total_frames是所有视频的总帧数,是从meta/episodes.jsonl中所有的length字段获取的总和,如果做了调整要重新计算更新一下这个total_frames。下面是重新计算的脚步。
import os
import json
import argparse
from pathlib import Path
def calibrate_total_frames(dataset_root):
dataset_root = Path(dataset_root)
# 手动指定 INFO_PATH 和 EPISODES_PATH
info_path = dataset_root / "info.json" # 替换为实际的元数据文件路径
episodes_path = dataset_root / "episodes.jsonl" # 替换为实际的剧集信息文件路径
# 检查元数据文件是否存在
if not info_path.exists():
print(f"Metadata file {info_path} does not exist.")
return
# 检查剧集信息文件是否存在
if not episodes_path.exists():
print(f"Episodes file {episodes_path} does not exist.")
return
# 加载元数据python ./src/lerobot/scripts/train.py \
--dataset.repo_id=${HF_USER}/record-07271539 \
--policy.type=act \
--output_dir=outputs/train/weigh_07271539 \
--job_name=act_so101_test \
--policy.device=cuda \
--policy.push_to_hub=false \
--wandb.enable=false
with open(info_path, 'r') as f:
info = json.load(f)
# 重新计算 total_frames
total_frames = 0
with open(episodes_path, 'r') as f:
for line in f:
episode = json.loads(line)
total_frames += episode.get('length', 0)
# 更新元数据
# info["total_frames"] = total_frames
# with open(info_path, 'w') as f:
# json.dump(info, f, indent=4)
print(f"Total frames calibrated to {total_frames}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Calibrate total frames in dataset metadata.')
parser.add_argument('dataset_root', type=str, help='Root path of the dataset')
args = parser.parse_args()
calibrate_total_frames(args.dataset_root)
训练
python ./src/lerobot/scripts/train.py \
--dataset.repo_id=laumy/record-07271539 \
--policy.type=act \
--output_dir=outputs/train/weigh_07271539 \
--job_name=act_so101_test \
--policy.device=cuda \
--policy.push_to_hub=false \
--wandb.enable=false
训练过程如果不小心终止了,执行下面命令可以接着上次的训练。
python ./src/lerobot/scripts/train.py \
--config_path=outputs/train/weigh_07271539/checkpoints/last/pretrained_model/train_config.json \
--resume=true --steps=200000
--steps参数表示迭代次数,这里表示200K次。
测试
python -m lerobot.record \
--robot.type=so101_follower \
--robot.disable_torque_on_disconnect=true \
--robot.port=/dev/ttyACM0 \
--robot.cameras="{ handeye: {type: opencv, index_or_path: 6, width: 640, height: 480, fps: 30}, fixed: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}}" \
--robot.id=R12252801 \
--display_data=false \
--dataset.single_task="Put brick into the box" \
--policy.path=outputs/weigh_07280842/pretrained_model \
--dataset.episode_time_s=240 \
--dataset.repo_id=laumy/eval_so101_07280842
默认录制时长是60s,60S后会停止,如果要改长加上--dataset.episode_time_s=640
class ACTConfig(PreTrainedConfig):
n_obs_steps: int = 1
chunk_size: int = 100
n_action_steps: int = 1
- n_obs_steps:传递给策略的观测时间窗口大小,具体是指包含当前步骤在内的连续观测步数。也就是说我要观测几步动作来预测接下来的动作。
- chunk_size=100: 动作预测分块大小,为单次模型前向传播预测的动作序列总长度(以环境步数为单位),简单理解就是预测的动作步数,实际执行的动作会从这里面选择。
- n_action_steps:从预测的动作分块中实际执行的步数,所以必须满足 n_action_steps ≤ chunk_size。
观测序列 → [O_t-n, ..., O_t] → 策略网络 → [A1...A100] → 执行[A1...A50]
↑ ↑ ↑ ↑
n_obs_steps=3 chunk_size=1 n_action_steps=50
一般来说如果是抓取固定的物体,n_obs_steps(3~5)设置可设较小值,chun_size设置大一点以减少策略调用频率,n_action_steps一般取chunk_size/2。如果是动态的环境(如装配、堆叠)n_obs_steps建议设置大一点10~20,chunk_size也缩减一点。
- action.xxx: 代表的是要设定执行的动作,也就是主臂或者模型推理处理发送的指令。
- observation.xxx:实际执行的动作。
一般情况下observation要跟action越吻合越好。
其他(废弃)
用于记录,可不用看
mac
找uart和摄像头
export HF_USER=laumy
python -m lerobot.find_port
python -m lerobot.find_cameras
从臂标定
python -m lerobot.calibrate \
--robot.type=so101_follower \
--robot.port=/dev/tty.usbmodem5A7A0576331 \
--robot.id=R12252801
主臂标定
python -m lerobot.calibrate \
--teleop.type=so101_leader \
--teleop.port=/dev/tty.usbmodem5A7A0582001 \
--teleop.id=R07252608
示教
python -m lerobot.teleoperate \
--robot.type=so101_follower \
--robot.port=/dev/ttyACM0 \
--robot.id=R12252801 \
--teleop.type=so101_leader \
--teleop.port=/dev/ttyACM1 \
--teleop.id=R07252608
采集数据
python -m lerobot.record \
--robot.disable_torque_on_disconnect=true \
--robot.type=so101_follower \
--robot.port=/dev/ttyACM0 \
--robot.id=R12252801 \
--robot.cameras="{ handeye: {type: opencv, index_or_path: 8, width: 640, height: 360, fps: 30}, fixed: {type: opencv, index_or_path: 10, width: 640, height: 360, fps: 30}}" \
--teleop.type=so101_leader \
--teleop.port=/dev/ttyACM1 \
--teleop.id=R07252608 \
--dataset.repo_id=${HF_USER}/record-test \
--dataset.num_episodes=10 \
--dataset.reset_time_s=5 \
--dataset.push_to_hub=false \
--dataset.single_task="Grab the cube"
训练
python ./src/lerobot/scripts/train.py \
--dataset.repo_id=${HF_USER}/data_07181406 \
--policy.type=act \
--output_dir=outputs/train/weigh_07181406 \
--job_name=act_so101_test \
--policy.device=cuda \
--policy.push_to_hub=false \
--wandb.enable=false
测试
python -m lerobot.record \
--robot.type=so101_follower \
--robot.disable_torque_on_disconnect=true \
--robot.port=/dev/ttyACM0 \
--robot.cameras="{ handeye: {type: opencv, index_or_path: 8, width: 640, height: 360, fps: 30}, fixed: {type: opencv, index_or_path: 10, width: 640, height: 360, fps: 30}}" \
--robot.id=R12252801 \
--display_data=false \
--dataset.single_task="Put lego brick into the transparent box" \
--policy.path=outputs/100000/pretrained_model \
--dataset.repo_id=${HF_USER}/eval_so101
windows
找uart和摄像头
set HF_USER=86152
python -m lerobot.find_port
python -m lerobot.find_cameras
从臂标定
python -m lerobot.calibrate `
--robot.type=so101_follower `
--robot.port=COM5 `
--robot.id=R12252801
主臂标定
python -m lerobot.calibrate `
--teleop.type=so101_leader `
--teleop.port=COM6 `
--teleop.id=R07252608
示教
python -m lerobot.teleoperate `
--robot.type=so101_follower `
--robot.port=COM5 `
--robot.id=R12252801 `
--teleop.type=so101_leader `
--teleop.port=COM6 `
--teleop.id=R07252608
录制
t
训练
python src/lerobot/scripts/train.py `
--dataset.repo_id=86152/data_07181406 `
--policy.type=act `
--output_dir=outputs/train/weigh_07181406 `
--job_name=act_so101_test `
--policy.device=cuda `
--policy.push_to_hub=false `
--wandb.enable=false
测试
python -m lerobot.record `
--robot.type=so101_follower `
--robot.disable_torque_on_disconnect=true `
--robot.port=COM5 `
--robot.cameras="{ handeye: {type: opencv, index_or_path: 1, width: 640, height: 360, fps: 30}, fixed: {type: opencv, index_or_path: 2, width: 640, height: 360, fps: 30}}" `
--robot.id=R12252801 `
--display_data=false `
--dataset.single_task="Put lego brick into the transparent box" `
--dataset.repo_id=${HF_USER}/eval_so101 `
--policy.path=outputs/train/weigh_07172300/checkpoints/last/pretrained_model
unbuntu
export HF_USER=laumy
python lerobot/scripts/find_motors_bus_port.py
python lerobot/common/robot_devices/cameras/opencv.py
python lerobot/scripts/control_robot.py \
--robot.type=so101 \
--control.type=record \
--control.fps=30 \
--control.single_task="Grasp a lego block and put it in the bin." \
--control.repo_id=${HF_USER}/so101_test \
--control.tags='["so101","tutorial"]' \
--control.warmup_time_s=5 \
--control.episode_time_s=30 \
--control.reset_time_s=5 \
--control.num_episodes=10 \
--control.push_to_hub=false
如果要继续上一次的录制,可以添加在上面命令基础上加上:--control.resume=true
可视化训练数据
python lerobot/scripts/visualize_dataset_html.py --repo-id ${HF_USER}/so101_test
拷贝数据到服务器
scp -P 18620 so101_test.tar.gz root@connect.bjb1.seetacloud.com:~/
python lerobot/scripts/train.py \
--dataset.repo_id=${HF_USER}/so101_test \
--policy.type=act \
--output_dir=outputs/train/act_so101_test0717 \
--job_name=act_so101_test \
--policy.device=cuda \
--wandb.enable=false
python lerobot/scripts/control_robot.py \
--robot.type=so101 \
--control.type=record \
--control.fps=30 \
--control.single_task="Grasp a lego block and put it in the bin." \
--control.repo_id=${HF_USER}/eval_act_so101_test \
--control.tags='["tutorial"]' \
--control.warmup_time_s=5 \
--control.episode_time_s=30 \
--control.reset_time_s=30 \
--control.num_episodes=10 \
--control.push_to_hub=false \
--control.policy.path=outputs/train/act_so101_test/checkpoints/last/pretrained_model