File size: 3,814 Bytes
7399b6f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
"""Convert an ARTICULATED RoboTwin object (SAPIEN-style URDF) to USD.

Most RoboTwin categories ship a single fused GLB, but some also ship articulated variants under
numbered sub-directories with a `mobility.urdf` and a `semantics.txt`. `060_kitchenpot/100015`,
for instance, is `link_0 = lid` on a PRISMATIC joint plus `link_1 = pot_body` -- i.e. a pot whose
lid genuinely lifts off, which the fused GLB cannot do.

    ROBOTWIN_SRC=... ROBOTWIN_USD=... \
    python scripts/robotwin_urdf_convert.py --headless --jobs 060_kitchenpot/100015
"""
import argparse, os, sys
from isaaclab.app import AppLauncher

p = argparse.ArgumentParser()
p.add_argument("--jobs", default="060_kitchenpot/100015",
               help="comma-separated <category>/<instance> dirs holding a mobility.urdf")
p.add_argument("--fix_base", action="store_true", help="pin the base in place (a static fixture)")
AppLauncher.add_app_launcher_args(p)
a = p.parse_args(); a.headless = True
app = AppLauncher(a).app

from isaaclab.sim.converters import UrdfConverter, UrdfConverterCfg

SRC = os.environ.get("ROBOTWIN_SRC", "/home/yu/internship_yu/robotwin_object/objects")
OUT = os.environ.get("ROBOTWIN_USD", "/home/yu/internship_yu/robotwin_usd")
os.makedirs(OUT, exist_ok=True)

for job in [j for j in a.jobs.split(",") if j]:
    cat, inst = job.split("/")
    urdf = f"{SRC}/{cat}/{inst}/mobility.urdf"
    if not os.path.exists(urdf):
        print(f"[urdf] MISSING {urdf}", flush=True); continue
    sem = f"{SRC}/{cat}/{inst}/semantics.txt"
    if os.path.exists(sem):
        print(f"[urdf] {cat}/{inst} parts: {open(sem).read().strip().splitlines()}", flush=True)
    # `fix_base` and the joint drive's PD gains are required fields in this Isaac Lab version --
    # a lid on a prismatic joint needs a soft drive so the arm can pull it open rather than
    # fighting a stiff actuator.
    cfg = UrdfConverterCfg(
        asset_path=urdf, usd_dir=f"{OUT}/{cat}", usd_file_name=f"{inst}.usd",
        force_usd_conversion=True, fix_base=a.fix_base,
        # THE default here is "convex_hull", and it is wrong for every one of these fixtures: it
        # collapses a whole microwave into a single box, swallowing the door, and the door's
        # collider then interpenetrates the body's so the hinge cannot move at all. It also makes
        # the asset RENDER as a featureless cube. Decomposition keeps the parts apart.
        collider_type="convex_decomposition",
        joint_drive=UrdfConverterCfg.JointDriveCfg(
            target_type="none",
            gains=UrdfConverterCfg.JointDriveCfg.PDGainsCfg(stiffness=0.0, damping=2.0),
        ),
    )
    try:
        conv = UrdfConverter(cfg)
        # The importer swallows its own failures: a hyphen in a mesh filename makes it die with
        # "Used null prim", write a 492-byte stub, and return normally. Size-check the result so
        # a broken conversion is caught here instead of as a missing ArticulationRootAPI later.
        size = os.path.getsize(conv.usd_path) if os.path.exists(conv.usd_path) else 0
        payload = sum(os.path.getsize(os.path.join(r, f))
                      for r, _d, fs in os.walk(os.path.dirname(conv.usd_path)) for f in fs)
        if payload < 12_000:
            print(f"[urdf] FAIL {cat}/{inst}: importer produced an EMPTY asset "
                  f"({size} B stub, {payload} B total). Almost always a USD-illegal character in "
                  f"a mesh/link name -- run scripts/sanitize_urdf_asset.py {cat}/{inst} first.",
                  flush=True)
        else:
            print(f"[urdf] OK {cat}/{inst} -> {conv.usd_path} ({payload//1024} KB)", flush=True)
    except Exception as e:
        print(f"[urdf] FAIL {cat}/{inst}: {type(e).__name__}: {e}", flush=True)

app.close(); print("URDF_CONVERT_DONE", flush=True)