Files
issacdataengine/migrate/custom_task_guide.md
Tangger 3d6b73753a feat: add test tube pick task with custom assets and grasp annotations
- Add pick_test_tube task: USDC asset repackaging, grasp generation, task config
- Add tools: usdc_to_obj.py, repackage_test_tube.py, fix_test_tube_materials.py
- Add custom_task_guide.md: full Chinese documentation for creating custom tasks
- Add crawled InternDataEngine online docs (23 pages)
- Add grasp generation script (gen_tube_grasp.py) and pipeline config
2026-04-05 11:01:59 +08:00

9.3 KiB
Raw Permalink Blame History

自定义任务创建指南:从 USDC 资产到完整任务

本文档记录了将外部 USDC 资产(以试管为例)转换为 InternDataEngine 可用任务的完整流程。

前提条件

  • InternDataEngine 项目已配置完成IS 5.0.0 + banana500 环境)
  • 有现成的 USD/USDC 3D 模型文件
  • conda 环境 banana450(用于 grasp 标注生成pyarmor 兼容)

完整流程

Step 1: 准备资产目录

workflows/simbox/example_assets/task/ 下创建任务目录:

mkdir -p workflows/simbox/example_assets/task/pick_test_tube/test_tube
mkdir -p workflows/simbox/example_assets/task/pick_test_tube/test_tube_rack

Step 2: 从 USDC 导出三角化 OBJ

InternDataEngine 的 grasp 生成工具需要 OBJ 格式输入,且必须是纯三角面。使用 migrate/usdc_to_obj.py 从 USDC 提取并三角化:

conda activate banana500
python migrate/usdc_to_obj.py \
  --input /path/to/your/model.usdc \
  --output workflows/simbox/example_assets/task/pick_test_tube/test_tube/

