rod 0.3.4__tar.gz → 0.3.4.dev2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. {rod-0.3.4 → rod-0.3.4.dev2}/.github/workflows/ci_cd.yml +2 -2
  2. rod-0.3.4.dev2/.github/workflows/style.yml +53 -0
  3. {rod-0.3.4 → rod-0.3.4.dev2}/LICENSE +1 -1
  4. {rod-0.3.4 → rod-0.3.4.dev2}/PKG-INFO +22 -56
  5. {rod-0.3.4 → rod-0.3.4.dev2}/README.md +3 -15
  6. rod-0.3.4.dev2/pyproject.toml +20 -0
  7. rod-0.3.4.dev2/setup.cfg +89 -0
  8. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/builder/primitive_builder.py +5 -6
  9. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/builder/primitives.py +26 -46
  10. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/kinematics/kinematic_tree.py +1 -1
  11. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/kinematics/tree_transforms.py +1 -3
  12. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/pretty_printer.py +1 -1
  13. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/sdf/geometry.py +1 -3
  14. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/sdf/joint.py +11 -10
  15. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/sdf/link.py +0 -41
  16. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/sdf/physics.py +2 -1
  17. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/sdf/sdf.py +26 -19
  18. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/sdf/visual.py +2 -1
  19. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/tree/directed_tree.py +3 -3
  20. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/urdf/exporter.py +2 -2
  21. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/utils/frame_convention.py +4 -2
  22. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/utils/gazebo.py +2 -1
  23. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod.egg-info/PKG-INFO +22 -56
  24. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod.egg-info/SOURCES.txt +3 -2
  25. rod-0.3.4.dev2/src/rod.egg-info/not-zip-safe +1 -0
  26. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod.egg-info/requires.txt +11 -5
  27. {rod-0.3.4 → rod-0.3.4.dev2}/tests/test_meshbuilder.py +2 -10
  28. {rod-0.3.4 → rod-0.3.4.dev2}/tests/test_urdf_parsing.py +0 -22
  29. rod-0.3.4/.github/CODEOWNERS +0 -1
  30. rod-0.3.4/.pre-commit-config.yaml +0 -34
  31. rod-0.3.4/pyproject.toml +0 -166
  32. rod-0.3.4/setup.cfg +0 -4
  33. {rod-0.3.4 → rod-0.3.4.dev2}/.gitignore +0 -0
  34. {rod-0.3.4 → rod-0.3.4.dev2}/setup.py +0 -0
  35. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/__init__.py +0 -0
  36. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/builder/__init__.py +0 -0
  37. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/kinematics/__init__.py +0 -0
  38. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/logging.py +0 -0
  39. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/sdf/__init__.py +0 -0
  40. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/sdf/collision.py +0 -0
  41. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/sdf/common.py +0 -0
  42. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/sdf/element.py +0 -0
  43. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/sdf/material.py +0 -0
  44. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/sdf/model.py +0 -0
  45. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/sdf/scene.py +0 -0
  46. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/sdf/world.py +0 -0
  47. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/tree/__init__.py +0 -0
  48. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/tree/tree_elements.py +0 -0
  49. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/urdf/__init__.py +0 -0
  50. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/utils/__init__.py +0 -0
  51. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/utils/resolve_frames.py +0 -0
  52. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod/utils/resolve_uris.py +0 -0
  53. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod.egg-info/dependency_links.txt +0 -0
  54. {rod-0.3.4 → rod-0.3.4.dev2}/src/rod.egg-info/top_level.txt +0 -0
  55. {rod-0.3.4 → rod-0.3.4.dev2}/tests/test_urdf_exporter.py +0 -0
  56. {rod-0.3.4 → rod-0.3.4.dev2}/tests/utils_models.py +0 -0
@@ -165,8 +165,6 @@ jobs:
165
165
  name: Publish to PyPI
166
166
  needs: test
167
167
  runs-on: ubuntu-latest
168
- permissions:
169
- id-token: write
170
168
 
171
169
  steps:
172
170
 
@@ -186,4 +184,6 @@ jobs:
186
184
  (github.event_name == 'release' && github.event.action == 'published'))
187
185
  uses: pypa/gh-action-pypi-publish@release/v1
188
186
  with:
187
+ user: __token__
188
+ password: ${{ secrets.PYPI_TOKEN }}
189
189
  skip_existing: true
