Skip to content

Commit 6d2a61c

Browse files
Merge pull request #99 from ft-lab/ghost_link
Fixed a bug where all the body0 components of joints would become root prims when a Ghost Link was present
2 parents 2def5a3 + bd4b89b commit 6d2a61c

4 files changed

Lines changed: 75 additions & 3 deletions

File tree

tests/data/link_first_ghost_link_fixed.urdf

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,27 @@
1515
</geometry>
1616
</collision>
1717
</link>
18+
<link name="link_box">
19+
<visual>
20+
<geometry>
21+
<box size="0.5 0.5 0.5"/>
22+
</geometry>
23+
</visual>
24+
<collision>
25+
<geometry>
26+
<box size="0.5 0.5 0.5"/>
27+
</geometry>
28+
</collision>
29+
</link>
1830

1931
<joint name="joint1" type="fixed">
2032
<origin rpy="0 0 0" xyz="0 0 1"/>
2133
<parent link="BaseLink"/>
2234
<child link="link1"/>
2335
</joint>
36+
<joint name="joint_box" type="fixed">
37+
<origin rpy="0 0 0" xyz="0 0 0.8"/>
38+
<parent link="link1"/>
39+
<child link="link_box"/>
40+
</joint>
2441
</robot>

tests/data/link_first_ghost_link_floating.urdf

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,28 @@
1515
</geometry>
1616
</collision>
1717
</link>
18+
<link name="link_box">
19+
<visual>
20+
<geometry>
21+
<box size="0.5 0.5 0.5"/>
22+
</geometry>
23+
</visual>
24+
<collision>
25+
<geometry>
26+
<box size="0.5 0.5 0.5"/>
27+
</geometry>
28+
</collision>
29+
</link>
1830

1931
<joint name="joint1" type="floating">
2032
<origin rpy="0 0 0" xyz="0 0 1"/>
2133
<parent link="BaseLink"/>
2234
<child link="link1"/>
2335
</joint>
36+
<joint name="joint_box" type="fixed">
37+
<origin rpy="0 0 0" xyz="0 0 0.8"/>
38+
<parent link="link1"/>
39+
<child link="link_box"/>
40+
</joint>
41+
2442
</robot>

tests/testGhostLink.py

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,16 @@ def test_link_first_ghost_link_fixed(self):
4040
self.assertTrue(link1_prim.HasAPI(UsdPhysics.ArticulationRootAPI))
4141
self.assertTrue(link1_prim.HasAPI("NewtonArticulationRootAPI"))
4242

43+
link_box_prim = link1_prim.GetChild("link_box")
44+
self.assertTrue(link_box_prim.IsValid())
45+
self.assertTrue(link_box_prim.HasAPI(UsdPhysics.RigidBodyAPI))
46+
self.assertFalse(link_box_prim.HasAPI(UsdPhysics.ArticulationRootAPI))
47+
self.assertFalse(link_box_prim.HasAPI("NewtonArticulationRootAPI"))
48+
4349
# Check physics joint.
4450
physics_scope_prim = default_prim.GetChild("Physics")
4551
self.assertTrue(physics_scope_prim.IsValid())
52+
self.assertEqual(len(physics_scope_prim.GetChildren()), 2)
4653

4754
joint1_prim = physics_scope_prim.GetChild("joint1")
4855
self.assertTrue(joint1_prim.IsValid())
@@ -55,6 +62,17 @@ def test_link_first_ghost_link_fixed(self):
5562
self.assertRotationsAlmostEqual(joint.GetLocalRot0Attr().Get(), Gf.Quatf(1, 0, 0, 0))
5663
self.assertRotationsAlmostEqual(joint.GetLocalRot1Attr().Get(), Gf.Quatf(1, 0, 0, 0))
5764

