mp_yam_code / scripts /yam_mesh_export.py
yqi19's picture
YAM bimanual task suite: env, solvers, tasks, converters
7399b6f verified
Raw
History Blame Contribute Delete
4.73 kB
"""Export YAM right-arm per-link meshes (in link-local frame) to OBJ for the web viewer."""
import argparse, sys, os
from isaaclab.app import AppLauncher
p=argparse.ArgumentParser(); AppLauncher.add_app_launcher_args(p); a=p.parse_args(); a.headless=True; a.enable_cameras=False
app=AppLauncher(a).app
import numpy as np, gymnasium as gym
REPO=os.path.dirname(os.path.dirname(os.path.abspath(__file__))); sys.path.insert(0,os.path.join(REPO,"source"))
import bimanual.tasks.manager_based.yam # noqa
from isaaclab_tasks.utils import parse_env_cfg
TASK="Template-YAM-Play-v0"
env=gym.make(TASK, cfg=parse_env_cfg(TASK, device="cuda:0", num_envs=1)); u=env.unwrapped; env.reset()
R=u.scene["right_robot"]
import omni.usd
from pxr import Usd, UsdGeom, Gf
stage=omni.usd.get_context().get_stage()
root_path=R.root_physx_view.prim_paths[0]
print("[m] root:", root_path, flush=True)
xf=UsdGeom.XformCache(Usd.TimeCode.Default())
OUT="/home/horde/project/xiaotong/outputs/yam_web/mesh"
os.makedirs(OUT, exist_ok=True)
def find_link_prim(name):
for pr in Usd.PrimRange(stage.GetPrimAtPath(root_path)):
if pr.GetName()==name:
return pr
return None
def gfmat_to_np(m):
return np.array([[m[i][j] for j in range(4)] for i in range(4)])
LINKS=["arm","link_1","link_2","link_3","link_4","link_5","link_6","left_finger","right_finger"]
linkpath={}; Lwinv={}
for n in LINKS:
lp=find_link_prim(n)
if lp is None: continue
linkpath[lp.GetPath().pathString]=n
Lwinv[n]=np.linalg.inv(gfmat_to_np(xf.GetLocalToWorldTransform(lp)))
# fingers are rigidly (approx) under link_6; export them in link_6's frame so they
# mount onto link_6's group in the viewer (their small prismatic slide is ignored for viz).
FRAME={n:n for n in LINKS}
FRAME["left_finger"]="link_6"; FRAME["right_finger"]="link_6"
def owning_link(prim):
p=prim.GetPath()
while not p.isEmpty and p.pathString!="/":
if p.pathString in linkpath: return linkpath[p.pathString]
p=p.GetParentPath()
return None
buck={n:{"V":[],"F":[]} for n in LINKS}
for pr in Usd.PrimRange(stage.GetPrimAtPath(root_path)):
if pr.GetTypeName()!="Mesh": continue
ln=owning_link(pr)
if ln is None: continue
mesh=UsdGeom.Mesh(pr); pts=mesh.GetPointsAttr().Get()
if not pts: continue
counts=mesh.GetFaceVertexCountsAttr().Get(); idx=mesh.GetFaceVertexIndicesAttr().Get()
Mw=gfmat_to_np(xf.GetLocalToWorldTransform(pr))
M=Mw@Lwinv[FRAME[ln]]
V=buck[ln]["V"]; F=buck[ln]["F"]; base=len(V)
P=np.array([[p[0],p[1],p[2],1.0] for p in pts]); Pl=P@M
for q in Pl: V.append((q[0],q[1],q[2]))
o=0
for c in counts:
for k in range(1,c-1): F.append((base+idx[o]+1, base+idx[o+k]+1, base+idx[o+k+1]+1))
o+=c
manifest={}
for ln in LINKS:
V=buck[ln]["V"]; F=buck[ln]["F"]
if not V: print(f"[m] {ln}: no mesh", flush=True); continue
fn=os.path.join(OUT, ln+".obj")
with open(fn,"w") as f:
for v in V: f.write(f"v {v[0]:.5f} {v[1]:.5f} {v[2]:.5f}\n")
for t in F: f.write(f"f {t[0]} {t[1]} {t[2]}\n")
manifest[ln]={"verts":len(V),"faces":len(F)}
print(f"[m] {ln}: {len(V)} verts {len(F)} tris -> {fn}", flush=True)
import json; json.dump(manifest, open(os.path.join(OUT,"manifest.json"),"w"))
# ---- authoritative chain: per-body world pose at HOME (from articulation) + joint axes ----
import numpy as _np
origin_env=u.scene.env_origins[0].cpu().numpy()
bn=list(R.data.body_names)
def body_pose(name):
i=bn.index(name)
p=R.data.body_pos_w[0,i].cpu().numpy()-origin_env
q=R.data.body_quat_w[0,i].cpu().numpy() # wxyz
return [float(x) for x in p],[float(x) for x in q]
# joint axes from USD physics revolute joints (axis token X/Y/Z in the joint's child frame)
from pxr import UsdPhysics
axis_map={}
for pr in Usd.PrimRange(stage.GetPrimAtPath(root_path)):
if pr.IsA(UsdPhysics.RevoluteJoint):
j=UsdPhysics.RevoluteJoint(pr)
ax=j.GetAxisAttr().Get()
rel=j.GetBody1Rel().GetTargets()
child=rel[0].name if rel else pr.GetName()
axis_map[child]={"axis":str(ax)}
CHAIN=["arm","link_1","link_2","link_3","link_4","link_5","link_6"]
pose={}
for n in CHAIN:
try: pose[n]={"pos":body_pose(n)[0],"quat":body_pose(n)[1]}
except Exception as e: print("[m] pose err",n,e,flush=True)
out={"pose":pose,"axis":axis_map,
"home":[0.0,1.5708,0.7854,0.7854,0.0,0.0],
"joint_child":["link_1","link_2","link_3","link_4","link_5","link_6"]}
json.dump(out, open(os.path.join(OUT,"chain_truth.json"),"w"))
print("[m] pose:", {n:[round(v,4) for v in pose[n]["pos"]] for n in pose}, flush=True)
print("[m] axis_map:", axis_map, flush=True)
env.close(); app.close(); print("MESH_OK", flush=True)