@@ -0,0 +1,53 @@
1
+ name: Code Style
2
+
3
+ on:
4
+ push:
5
+ branches: [ "**" ]
6
+ tags-ignore: [ "**" ]
7
+ pull_request:
8
+ workflow_dispatch:
9
+
10
+ jobs:
11
+
12
+ black:
13
+
14
+ name: black
15
+ runs-on: ubuntu-latest
16
+
17
+ steps:
18
+
19
+ - name: "🔀 Checkout repository"
20
+ uses: actions/checkout@v2
21
+
22
+ - name: '🐍 Initialize Python'
23
+ uses: actions/setup-python@v2
24
+ with:
25
+ python-version: "3.10"
26
+
27
+ - name: "📝 Black Code Formatter"
28
+ uses: psf/black@stable
29
+ with:
30
+ options: --check --diff --color
31
+
32
+ isort:
33
+
34
+ name: isort
35
+ runs-on: ubuntu-latest
36
+
37
+ steps:
38
+
39
+ - name: "🔀 Checkout repository"
40
+ uses: actions/checkout@v2
41
+
42
+ - name: '🐍 Initialize Python'
43
+ uses: actions/setup-python@v2
44
+ with:
45
+ python-version: "3.10"
46
+
47
+ # Workaround for https://github.com/isort/isort-action/issues/70
48
+ - run: pip install colorama
49
+
50
+ - name: "📝 isort"
51
+ uses: isort/isort-action@master
52
+ with:
53
+ configuration: --check --diff --color
@@ -1,6 +1,6 @@
1
1
  BSD 3-Clause License
2
2
 
3
- Copyright (c) 2022, Artificial and Mechanical Intelligence
3
+ Copyright (c) 2022, Artificial and Mechanical Intelligence
4
4
  All rights reserved.
5
5
 
6
6
  Redistribution and use in source and binary forms, with or without
@@ -1,43 +1,16 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: rod
3
- Version: 0.3.4
3
+ Version: 0.3.4.dev2
4
4
  Summary: The ultimate Python tool for RObot Descriptions processing.
5
- Author-email: Diego Ferigo <dgferigo@gmail.com>
6
- Maintainer-email: Filippo Luca Ferretti <filippo.ferretti@iit.it>, Carlotta Sartore <carlotta.sartore@iit.it>
7
- License: BSD 3-Clause License
8
-
9
- Copyright (c) 2022, Artificial and Mechanical Intelligence
10
- All rights reserved.
11
-
12
- Redistribution and use in source and binary forms, with or without
13
- modification, are permitted provided that the following conditions are met:
14
-
15
- 1. Redistributions of source code must retain the above copyright notice, this
16
- list of conditions and the following disclaimer.
17
-
18
- 2. Redistributions in binary form must reproduce the above copyright notice,
19
- this list of conditions and the following disclaimer in the documentation
20
- and/or other materials provided with the distribution.
21
-
22
- 3. Neither the name of the copyright holder nor the names of its
23
- contributors may be used to endorse or promote products derived from
24
- this software without specific prior written permission.
25
-
26
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
30
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33
- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
34
- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36
-
5
+ Home-page: https://github.com/ami-iit/rod
6
+ Author: Diego Ferigo
7
+ Author-email: diego.ferigo@iit.it
8
+ License: BSD
37
9
  Project-URL: Changelog, https://github.com/ami-iit/rod/releases
38
10
  Project-URL: Source, https://github.com/ami-iit/rod
39
11
  Project-URL: Tracker, https://github.com/ami-iit/rod/issues
40
12
  Keywords: description,gazebo,parser,robot,robotics,ros,sdf,sdformat,simulator,simulation,urdf
13
+ Platform: any
41
14
  Classifier: Development Status :: 5 - Production/Stable
42
15
  Classifier: Framework :: Robot Framework
43
16
  Classifier: Intended Audience :: Science/Research
@@ -52,7 +25,6 @@ Classifier: Programming Language :: Python :: 3
52
25
  Classifier: Programming Language :: Python :: 3.10
53
26
  Classifier: Programming Language :: Python :: 3.11
54
27
  Classifier: Programming Language :: Python :: 3.12
55
- Classifier: Programming Language :: Python :: 3.13
56
28
  Classifier: Programming Language :: Python :: 3 :: Only
57
29
  Classifier: Programming Language :: Python :: Implementation :: CPython
58
30
  Classifier: Topic :: Games/Entertainment :: Simulation