65+
joint_box_prim = physics_scope_prim.GetChild("joint_box")
66+
self.assertTrue(joint_box_prim.IsValid())
67+
self.assertTrue(joint_box_prim.IsA(UsdPhysics.FixedJoint))
68+
joint = UsdPhysics.FixedJoint(joint_box_prim)
69+
self.assertEqual(joint.GetBody0Rel().GetTargets(), ["/link_first_ghost_link_fixed/Geometry/BaseLink/link1"])
70+
self.assertEqual(joint.GetBody1Rel().GetTargets(), ["/link_first_ghost_link_fixed/Geometry/BaseLink/link1/link_box"])
71+
self.assertTrue(Gf.IsClose(joint.GetLocalPos0Attr().Get(), Gf.Vec3f(0, 0, 0.8), 1e-6))
72+
self.assertTrue(Gf.IsClose(joint.GetLocalPos1Attr().Get(), Gf.Vec3f(0, 0, 0), 1e-6))
73+
self.assertRotationsAlmostEqual(joint.GetLocalRot0Attr().Get(), Gf.Quatf(1, 0, 0, 0))
74+
self.assertRotationsAlmostEqual(joint.GetLocalRot1Attr().Get(), Gf.Quatf(1, 0, 0, 0))
75+
5876
def test_link_first_ghost_link_floating(self):
5977
input_path = "tests/data/link_first_ghost_link_floating.urdf"
6078
output_dir = self.tmpDir()
@@ -86,7 +104,25 @@ def test_link_first_ghost_link_floating(self):
86104
self.assertTrue(link1_prim.HasAPI(UsdPhysics.ArticulationRootAPI))
87105
self.assertTrue(link1_prim.HasAPI("NewtonArticulationRootAPI"))
88106

89-
# The physics joint does not exist.
107+
link_box_prim = link1_prim.GetChild("link_box")
108+
self.assertTrue(link_box_prim.IsValid())
109+
self.assertTrue(link_box_prim.HasAPI(UsdPhysics.RigidBodyAPI))
110+
self.assertFalse(link_box_prim.HasAPI(UsdPhysics.ArticulationRootAPI))
111+
self.assertFalse(link_box_prim.HasAPI("NewtonArticulationRootAPI"))
112+
113+
# Check physics joint.
114+
# There is only one physics joint, which is the joint between the link1 and the link_box.
90115
physics_scope_prim = default_prim.GetChild("Physics")
91116
self.assertTrue(physics_scope_prim.IsValid())
92-
self.assertEqual(len(physics_scope_prim.GetChildren()), 0)
117+
self.assertEqual(len(physics_scope_prim.GetChildren()), 1)
118+
119+
joint_box_prim = physics_scope_prim.GetChild("joint_box")
120+
self.assertTrue(joint_box_prim.IsValid())
121+
self.assertTrue(joint_box_prim.IsA(UsdPhysics.FixedJoint))
122+
joint = UsdPhysics.FixedJoint(joint_box_prim)
123+
self.assertEqual(joint.GetBody0Rel().GetTargets(), ["/link_first_ghost_link_floating/Geometry/BaseLink/link1"])
124+
self.assertEqual(joint.GetBody1Rel().GetTargets(), ["/link_first_ghost_link_floating/Geometry/BaseLink/link1/link_box"])
125+
self.assertTrue(Gf.IsClose(joint.GetLocalPos0Attr().Get(), Gf.Vec3f(0, 0, 0.8), 1e-6))
126+
self.assertTrue(Gf.IsClose(joint.GetLocalPos1Attr().Get(), Gf.Vec3f(0, 0, 0), 1e-6))
127+
self.assertRotationsAlmostEqual(joint.GetLocalRot0Attr().Get(), Gf.Quatf(1, 0, 0, 0))
128+
self.assertRotationsAlmostEqual(joint.GetLocalRot1Attr().Get(), Gf.Quatf(1, 0, 0, 0))

urdf_usd_converter/_impl/link.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,8 @@ def physics_joints(parent: Usd.Prim, link: ElementLink, data: ConversionData):
291291
body0_link_name = joint.parent.get_with_default("link")
292292
body1_link_name = joint.child.get_with_default("link")
293293

294-
body0 = data.references[Tokens.Physics][body0_link_name] if not is_ghost_link else default_prim
294+
has_ghost_link = is_ghost_link and root_link.name == body0_link_name
295+
body0 = data.references[Tokens.Physics][body0_link_name] if not has_ghost_link else default_prim
295296
body1 = data.references[Tokens.Physics][body1_link_name]
296297

297298
# Specifies that the origin position of Body1 (the "child" of the joint in the URDF) is the center.

0 commit comments

Comments
 (0)