Inconsistent values from isaacsim's dc.get_joint_<parent / child>_body(...)

Hi Omniverse devs!

Thank you for putting together these forums – very cool to see what other people have been working on with omniverse.

Our team is trying to import the Fetch robot into IsaacSim based on its URDF defined HERE. We are able to import the robot using the URDF Importer extension, but it behaves very strangely when we try to articulate the robot.

Moreover, when trying to programmatically control the robot, it seems that trying to access the robot’s joint parent / child links via dc.get_joint_<parent / child>_body(joint_handle)returns inconsistent values – for some joints, it appears to return the flipped values – i.e.: calling the parent link actually returns the child link name, and vise versa.

This behavior can be easily reproduced via the following:

# Assumes fetch has already been imported to USD format from URDF

class HelloWorld(BaseSample):
    def __init__(self) -> None:

    def setup_scene(self):

        world = self.get_world()
        # Import robot
        add_reference_to_stage(usd_path=<PATH_TO_FETCH>.usd, prim_path=f"/World/fetch")
        fetch_robot = world.scene.add(Robot(prim_path="/World/fetch", name="fetch"))

    async def setup_post_load(self):
        self._world = self.get_world()
        self._fetch = self._world.scene.get_object("fetch")

        # Get joint info
        dc = self._fetch._dc_interface
        art = dc.get_articulation(self._fetch.prim_path)
        n_joints = dc.get_articulation_joint_count(art)
        joint_handles = [dc.get_articulation_joint(art, i) for i in range(n_joints)]
        self._joints = OrderedDict()

        n_dofs = dc.get_articulation_dof_count(art)
        self.dof_handles = [dc.get_articulation_dof(art, i) for i in range(n_dofs)]
        dof_names = [dc.get_dof_name(handle) for handle in self.dof_handles]

        dof_count = 0
        for i, joint_handle in enumerate(joint_handles):
            # Here is the problem: Sometimes parent / child names are flipped, e.g. for joint shoulder_lift_joint, see attached screenshot of Fetch tree structure
            name = dc.get_joint_name(joint_handle)
            print(f"joint {i} name: {dc.get_joint_name(joint_handle)}")
            parent_handle = dc.get_joint_parent_body(joint_handle)
            parent_name = dc.get_rigid_body_name(parent_handle)
            joint_type = dc.get_joint_type(joint_handle)
            self._joints[name] = {
                "handle": joint_handle,
                "parent_handle": parent_handle,
                "type": joint_type,
            print(f"joint {i} parent name: {parent_name}")
            child_handle = dc.get_joint_child_body(joint_handle)
            child_name = dc.get_rigid_body_name(child_handle)
            print(f"joint {i} child name: {child_name}")

I tried to upload directly the fetch .usd file I was using, but it’s apparently much too large (>800MB). I’ve instead uploaded it to google drive; the files can be downloaded HERE.

Any help would be greatly appreciated!

Thanks for bringing up the issue!
We have been fixing some joint order related issues for our next release, I will file a ticket for this to check if this issue was fixed as well.

During URDF import did you use the Merge fixed joints option? Or leave that option off. Merging fixed joints can change the joint ordering in some cases.

Hi! Thanks for the response. This was done NOT with merge fixed joints.

was this done with “fixed base link” checked? We’ve also seen joint order inconsistency when the robot is mobile.

A temporary fix can be done with the following steps:

  • Select the robot’s root prim on the Stage Tree, in its “Raw USD Properties” tab, find the “Articulation Root” Section. Delete it by click on the “X” on the right upper corner inside the section.
  • Select the actual root link on the Stage Tree, inside its “Raw USD Properties” Tab, click on the +ADD button, and add Physics > Articulation Root .

It was done without “fixed base link” (as you suggest, our robot is indeed mobile).

I will try this fix! Is the purpose of this solution to “reset” the internal articulation structure that presumably gets dynamically loaded when you add an Articulation Root to a prim?