@@ -68,17 +40,23 @@ Requires-Dist: scipy
68
40
  Requires-Dist: trimesh
69
41
  Requires-Dist: xmltodict
70
42
  Provides-Extra: style
71
- Requires-Dist: black~=24.0; extra == "style"
43
+ Requires-Dist: black; extra == "style"
72
44
  Requires-Dist: isort; extra == "style"
73
45
  Provides-Extra: pptree
74
46
  Requires-Dist: pptree; extra == "pptree"
75
- Provides-Extra: testing
76
- Requires-Dist: idyntree>=12.2.1; extra == "testing"
77
- Requires-Dist: pytest>=6.0; extra == "testing"
78
- Requires-Dist: pytest-icdiff; extra == "testing"
79
- Requires-Dist: robot-descriptions; extra == "testing"
47
+ Provides-Extra: test
48
+ Requires-Dist: idyntree; extra == "test"
49
+ Requires-Dist: pytest; extra == "test"
50
+ Requires-Dist: pytest-icdiff; extra == "test"
51
+ Requires-Dist: robot-descriptions; extra == "test"
80
52
  Provides-Extra: all
81
- Requires-Dist: rod[pptree,style,testing]; extra == "all"
53
+ Requires-Dist: black; extra == "all"
54
+ Requires-Dist: isort; extra == "all"
55
+ Requires-Dist: pptree; extra == "all"
56
+ Requires-Dist: idyntree; extra == "all"
57
+ Requires-Dist: pytest; extra == "all"
58
+ Requires-Dist: pytest-icdiff; extra == "all"
59
+ Requires-Dist: robot-descriptions; extra == "all"
82
60
 
83
61
  # RObot Description processor
84
62
 
@@ -144,7 +122,7 @@ Installing ROD using `conda` is the recommended way to obtain a complete install
144
122
  conda install rod -c conda-forge
145
123
  ```
146
124
 
147
- This will automatically install `sdformat` and `gz-tools`.
125
+ This will automatically install `sdformat` and `gz-tools`.
148
126
 
149
127
  </details>
150
128
 
@@ -324,28 +302,16 @@ print(urdf_string)
324
302
 
325
303
  ## Contributing
326
304
 
327
- Pull requests are welcome.
305
+ Pull requests are welcome.
328
306
  For major changes, please open an issue first to discuss what you would like to change.
329
307
 
330
- ## People
331
-
332
- ### Author
308
+ ## Maintainers
333
309
 
334
310
  | [<img src="https://github.com/diegoferigo.png" width="40">][df] | [@diegoferigo][df] |
335
311
  |:---------------------------------------------------------------:|:------------------:|
336
312
 
337
313
  [df]: https://github.com/diegoferigo
338
314
 
339
- ### Maintainers
340
-
341
- | [<img src="https://github.com/flferretti.png" width="40">][ff] | [@flferretti][ff] | [<img src="https://github.com/CarlottaSartore.png" width="40">][cs] | [@CarlottaSartore][cs] |
342
- |:---------------------------------------------------------------:|:------------------:|:---------------------------------------------------------------:|:------------------:|
343
-
344
-
345
-
346
- [ff]: https://github.com/flferretti
347
- [cs]: https://github.com/CarlottaSartore
348
-
349
315
  ## License
350
316
 
351
317
  [BSD3](https://choosealicense.com/licenses/bsd-3-clause/)
@@ -62,7 +62,7 @@ Installing ROD using `conda` is the recommended way to obtain a complete install
62
62
  conda install rod -c conda-forge
63
63
  ```
64
64
 
65
- This will automatically install `sdformat` and `gz-tools`.
65
+ This will automatically install `sdformat` and `gz-tools`.
66
66
 
67
67
  </details>
68
68
 
@@ -242,28 +242,16 @@ print(urdf_string)
242
242
 
243
243
  ## Contributing
244
244
 
245
- Pull requests are welcome.
245
+ Pull requests are welcome.
246
246
  For major changes, please open an issue first to discuss what you would like to change.
247
247
 
248
- ## People
249
-
250
- ### Author
248
+ ## Maintainers
251
249
 
252
250
  | [<img src="https://github.com/diegoferigo.png" width="40">][df] | [@diegoferigo][df] |
253
251
  |:---------------------------------------------------------------:|:------------------:|
254
252
 
255
253
  [df]: https://github.com/diegoferigo
256
254
 
