diff --git a/aao_configs/open_door.yaml b/aao_configs/open_door.yaml index 19d442b..171f55c 100644 --- a/aao_configs/open_door.yaml +++ b/aao_configs/open_door.yaml @@ -6,14 +6,31 @@ scene_name: open_door task_name: open_door env: - # Task-specific arm home — gripper facing the door handle. Shifted for the - # consolidated demo.xml: door frame is at world (1.54, 0.1, -1.0) vs the - # legacy robotiq scene's (1.49, 0.1, 0.0), so the arm home moves +0.05 x - # and -1.0 z to keep the same relative pose to the handle. + # Task-specific arm home — gripper horizontal, pointing +X (fingers toward the + # door, body/wrist toward the robot). The robotiq palm/wrist sits ~0.14m BEHIND + # the fingertips, so pointing +X keeps the bulky body clear of both the lever + # and the door panel (only ~8cm apart) while the fingers reach in to clamp the + # lever bar vertically (jaw along world Z, straddling the bar top/bottom). + # NOTE: for the mocap gripper this value is the *mocap target*; the TCP/pads + # land ~0.34m ahead of it, so this freejoint pose was calibrated so the open + # finger pads sit ~5.5cm in front of the bar (a clean pre-grasp) with the palm + # back at x~1.27 (clear of the 1.46 bar and 1.52 panel). initial_joint_positions: - robotiq_freejoint: [1.285, 0.3155, -0.195, 0.5, 0.5, -0.5, -0.5] + robotiq_freejoint: [1.057, 0.436, -0.367, -0.5, -0.5, 0.5, 0.5] mask_objects: ["handle_lever_body", "handle_body_phys"] - operations: ["pick", "push"] + operations: ["push"] + # Door latch: keeps door_hinge spring-locked near zero until the handle is + # pressed past unlock_threshold. Without this the door swings freely the + # instant the gripper touches it, so the handle never gets pressed and the + # approach just bulldozes the (unlatched) door. + pre_step_callbacks: + - _target_: auto_atom.callbacks.door_latch.DoorLatchCallback + door_joint: door_hinge + handle_joint: handle_hinge + kp: 80.0 + kd: 8.0 + unlock_threshold: 0.12 + lock_zone: 0.05 viewer: lookat: [1.45, 0.12, 0.8] distance: 1.2 @@ -23,56 +40,73 @@ env: hold_seconds: 1.0 task: + randomization: + arm: + eef: + x: [-0.03, 0.03] + y: [-0.03, 0.03] + z: [-0.03, 0.03] + roll: [-0.0873, 0.0873] + pitch: [-0.0873, 0.0873] + yaw: [-0.0873, 0.0873] stages: - - name: rotate_handle - object: handle_lever_body - operation: pick + # One continuous push: press the lever down to unlock, then swing the door + # open. The success object is handle_body_phys (rides on the door panel), so + # the door's translation satisfies the "pushed" displacement check — the + # lever only rotates in place, which a displacement check would reject. + - name: open_door + object: handle_body_phys + operation: push operator: arm param: pre_move: - - position: [0.095, 0.106, 0.0] - reference: object - max_linear_step: 0.02 + # 0. Re-home in front of the lever bar with the open finger pads + # straddling it in Z (~5.5cm in front). The mocap reset settles to a + # slightly different pose per batch env, so drive to an explicit + # object-referenced point (world axes) to converge every env. + - position: [-0.13, 0.079, 0.0] + reference: object_world + max_linear_step: 0.1 + max_angular_step: 0.3 + # 1. Advance +X so the bar enters the jaw (between the top/bottom pads). + - position: [0.06, 0.0, 0.0] + reference: eef_world + max_linear_step: 0.1 max_angular_step: 0.25 - - position: [0.095, 0.055, 0.0] - reference: object - max_linear_step: 0.01 - max_angular_step: 0.2 eef: close: true post_move: + # 2. Press the lever down to unlock. handle_hinge's local Y axis maps + # to world -X (door frame is rotated +90deg about Z), so the arc + # axis is world [-1,0,0]; a positive target angle presses the lever + # down past the latch's unlock_threshold. max_step 0.15 keeps each + # arc sub-step (>~0.014m) above the 0.01m tolerance so it moves. - arc: pivot: handle_hinge - axis: [0, 1, 0] + axis: [-1, 0, 0] angle: 0.45 absolute: true - max_step: 0.03 - reference: world - - name: push_open - object: handle_body_phys - operation: push - operator: arm - param: - pre_move: - - position: [0.0, 0.0, 0.0] - reference: eef_world - max_linear_step: 0.01 - max_angular_step: 0.15 - post_move: - - arc: - pivot: handle_hinge - axis: [0, 1, 0] - angle: 0.55 - absolute: true - max_step: 0.03 + max_step: 0.15 reference: world + # 3. Swing the door open by sweeping the gripper +0.9rad around the + # door_hinge (world +Z). RELATIVE (not absolute) on purpose: a + # snapshot-based arc rotates the gripper from its pose at action + # start by the cumulative angle, so the orientation target stays a + # clean horizontal Z-sweep. An absolute arc instead re-references + # the live (contact-deflected) pose every tick, so when the door + # momentarily stalls on its high frictionloss (5.0) the grip twists + # the gripper and it accumulates into the wrist flipping to point + # straight up. The per-waypoint tolerance lets the sweep finish when + # the door stalls a hair short of the full angle. - arc: pivot: door_hinge - axis: [0, 0, -1] - angle: -1.2 - absolute: true - max_step: 0.04 + axis: [0, 0, 1] + angle: 0.9 + max_step: 0.2 reference: world + tolerance: + position: 0.06 + orientation: 0.12 operators: - name: arm diff --git a/examples/act_policy_eval.md b/examples/act_policy_eval.md new file mode 100644 index 0000000..9fececc --- /dev/null +++ b/examples/act_policy_eval.md @@ -0,0 +1,381 @@ +# ACT 策略训练与评估完整流程 + +本文档介绍如何在 aao 仿真环境中采集数据、训练 ACT 模型、并进行闭环评估的完整流程。 + +## 一、数据采集 + +### 1.1 环境准备 + +确保已安装 [AIRBOT-Data-Collection](https://github.com/DISCOVER-Robotics/AIRBOT-Data-Collection): + +```bash +# 使用 Pixi(推荐) +pixi install +pixi shell -e collect + +# 或使用传统方式 +pip install -e .[all,airbot] +``` + +### 1.2 启动数据采集 + +在 `AIRBOT-Data-Collection` 目录下运行: + +```bash +airdc --path airbot_ie/configs/aao_config.yaml dataset.directory=my_task +``` + +- `--path`:指定配置文件路径 +- `dataset.directory`:数据保存目录名(保存在 `data/` 下) + +采集过程中使用键盘控制流程,按 `i` 键查看按键说明。 + +### 1.3 数据说明 + +采集完成后,数据保存为 `.mcap` 格式文件,位于 `data/my_task/` 目录。每个 episode 对应一个 `.mcap` 文件,包含: + +- **状态数据**:机械臂位姿、夹爪状态等 +- **动作数据**:示教端的位姿指令 +- **图像数据**:相机采集的 RGB 图像 + +## 二、模型训练 + +### 2.1 安装训练环境 + +确保已安装 [MCAP-DataLoader](https://github.com/OpenGHz/MCAP-DataLoader) 和 lerobot: + +```bash +pip install mcap-data-loader lerobot +``` + +### 2.2 准备训练配置 + +创建训练配置文件 `configs/config.yaml`: + +```yaml +batch_size: 8 +num_workers: 4 +policy: + type: act + chunk_size: 100 + n_action_steps: 100 + +dataset: + root: data # MCAP 数据根目录 + repo_id: my_task # 与采集时 dataset.directory 一致 + +mcap: + states: + - /follow/arm/pose/position + - /follow/arm/pose/rotation_6d + - /follow/gripper/joint_state/position + actions: + - /lead/arm/pose/position + - /lead/arm/pose/orientation + - /lead/gripper/joint_state/position + images: + - /wrist_cam/color/image_raw + - /env0_cam/color/image_raw +``` + +**配置说明:** + +- `states`:观测状态 topic 列表,会拼接成 `observation.state` +- `actions`:动作 topic 列表,会拼接成 `action` +- `images`:图像 topic 列表,会添加到 `observation.images` + +**关键要求:** + +- `states` / `actions` / `images` 的顺序必须固定,训练和评估时必须完全一致 +- topic 名称必须与 MCAP 数据中的 topic 名称匹配 + +### 2.3 开始训练 + +```bash +mcap-lerobot-train -c configs/config.yaml +``` + +训练过程中会自动: +- 加载 MCAP 数据并转换为 lerobot 格式 +- 保存 checkpoint 到 `outputs/train/_act/checkpoints/` +- 记录训练日志 + +训练完成后,模型保存在 `outputs/train//