44# SPDX-License-Identifier: Apache-2.0
55
66
7+ import functools
78import torch
9+ import warnings
810from abc import ABC
911from dataclasses import MISSING
1012from typing import Any
4951_DEFAULT_STAND_HEIGHT_SCALE : float = 1.7
5052
5153# The stand's top is pinned at the robot base and it extends downward to the floor, so scaling its
52- # height moves the floor contact, not the mount. Measured native (scale=1.0) stand height in meters;
53- # used to lift the robot base by the same amount the stand grows, keeping the stand's bottom on the
54- # floor while the robot rides higher.
55- _STAND_UNIT_HEIGHT_M : float = 0.795
54+ # height moves the floor contact, not the mount. We lift the robot base by the amount the stand
55+ # grows (native height x scale delta), keeping the stand's bottom on the floor while the robot rides
56+ # higher. The native height is read from the stand USD; this measured value is the fallback used when
57+ # the asset can't be opened (e.g. no asset resolver / network outside a running SimulationApp).
58+ _FALLBACK_STAND_UNIT_HEIGHT_M : float = 0.795
59+
60+
61+ @functools .lru_cache (maxsize = None )
62+ def _stand_unit_height_m (usd_path : str ) -> float :
63+ """Native (scale=1.0) z-height of the stand USD in meters, cached per asset path.
64+
65+ Falls back to ``_FALLBACK_STAND_UNIT_HEIGHT_M`` if the asset cannot be opened or measured.
66+ """
67+ try :
68+ from pxr import Usd , UsdGeom
69+
70+ stage = Usd .Stage .Open (usd_path )
71+ assert stage is not None , f"could not open stand USD: { usd_path } "
72+ # Bound the asset's default prim (its geometry root), not the pseudo-root, so stray stage
73+ # prims (lights, cameras, guides) can't inflate the measured height.
74+ root_prim = stage .GetDefaultPrim () or stage .GetPseudoRoot ()
75+ bound = UsdGeom .BBoxCache (Usd .TimeCode .Default (), [UsdGeom .Tokens .default_ ]).ComputeWorldBound (root_prim )
76+ height = bound .ComputeAlignedRange ().GetSize ()[2 ]
77+ assert height > 0.0 , f"non-positive stand height { height } from { usd_path } "
78+ return height
79+ except Exception as exc : # noqa: BLE001 - any failure falls back to the measured constant
80+ warnings .warn (
81+ f"Falling back to { _FALLBACK_STAND_UNIT_HEIGHT_M } m for the stand height; "
82+ f"could not measure { usd_path } : { exc !r} "
83+ )
84+ return _FALLBACK_STAND_UNIT_HEIGHT_M
5685
5786
5887class DroidEmbodimentBase (EmbodimentBase , ABC ):
@@ -78,7 +107,8 @@ def __init__(
78107 self .scene_config = DroidSceneCfg ()
79108 self .scene_config .stand .spawn .scale = (* _STAND_FOOTPRINT_SCALE_XY , stand_height )
80109 # Lift the robot base (and stand) so a taller/shorter stand keeps its bottom on the floor.
81- self ._robot_base_z_offset = _STAND_UNIT_HEIGHT_M * (stand_height - _DEFAULT_STAND_HEIGHT_SCALE )
110+ stand_unit_height = _stand_unit_height_m (self .scene_config .stand .spawn .usd_path )
111+ self ._robot_base_z_offset = stand_unit_height * (stand_height - _DEFAULT_STAND_HEIGHT_SCALE )
82112 self .scene_config .robot .init_state .pos = self ._lift_z (self .scene_config .robot .init_state .pos )
83113 self .scene_config .stand .init_state .pos = self ._lift_z (self .scene_config .stand .init_state .pos )
84114 self .action_config = None
0 commit comments