257
- ### Maintainers
258
-
259
- | [<img src="https://github.com/flferretti.png" width="40">][ff] | [@flferretti][ff] | [<img src="https://github.com/CarlottaSartore.png" width="40">][cs] | [@CarlottaSartore][cs] |
260
- |:---------------------------------------------------------------:|:------------------:|:---------------------------------------------------------------:|:------------------:|
261
-
262
-
263
-
264
- [ff]: https://github.com/flferretti
265
- [cs]: https://github.com/CarlottaSartore
266
-
267
255
  ## License
268
256
 
269
257
  [BSD3](https://choosealicense.com/licenses/bsd-3-clause/)
@@ -0,0 +1,20 @@
1
+ [build-system]
2
+ requires = [
3
+ "wheel",
4
+ "setuptools>=45",
5
+ "setuptools_scm[toml]>=6.2",
6
+ ]
7
+ build-backend = "setuptools.build_meta"
8
+
9
+ [tool.setuptools_scm]
10
+ local_scheme = "dirty-tag"
11
+
12
+ [tool.black]
13
+ line-length = 88
14
+
15
+ [tool.isort]
16
+ profile = "black"
17
+ multi_line_output = 3
18
+
19
+ [tool.cibuildwheel]
20
+ build-frontend = "build"
@@ -0,0 +1,89 @@
1
+ [metadata]
2
+ name = rod
3
+ description = The ultimate Python tool for RObot Descriptions processing.
4
+ long_description = file: README.md
5
+ long_description_content_type = text/markdown
6
+ author = Diego Ferigo
7
+ author_email = diego.ferigo@iit.it
8
+ license = BSD
9
+ license_files = LICENSE
10
+ platforms = any
11
+ url = https://github.com/ami-iit/rod
12
+ project_urls =
13
+ Changelog = https://github.com/ami-iit/rod/releases
14
+ Source = https://github.com/ami-iit/rod
15
+ Tracker = https://github.com/ami-iit/rod/issues
16
+ keywords =
17
+ description
18
+ gazebo
19
+ parser
20
+ robot
21
+ robotics
22
+ ros
23
+ sdf
24
+ sdformat
25
+ simulator
26
+ simulation
27
+ urdf
28
+ classifiers =
29
+ Development Status :: 5 - Production/Stable
30
+ Framework :: Robot Framework
31
+ Intended Audience :: Science/Research
32
+ Intended Audience :: Developers
33
+ Intended Audience :: Education
34
+ License :: OSI Approved :: BSD License
35
+ Operating System :: OS Independent
36
+ Operating System :: POSIX :: Linux
37
+ Operating System :: MacOS
38
+ Operating System :: Microsoft :: Windows
39
+ Programming Language :: Python :: 3
40
+ Programming Language :: Python :: 3.10
41
+ Programming Language :: Python :: 3.11
42
+ Programming Language :: Python :: 3.12
43
+ Programming Language :: Python :: 3 :: Only
44
+ Programming Language :: Python :: Implementation :: CPython
45
+ Topic :: Games/Entertainment :: Simulation
46
+
47
+ [options]
48
+ zip_safe = False
49
+ packages = find:
50
+ package_dir =
51
+ =src
52
+ python_requires = >=3.10
53
+ install_requires =
54
+ coloredlogs
55
+ mashumaro
56
+ numpy
57
+ packaging
58
+ resolve-robotics-uri-py
59
+ scipy
60
+ trimesh
61
+ xmltodict
62
+
63
+ [options.extras_require]
64
+ style =
65
+ black
66
+ isort
67
+ pptree =
68
+ pptree
69
+ test =
70
+ idyntree
71
+ pytest
72
+ pytest-icdiff
73
+ robot-descriptions
74
+ all =
75
+ %(style)s
76
+ %(pptree)s
77
+ %(test)s
78
+
79
+ [options.packages.find]
80
+ where = src
81
+
82
+ [tool:pytest]
83
+ addopts = -rsxX -v --strict-markers
84
+ testpaths = tests
85
+
86
+ [egg_info]
87
+ tag_build =
88
+ tag_date = 0
89
+
@@ -12,9 +12,8 @@ from rod import logging
12
12
 
13
13
  @dataclasses.dataclass
14
14
  class PrimitiveBuilder(abc.ABC):
15
-
16
- name: str = dataclasses.field(kw_only=True)
17
- mass: float = dataclasses.field(kw_only=True)
15
+ name: str
16
+ mass: float
18
17
 
19
18
  element: rod.Model | rod.Link | rod.Inertial | rod.Collision | rod.Visual = (
20
19
  dataclasses.field(
@@ -121,7 +120,7 @@ class PrimitiveBuilder(abc.ABC):
121
120
  pose: rod.Pose | None = None,
122
121
  inertial: rod.Inertial | None = None,
123
122
  ) -> PrimitiveBuilder:
124
- if not isinstance(self.element, rod.Model | rod.Link):
123
+ if not isinstance(self.element, (rod.Model, rod.Link)):
125
124
  raise ValueError(type(self.element))
126
125
 
127
126
  if isinstance(self.element, rod.Model):
@@ -151,7 +150,7 @@ class PrimitiveBuilder(abc.ABC):
151
150
  pose: rod.Pose | None = None,
152
151
  visual: rod.Visual | None = None,
153
152
  ) -> PrimitiveBuilder:
154
- if not isinstance(self.element, rod.Model | rod.Link):
153
+ if not isinstance(self.element, (rod.Model, rod.Link)):
155
154
  raise ValueError(type(self.element))
156
155
 
157
156
  if isinstance(self.element, rod.Model):
@@ -187,7 +186,7 @@ class PrimitiveBuilder(abc.ABC):
187
186
  pose: rod.Pose | None = None,
188
187
  collision: rod.Collision | None = None,
189
188
  ) -> PrimitiveBuilder:
