rod 0.2.dev12__tar.gz → 0.2.1.dev16__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.
- {rod-0.2.dev12 → rod-0.2.1.dev16}/.github/workflows/ci_cd.yml +2 -1
- {rod-0.2.dev12 → rod-0.2.1.dev16}/PKG-INFO +2 -1
- {rod-0.2.dev12 → rod-0.2.1.dev16}/setup.cfg +1 -0
- rod-0.2.1.dev16/src/rod/builder/primitives.py +110 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod.egg-info/PKG-INFO +2 -1
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod.egg-info/SOURCES.txt +1 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod.egg-info/requires.txt +1 -0
- rod-0.2.1.dev16/tests/test_meshbuilder.py +61 -0
- rod-0.2.dev12/src/rod/builder/primitives.py +0 -56
- {rod-0.2.dev12 → rod-0.2.1.dev16}/.github/workflows/style.yml +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/.gitignore +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/LICENSE +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/README.md +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/pyproject.toml +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/setup.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/__init__.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/builder/__init__.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/builder/primitive_builder.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/kinematics/__init__.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/kinematics/kinematic_tree.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/kinematics/tree_transforms.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/logging.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/pretty_printer.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/sdf/__init__.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/sdf/collision.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/sdf/common.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/sdf/element.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/sdf/geometry.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/sdf/joint.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/sdf/link.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/sdf/material.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/sdf/model.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/sdf/physics.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/sdf/scene.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/sdf/sdf.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/sdf/visual.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/sdf/world.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/tree/__init__.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/tree/directed_tree.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/tree/tree_elements.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/urdf/__init__.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/urdf/exporter.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/utils/__init__.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/utils/frame_convention.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/utils/gazebo.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/utils/resolve_frames.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/utils/resolve_uris.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod.egg-info/dependency_links.txt +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod.egg-info/not-zip-safe +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod.egg-info/top_level.txt +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/tests/test_urdf_parsing.py +0 -0
- {rod-0.2.dev12 → rod-0.2.1.dev16}/tests/utils_models.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: rod
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1.dev16
|
|
4
4
|
Summary: The ultimate Python tool for RObot Descriptions processing.
|
|
5
5
|
Home-page: https://github.com/ami-iit/rod
|
|
6
6
|
Author: Diego Ferigo
|
|
@@ -38,6 +38,7 @@ Requires-Dist: numpy
|
|
|
38
38
|
Requires-Dist: packaging
|
|
39
39
|
Requires-Dist: resolve-robotics-uri-py
|
|
40
40
|
Requires-Dist: scipy
|
|
41
|
+
Requires-Dist: trimesh
|
|
41
42
|
Requires-Dist: xmltodict
|
|
42
43
|
Provides-Extra: style
|
|
43
44
|
Requires-Dist: black; extra == "style"
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
import pathlib
|
|
3
|
+
from typing import Union
|
|
4
|
+
|
|
5
|
+
import trimesh
|
|
6
|
+
from numpy.typing import NDArray
|
|
7
|
+
|
|
8
|
+
import rod
|
|
9
|
+
from rod.builder.primitive_builder import PrimitiveBuilder
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclasses.dataclass
|
|
13
|
+
class SphereBuilder(PrimitiveBuilder):
|
|
14
|
+
radius: float
|
|
15
|
+
|
|
16
|
+
def _inertia(self) -> rod.Inertia:
|
|
17
|
+
return rod.Inertia(
|
|
18
|
+
ixx=2 / 5 * self.mass * (self.radius) ** 2,
|
|
19
|
+
iyy=2 / 5 * self.mass * (self.radius) ** 2,
|
|
20
|
+
izz=2 / 5 * self.mass * (self.radius) ** 2,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
def _geometry(self) -> rod.Geometry:
|
|
24
|
+
return rod.Geometry(sphere=rod.Sphere(radius=self.radius))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclasses.dataclass
|
|
28
|
+
class BoxBuilder(PrimitiveBuilder):
|
|
29
|
+
x: float
|
|
30
|
+
y: float
|
|
31
|
+
z: float
|
|
32
|
+
|
|
33
|
+
def _inertia(self) -> rod.Inertia:
|
|
34
|
+
return rod.Inertia(
|
|
35
|
+
ixx=self.mass / 12 * (self.y**2 + self.z**2),
|
|
36
|
+
iyy=self.mass / 12 * (self.x**2 + self.z**2),
|
|
37
|
+
izz=self.mass / 12 * (self.x**2 + self.y**2),
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
def _geometry(self) -> rod.Geometry:
|
|
41
|
+
return rod.Geometry(box=rod.Box(size=[self.x, self.y, self.z]))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclasses.dataclass
|
|
45
|
+
class CylinderBuilder(PrimitiveBuilder):
|
|
46
|
+
radius: float
|
|
47
|
+
length: float
|
|
48
|
+
|
|
49
|
+
def _inertia(self) -> rod.Inertia:
|
|
50
|
+
ixx_iyy = self.mass * (3 * self.radius**2 + self.length**2) / 12
|
|
51
|
+
|
|
52
|
+
return rod.Inertia(
|
|
53
|
+
ixx=ixx_iyy,
|
|
54
|
+
iyy=ixx_iyy,
|
|
55
|
+
izz=0.5 * self.mass * self.radius**2,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
def _geometry(self) -> rod.Geometry:
|
|
59
|
+
return rod.Geometry(
|
|
60
|
+
cylinder=rod.Cylinder(radius=self.radius, length=self.length)
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@dataclasses.dataclass
|
|
65
|
+
class MeshBuilder(PrimitiveBuilder):
|
|
66
|
+
mesh_path: Union[str, pathlib.Path]
|
|
67
|
+
scale: NDArray
|
|
68
|
+
|
|
69
|
+
def __post_init__(self) -> None:
|
|
70
|
+
"""
|
|
71
|
+
Post-initialization method for the class.
|
|
72
|
+
Loads the mesh from the specified file path and performs necessary checks.
|
|
73
|
+
|
|
74
|
+
Raises:
|
|
75
|
+
AssertionError: If the scale is not a 3D vector.
|
|
76
|
+
TypeError: If the mesh_path is not a str or pathlib.Path.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
if isinstance(self.mesh_path, str):
|
|
80
|
+
extension = pathlib.Path(self.mesh_path).suffix
|
|
81
|
+
elif isinstance(self.mesh_path, pathlib.Path):
|
|
82
|
+
extension = self.mesh_path.suffix
|
|
83
|
+
else:
|
|
84
|
+
raise TypeError(
|
|
85
|
+
f"Expected str or pathlib.Path for mesh_path, got {type(self.mesh_path)}"
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
self.mesh: trimesh.base.Trimesh = trimesh.load(
|
|
89
|
+
str(self.mesh_path),
|
|
90
|
+
force="mesh",
|
|
91
|
+
file_type=extension,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
assert self.scale.shape == (
|
|
95
|
+
3,
|
|
96
|
+
), f"Scale must be a 3D vector, got {self.scale.shape}"
|
|
97
|
+
|
|
98
|
+
def _inertia(self) -> rod.Inertia:
|
|
99
|
+
inertia = self.mesh.moment_inertia
|
|
100
|
+
return rod.Inertia(
|
|
101
|
+
ixx=inertia[0, 0],
|
|
102
|
+
ixy=inertia[0, 1],
|
|
103
|
+
ixz=inertia[0, 2],
|
|
104
|
+
iyy=inertia[1, 1],
|
|
105
|
+
iyz=inertia[1, 2],
|
|
106
|
+
izz=inertia[2, 2],
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
def _geometry(self) -> rod.Geometry:
|
|
110
|
+
return rod.Geometry(mesh=rod.Mesh(uri=str(self.mesh_path), scale=self.scale))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: rod
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1.dev16
|
|
4
4
|
Summary: The ultimate Python tool for RObot Descriptions processing.
|
|
5
5
|
Home-page: https://github.com/ami-iit/rod
|
|
6
6
|
Author: Diego Ferigo
|
|
@@ -38,6 +38,7 @@ Requires-Dist: numpy
|
|
|
38
38
|
Requires-Dist: packaging
|
|
39
39
|
Requires-Dist: resolve-robotics-uri-py
|
|
40
40
|
Requires-Dist: scipy
|
|
41
|
+
Requires-Dist: trimesh
|
|
41
42
|
Requires-Dist: xmltodict
|
|
42
43
|
Provides-Extra: style
|
|
43
44
|
Requires-Dist: black; extra == "style"
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import pathlib
|
|
3
|
+
import tempfile
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import trimesh
|
|
7
|
+
|
|
8
|
+
from rod.builder.primitives import MeshBuilder
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_builder_creation():
|
|
12
|
+
mesh = trimesh.creation.box([1, 1, 1])
|
|
13
|
+
|
|
14
|
+
# Temporary write to file because rod Mesh works with uri
|
|
15
|
+
with tempfile.NamedTemporaryFile(suffix=".stl") as fp:
|
|
16
|
+
mesh.export(fp.name, file_type="stl")
|
|
17
|
+
|
|
18
|
+
builder = MeshBuilder(
|
|
19
|
+
name="test_mesh",
|
|
20
|
+
mesh_path=fp.name,
|
|
21
|
+
mass=1.0,
|
|
22
|
+
scale=np.array([1.0, 1.0, 1.0]),
|
|
23
|
+
)
|
|
24
|
+
assert (
|
|
25
|
+
builder.mesh.vertices.shape == mesh.vertices.shape
|
|
26
|
+
), f"{builder.mesh.vertices.shape} != {mesh.vertices.shape}"
|
|
27
|
+
assert (
|
|
28
|
+
builder.mesh.faces.shape == mesh.faces.shape
|
|
29
|
+
), f"{builder.mesh.faces.shape} != {mesh.faces.shape}"
|
|
30
|
+
assert (
|
|
31
|
+
builder.mesh.moment_inertia.all() == mesh.moment_inertia.all()
|
|
32
|
+
), f"{builder.mesh.moment_inertia} != {mesh.moment_inertia}"
|
|
33
|
+
assert builder.mesh.volume == mesh.volume, f"{builder.mesh.volume} != {mesh.volume}"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_builder_creation_custom_mesh():
|
|
37
|
+
# Create a custom mesh
|
|
38
|
+
vertices = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]])
|
|
39
|
+
faces = np.array([[0, 1, 2], [0, 2, 3]])
|
|
40
|
+
mesh = trimesh.Trimesh(vertices=vertices, faces=faces)
|
|
41
|
+
|
|
42
|
+
# Temporary write to file because rod Mesh works with uri
|
|
43
|
+
with tempfile.NamedTemporaryFile(suffix=".stl") as fp:
|
|
44
|
+
mesh.export(fp.name, file_type="stl")
|
|
45
|
+
|
|
46
|
+
builder = MeshBuilder(
|
|
47
|
+
name="test_mesh",
|
|
48
|
+
mesh_path=fp.name,
|
|
49
|
+
mass=1.0,
|
|
50
|
+
scale=np.array([1.0, 1.0, 1.0]),
|
|
51
|
+
)
|
|
52
|
+
assert (
|
|
53
|
+
builder.mesh.vertices.shape == mesh.vertices.shape
|
|
54
|
+
), f"{builder.mesh.vertices.shape} != {mesh.vertices.shape}"
|
|
55
|
+
assert (
|
|
56
|
+
builder.mesh.faces.shape == mesh.faces.shape
|
|
57
|
+
), f"{builder.mesh.faces.shape} != {mesh.faces.shape}"
|
|
58
|
+
assert (
|
|
59
|
+
builder.mesh.moment_inertia.all() == mesh.moment_inertia.all()
|
|
60
|
+
), f"{builder.mesh.moment_inertia} != {mesh.moment_inertia}"
|
|
61
|
+
assert builder.mesh.volume == mesh.volume, f"{builder.mesh.volume} != {mesh.volume}"
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import dataclasses
|
|
2
|
-
|
|
3
|
-
import rod
|
|
4
|
-
from rod.builder.primitive_builder import PrimitiveBuilder
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
@dataclasses.dataclass
|
|
8
|
-
class SphereBuilder(PrimitiveBuilder):
|
|
9
|
-
radius: float
|
|
10
|
-
|
|
11
|
-
def _inertia(self) -> rod.Inertia:
|
|
12
|
-
return rod.Inertia(
|
|
13
|
-
ixx=2 / 5 * self.mass * (self.radius) ** 2,
|
|
14
|
-
iyy=2 / 5 * self.mass * (self.radius) ** 2,
|
|
15
|
-
izz=2 / 5 * self.mass * (self.radius) ** 2,
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
def _geometry(self) -> rod.Geometry:
|
|
19
|
-
return rod.Geometry(sphere=rod.Sphere(radius=self.radius))
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
@dataclasses.dataclass
|
|
23
|
-
class BoxBuilder(PrimitiveBuilder):
|
|
24
|
-
x: float
|
|
25
|
-
y: float
|
|
26
|
-
z: float
|
|
27
|
-
|
|
28
|
-
def _inertia(self) -> rod.Inertia:
|
|
29
|
-
return rod.Inertia(
|
|
30
|
-
ixx=self.mass / 12 * (self.y**2 + self.z**2),
|
|
31
|
-
iyy=self.mass / 12 * (self.x**2 + self.z**2),
|
|
32
|
-
izz=self.mass / 12 * (self.x**2 + self.y**2),
|
|
33
|
-
)
|
|
34
|
-
|
|
35
|
-
def _geometry(self) -> rod.Geometry:
|
|
36
|
-
return rod.Geometry(box=rod.Box(size=[self.x, self.y, self.z]))
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
@dataclasses.dataclass
|
|
40
|
-
class CylinderBuilder(PrimitiveBuilder):
|
|
41
|
-
radius: float
|
|
42
|
-
length: float
|
|
43
|
-
|
|
44
|
-
def _inertia(self) -> rod.Inertia:
|
|
45
|
-
ixx_iyy = self.mass * (3 * self.radius**2 + self.length**2) / 12
|
|
46
|
-
|
|
47
|
-
return rod.Inertia(
|
|
48
|
-
ixx=ixx_iyy,
|
|
49
|
-
iyy=ixx_iyy,
|
|
50
|
-
izz=0.5 * self.mass * self.radius**2,
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
def _geometry(self) -> rod.Geometry:
|
|
54
|
-
return rod.Geometry(
|
|
55
|
-
cylinder=rod.Cylinder(radius=self.radius, length=self.length)
|
|
56
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|