From d336b73aa3e30a9375e41ddb9b4c602b34776d60 Mon Sep 17 00:00:00 2001 From: Saberlve Date: Fri, 7 Aug 2026 16:44:18 +0800 Subject: [PATCH] Fix bug in camera config --- .gitignore | 3 +- README.md | 20 +--- README_ZH.md | 20 +--- .../xarm7_manual_record_config.yaml | 11 +- pyproject.toml | 1 - .../scripts/uf_xarm_manual_mode.py | 107 ------------------ start_manual_record.sh | 50 ++++++++ 7 files changed, 70 insertions(+), 142 deletions(-) delete mode 100644 src/lerobot_robot_ufactory/scripts/uf_xarm_manual_mode.py create mode 100755 start_manual_record.sh diff --git a/.gitignore b/.gitignore index 1f82ff6..32dee99 100644 --- a/.gitignore +++ b/.gitignore @@ -88,4 +88,5 @@ models/ *.trt *.xvcd ufactory_usage/ -.history/ \ No newline at end of file +.history/ +xarm7_manual_datas \ No newline at end of file diff --git a/README.md b/README.md index 4fe67fc..05e3ee9 100644 --- a/README.md +++ b/README.md @@ -155,28 +155,18 @@ uv run uf-robot-teleop --config_path path/to/config.yaml --fps 60 # specify fre uv run uf-robot-teleop --config_path config/umi/xarm6_umi_record_config.yaml ``` -### 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. Manual Drag Data Collection +### 2. Manual Drag Data Collection Manual drag recording uses `manual_mode: true` in the robot configuration and does not configure a teleoperator. During recording, the actual joint state is written as both the observation and action in the LeRobot dataset. When a gripper is configured, hold `C` to close it slowly and `O` to open it slowly. Adjust the speed with `manual_gripper_speed`, which defaults to `0.5`: ```bash -uv run uf-lerobot-record --config_path config/manual_mode/xarm7_manual_record_config.yaml -uv run uf-lerobot-record --config_path config/manual_mode/xarm7_manual_record_config.yaml --resume true +./start_manual_record.sh +./start_manual_record.sh -r ``` -Press `Space` to start an episode, `Right` to save it, `Left` to discard and re-record it, and `Esc` to stop recording. Reset the arm manually between episodes. +The launcher creates a dataset on its first run and automatically resumes an existing valid dataset. If it reports an empty or incomplete dataset directory, choose a new `dataset.root` or remove that directory after confirming it contains no data. Press `Space` to start an episode, `Right` to save it, `Left` to discard and re-record it, and `Esc` to stop recording. Reset the arm manually between episodes. -### 4. Teleop Data Collection +### 3. Teleop Data Collection Record datasets via teleop. diff --git a/README_ZH.md b/README_ZH.md index 099f769..9e1d02c 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -154,28 +154,18 @@ uv run uf-robot-teleop --config_path path/to/config.yaml --fps 60 # 指定频 uv run uf-robot-teleop --config_path config/umi/xarm6_umi_record_config.yaml ``` -### 2. xArm 人工拖拽模式测试 - -使用 xArm 的关节示教模式(`mode=2`)进行人工拖拽: - -```bash -uv run uf-xarm-manual-mode --config_path config/manual_mode/xarm_manual_mode_config.yaml -``` - -配置中的 `manual_mode` 为 `true` 时进入拖拽模式,按回车后恢复为普通模式;设置为 `false` 可直接恢复为普通模式。`return_to_initial: true` 会通过 xArm Studio 接口读取保存的初始位置,并在退出拖拽后自动回位。 - -### 3. 人工拖拽数据采集 +### 2. 人工拖拽数据采集 人工拖拽录制使用 robot 配置中的 `manual_mode: true`,不需要配置 teleop。录制过程中,机械臂的实际关节状态会作为 observation 和 action 写入 LeRobot 数据集;如果配置了夹爪,还可以按住 `C` 缓慢闭合、按住 `O` 缓慢张开。夹爪速度通过 `manual_gripper_speed` 配置,默认值为 `0.5`: ```bash -uv run uf-lerobot-record --config_path config/manual_mode/xarm7_manual_record_config.yaml -uv run uf-lerobot-record --config_path config/manual_mode/xarm7_manual_record_config.yaml --resume true +./start_manual_record.sh +./start_manual_record.sh -r ``` -按 `Space` 开始当前 episode,按 `Right` 保存,按 `Left` 放弃并重录当前 episode,按 `Esc` 停止录制。episode 之间可以手动复位机械臂。 +启动脚本首次运行时创建数据集,检测到有效数据集时会自动续录。如果提示数据目录为空或不完整,请修改 `dataset.root`,或者确认没有数据后删除该目录。按 `Space` 开始当前 episode,按 `Right` 保存,按 `Left` 放弃并重录当前 episode,按 `Esc` 停止录制。episode 之间可以手动复位机械臂。 -### 4. 遥操作数据采集 +### 3. 遥操作数据采集 通过遥操作录制数据集。 diff --git a/config/manual_mode/xarm7_manual_record_config.yaml b/config/manual_mode/xarm7_manual_record_config.yaml index 83b32f1..6f67570 100644 --- a/config/manual_mode/xarm7_manual_record_config.yaml +++ b/config/manual_mode/xarm7_manual_record_config.yaml @@ -15,11 +15,16 @@ robot: # Whether to record joint velocities in observations. observe_joint_vel: false - # Camera definitions; leave empty when no cameras are used. - cameras: {} + cameras: + camera: + type: intelrealsense + serial_number_or_name: "148522072685" + width: 640 + height: 480 + fps: 30 dataset: - root: "/home/uf/Data/lerobot_datas/record/ufactory/xarm7_manual_datas" + root: "/home/wsx/code/lerobot_robot_ufactory/xarm7_manual_datas" repo_id: "ufactory/xarm7_manual_datas" # Task description stored with each recorded frame. single_task: "Describe the task being demonstrated." diff --git a/pyproject.toml b/pyproject.toml index f6960fd..6a3a8b0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,6 @@ dependencies = [ [project.scripts] uf-robot-teleop = "lerobot_robot_ufactory.scripts.uf_robot_teleop:main" uf-lerobot-record = "lerobot_robot_ufactory.scripts.uf_lerobot_record:main" -uf-xarm-manual-mode = "lerobot_robot_ufactory.scripts.uf_xarm_manual_mode:main" uf-lerobot-eval = "lerobot_robot_ufactory.scripts.uf_lerobot_eval:main" uf-vive-calibrate = "lerobot_robot_ufactory.scripts.vive_calibrate:main" uf-camera-view = "lerobot_robot_ufactory.scripts.uf_camera_view:main" diff --git a/src/lerobot_robot_ufactory/scripts/uf_xarm_manual_mode.py b/src/lerobot_robot_ufactory/scripts/uf_xarm_manual_mode.py deleted file mode 100644 index 1a2e814..0000000 --- a/src/lerobot_robot_ufactory/scripts/uf_xarm_manual_mode.py +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import sys -from dataclasses import dataclass - -import lerobot_robot_ufactory # noqa: F401 # register UFACTORY plugins -from xarm.wrapper import XArmAPI -from lerobot_robot_ufactory.configs import parser as config_parser - - -@dataclass -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() -def get_cfg(cfg: ManualModeConfig) -> ManualModeConfig: - return cfg - - -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}") - - arm.motion_enable(enable=True) - arm.clean_error() - 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) - if code != 0: - raise RuntimeError(f"set_teach_sensitivity failed, code={code}") - - code = arm.set_mode(2) - if code != 0: - raise RuntimeError(f"set_mode(2) failed, code={code}") - code = arm.set_state(0) - if code != 0: - raise RuntimeError(f"set_state(0) failed, code={code}") - - print("Joint teaching mode enabled. Drag the arm manually.") - input("Press Enter to disable mode 2... ") - else: - code = arm.set_mode(0) - if code != 0: - raise RuntimeError(f"set_mode(0) failed, code={code}") - code = arm.set_state(0) - if code != 0: - raise RuntimeError(f"set_state(0) failed, code={code}") - print("Joint teaching mode disabled.") - finally: - if arm.connected: - 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(): - cli_parser = argparse.ArgumentParser(description="Control xArm joint teaching mode from YAML") - _, unknown = cli_parser.parse_known_args() - sys.argv = [sys.argv[0]] + unknown - cfg = get_cfg() - run(cfg) - - -if __name__ == "__main__": - main() diff --git a/start_manual_record.sh b/start_manual_record.sh new file mode 100755 index 0000000..39db6c2 --- /dev/null +++ b/start_manual_record.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash + +set -euo pipefail + +repo_root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +cd "$repo_root" + +config_path="config/manual_mode/xarm7_manual_record_config.yaml" +dataset_root="$( + sed -n '/^dataset:/,/^[^[:space:]]/s/^[[:space:]]*root:[[:space:]]*//p' "$config_path" \ + | head -n 1 \ + | tr -d "\"'" +)" + +if [[ -z "$dataset_root" ]]; then + printf 'Could not read dataset.root from %s\n' "$config_path" >&2 + exit 1 +fi + +if [[ "$dataset_root" != /* ]]; then + dataset_root="$repo_root/$dataset_root" +fi + +record_args=("$@") +resume_requested=false +for arg in "${record_args[@]}"; do + if [[ "$arg" == "-r" ]]; then + resume_requested=true + break + fi +done + +if [[ -e "$dataset_root" ]]; then + if [[ ! -f "$dataset_root/meta/info.json" ]]; then + printf 'Dataset directory exists but is not a valid LeRobot dataset: %s\n' "$dataset_root" >&2 + printf 'Choose a new dataset.root, or remove this empty/incomplete directory before recording.\n' >&2 + exit 1 + fi + + if [[ "$resume_requested" == false ]]; then + record_args=("-r" "${record_args[@]}") + fi +elif [[ "$resume_requested" == true ]]; then + printf 'Cannot resume because the dataset directory does not exist: %s\n' "$dataset_root" >&2 + exit 1 +fi + +exec uv run uf-lerobot-record \ + --config_path "$config_path" \ + "${record_args[@]}"