190
- if not isinstance(self.element, rod.Model | rod.Link):
189
+ if not isinstance(self.element, (rod.Model, rod.Link)):
191
190
  raise ValueError(type(self.element))
192
191
 
193
192
  if isinstance(self.element, rod.Model):
@@ -1,13 +1,10 @@
1
1
  import dataclasses
2
2
  import pathlib
3
3
 
4
- import numpy as np
5
- import numpy.typing as npt
6
- import resolve_robotics_uri_py
7
4
  import trimesh
5
+ from numpy.typing import NDArray
8
6
 
9
7
  import rod
10
- from rod import logging
11
8
  from rod.builder.primitive_builder import PrimitiveBuilder
12
9
 
13
10
 
@@ -65,13 +62,8 @@ class CylinderBuilder(PrimitiveBuilder):
65
62
 
66
63
  @dataclasses.dataclass
67
64
  class MeshBuilder(PrimitiveBuilder):
68
-
69
- mesh_uri: str | pathlib.Path
70
-
71
- scale: npt.NDArray = dataclasses.field(default_factory=lambda: np.ones(3))
72
-
73
- mass: float | None = dataclasses.field(default=None, kw_only=True)
74
- inertia_tensor: npt.NDArray | None = dataclasses.field(default=None, kw_only=True)
65
+ mesh_path: str | pathlib.Path
66
+ scale: NDArray
75
67
 
76
68
  def __post_init__(self) -> None:
77
69
  """
@@ -82,46 +74,34 @@ class MeshBuilder(PrimitiveBuilder):
82
74
  AssertionError: If the scale is not a 3D vector.
83
75
  TypeError: If the mesh_path is not a str or pathlib.Path.
84
76
  """
85
- # Adjust the shape of the scale.
86
- self.scale = self.scale.squeeze()
87
-
88
- if self.scale.shape != (3,):
89
- raise RuntimeError(f"Scale must be a 3D vector, got '{self.scale.shape}'")
90
-
91
- # Resolve the mesh URI.
92
- mesh_path = resolve_robotics_uri_py.resolve_robotics_uri(uri=str(self.mesh_uri))
93
-
94
- # Build the trimesh object from the mesh path.
95
- self.mesh: trimesh.base.Trimesh = trimesh.load_mesh(file_obj=mesh_path)
96
-
97
- # Populate the mass from the mesh if it was not provided externally.
98
- if self.mass is None:
99
-
100
- if self.mesh.is_watertight:
101
- self.mass = self.mesh.mass
102
77
 
103
- else:
104
- msg = "Mesh '{}' is not watertight. Using a dummy mass value."
105
- logging.warning(msg.format(self.mesh_uri))
106
- self.mass = 1.0
78
+ mesh_path = (
79
+ self.mesh_path
80
+ if isinstance(self.mesh_path, pathlib.Path)
81
+ else pathlib.Path(self.mesh_path)
82
+ )
107
83
 