输出文件:Aligned_obj.obj(三角化的 OBJ

注意:原始 USDC 中的面可能是四边形或多边形,脚本会自动进行 fan 三角化。

Step 3: 重新打包 USD 结构

InternDataEngine 要求 USD 资产具有特定的层级结构:

/World (defaultPrim, Xform, 无物理属性)
├── /Looks (Scope, 材质)
│   ├── Material_0
│   └── Material_1
├── /Aligned (Xform, PhysicsRigidBodyAPI + PhysicsMassAPI)
│   └── /mesh (Mesh, PhysicsCollisionAPI + PhysicsMeshCollisionAPI)
└── /PhysicsMaterial (Material, PhysicsMaterialAPI)

关键要求

  • /World 必须是 defaultPrim且不能有任何物理 schema
  • /Alignedprim_path_child,必须有 PhysicsRigidBodyAPI
  • 碰撞体必须使用 convexHull 近似(不能用 triangle mesh
  • /Looks 必须和 /Aligned 平级(在同一引用范围内)

使用 migrate/repackage_test_tube.py 自动重构:

python migrate/repackage_test_tube.py

脚本逻辑:

  1. 创建新 USD定义 /World 为 defaultPrim纯净 Xform不挂引用
  2. /World/Aligned 上添加引用,指向源 USD 的子节点(如 /Test_Tube_AA_01/Test_Tube
  3. /World/Looks 上添加引用,指向源 USD 的材质(如 /Test_Tube_AA_01/Looks
  4. /World/Aligned 添加 PhysicsRigidBodyAPIPhysicsMassAPI
  5. 给碰撞 mesh 设置 convexHull 近似

重新绑定材质:由于引用子节点后,原始材质绑定路径超出引用范围,需要手动重新绑定:

python migrate/fix_test_tube_materials.py

Step 4: 生成 Grasp 抓取标注

使用项目自带的 grasp 生成工具(需要 banana450 环境,因为 pyarmor 加密对 Python 版本敏感):

conda activate banana450
python workflows/simbox/tools/grasp/gen_sparse_label.py \
  --obj_path workflows/simbox/example_assets/task/pick_test_tube/test_tube/Aligned_obj.obj \
  --unit m --sparse_num 3000 --max_widths 0.1

输出:Aligned_grasp_sparse.npy3000 x 17 的数组)

可视化验证

python workflows/simbox/tools/grasp/vis_grasp.py \
  --obj_path workflows/simbox/example_assets/task/pick_test_tube/test_tube/Aligned_obj.obj \
  --unit m --N 200

会弹出 Open3D 窗口,蓝色线条表示 gripper 姿态,应该合理地分布在物体周围。

Grasp 标注格式N x 17

维度 含义
0 1 score质量分数0.1-1.0,越小越好)
1 1 width夹持器开口宽度
2 1 height
3 1 depth
4:13 9 旋转矩阵3x3row-major
13:16 3 抓取中心点位置(物体坐标系)
16 1 obj_id通常为 -1

Step 5: 创建任务配置 YAML

文件:workflows/simbox/core/configs/tasks/example/pick_test_tube.yaml

tasks:
  -
    name: banana_base_task
    asset_root: workflows/simbox/example_assets
    task: BananaBaseTask
    task_id: 0
    offset: null
    render: True
    neglect_collision_names: ["table"]

    arena_file: workflows/simbox/core/configs/arenas/example.yaml

    env_map:
      envmap_lib: envmap_lib
      apply_randomization: False
      intensity_range: [5000, 5000]
      rotation_range: [0, 0]

    robots:
      -
        name: "split_aloha"
        robot_config_file: workflows/simbox/core/configs/robots/split_aloha.yaml
        euler: [0.0, 0.0, 90.0]
        ignore_substring: ["material", "table", "test_tube_rack"]

    objects:
      -
        name: test_tube_right
        path: task/pick_test_tube/test_tube/Aligned_obj.usd
        target_class: RigidObject
        dataset: custom
        category: test_tube
        prim_path_child: Aligned
        translation: [0.0, 0.0, 0.0]
        euler: [0.0, 0.0, 0.0]
        scale: [1, 1, 1]
        apply_randomization: False
        orientation_mode: keep

    regions:
      -
        object: test_tube_right
        target: table
        random_type: A_on_B_region_sampler
        random_config:
          pos_range: [[0.05, -0.05, 0.0], [0.15, 0.05, 0.0]]
          yaw_rotation: [0.0, 0.0]
      -
        object: split_aloha
        target: table
        random_type: A_on_B_region_sampler
        random_config:
          pos_range: [[0.0, -0.86, -0.75], [0.0, -0.86, -0.75]]
          yaw_rotation: [0.0, 0.0]

    cameras:
      # ... 复用 split_aloha 的相机配置(详见完整配置文件)

    data:
      task_dir: "pick_test_tube"
      language_instruction: "Pick up the test tube from the table."
      detailed_language_instruction: "Use the right arm to grasp the test tube."
      collect_info: "Test tube picking task"
      version: "v1.0"
      update: True
      max_episode_length: 2000

    skills:
      -
        split_aloha:
          -
            right:
              -
                name: pick
                objects: [test_tube_right]
                npy_name: Aligned_grasp_sparse.npy
                filter_y_dir: ["forward", 60]
                filter_z_dir: ["downward", 150]
                pre_grasp_offset: 0.05
                gripper_change_steps: 10
                t_eps: 0.025
                o_eps: 1
                process_valid: True
                lift_th: 0.02
                post_grasp_offset_min: 0.10
                post_grasp_offset_max: 0.15
              -
                name: heuristic__skill
                mode: home
                gripper_state: 1.0

Skill 名称注意:使用 register_skill 装饰器注册的名称(类名转 snake_case例如

  • Pickpick
  • Heuristic_Skillheuristic__skill(双下划线)
  • Goto_Posegoto__pose(双下划线)

Step 6: 创建 Pipeline 配置

文件:configs/simbox/de_pick_test_tube.yaml

name: simbox_pick_test_tube
load_stage:
  scene_loader:
    type: env_loader
    args:
      workflow_type: SimBoxDualWorkFlow
      cfg_path: workflows/simbox/core/configs/tasks/example/pick_test_tube.yaml
      simulator:
        physics_dt: 1/30
        rendering_dt: 1/30
        stage_units_in_meters: 1.0
        headless: False    # 调试时用 FalseGUI生产时改 True
        renderer: "RayTracedLighting"
        anti_aliasing: 0
  layout_random_generator:
    type: env_randomizer
    args:
      random_num: 1        # 调试时用 1生产时增大
      strict_mode: true
plan_stage:
  seq_planner:
    type: env_planner
render_stage:
  renderer:
    type: env_renderer
store_stage:
  writer:
    type: env_writer
    args:
      batch_async: true
      output_dir: output/${name}/

Step 7: 运行测试

conda activate banana500

# GUI 模式调试headless: False
python launcher.py --config configs/simbox/de_pick_test_tube.yaml

# 确认后改 headless: True增大 random_num 批量生产

Step 8: 检查输出

输出目录:output/simbox_pick_test_tube/

output/simbox_pick_test_tube/
├── pick_test_tube/split_aloha/<task>/right/
│   ├── <timestamp>/
│   │   ├── images.rgb.head/
│   │   ├── images.rgb.hand_right/
│   │   ├── images.rgb.hand_left/
│   │   └── lmdb/
│   └── ...
└── de_config.yaml

常见问题

Q: gen_sparse_label.py_PyFloat_Pack8 错误

A: pyarmor 加密对 Python 版本敏感,使用 banana450 环境Python 3.10 + 旧版依赖)。

Q: USD 打开后材质丢失

A: 引用子节点时材质路径超出引用范围。需要用 fix_test_tube_materials.py 重新绑定。

Q: RigidContactViewsensor_count 错误

A: USD 结构不对。确保 /World (defaultPrim) 没有 PhysicsRigidBodyAPI,物理属性只在 /World/Aligned 子节点上。

Q: OBJ 导出后 grasp 生成为空0 条)

A: OBJ 文件包含非三角形面。使用 migrate/usdc_to_obj.py 导出时会自动三角化。

Q: Plan 不收敛

A: 检查 grasp 标注质量(用 vis_grasp.py 可视化),确认姿态合理。调整 filter_y_dir / filter_z_dir 放宽过滤条件。

工具脚本一览

脚本 用途
migrate/usdc_to_obj.py USDC → 三角化 OBJ
migrate/repackage_test_tube.py 重构 USD 层级结构
migrate/fix_test_tube_materials.py 修复材质绑定
workflows/simbox/tools/grasp/gen_sparse_label.py 生成 grasp 标注(需 banana450
workflows/simbox/tools/grasp/vis_grasp.py 可视化 grasp 标注