"""Copy a SAPIEN articulated asset with USD-legal names, so the URDF importer can read it. SAPIEN names its collision meshes `original-7.obj`. A hyphen is illegal in a USD prim path, and Isaac's URDF importer half-handles it: it renames the prim to `original_7` but then still tries to create ``, which fails to parse, and the import dies with "Used null prim". It writes a 492-byte stub anyway and reports success, so the breakage only surfaces later as "Failed to find an articulation ... ArticulationRootAPI". This makes a sanitized copy: hyphens in mesh filenames and in the URDF's references become underscores. Everything else is untouched. python scripts/sanitize_urdf_asset.py 036_cabinet/46653 044_microwave/7310 """ import os import re import shutil import sys SRC = os.environ.get("ROBOTWIN_SRC", "/home/yu/internship_yu/robotwin_object/objects") def sanitize(job): cat, inst = job.split("/") src = f"{SRC}/{cat}/{inst}" dst = f"{SRC}/{cat}/{inst}_clean" if not os.path.isdir(src): print(f"[san] MISSING {src}") return None if os.path.isdir(dst): shutil.rmtree(dst) shutil.copytree(src, dst) renamed = 0 for root, _dirs, files in os.walk(dst): for fn in files: if "-" in fn: os.rename(os.path.join(root, fn), os.path.join(root, fn.replace("-", "_"))) renamed += 1 # An OBJ names its material library INSIDE the file (`mtllib original-1.mtl`). Renaming the # .mtl on disk without rewriting that line leaves every mesh material-less, and the whole # asset imports as featureless grey -- the microwave rendered as a plain cube. fixed = 0 for root, _dirs, files in os.walk(dst): for fn in files: if not fn.lower().endswith((".obj", ".mtl")): continue p = os.path.join(root, fn) try: txt = open(p, errors="ignore").read() except OSError: continue new = re.sub(r'^(mtllib|usemtl|map_Kd|map_Ka|map_Bump|bump)\s+(.+)$', lambda m: f"{m.group(1)} {m.group(2).replace('-', '_')}", txt, flags=re.M) if new != txt: open(p, "w").write(new) fixed += 1 urdf = os.path.join(dst, "mobility.urdf") text = open(urdf).read() # only rewrite hyphens inside filename references, not elsewhere in the XML text = re.sub(r'(filename\s*=\s*")([^"]+)(")', lambda m: m.group(1)+m.group(2).replace("-", "_")+m.group(3), text) # link and joint names feed prim paths too text = re.sub(r'((?:link|joint|parent|child)\s+(?:name|link)\s*=\s*")([^"]+)(")', lambda m: m.group(1)+m.group(2).replace("-", "_")+m.group(3), text) open(urdf, "w").write(text) print(f"[san] {job} -> {cat}/{inst}_clean ({renamed} files renamed, " f"{fixed} mesh files had internal references rewritten)") return f"{cat}/{inst}_clean" if __name__ == "__main__": out = [sanitize(j) for j in sys.argv[1:]] print("JOBS=" + ",".join(j for j in out if j))