108
- # Populate the inertia tensor from the mesh if it was not provided externally.
109
- if self.inertia_tensor is None:
84
+ if not mesh_path.is_file():
85
+ raise FileNotFoundError(f"Mesh file not found at {self.mesh_path}")
110
86
 
111
- if self.mesh.is_watertight:
112
- self.inertia_tensor = self.mesh.moment_inertia
87
+ self.mesh: trimesh.base.Trimesh = trimesh.load_mesh(
88
+ file_obj=mesh_path,
89
+ )
113
90
 
114
- else:
115
- msg = "Mesh '{}' is not watertight. Using a dummy inertia tensor."
116
- logging.warning(msg.format(self.mesh_uri))
117
- self.inertia_tensor = np.eye(3)
91
+ assert self.scale.shape == (
92
+ 3,
93
+ ), f"Scale must be a 3D vector, got {self.scale.shape}"
118
94
 
119
95
  def _inertia(self) -> rod.Inertia:
120
-
121
- return rod.Inertia.from_inertia_tensor(inertia_tensor=self.inertia_tensor)
96
+ inertia = self.mesh.moment_inertia
97
+ return rod.Inertia(
98
+ ixx=inertia[0, 0],
99
+ ixy=inertia[0, 1],
100
+ ixz=inertia[0, 2],
101
+ iyy=inertia[1, 1],
102
+ iyz=inertia[1, 2],
103
+ izz=inertia[2, 2],
104
+ )
122
105
 
123
106
  def _geometry(self) -> rod.Geometry:
124
-
125
- return rod.Geometry(
126
- mesh=rod.Mesh(uri=str(self.mesh_uri), scale=self.scale.tolist())
127
- )
107
+ return rod.Geometry(mesh=rod.Mesh(uri=str(self.mesh_path), scale=self.scale))
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  import copy
4
4
  import dataclasses
5
5
  import functools
6
- from collections.abc import Sequence
6
+ from typing import Sequence
7
7
 
8
8
  import numpy as np
9
9
 
@@ -13,9 +13,7 @@ from rod.tree import TreeFrame
13
13
 
14
14
  @dataclasses.dataclass
15
15
  class TreeTransforms:
16
- kinematic_tree: KinematicTree = dataclasses.field(
17
- default_factory=dataclasses.dataclass(init=False)
18
- )
16
+ kinematic_tree: KinematicTree = dataclasses.dataclass(init=False)
19
17
  _transform_cache: dict[str, npt.NDArray] = dataclasses.field(default_factory=dict)
20
18
 
21
19
  @staticmethod
@@ -13,7 +13,7 @@ class DataclassPrettyPrinter(abc.ABC):
13
13
  if not isinstance(obj, list):
14
14
  raise TypeError(obj, type(obj))
15
15
 
16
- if all(isinstance(el, numbers.Number | str) for el in obj):
16
+ if all(isinstance(el, (numbers.Number, str)) for el in obj):
17
17
  return str(obj)
18
18
 
19
19
  spacing = " " * 4
@@ -2,12 +2,10 @@ from __future__ import annotations
2
2
 
3
3
  import dataclasses
4
4
  import types
5
- from typing import ClassVar
5
+ from typing import ClassVar, Union
6
6
 
7
7
  import mashumaro
8
8
 
9
- from rod import logging
10
-
11
9
  from .element import Element
12
10
 
13
11
 
@@ -1,4 +1,5 @@
1
1
  import dataclasses
2
+ from typing import Optional
2
3
 
3
4
  import mashumaro
4
5
 
@@ -9,32 +10,32 @@ from .element import Element
9
10
  @dataclasses.dataclass
10
11
  class Limit(Element):
11
12
 
