fix: IS 4.5.0 -> 5.0.0 migration — USD metadata, DomeLight, scene reuse

- Fix USD metersPerUnit/upAxis for IS 5.0.0 (no longer auto-compensated)
- Batch fix all Aligned_obj.usd, table, and art USD files with backups
- Fix DomeLight rotation to Z-axis only (prevent tilted environment map)
- Fix scene reuse across episodes (arena_file caching, task clearing, prim guard)
- Add migration tools: scan_usd_metadata.py, fix_usd_metadata.py
- Add migration guide: migerate/migerate.md
- Add nvidia-curobo to .gitignore
- Fix sort_the_rubbish config: obj_0 -> obj_1 (obj_0 does not exist)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Tangger
2026-04-03 11:10:39 +08:00
parent f338199bcb
commit 03d9a5b909
65 changed files with 862 additions and 6 deletions

View File

@@ -29,7 +29,7 @@ tasks:
objects:
-
name: pick_object_left
path: task/sort_the_rubbish/non_recyclable_garbage/obj_0/Aligned_obj.usd
path: task/sort_the_rubbish/non_recyclable_garbage/obj_1/Aligned_obj.usd
target_class: RigidObject
dataset: oo3d
category: bottle

View File

@@ -249,6 +249,12 @@ class TemplateController(BaseController):
obstacles = self.usd_help.get_obstacles_from_stage(
ignore_substring=self.ignore_substring, reference_prim_path=self.reference_prim_path
).get_collision_check_world()
# Diagnostic: print what curobo sees as the collision world
n_cuboid = len(obstacles.cuboid) if obstacles.cuboid else 0
n_mesh = len(obstacles.mesh) if obstacles.mesh else 0
mesh_names = [m.name for m in obstacles.mesh] if obstacles.mesh else []
print(f"[CUROBO_WORLD] cuboids={n_cuboid}, meshes={n_mesh}, "
f"mesh_names={mesh_names[:5]}{'...' if n_mesh > 5 else ''}", flush=True)
if self.motion_gen is not None:
self.motion_gen.update_world(obstacles)
self.world_cfg = obstacles
@@ -277,6 +283,10 @@ class TemplateController(BaseController):
self.T_world_base_init = get_relative_transform(
get_prim_at_path(self.robot_base_path), get_prim_at_path(self.task.root_prim_path)
)
print(f"[TRANSFORM_DBG] robot_base_path={self.robot_base_path}", flush=True)
print(f"[TRANSFORM_DBG] root_prim_path={self.task.root_prim_path}", flush=True)
print(f"[TRANSFORM_DBG] T_world_base_init translation={self.T_world_base_init[:3, 3]}", flush=True)
print(f"[TRANSFORM_DBG] T_world_base_init full=\n{self.T_world_base_init}", flush=True)
self.T_world_ee_init = self.T_world_base_init @ self.T_base_ee_init
self._ee_trans, self._ee_ori = self.get_ee_pose()
self._ee_trans = self.tensor_args.to_device(self._ee_trans)

View File

@@ -47,6 +47,21 @@ class RigidObject(RigidPrim):
self.base_prim_path = prim_path
rigid_prim_path = os.path.join(self.base_prim_path, cfg["prim_path_child"])
self.mesh_prim_path = str(get_prim_at_path(rigid_prim_path).GetChildren()[0].GetPrimPath())
# [LOAD_DBG] Print xformOps right after create_prim, before physics
try:
from pxr import UsdGeom
_xf = UsdGeom.Xformable(get_prim_at_path(rigid_prim_path))
for _op in _xf.GetOrderedXformOps():
print(f"[LOAD_DBG] {cfg_name} after_create_prim: {_op.GetName()} = {_op.Get()}", flush=True)
_l2w = _xf.ComputeLocalToWorldTransform(0)
print(f"[LOAD_DBG] {cfg_name} after_create_prim l2w=({_l2w[3][0]:.6f}, {_l2w[3][1]:.6f}, {_l2w[3][2]:.6f})", flush=True)
# Also check the USD file's own metersPerUnit
_ref_stage = get_prim_at_path(prim_path).GetStage()
_mpu = UsdGeom.GetStageMetersPerUnit(_ref_stage)
_up = UsdGeom.GetStageUpAxis(_ref_stage)
print(f"[LOAD_DBG] {cfg_name} stage metersPerUnit={_mpu} upAxis={_up}", flush=True)
except Exception as _e:
print(f"[LOAD_DBG] {cfg_name} error: {_e}", flush=True)
super().__init__(prim_path=rigid_prim_path, name=cfg["name"], *args, **kwargs)
def get_observations(self):

View File

