Joint bodies are not accessible through Omnigraph

Isaac Sim Version

4.5.0

Operating System

Ubuntu 22.04
Windows 11

GPU Information

  • Model: GeForce 4090
  • Driver Version: 570.133

Topic Description

Detailed Description

Trying to read the body0 and body1 prim names of a joint from Omnigraph, they are not exposed as valid attributes.

Steps to Reproduce

  1. Create two bodies, connect them with a joint (any type)
  2. Create a new Omnigraph, drag and drop the joint into it, then select Read Attribute
  3. Go through the list of Attribute Names. physics:body0 and physics:body1 are not there.

Error Messages

Attempting to use a constant token to select the bodies is not permitted either, showing the following error:

Hi @christianbarcelo, thanks for your question! I was able to repro this on my end, and was also unable to see the physics:body0 and physics:body1 in the attribute list. Could I get some more context on what your use case is for accessing the prim names in this way?

It’s a little hard to understand and it’s a particular use case, but I have the need to query all the joints in the scene and do something with a custom extension on the connected bodies of all those joints.
Given I have a HUGE amount of joints, I need to be able to iterate through them all and consume the bodies.

I have a tick connected to a get prims and a for loop to get each joint in the scene. Is there any other way I can consume the bodies?

Thanks for giving it a try!

Hi , here is a sample script for getting the joint bodies for a Franka robot

#!/usr/bin/env python3

"""
Sample Isaac Sim script to iterate through joints in a scene and get body names.
This script demonstrates multiple approaches to inspect joints and their associated bodies.
"""

import numpy as np
from isaacsim import SimulationApp

# Create simulation app
simulation_app = SimulationApp({"headless": False})

from isaacsim.core.api import World
from isaacsim.robot.manipulators.examples.franka import Franka
from pxr import UsdPhysics
from omni.isaac.core.utils.stage import get_current_stage


def get_all_joints_in_scene():
    stage = get_current_stage()
    
    # Find all joint prims in the scene
    joint_prims = []
    for prim in stage.Traverse():
        if prim.IsA(UsdPhysics.Joint):
            joint_prims.append(prim)
    
    print(f"Found {len(joint_prims)} joints in the scene:")
    
    for i, joint_prim in enumerate(joint_prims):
        joint_path = joint_prim.GetPath()
        joint_name = joint_prim.GetName()
        
        # Get joint type
        joint_type = "Unknown"
        if joint_prim.IsA(UsdPhysics.RevoluteJoint):
            joint_type = "Revolute"
        elif joint_prim.IsA(UsdPhysics.PrismaticJoint):
            joint_type = "Prismatic"
        elif joint_prim.IsA(UsdPhysics.SphericalJoint):
            joint_type = "Spherical"
        elif joint_prim.IsA(UsdPhysics.FixedJoint):
            joint_type = "Fixed"
        elif joint_prim.IsA(UsdPhysics.DistanceJoint):
            joint_type = "Distance"
        
        # Get connected bodies
        joint_api = UsdPhysics.Joint(joint_prim)
        body0_rel = joint_api.GetBody0Rel()
        body1_rel = joint_api.GetBody1Rel()
        
        body0_path = "None"
        body1_path = "None"
        body0_name = "None"
        body1_name = "None"
        
        if body0_rel:
            targets = body0_rel.GetTargets()
            if targets:
                body0_path = str(targets[0])
                body0_prim = stage.GetPrimAtPath(targets[0])
                if body0_prim:
                    body0_name = body0_prim.GetName()
        
        if body1_rel:
            targets = body1_rel.GetTargets()
            if targets:
                body1_path = str(targets[0])
                body1_prim = stage.GetPrimAtPath(targets[0])
                if body1_prim:
                    body1_name = body1_prim.GetName()
        
        print(f"\n  Joint {i+1}:")
        print(f"    Name: {joint_name}")
        print(f"    Type: {joint_type}")
        print(f"    Path: {joint_path}")
        print(f"    Body 0: {body0_name} ({body0_path})")
        print(f"    Body 1: {body1_name} ({body1_path})")

def main():
    print("Isaac Sim Joint and Body Inspector")
    print("=" * 60)
    
    # Create world
    world = World(stage_units_in_meters=1.0)
    
    # Add default ground plane
    world.scene.add_default_ground_plane()
    
    # Add a Franka robot for demonstration
    print("Adding Franka robot to scene...")
    franka = world.scene.add(
        Franka(
            prim_path="/World/Franka",
            name="franka_robot",
            gripper_dof_names=["panda_finger_joint1", "panda_finger_joint2"],
            end_effector_prim_name="panda_rightfinger",
        )
    )
    
    # Reset world to initialize everything
    world.reset()
    
    # Find all joints using USD traversal
    get_all_joints_in_scene()
    
    # Cleanup
    simulation_app.close()

if __name__ == "__main__":
    main() 

Thanks for looking into it @shalinj !

I agree that code-wise your suggestion may be what makes the most sense, but my question was mostly related on how to capture that information from an Omnigraph.

I’m much more comfortable writing custom code rather than using Omnigraphs, but this was a special use case that required being able to consume that data from a pre-existing Omnigraph.

Is this a bug or an expected (weird) behavior? I can report it in the Isaac Sim 5.0 repo if there’s no internal ticket yet.

Thanks!