12
- lower: float | None = dataclasses.field(
13
+ lower: Optional[float] = dataclasses.field(
13
14
  default=None,
14
15
  metadata=mashumaro.field_options(serialize=Element.serialize_float),
15
16
  )
16
17
 
17
- upper: float | None = dataclasses.field(
18
+ upper: Optional[float] = dataclasses.field(
18
19
  default=None,
19
20
  metadata=mashumaro.field_options(serialize=Element.serialize_float),
20
21
  )
21
22
 
22
- effort: float | None = dataclasses.field(
23
+ effort: Optional[float] = dataclasses.field(
23
24
  default=None,
24
25
  metadata=mashumaro.field_options(serialize=Element.serialize_float),
25
26
  )
26
27
 
27
- velocity: float | None = dataclasses.field(
28
+ velocity: Optional[float] = dataclasses.field(
28
29
  default=None,
29
30
  metadata=mashumaro.field_options(serialize=Element.serialize_float),
30
31
  )
31
32
 
32
- stiffness: float | None = dataclasses.field(
33
+ stiffness: Optional[float] = dataclasses.field(
33
34
  default=None,
34
35
  metadata=mashumaro.field_options(serialize=Element.serialize_float),
35
36
  )
36
37
 
37
- dissipation: float | None = dataclasses.field(
38
+ dissipation: Optional[float] = dataclasses.field(
38
39
  default=None,
39
40
  metadata=mashumaro.field_options(serialize=Element.serialize_float),
40
41
  )
@@ -50,12 +51,12 @@ class Dynamics(Element):
50
51
  metadata=mashumaro.field_options(serialize=Element.serialize_float),
51
52
  )
52
53
 
53
- damping: float | None = dataclasses.field(
54
+ damping: Optional[float] = dataclasses.field(
54
55
  default=None,
55
56
  metadata=mashumaro.field_options(serialize=Element.serialize_float),
56
57
  )
57
58
 
58
- friction: float | None = dataclasses.field(
59
+ friction: Optional[float] = dataclasses.field(
59
60
  default=None,
60
61
  metadata=mashumaro.field_options(serialize=Element.serialize_float),
61
62
  )
@@ -65,7 +66,7 @@ class Dynamics(Element):
65
66
  class Axis(Element):
66
67
  xyz: Xyz
67
68
  limit: Limit
68
- dynamics: Dynamics | None = dataclasses.field(default=None)
69
+ dynamics: Optional[Dynamics] = dataclasses.field(default=None)
69
70
 
70
71
 
71
72
  @dataclasses.dataclass
@@ -77,4 +78,4 @@ class Joint(Element):
77
78
  child: str
78
79
 
79
80
  pose: Pose | None = dataclasses.field(default=None)
80
- axis: Axis | None = dataclasses.field(default=None)
81
+ axis: Optional[Axis] = dataclasses.field(default=None)
@@ -1,13 +1,9 @@
1
- from __future__ import annotations
2
-
3
1
  import dataclasses
4
2
 
5
3
  import mashumaro
6
4
  import numpy as np
7
5
  import numpy.typing as npt
8
6
 
9
- from rod import logging
10
-
11
7
  from .collision import Collision
12
8
  from .common import Pose
13
9
  from .element import Element
@@ -16,7 +12,6 @@ from .visual import Visual
16
12
 
17
13
  @dataclasses.dataclass
18
14
  class Inertia(Element):
19
-
20
15
  ixx: float = dataclasses.field(
21
16
  default=1.0,
22
17
  metadata=mashumaro.field_options(serialize=Element.serialize_float),
@@ -47,42 +42,6 @@ class Inertia(Element):
47
42
  metadata=mashumaro.field_options(serialize=Element.serialize_float),
48
43
  )
49
44
 
50
- @staticmethod
51
- def from_inertia_tensor(
52
- inertia_tensor: npt.NDArray, validate: bool = True
53
- ) -> Inertia:
54
-
55
- inertia_tensor = inertia_tensor.squeeze()
56
-
57
- if inertia_tensor.shape != (3, 3):
58
- raise ValueError(f"Expected shape (3, 3), got {inertia_tensor.shape}")
59
-
60
- # Extract the diagonal terms.
61
- I1, I2, I3 = np.diag(inertia_tensor)
62
-
63
- # Check if the inertia tensor meets the triangular inequality.
64
- valid = True
65
- valid = valid and I1 + I2 >= I3
66
- valid = valid and I1 + I3 >= I2
67
- valid = valid and I2 + I3 >= I1
68
-
69
- if not valid:
70
- msg = "Inertia tensor does not meet the triangular inequality"
71
-
72
- if not validate:
73
- logging.warning(msg)
74
- else:
75
- raise ValueError(msg)
76
-
77
- return Inertia(
78
- ixx=float(inertia_tensor[0, 0]),
79
- ixy=float(inertia_tensor[0, 1]),
80
- ixz=float(inertia_tensor[0, 2]),
81
- iyy=float(inertia_tensor[1, 1]),
82
- iyz=float(inertia_tensor[1, 2]),
83
- izz=float(inertia_tensor[2, 2]),
84
- )
85
-
86
45
  def matrix(self) -> npt.NDArray:
87
46
  return np.array(
88
47
  [