@@ -284,8 +284,49 @@ class Pick(BaseSkill):
if frame == "body":
return self.T_obj_ee
T_world_obj = tf_matrix_from_pose(*self.pick_obj.get_local_pose())
local_pose = self.pick_obj.get_local_pose()
world_pose = self.pick_obj.get_world_pose()
print(f"[PICK_DBG] prim_path={self.pick_obj.prim_path}", flush=True)
print(f"[PICK_DBG] local_pose trans={local_pose[0]}", flush=True)
print(f"[PICK_DBG] world_pose trans={world_pose[0]}", flush=True)
print(f"[PICK_DBG] local_pose ori={local_pose[1]}", flush=True)
print(f"[PICK_DBG] world_pose ori={world_pose[1]}", flush=True)
parent_prim = get_prim_at_path(self.pick_obj.prim_path).GetParent()
print(f"[PICK_DBG] parent_prim_path={parent_prim.GetPrimPath()}", flush=True)
grandparent_prim = parent_prim.GetParent()
print(f"[PICK_DBG] grandparent_prim_path={grandparent_prim.GetPrimPath()}", flush=True)
try:
from pxr import UsdGeom
obj_prim = get_prim_at_path(self.pick_obj.prim_path)
obj_xf = UsdGeom.Xformable(obj_prim)
xform_ops = obj_xf.GetOrderedXformOps()
print(f"[PICK_DBG] obj_xformOps_count={len(xform_ops)}", flush=True)
for op in xform_ops:
print(f"[PICK_DBG] obj_xformOp: {op.GetName()} val={op.Get()}", flush=True)
obj_l2w = obj_xf.ComputeLocalToWorldTransform(0)
print(f"[PICK_DBG] obj_USD_l2w=({obj_l2w[3][0]:.6f}, {obj_l2w[3][1]:.6f}, {obj_l2w[3][2]:.6f})", flush=True)
parent_xf = UsdGeom.Xformable(parent_prim)
parent_l2w = parent_xf.ComputeLocalToWorldTransform(0)
print(f"[PICK_DBG] parent_l2w_translate=({parent_l2w[3][0]}, {parent_l2w[3][1]}, {parent_l2w[3][2]})", flush=True)
gp_xf = UsdGeom.Xformable(grandparent_prim)
gp_l2w = gp_xf.ComputeLocalToWorldTransform(0)
print(f"[PICK_DBG] grandparent_l2w_translate=({gp_l2w[3][0]}, {gp_l2w[3][1]}, {gp_l2w[3][2]})", flush=True)
stage = parent_prim.GetStage()
mpu = UsdGeom.GetStageMetersPerUnit(stage)
print(f"[PICK_DBG] stage_metersPerUnit={mpu}", flush=True)
# Check get_local_pose source
glp_method = type(self.pick_obj).get_local_pose
print(f"[PICK_DBG] get_local_pose_from={glp_method.__qualname__}", flush=True)
except Exception as e:
import traceback
print(f"[PICK_DBG] UsdGeom error: {e}", flush=True)
traceback.print_exc()
print(f"[PICK_DBG] root_prim_path={self.task.root_prim_path}", flush=True)
print(f"[PICK_DBG] reference_prim_path={self.controller.reference_prim_path}", flush=True)
T_world_obj = tf_matrix_from_pose(*local_pose)
print(f"[PICK_DBG] T_world_obj translation={T_world_obj[:3,3]}", flush=True)
T_world_ee = T_world_obj[None] @ self.T_obj_ee
print(f"[PICK_DBG] T_world_ee[0] translation={T_world_ee[0,:3,3]}", flush=True)
if frame == "world":
return T_world_ee
@@ -294,8 +335,11 @@ class Pick(BaseSkill):
T_world_base = get_relative_transform(
get_prim_at_path(self.controller.reference_prim_path), get_prim_at_path(self.task.root_prim_path)
)
print(f"[PICK_DBG] T_world_base translation={T_world_base[:3,3]}", flush=True)
T_base_world = np.linalg.inv(T_world_base)
print(f"[PICK_DBG] T_base_world translation={T_base_world[:3,3]}", flush=True)
T_base_ee = T_base_world[None] @ T_world_ee
print(f"[PICK_DBG] T_base_ee[0] translation={T_base_ee[0,:3,3]}", flush=True)
return T_base_ee
def get_contact(self, contact_threshold=0.0):

View File

@@ -143,6 +143,8 @@ class Track(BaseSkill):
def cal_table_2_base(self):
tgt = self.task.fixtures["table"]
bbox_tgt = compute_bbox(tgt.prim)
print(f"[BBOX_DBG] table bbox min={list(bbox_tgt.min)}, max={list(bbox_tgt.max)}", flush=True)
print(f"[BBOX_DBG] T_base_2_world translation={self.T_base_2_world[:3, 3]}", flush=True)
table_center = (np.asarray(bbox_tgt.min) + np.asarray(bbox_tgt.max)) / 2
tgt_z_max = bbox_tgt.max[2]
table_center[2] = tgt_z_max

View File

@@ -335,6 +335,14 @@ class BananaBaseTask(BaseTask):
orientation = get_orientation(cfg.get("euler"), cfg.get("quaternion"))
obj.set_local_pose(translation=cfg.get("translation"), orientation=orientation)
obj.set_local_scale(cfg.get("scale", [1.0, 1.0, 1.0]))
# [LOAD_DBG] Print after set_local_pose
try:
from pxr import UsdGeom
_xf = UsdGeom.Xformable(get_prim_at_path(obj.prim_path))
for _op in _xf.GetOrderedXformOps():
print(f"[LOAD_DBG] {cfg['name']} after_set_local_pose: {_op.GetName()} = {_op.Get()}", flush=True)
except Exception as _e:
print(f"[LOAD_DBG] {cfg['name']} after_set_local_pose error: {_e}", flush=True)
obj.set_visibility(cfg.get("visible", True))
# Extra behavior per type
@@ -490,7 +498,7 @@ class BananaBaseTask(BaseTask):
if cfg.get("apply_randomization", False):
envmap_id = random.randint(0, len(envmap_hdr_path_list) - 1)
intensity = random.uniform(cfg["intensity_range"][0], cfg["intensity_range"][1])
rotation = [random.uniform(cfg["rotation_range"][0], cfg["rotation_range"][1]) for _ in range(3)]
rotation = [0.0, 0.0, random.uniform(cfg["rotation_range"][0], cfg["rotation_range"][1])]
else:
envmap_id = 0
intensity = 1000.0