diff --git a/README.md b/README.md index 6f8e9ee..ff9f6c3 100644 --- a/README.md +++ b/README.md @@ -55,12 +55,9 @@ UFACTORY robot arm integration with the LeRobot framework for robot learning, da git clone https://github.com/xArm-Developer/lerobot_robot_ufactory.git cd lerobot_robot_ufactory -# Create conda environment -conda create -n uf_lerobot python=3.10 -y -conda activate uf_lerobot - -# Install project -pip install -e . +# Create a uv virtual environment and sync project dependencies +uv venv --python 3.10 +uv sync ``` Includes: `lerobot==0.4.3`, `xarm-python-sdk`, `numpy`, `pyyaml`. LeRobot already pulls in torch, opencv, wandb, etc. @@ -77,7 +74,7 @@ Dynamixel-based leader arm, joint-space control. ```bash # 1. Install GELLO module -pip install -e ".[gello]" +uv sync --extra gello # 2. Add serial port permissions (re-login required) sudo usermod -aG dialout $USER @@ -91,7 +88,7 @@ Pika Sense handheld + Vive Tracker, Cartesian-space control. ```bash # 1. Install peripheral deps (skip transitive deps) -pip install pysurvive agx-pypika --no-deps +uv pip install pysurvive agx-pypika --no-deps # 2. Install udev rules (re-plug devices afterwards) sudo cp src/rules/*.rules /etc/udev/rules.d/ @@ -110,7 +107,7 @@ curl -sL https://raw.githubusercontent.com/xArm-Developer/ufactory_resources/mai sudo apt install -y --fix-broken # 2. Install peripheral deps -pip install pysurvive --no-deps +uv pip install pysurvive --no-deps # 3. Install udev rules (re-plug devices afterwards) sudo cp src/rules/*.rules /etc/udev/rules.d/ @@ -135,7 +132,7 @@ sudo reboot ```bash # 1. Install SpaceMouse module -pip install -e ".[spacemouse]" +uv sync --extra spacemouse # 2. Install udev rules (re-plug device afterwards) sudo cp src/rules/*.rules /etc/udev/rules.d/ @@ -151,36 +148,46 @@ Test teleop-to-robot control loop without recording. ```bash # Generic usage -uf-robot-teleop --config_path path/to/config.yaml -uf-robot-teleop --config_path path/to/config.yaml --fps 60 # specify frequency +uv run uf-robot-teleop --config_path path/to/config.yaml +uv run uf-robot-teleop --config_path path/to/config.yaml --fps 60 # specify frequency # Example: xArm6 + UMI teleop -uf-robot-teleop --config_path config/umi/xarm6_umi_record_config.yaml +uv run uf-robot-teleop --config_path config/umi/xarm6_umi_record_config.yaml ``` -### 2. Data Collection +### 2. xArm Manual Drag Mode + +Use xArm joint teaching mode (`mode=2`) for manual dragging: + +```bash +uv run uf-xarm-manual-mode --config_path config/manual_mode/xarm_manual_mode_config.yaml +``` + +Set `manual_mode` to `true` to enter drag mode. Press Enter to restore normal mode; set it to `false` to restore normal mode directly. With `return_to_initial: true`, the script reads the saved initial point through the xArm Studio API and returns to it when drag mode exits. + +### 3. Data Collection Record datasets via teleop. ```bash # Generic usage -uf-lerobot-record --config_path path/to/record_config.yaml -uf-lerobot-record --config_path path/to/config.yaml --resume true # resume recording +uv run uf-lerobot-record --config_path path/to/record_config.yaml +uv run uf-lerobot-record --config_path path/to/config.yaml --resume true # resume recording # Example: xArm6 + UMI data collection -uf-lerobot-record --config_path config/umi/xarm6_umi_record_config.yaml +uv run uf-lerobot-record --config_path config/umi/xarm6_umi_record_config.yaml ``` -### 3. Policy Training +### 4. Policy Training Train imitation learning policies on collected data. ```bash # Generic usage -lerobot-train --policy act --dataset your_dataset_name +uv run lerobot-train --policy act --dataset your_dataset_name # Example: train ACT on xArm6 UMI dataset -lerobot-train --policy act --dataset ufactory/xarm6_umi_datas +uv run lerobot-train --policy act --dataset ufactory/xarm6_umi_datas ``` Important parameters: @@ -189,7 +196,7 @@ Important parameters: # Note: repo_id is the same as in the record config # Policy type: ACT, training steps: 800k # Checkpoints saved every 20k steps, output to lerobot_datas/train (sibling of lerobot directory) -lerobot-train \ +uv run lerobot-train \ --dataset.root=../../../../lerobot_datas/record/ufactory/xarm6_umi_datas \ --dataset.repo_id=ufactory/xarm6_umi_datas \ --policy.type=act \ @@ -202,16 +209,16 @@ lerobot-train \ --save_freq=20000 ``` -### 4. Inference & Evaluation +### 5. Inference & Evaluation Run inference with a trained policy. ```bash # Generic usage -uf-lerobot-eval --config_path path/to/config.yaml --policy.path your_train_path +uv run uf-lerobot-eval --config_path path/to/config.yaml --policy.path your_train_path # Example: run inference with trained ACT policy -uf-lerobot-eval --config_path config/umi/xarm6_umi_record_config.yaml --policy.path ../../../../lerobot_datas/train/xarm6_umi_datas/checkpoints/last/pretrained_model/ +uv run uf-lerobot-eval --config_path config/umi/xarm6_umi_record_config.yaml --policy.path ../../../../lerobot_datas/train/xarm6_umi_datas/checkpoints/last/pretrained_model/ ``` ## Tools @@ -221,11 +228,11 @@ uf-lerobot-eval --config_path config/umi/xarm6_umi_record_config.yaml --policy.p View and stitch multiple camera feeds. ```bash -uf-camera-view -l # list all cameras -uf-camera-view -l -T xvisio # list XVisio cameras only -uf-camera-view -T xvisio # view XVisio cameras (default 1280x1280 YU12) -uf-camera-view -T xvisio -W 640 -H 1920 -F NV12 # specify format -uf-camera-view -T other # view other camera types +uv run uf-camera-view -l # list all cameras +uv run uf-camera-view -l -T xvisio # list XVisio cameras only +uv run uf-camera-view -T xvisio # view XVisio cameras (default 1280x1280 YU12) +uv run uf-camera-view -T xvisio -W 640 -H 1920 -F NV12 # specify format +uv run uf-camera-view -T other # view other camera types ``` ### 2. LeRobot Dataset Tools @@ -235,7 +242,7 @@ LeRobot provides dataset utilities for inspecting, editing and managing collecte #### View an episode: e.g. view episode index 17: ```bash -lerobot-dataset-viz \ +uv run lerobot-dataset-viz \ --root=../../../../lerobot_datas/record/ufactory/xarm7_record_datas \ --repo-id ufactory/xarm7_record_datas \ --display-compressed-images true \ @@ -245,7 +252,7 @@ lerobot-dataset-viz \ #### Delete specific episodes: e.g. delete episodes 18 and 19: ```bash -lerobot-edit-dataset \ +uv run lerobot-edit-dataset \ --root=../../../../lerobot_datas/record/ufactory/xarm7_record_datas \ --repo_id ufactory/xarm7_record_datas \ --new_repo_id ../xarm7_record_datas_new \ @@ -255,7 +262,7 @@ lerobot-edit-dataset \ #### Merge datasets: ```bash -lerobot-edit-dataset \ +uv run lerobot-edit-dataset \ --root=../../../../lerobot_datas/record \ --repo_id ufactory/xarm7_record_datas_merge_1_2 \ --operation.type merge \ diff --git a/README_ZH.md b/README_ZH.md index 1d0b464..7adcd4d 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -55,12 +55,9 @@ UFACTORY(深圳市众为创造科技有限公司) 机械臂与 LeRobot 框架集 git clone https://github.com/xArm-Developer/lerobot_robot_ufactory.git cd lerobot_robot_ufactory -# 创建 conda 环境 -conda create -n uf_lerobot python=3.10 -y -conda activate uf_lerobot - -# 安装项目 -pip install -e . +# 创建 uv 虚拟环境并同步项目依赖 +uv venv --python 3.10 +uv sync ``` 包含:`lerobot==0.4.3`、`xarm-python-sdk`、`numpy`、`pyyaml`(lerobot 已自动携带 torch、opencv、wandb 等训练相关依赖)。 @@ -77,7 +74,7 @@ pip install -e . ```bash # 1. 安装 GELLO 模块 -pip install -e ".[gello]" +uv sync --extra gello # 2. 添加串口权限(重新登录后生效) sudo usermod -aG dialout $USER @@ -91,7 +88,7 @@ sudo usermod -aG dialout $USER ```bash # 1. 安装外设依赖(不需要它们的间接依赖) -pip install pysurvive agx-pypika --no-deps +uv pip install pysurvive agx-pypika --no-deps # 2. 安装 udev 规则(重新插拔设备后生效) sudo cp rules/*.rules /etc/udev/rules.d/ @@ -110,7 +107,7 @@ curl -sL https://raw.githubusercontent.com/xArm-Developer/ufactory_resources/mai sudo apt install -y --fix-broken # 2. 安装外设依赖 -pip install pysurvive --no-deps +uv pip install pysurvive --no-deps # 3. 安装 udev 规则(重新插拔设备后生效) sudo cp rules/*.rules /etc/udev/rules.d/ @@ -135,7 +132,7 @@ sudo reboot ```bash # 1. 安装 SpaceMouse 模块 -pip install -e ".[spacemouse]" +uv sync --extra spacemouse # 2. 安装 udev 规则(重新插拔设备后生效) sudo cp rules/*.rules /etc/udev/rules.d/ @@ -150,11 +147,11 @@ sudo udevadm control --reload-rules && sudo udevadm trigger ```bash # 通用格式 -uf-robot-teleop --config_path path/to/config.yaml -uf-robot-teleop --config_path path/to/config.yaml --fps 60 # 指定频率 +uv run uf-robot-teleop --config_path path/to/config.yaml +uv run uf-robot-teleop --config_path path/to/config.yaml --fps 60 # 指定频率 # 示例: xArm6 + UMI 遥操作 -uf-robot-teleop --config_path config/umi/xarm6_umi_record_config.yaml +uv run uf-robot-teleop --config_path config/umi/xarm6_umi_record_config.yaml ``` ### 2. xArm 人工拖拽模式测试 @@ -162,10 +159,10 @@ uf-robot-teleop --config_path config/umi/xarm6_umi_record_config.yaml 使用 xArm 的关节示教模式(`mode=2`)进行人工拖拽: ```bash -uf-xarm-manual-mode --config_path config/manual_mode/xarm_manual_mode_config.yaml +uv run uf-xarm-manual-mode --config_path config/manual_mode/xarm_manual_mode_config.yaml ``` -配置中的 `manual_mode` 为 `true` 时进入拖拽模式,按回车后恢复为普通模式;设置为 `false` 可直接恢复为普通模式。 +配置中的 `manual_mode` 为 `true` 时进入拖拽模式,按回车后恢复为普通模式;设置为 `false` 可直接恢复为普通模式。`return_to_initial: true` 会通过 xArm Studio 接口读取保存的初始位置,并在退出拖拽后自动回位。 ### 3. 数据采集 @@ -173,11 +170,11 @@ uf-xarm-manual-mode --config_path config/manual_mode/xarm_manual_mode_config.yam ```bash # 通用格式 -uf-lerobot-record --config_path path/to/record_config.yaml -uf-lerobot-record --config_path path/to/config.yaml --resume true # 续录 +uv run uf-lerobot-record --config_path path/to/record_config.yaml +uv run uf-lerobot-record --config_path path/to/config.yaml --resume true # 续录 # 示例: xArm6 + UMI 数据采集 -uf-lerobot-record --config_path config/umi/xarm6_umi_record_config.yaml +uv run uf-lerobot-record --config_path config/umi/xarm6_umi_record_config.yaml ``` ### 4. Lerobot训练 @@ -186,7 +183,7 @@ uf-lerobot-record --config_path config/umi/xarm6_umi_record_config.yaml ```bash # 通用格式 -lerobot-train --policy act --dataset your_dataset_name +uv run lerobot-train --policy act --dataset your_dataset_name ``` 参数示例: @@ -195,7 +192,7 @@ lerobot-train --policy act --dataset your_dataset_name # 注意: repo_id就是采集时配置文件里面的repo_id # 这里训练策略policy.type选用act,训练steps为80w次 # 训练过程每2w次保存一次结果,结果输出到和lerobot同级目录下的lerobot_datas/train里面 -lerobot-train \ +uv run lerobot-train \ --dataset.root=../../../../lerobot_datas/record/ufactory/xarm6_umi_datas \ --dataset.repo_id=ufactory/xarm6_umi_datas \ --policy.type=act \ @@ -214,10 +211,10 @@ lerobot-train \ ```bash # 通用格式 -uf-lerobot-eval --config_path path/to/config.yaml --policy.path your_train_path +uv run uf-lerobot-eval --config_path path/to/config.yaml --policy.path your_train_path # 示例:使用训练好的 ACT 策略进行推理 -uf-lerobot-eval --config_path config/umi/xarm6_umi_record_config.yaml --policy.path ../../../../lerobot_datas/train/xarm6_umi_datas/checkpoints/last/pretrained_model/ +uv run uf-lerobot-eval --config_path config/umi/xarm6_umi_record_config.yaml --policy.path ../../../../lerobot_datas/train/xarm6_umi_datas/checkpoints/last/pretrained_model/ ``` ## 工具集 @@ -227,11 +224,11 @@ uf-lerobot-eval --config_path config/umi/xarm6_umi_record_config.yaml --policy.p 查看和拼接多路摄像头画面。 ```bash -uf-camera-view -l # 列出所有摄像头 -uf-camera-view -l -T xvisio # 仅列出 XVisio 摄像头 -uf-camera-view -T xvisio # 查看 XVisio 摄像头(默认 1280x1280 YU12) -uf-camera-view -T xvisio -W 640 -H 1920 -F NV12 # 指定格式 -uf-camera-view -T other # 查看其他类型摄像头 +uv run uf-camera-view -l # 列出所有摄像头 +uv run uf-camera-view -l -T xvisio # 仅列出 XVisio 摄像头 +uv run uf-camera-view -T xvisio # 查看 XVisio 摄像头(默认 1280x1280 YU12) +uv run uf-camera-view -T xvisio -W 640 -H 1920 -F NV12 # 指定格式 +uv run uf-camera-view -T other # 查看其他类型摄像头 ``` ### 2. Lerobot数据集工具 @@ -240,7 +237,7 @@ Lerobot提供一些数据集工具,方便对采集的数据集进行增删查 ### 查看某个索引的episode: 例如查看索引号为17的episode: ```bash -lerobot-dataset-viz \ +uv run lerobot-dataset-viz \ --root=../../../../lerobot_datas/record/ufactory/xarm7_record_datas \ --repo-id ufactory/xarm7_record_datas \ --display-compressed-images true \ @@ -250,7 +247,7 @@ lerobot-dataset-viz \ ### 删除某些索引的episodes: 例如删除索引号为18和19的episode: ```bash -lerobot-edit-dataset \ +uv run lerobot-edit-dataset \ --root=../../../../lerobot_datas/record/ufactory/xarm7_record_datas \ --repo_id ufactory/xarm7_record_datas \ --new_repo_id ../xarm7_record_datas_new \ @@ -260,7 +257,7 @@ lerobot-edit-dataset \ ### 合并数据集 ```bash -lerobot-edit-dataset \ +uv run lerobot-edit-dataset \ --root=../../../../lerobot_datas/record \ --repo_id ufactory/xarm7_record_datas_merge_1_2 \ --operation.type merge \ diff --git a/config/manual_mode/xarm_manual_mode_config.yaml b/config/manual_mode/xarm_manual_mode_config.yaml index b59aeaf..8a18252 100644 --- a/config/manual_mode/xarm_manual_mode_config.yaml +++ b/config/manual_mode/xarm_manual_mode_config.yaml @@ -6,3 +6,9 @@ manual_mode: true # xArm teach sensitivity, valid range: 1-5. teach_sensitivity: 3 + +# Read the initial point saved in xArm Studio and return to it after pressing Enter. +return_to_initial: true + +# Return speed in degrees per second. +reset_speed: 30 diff --git a/src/lerobot_robot_ufactory/scripts/uf_xarm_manual_mode.py b/src/lerobot_robot_ufactory/scripts/uf_xarm_manual_mode.py index 92061e1..1a2e814 100644 --- a/src/lerobot_robot_ufactory/scripts/uf_xarm_manual_mode.py +++ b/src/lerobot_robot_ufactory/scripts/uf_xarm_manual_mode.py @@ -14,6 +14,8 @@ class ManualModeConfig: robot_ip: str = "192.168.1.127" manual_mode: bool = True teach_sensitivity: int | None = 3 + return_to_initial: bool = True + reset_speed: float = 30.0 @config_parser.wrap() @@ -24,8 +26,11 @@ def get_cfg(cfg: ManualModeConfig) -> ManualModeConfig: def run(cfg: ManualModeConfig): if cfg.teach_sensitivity is not None and not 1 <= cfg.teach_sensitivity <= 5: raise ValueError("teach_sensitivity must be between 1 and 5") + if cfg.reset_speed <= 0: + raise ValueError("reset_speed must be greater than 0") arm = XArmAPI(cfg.robot_ip) + initial_point = None try: if not arm.connected: raise ConnectionError(f"Failed to connect to xArm at {cfg.robot_ip}") @@ -35,6 +40,16 @@ def run(cfg: ManualModeConfig): arm.set_mode(0) arm.set_state(0) + code, initial_point = arm.get_initial_point() + if code != 0: + raise RuntimeError(f"get_initial_point failed, code={code}") + if not initial_point or len(initial_point) < arm.axis: + raise RuntimeError( + f"Invalid initial point returned by xArm: {initial_point}" + ) + initial_point = list(initial_point[:arm.axis]) + print(f"Initial point loaded from xArm Studio: {initial_point}") + if cfg.manual_mode: if cfg.teach_sensitivity is not None: code = arm.set_teach_sensitivity(cfg.teach_sensitivity) @@ -60,10 +75,24 @@ def run(cfg: ManualModeConfig): print("Joint teaching mode disabled.") finally: if arm.connected: - # Always leave the robot in normal position-control mode. - arm.set_mode(0) - arm.set_state(0) - arm.disconnect() + try: + arm.set_mode(0) + arm.set_state(0) + if cfg.return_to_initial and initial_point is not None: + _move_to_initial(arm, initial_point, cfg.reset_speed) + finally: + arm.disconnect() + + +def _move_to_initial(arm: XArmAPI, initial_point: list[float], speed: float): + code = arm.set_servo_angle( + angle=initial_point, + speed=speed, + is_radian=False, + wait=True, + ) + if code != 0: + raise RuntimeError(f"Failed to move to xArm initial point, code={code}") def main():