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

304 lines
9.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 自定义任务创建指南:从 USDC 资产到完整任务
本文档记录了将外部 USDC 资产(以试管为例)转换为 InternDataEngine 可用任务的完整流程。
## 前提条件
- InternDataEngine 项目已配置完成IS 5.0.0 + banana500 环境)
- 有现成的 USD/USDC 3D 模型文件
- conda 环境 `banana450`(用于 grasp 标注生成pyarmor 兼容)
## 完整流程
### Step 1: 准备资产目录
`workflows/simbox/example_assets/task/` 下创建任务目录:
```bash
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 提取并三角化:
```bash
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
- `/Aligned``prim_path_child`,必须有 `PhysicsRigidBodyAPI`
- 碰撞体必须使用 `convexHull` 近似(不能用 triangle mesh
- `/Looks` 必须和 `/Aligned` 平级(在同一引用范围内)
使用 `migrate/repackage_test_tube.py` 自动重构:
```bash
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` 添加 `PhysicsRigidBodyAPI``PhysicsMassAPI`
5. 给碰撞 mesh 设置 `convexHull` 近似
**重新绑定材质**:由于引用子节点后,原始材质绑定路径超出引用范围,需要手动重新绑定:
```bash
python migrate/fix_test_tube_materials.py
```
### Step 4: 生成 Grasp 抓取标注
使用项目自带的 grasp 生成工具(需要 `banana450` 环境,因为 pyarmor 加密对 Python 版本敏感):
```bash
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.npy`3000 x 17 的数组)
**可视化验证**
```bash
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`
```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例如
- `Pick``pick`
- `Heuristic_Skill``heuristic__skill`(双下划线)
- `Goto_Pose``goto__pose`(双下划线)
### Step 6: 创建 Pipeline 配置
文件:`configs/simbox/de_pick_test_tube.yaml`
```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: 运行测试
```bash
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: `RigidContactView` 报 `sensor_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 标注 |