Joint Dependent Mesh/BBox for Embodiment - #968
Conversation
| return PlacementGeometrySource( | ||
| usd_path=spawn.usd_path, | ||
| scale=(scale_x, scale_y, scale_z), | ||
| joint_pos=dict(robot.init_state.joint_pos or {}), |
There was a problem hiding this comment.
When a Franka or Droid embodiment receives a non-default initial_joint_pose, the reset event applies that pose while placement geometry still reads robot.init_state.joint_pos, causing relation placement to use a bounding box and collision mesh for the wrong arm configuration.
Knowledge Base Used:
There was a problem hiding this comment.
This is better handle in droid/franka. set_initial_joint_pose currently only updates the reset event's default_pose.
can expand set_initial_joint_pose to also all self.set_joint_initial_pos(...) with a name→value map matching set_default_joint_pose order.
There was a problem hiding this comment.
That's the right fix. Looking at both constructors, set_initial_joint_pose only writes to the event's positional default_pose list but leaves init_state.joint_pos (what get_placement_geometry_source reads) unchanged.
One ordering issue to watch in FrankaEmbodimentBase.__init__: set_initial_joint_pose is called before self.scene_config is assigned:
self.event_config = FrankaEventCfg()
if initial_joint_pose is not None:
self.set_initial_joint_pose(initial_joint_pose) # scene_config is still None here
...
self.scene_config = FrankaSceneCfg() # assigned afterSo if you expand set_initial_joint_pose to also call self.set_joint_initial_pos(...), it'll hit the assert self.scene_config is not None in the base class. Droid doesn't have this problem since self.scene_config = DroidSceneCfg() is assigned before the call.
The simplest fix for Franka is to move scene_config assignment before the joint pose call:
self.scene_config = FrankaSceneCfg()
self.event_config = FrankaEventCfg()
if initial_joint_pose is not None:
self.set_initial_joint_pose(initial_joint_pose)Then the expanded set_initial_joint_pose in both Franka and Droid can safely call self.set_joint_initial_pos(joint_name_map) alongside the existing default_pose update, and placement geometry will reflect the correct configuration.
| def asset_key(source_usd_path: str) -> str: | ||
| """Return the identity a published artifact is named and validated by: the source USD's stem.""" | ||
| # The stem rather than the full path, so an artifact exported from a per-user cache directory | ||
| # still matches elsewhere. Stems already spell out the variant: droid_franka_robotiq_on_stand_1.350. | ||
| return Path(str(source_usd_path)).stem |
There was a problem hiding this comment.
Source changes retain stale meshes
When a robot USD is updated without changing its stem or configured pose, artifact validation still accepts the previous mesh because it checks only the stem and pose key. Developers must manually clear or republish artifacts before placement reflects the updated geometry.
Knowledge Base Used: Scene Composition, Affordances, and Relation Solving
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Greptile SummaryThis PR introduces joint-dependent placement geometry and reusable collision-mesh artifacts.
Confidence Score: 3/5The PR should not merge until Franka and Droid placement geometry honors constructor-supplied initial joint poses; source-aware cache invalidation should also be strengthened. Franka and Droid can reset into a constructor-selected arm pose while their newly introduced bounding box and collision mesh are computed from a different joint mapping, causing incorrect placement geometry on a supported path. Files Needing Attention: isaaclab_arena/embodiments/embodiment_base.py, isaaclab_arena/embodiments/franka/franka.py, isaaclab_arena/embodiments/droid/droid.py, isaaclab_arena/utils/collision_mesh_store.py Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart LR
Config[Embodiment scene config] --> Source[PlacementGeometrySource]
Source --> Pose[USD articulation posing]
Pose --> BBox[Posed bounding box]
Pose --> Extract[Mesh extraction]
Source --> Store{Stored artifact valid?}
Store -->|yes| Mesh[Scaled collision mesh]
Store -->|no| Extract
Extract --> Cache[Local/published mesh store]
Cache --> Mesh
BBox --> Placement[Relation placement]
Mesh --> Placement
Reviews (1): Last reviewed commit: "add joint support for robots" | Re-trigger Greptile |
| what makes a mesh reusable: embodiments spawn at their configured pose rather than at zero, so keying | ||
| on the asset alone would store a mesh nobody asks for. | ||
|
|
||
| Lookup order is the local cache, then the robot's own folder under ``ARENA_ROBOT_LIBRARY_DIR`` on |
There was a problem hiding this comment.
🟡 Does the published robot library need to ship now?
The in-process lru_cache on the posed-geometry helpers already covers the relation-solver hot path (repeated bbox queries within a run), so this disk + Nucleus layer's marginal benefit is the one-time 0.1–2.5 s extraction per fresh process. Weighed against that, it adds a publish pipeline that must be re-run on every USD/joint change, a Nucleus dependency in the placement path, and a 1 GiB ~/.cache cache that is now on by default for every user (a default-path change, not opt-in). Could we ship the in-process cache first — plus a plain local disk cache if the cross-process cost actually bites — and defer the exported-library machinery until it's shown to be a bottleneck?
🤖 Isaac Lab-Arena Review BotSummaryThis PR makes an embodiment's placement bounding box and collision mesh reflect the robot as actually spawned — posed at its configured Design, Boundaries & ScopeMy one real question is scope, raised inline on Boundaries otherwise hold: the new FK/store code is generic USD/IO utility, no robot-specific logic leaks into core, and the embodiment geometry methods stay pure (no live Findings🟡 collision_mesh_store.py — question whether the published-library + disk-LRU persistence needs to ship now, or could be deferred behind the in-process cache (inline). Test CoverageExcellent. New tests follow the inner/outer VerdictMinor fixes needed — essentially ship-ready; please just weigh in on the persistence-layer scope question before merge. |
qianl-nv
left a comment
There was a problem hiding this comment.
I have some general questions on why we need the "local/Omniverse cache for pre-computed mesh" part.
- collecting the mesh for droid is only taking about 1s, it's hardly the bottlenet in the overall pipeline atm. we don't think we need to go done for the perf there using cache. Finding ways the speed up the mesh mode for Background (where we absolutely need it) is more important imo.
- for embodiment, what's blocking is actually the joint-angle-based bounding box collection. unless we are confident of shipping v0.3 with both background and embodiment using mesh mode (so far it has always take forever for solver), we need a working version of background in mesh mode + embodiment in bbox mode.
| def get_arena_usd_cache_dir() -> pathlib.Path: | ||
| """Return the cache root for USDs Arena generates, such as composed and baked-geometry assets. | ||
|
|
||
| The directory is not created, so callers that only compute a path do not leave one behind. |
There was a problem hiding this comment.
is there any risk of having an empty directory? if not let's just create the dir here following get_arena_asset_cache_dir
| return PlacementGeometrySource( | ||
| usd_path=spawn.usd_path, | ||
| scale=(scale_x, scale_y, scale_z), | ||
| joint_pos=dict(robot.init_state.joint_pos or {}), |
There was a problem hiding this comment.
This is better handle in droid/franka. set_initial_joint_pose currently only updates the reset event's default_pose.
can expand set_initial_joint_pose to also all self.set_joint_initial_pos(...) with a name→value map matching set_default_joint_pose order.
1426652 to
4e98441
Compare
Signed-off-by: zhx06 <zihaox@nvidia.com>
Signed-off-by: zhx06 <zihaox@nvidia.com>
Signed-off-by: zhx06 <zihaox@nvidia.com>
Signed-off-by: zhx06 <zihaox@nvidia.com>
Signed-off-by: zhx06 <zihaox@nvidia.com>
4e98441 to
204ab44
Compare
Summary
Joint-dependent mesh/bbox for embodiments
Detailed description
EmbodimentBase.get_bounding_box/get_collision_meshnow pose the USD atinit_state.joint_posrobot_library_folderper embodiment andexport_ready_pose_collision_meshes.pyto generate them