Skip to content

Commit 992b0f0

Browse files
authored
Convert custom elements as Scopes and custom attributes with custom and urdf: namepsace (#79)
1 parent 674b658 commit 992b0f0

File tree

17 files changed

+1190
-481
lines changed

17 files changed

+1190
-481
lines changed

benchmarks.md

Lines changed: 390 additions & 390 deletions
Large diffs are not rendered by default.

docs/concept_mapping.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,3 +1092,20 @@ def Scope "foo"
10921092
def Scope "bar1"
10931093
custom uniform string baz = "qux"
10941094
```
1095+
1096+
It is recommended that parameters defined in the URDF but not supported in USD be stored as custom attributes on the parent `UsdPrim`.
1097+
1098+
For example, parameters within a joint ([calibration](#element-calibration), [dynamics](#element-dynamics), [safety_controller](#element-safety_controller)) can be stored as custom attributes of `UsdPhysicsJoints`.
1099+
1100+
```
1101+
<joint name="foo" type="fixed">
1102+
<calibration rising="0.3" falling="0.2" reference_position="0.1"/>
1103+
</joint>
1104+
```
1105+
1106+
```
1107+
def PhysicsFixedJoint "foo"
1108+
custom float urdf:calibration:rising = 0.3
1109+
custom float urdf:calibration:falling = 0.2
1110+
custom float urdf:calibration:reference_position = 0.1
1111+
```

tests/data/mimic_joint.urdf

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?xml version="1.0"?>
2+
<robot name="mimic_joint">
3+
<link name="BaseLinkA">
4+
<visual>
5+
<origin rpy="0 0 0" xyz="-0.12 0 0"/>
6+
<geometry>
7+
<box size="0.2 0.2 0.2"/>
8+
</geometry>
9+
</visual>
10+
</link>
11+
<link name="BaseLinkB">
12+
<visual>
13+
<origin rpy="0 0 0" xyz="-0.12 0 0"/>
14+
<geometry>
15+
<box size="0.2 0.2 0.2"/>
16+
</geometry>
17+
</visual>
18+
</link>
19+
20+
<link name="linkA">
21+
<visual>
22+
<origin rpy="0 0 0" xyz="0.27 0 0"/>
23+
<geometry>
24+
<box size="0.5 0.2 0.2"/>
25+
</geometry>
26+
</visual>
27+
</link>
28+
29+
<link name="linkB">
30+
<visual>
31+
<origin rpy="0 0 0" xyz="0.27 0 0"/>
32+
<geometry>
33+
<box size="0.5 0.2 0.2"/>
34+
</geometry>
35+
</visual>
36+
</link>
37+
38+
<joint name="joint_base" type="fixed">
39+
<origin rpy="0 0 0" xyz="0 0.4 0"/>
40+
<parent link="BaseLinkA"/>
41+
<child link="BaseLinkB"/>
42+
</joint>
43+
<joint name="jointA" type="revolute">
44+
<origin rpy="0 0 0" xyz="0 0 0"/>
45+
<parent link="BaseLinkA"/>
46+
<child link="linkA"/>
47+
<axis xyz="0 1 0"/>
48+
<limit lower="-0.7" upper="0.5"/>
49+
</joint>
50+
<joint name="jointB" type="revolute">
51+
<origin rpy="0 0 0" xyz="0 0 0"/>
52+
<parent link="BaseLinkB"/>
53+
<child link="linkB"/>
54+
<axis xyz="0 1 0"/>
55+
<limit lower="-0.7" upper="0.5"/>
56+
<mimic joint="jointA" multiplier="2.0" offset="0.0"/>
57+
</joint>
58+
</robot>
59+

tests/data/undefined.urdf

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?xml version="1.0"?>
2+
<robot name="undefined">
3+
<!-- custom attribute -->
4+
<material name="blue" custom_attr="blue_material">
5+
<color rgba="0.0 0.0 1.0 1.0"/>
6+
</material>
7+
<material name="green">
8+
<color rgba="0.0 1.0 0.0 1.0"/>
9+
</material>
10+
11+
<link name="link_box">
12+
<!-- custom attribute -->
13+
<visual custom_attr="visual">
14+
<geometry>
15+
<box size="1.0 1.0 1.0"/>
16+
</geometry>
17+
<material name="blue"/>
18+
</visual>
19+
<collision name="collision_box" custom_attr="collision">
20+
<geometry>
21+
<box size="1.0 1.0 1.0"/>
22+
</geometry>
23+
<!-- custom element and body text -->
24+
<collision_data>custom collision data</collision_data>
25+
</collision>
26+
27+
<!-- custom elements -->
28+
<custom>
29+
<item1 name="data1" value="foo1"/>
30+
<test-item name="data2" value="foo2"/>
31+
<japanese_text>日本語の文字列</japanese_text>
32+
<korean_text>한글 문자열</korean_text>
33+
</custom>
34+
35+
<!-- custom elements. Same name as "custom" -->
36+
<custom>
37+
<item3 name="data3" value="foo3"/>
38+
</custom>
39+
</link>
40+
<link name="link_box2">
41+
<visual>
42+
<geometry>
43+
<mesh filename="assets/box.dae"/>
44+
</geometry>
45+
</visual>
46+
</link>
47+
48+
<joint name="joint_box" type="fixed" custom_attr="joint">
49+
<origin rpy="0 0 0" xyz="1.5 0 0"/>
50+
<parent link="link_box"/>
51+
<child link="link_box2"/>
52+
53+
<!-- custom element -->
54+
<data>joint data</data>
55+
56+
<!-- calibration is currently not supported, so it is stored as custom attributes. -->
57+
<calibration rising="0.3" falling="0.2" reference_position="0.1"/>
58+
59+
<!-- dynamics is currently not supported, so it is stored as custom attributes. -->
60+
<dynamics damping="0.0" friction="0.0"/>
61+
62+
<!-- safety_controller is currently not supported, so it is stored as custom attributes. -->
63+
<safety_controller k_velocity="10" k_position="15" soft_lower_limit="-2.0" soft_upper_limit="0.5" />
64+
</joint>
65+
66+
<!-- transmission is currently not supported, so it is a custom element. -->
67+
<transmission name="trans1">
68+
<type>transmission_interface/SimpleTransmission</type>
69+
</transmission>
70+
71+
<transmission name="trans2">
72+
<type>transmission_interface/SimpleTransmission</type>
73+
</transmission>
74+
75+
<!-- gazebo is currently not supported, so it is a custom element. -->
76+
<gazebo>
77+
<static>true</static>
78+
</gazebo>
79+
80+
</robot>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?xml version="1.0"?>
2+
<robot name="undefined_same_name">
3+
<!-- The link name is intentionally set to "custom" to allow duplicate names when creating custom elements.-->
4+
<link name="custom">
5+
<visual>
6+
<geometry>
7+
<box size="1.0 1.0 1.0"/>
8+
</geometry>
9+
</visual>
10+
</link>
11+
12+
<!-- custom elements -->
13+
<foo>
14+
<item1 name="data1" value="foo1"/>
15+
</foo>
16+
</robot>

tests/testCli.py

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,7 @@ class TestCli(ConverterTestCase):
1515

1616
def test_run(self):
1717
input_path = "tests/data/simple-primitives.urdf"
18-
with (
19-
patch("sys.argv", ["urdf_usd_converter", input_path, self.tmpDir()]),
20-
usdex.test.ScopedDiagnosticChecker(
21-
self,
22-
[
23-
(Tf.TF_DIAGNOSTIC_WARNING_TYPE, ".*Calibration is not supported"),
24-
(Tf.TF_DIAGNOSTIC_WARNING_TYPE, ".*Dynamics is not supported"),
25-
],
26-
level=usdex.core.DiagnosticsLevel.eWarning,
27-
),
28-
):
18+
with patch("sys.argv", ["urdf_usd_converter", input_path, self.tmpDir()]):
2919
self.assertEqual(run(), 0, f"Failed to convert {input_path}")
3020
self.assertTrue((pathlib.Path(self.tmpDir()) / "simple-primitives.usda").exists())
3121

@@ -151,21 +141,7 @@ def test_conversion_warning_verifying_elements(self):
151141
robot = "tests/data/verifying_elements.urdf"
152142
robot_name = pathlib.Path(robot).stem
153143
output_dir = self.tmpDir()
154-
with (
155-
patch("sys.argv", ["urdf_usd_converter", robot, str(output_dir)]),
156-
usdex.test.ScopedDiagnosticChecker(
157-
self,
158-
[
159-
(Tf.TF_DIAGNOSTIC_WARNING_TYPE, ".*Transmission is not supported.*"),
160-
(Tf.TF_DIAGNOSTIC_WARNING_TYPE, ".*Gazebo is not supported.*"),
161-
(Tf.TF_DIAGNOSTIC_WARNING_TYPE, ".*Calibration is not supported.*"),
162-
(Tf.TF_DIAGNOSTIC_WARNING_TYPE, ".*Dynamics is not supported.*"),
163-
(Tf.TF_DIAGNOSTIC_WARNING_TYPE, ".*Mimic is not supported.*"),
164-
(Tf.TF_DIAGNOSTIC_WARNING_TYPE, ".*Safety controller is not supported.*"),
165-
],
166-
level=usdex.core.DiagnosticsLevel.eWarning,
167-
),
168-
):
144+
with patch("sys.argv", ["urdf_usd_converter", robot, str(output_dir)]):
169145
self.assertEqual(run(), 0, "Expected non-zero exit code for invalid input")
170146
self.assertTrue((pathlib.Path(self.tmpDir()) / f"{robot_name}.usda").exists())
171147

tests/testGeometry.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import pathlib
44

55
import usdex.core
6-
from pxr import Gf, Tf, Usd, UsdGeom
6+
from pxr import Gf, Usd, UsdGeom
77

88
import urdf_usd_converter
99
from tests.util.ConverterTestCase import ConverterTestCase
@@ -15,15 +15,7 @@ def test_geometries(self):
1515
output_dir = self.tmpDir()
1616

1717
converter = urdf_usd_converter.Converter()
18-
with usdex.test.ScopedDiagnosticChecker(
19-
self,
20-
[
21-
(Tf.TF_DIAGNOSTIC_WARNING_TYPE, ".*Calibration is not supported.*"),
22-
(Tf.TF_DIAGNOSTIC_WARNING_TYPE, ".*Dynamics is not supported.*"),
23-
],
24-
level=usdex.core.DiagnosticsLevel.eWarning,
25-
):
26-
asset_path = converter.convert(input_path, output_dir)
18+
asset_path = converter.convert(input_path, output_dir)
2719
self.assertIsNotNone(asset_path)
2820
self.assertTrue(pathlib.Path(asset_path.path).exists())
2921

tests/testJoints.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,10 @@ def test_revolute_joints(self):
6363

6464
# Custom attributes.
6565
self.assertTrue(revolute_joint.GetPrim().GetAttribute("urdf:limit:effort").HasAuthoredValue())
66+
self.assertTrue(revolute_joint.GetPrim().GetAttribute("urdf:limit:effort").IsCustom())
6667
self.assertAlmostEqual(revolute_joint.GetPrim().GetAttribute("urdf:limit:effort").Get(), 0.0, places=6)
6768
self.assertTrue(revolute_joint.GetPrim().GetAttribute("urdf:limit:velocity").HasAuthoredValue())
69+
self.assertTrue(revolute_joint.GetPrim().GetAttribute("urdf:limit:velocity").IsCustom())
6870
self.assertAlmostEqual(revolute_joint.GetPrim().GetAttribute("urdf:limit:velocity").Get(), 0.0, places=6)
6971

7072
# Joint_arm_2.
@@ -84,8 +86,10 @@ def test_revolute_joints(self):
8486

8587
# Custom attributes.
8688
self.assertTrue(revolute_joint.GetPrim().GetAttribute("urdf:limit:effort").HasAuthoredValue())
89+
self.assertTrue(revolute_joint.GetPrim().GetAttribute("urdf:limit:effort").IsCustom())
8790
self.assertAlmostEqual(revolute_joint.GetPrim().GetAttribute("urdf:limit:effort").Get(), 0.0, places=6)
8891
self.assertTrue(revolute_joint.GetPrim().GetAttribute("urdf:limit:velocity").HasAuthoredValue())
92+
self.assertTrue(revolute_joint.GetPrim().GetAttribute("urdf:limit:velocity").IsCustom())
8993
self.assertAlmostEqual(revolute_joint.GetPrim().GetAttribute("urdf:limit:velocity").Get(), 0.0, places=6)
9094

9195
# Joint_arm_3.
@@ -105,8 +109,10 @@ def test_revolute_joints(self):
105109

106110
# Custom attributes.
107111
self.assertTrue(revolute_joint.GetPrim().GetAttribute("urdf:limit:effort").HasAuthoredValue())
112+
self.assertTrue(revolute_joint.GetPrim().GetAttribute("urdf:limit:effort").IsCustom())
108113
self.assertAlmostEqual(revolute_joint.GetPrim().GetAttribute("urdf:limit:effort").Get(), 0.01, places=6)
109114
self.assertTrue(revolute_joint.GetPrim().GetAttribute("urdf:limit:velocity").HasAuthoredValue())
115+
self.assertTrue(revolute_joint.GetPrim().GetAttribute("urdf:limit:velocity").IsCustom())
110116
self.assertAlmostEqual(revolute_joint.GetPrim().GetAttribute("urdf:limit:velocity").Get(), 0.02, places=6)
111117

112118
def test_fixed_continuous_joints(self):
@@ -214,8 +220,10 @@ def test_fixed_prismatic_joints(self):
214220

215221
# Custom attributes.
216222
self.assertTrue(prismatic_joint.GetPrim().GetAttribute("urdf:limit:effort").HasAuthoredValue())
223+
self.assertTrue(prismatic_joint.GetPrim().GetAttribute("urdf:limit:effort").IsCustom())
217224
self.assertAlmostEqual(prismatic_joint.GetPrim().GetAttribute("urdf:limit:effort").Get(), 0.01, places=6)
218225
self.assertTrue(prismatic_joint.GetPrim().GetAttribute("urdf:limit:velocity").HasAuthoredValue())
226+
self.assertTrue(prismatic_joint.GetPrim().GetAttribute("urdf:limit:velocity").IsCustom())
219227
self.assertAlmostEqual(prismatic_joint.GetPrim().GetAttribute("urdf:limit:velocity").Get(), 0.0, places=6)
220228

221229
# Joint_arm_2.
@@ -235,8 +243,10 @@ def test_fixed_prismatic_joints(self):
235243

236244
# Custom attributes.
237245
self.assertTrue(prismatic_joint.GetPrim().GetAttribute("urdf:limit:effort").HasAuthoredValue())
246+
self.assertTrue(prismatic_joint.GetPrim().GetAttribute("urdf:limit:effort").IsCustom())
238247
self.assertAlmostEqual(prismatic_joint.GetPrim().GetAttribute("urdf:limit:effort").Get(), 0.02, places=6)
239248
self.assertTrue(prismatic_joint.GetPrim().GetAttribute("urdf:limit:velocity").HasAuthoredValue())
249+
self.assertTrue(prismatic_joint.GetPrim().GetAttribute("urdf:limit:velocity").IsCustom())
240250
self.assertAlmostEqual(prismatic_joint.GetPrim().GetAttribute("urdf:limit:velocity").Get(), 0.01, places=6)
241251

242252
# Joint_arm_3.
@@ -256,8 +266,10 @@ def test_fixed_prismatic_joints(self):
256266

257267
# Custom attributes.
258268
self.assertTrue(prismatic_joint.GetPrim().GetAttribute("urdf:limit:effort").HasAuthoredValue())
269+
self.assertTrue(prismatic_joint.GetPrim().GetAttribute("urdf:limit:effort").IsCustom())
259270
self.assertAlmostEqual(prismatic_joint.GetPrim().GetAttribute("urdf:limit:effort").Get(), 0.03, places=6)
260271
self.assertTrue(prismatic_joint.GetPrim().GetAttribute("urdf:limit:velocity").HasAuthoredValue())
272+
self.assertTrue(prismatic_joint.GetPrim().GetAttribute("urdf:limit:velocity").IsCustom())
261273
self.assertAlmostEqual(prismatic_joint.GetPrim().GetAttribute("urdf:limit:velocity").Get(), 0.01, places=6)
262274

263275
def test_fixed_planar_joints(self):

tests/testPhysics.py

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
# SPDX-License-Identifier: Apache-2.0
33
import pathlib
44

5-
import usdex.test
6-
from pxr import Gf, Tf, Usd, UsdPhysics
5+
from pxr import Gf, Usd, UsdPhysics
76

87
import urdf_usd_converter
98
from tests.util.ConverterTestCase import ConverterTestCase
@@ -17,15 +16,7 @@ def setUp(self):
1716
output_dir = self.tmpDir()
1817

1918
converter = urdf_usd_converter.Converter()
20-
with usdex.test.ScopedDiagnosticChecker(
21-
self,
22-
[
23-
(Tf.TF_DIAGNOSTIC_WARNING_TYPE, ".*Calibration is not supported.*"),
24-
(Tf.TF_DIAGNOSTIC_WARNING_TYPE, ".*Dynamics is not supported.*"),
25-
],
26-
level=usdex.core.DiagnosticsLevel.eWarning,
27-
):
28-
asset_path = converter.convert(input_path, output_dir)
19+
asset_path = converter.convert(input_path, output_dir)
2920
self.assertIsNotNone(asset_path)
3021
self.assertTrue(pathlib.Path(asset_path.path).exists())
3122

0 commit comments

Comments
 (0)