cookie_description 1.0.0__py3-none-any.whl
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.
- cookie_description/__init__.py +17 -0
- cookie_description/__main__.py +30 -0
- cookie_description/collision_viser_visualizer.py +96 -0
- cookie_description/meshes/ankle_stator.stl +0 -0
- cookie_description/meshes/knee_bumper.stl +0 -0
- cookie_description/meshes/knee_stator.stl +0 -0
- cookie_description/meshes/mj5208_rotor.stl +0 -0
- cookie_description/meshes/mj5208_stator.stl +0 -0
- cookie_description/meshes/oak_d_lite.stl +0 -0
- cookie_description/meshes/qdd100_rotor.stl +0 -0
- cookie_description/meshes/qdd100_stator.stl +0 -0
- cookie_description/meshes/rotor_connector.stl +0 -0
- cookie_description/meshes/torso.stl +0 -0
- cookie_description/meshes/wheel_hub.stl +0 -0
- cookie_description/meshes/wheel_tire.stl +0 -0
- cookie_description/paths.py +29 -0
- cookie_description/simulation.py +69 -0
- cookie_description/urdf/cookie.urdf +1187 -0
- cookie_description/visualizer.py +469 -0
- cookie_description/xacro/cookie.xacro +19 -0
- cookie_description/xacro/leg.xacro +228 -0
- cookie_description/xacro/materials.xacro +40 -0
- cookie_description/xacro/torso.xacro +148 -0
- cookie_description/xacro/utils/box_collision_inertial.xacro +17 -0
- cookie_description/xacro/utils/box_inertial.xacro +18 -0
- cookie_description/xacro/utils/bumper_segment.xacro +20 -0
- cookie_description/xacro/utils/cylinder_collision_inertial.xacro +18 -0
- cookie_description/xacro/utils/cylinder_inertial.xacro +18 -0
- cookie_description/xacro/utils/mj5208_joint.xacro +54 -0
- cookie_description/xacro/utils/qdd100_joint.xacro +51 -0
- cookie_description/xacro/utils/virtual_link.xacro +19 -0
- cookie_description-1.0.0.dist-info/METADATA +86 -0
- cookie_description-1.0.0.dist-info/RECORD +36 -0
- cookie_description-1.0.0.dist-info/WHEEL +4 -0
- cookie_description-1.0.0.dist-info/entry_points.txt +3 -0
- cookie_description-1.0.0.dist-info/licenses/LICENSE +212 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
#
|
|
4
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
|
|
6
|
+
"""Robot description for Cookie."""
|
|
7
|
+
|
|
8
|
+
from .paths import MESHES_PATH, PATH, URDF_PATH, XACRO_PATH
|
|
9
|
+
|
|
10
|
+
__version__ = "1.0.0"
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"MESHES_PATH",
|
|
14
|
+
"PATH",
|
|
15
|
+
"URDF_PATH",
|
|
16
|
+
"XACRO_PATH",
|
|
17
|
+
]
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
#
|
|
4
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
|
|
6
|
+
"""Entry point for ``uvx cookie_description <command>``."""
|
|
7
|
+
|
|
8
|
+
import runpy
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
COMMANDS = {
|
|
12
|
+
"simulation": "cookie_description.simulation",
|
|
13
|
+
"visualizer": "cookie_description.visualizer",
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def main():
|
|
18
|
+
"""Run a cookie_description command."""
|
|
19
|
+
if len(sys.argv) < 2 or sys.argv[1] not in COMMANDS:
|
|
20
|
+
available = ", ".join(sorted(COMMANDS))
|
|
21
|
+
print("Usage: cookie_description <command>")
|
|
22
|
+
print(f"Available commands: {available}")
|
|
23
|
+
sys.exit(1)
|
|
24
|
+
command = sys.argv[1]
|
|
25
|
+
sys.argv = sys.argv[1:] # shift so the submodule sees clean argv
|
|
26
|
+
runpy.run_module(COMMANDS[command], run_name="__main__")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
if __name__ == "__main__":
|
|
30
|
+
main()
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
#
|
|
4
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
|
|
6
|
+
from pinocchio import visualize
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class CollisionViserVisualizer(visualize.ViserVisualizer):
|
|
10
|
+
"""ViserVisualizer that renders collision geometries as wireframes.
|
|
11
|
+
|
|
12
|
+
While making Cookie's URDF, it is useful to overlay collision meshes on top
|
|
13
|
+
of the visual meshes to verify their fit. Viser's alpha-blending is
|
|
14
|
+
order-dependent and doesn't perform depth sorting, so transparent collision
|
|
15
|
+
meshes appear incorrectly from certain viewing angles. We thus render them
|
|
16
|
+
as wireframes.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
_visual_opacity: float = 1.0
|
|
20
|
+
_visual_handles: list # list of (handle, parent_frame_id) pairs
|
|
21
|
+
_collision_handles: list # list of (handle, parent_frame_id) pairs
|
|
22
|
+
|
|
23
|
+
def loadViewerModel(self, *args, **kwargs):
|
|
24
|
+
"""Reset tracked handles before (re)loading the model."""
|
|
25
|
+
self._visual_handles = []
|
|
26
|
+
self._collision_handles = []
|
|
27
|
+
super().loadViewerModel(*args, **kwargs)
|
|
28
|
+
|
|
29
|
+
def loadViewerGeometryObject(self, geometry_object, prefix="", color=None):
|
|
30
|
+
"""Load geometry object with wireframe rendering for collision meshes.
|
|
31
|
+
|
|
32
|
+
Temporarily patches the Viser scene creation methods to inject
|
|
33
|
+
wireframe=True before delegating to the parent implementation. The
|
|
34
|
+
patch is scoped to a single geometry object and cleaned up in a finally
|
|
35
|
+
block.
|
|
36
|
+
"""
|
|
37
|
+
scene = self.viewer.scene
|
|
38
|
+
_METHODS = ("add_box", "add_icosphere", "add_mesh_simple")
|
|
39
|
+
|
|
40
|
+
is_collision = "collision" in prefix
|
|
41
|
+
parent_frame = int(geometry_object.parentFrame)
|
|
42
|
+
|
|
43
|
+
for method_name in _METHODS:
|
|
44
|
+
original = getattr(scene, method_name)
|
|
45
|
+
|
|
46
|
+
def patched(
|
|
47
|
+
*args,
|
|
48
|
+
_orig=original,
|
|
49
|
+
_collision=is_collision,
|
|
50
|
+
_pf=parent_frame,
|
|
51
|
+
**kwargs,
|
|
52
|
+
):
|
|
53
|
+
if _collision:
|
|
54
|
+
kwargs["wireframe"] = True
|
|
55
|
+
kwargs.pop("opacity", None)
|
|
56
|
+
else:
|
|
57
|
+
kwargs["opacity"] = self._visual_opacity
|
|
58
|
+
handle = _orig(*args, **kwargs)
|
|
59
|
+
if _collision:
|
|
60
|
+
self._collision_handles.append((handle, _pf))
|
|
61
|
+
else:
|
|
62
|
+
self._visual_handles.append((handle, _pf))
|
|
63
|
+
return handle
|
|
64
|
+
|
|
65
|
+
setattr(scene, method_name, patched)
|
|
66
|
+
|
|
67
|
+
try:
|
|
68
|
+
super().loadViewerGeometryObject(geometry_object, prefix, color)
|
|
69
|
+
finally:
|
|
70
|
+
for method_name in _METHODS:
|
|
71
|
+
delattr(scene, method_name)
|
|
72
|
+
|
|
73
|
+
def set_visual_opacity(self, value: float) -> None:
|
|
74
|
+
"""Update opacity of all loaded visual meshes uniformly."""
|
|
75
|
+
self._visual_opacity = value
|
|
76
|
+
for handle, _ in self._visual_handles:
|
|
77
|
+
handle.opacity = value
|
|
78
|
+
|
|
79
|
+
def set_joint_focus(
|
|
80
|
+
self, highlighted_frames: frozenset, dim_opacity: float = 0.2
|
|
81
|
+
) -> None:
|
|
82
|
+
"""Make parent and child link visuals opaque, dim everything else.
|
|
83
|
+
|
|
84
|
+
Also restricts collision mesh visibility to the highlighted frames.
|
|
85
|
+
"""
|
|
86
|
+
for handle, parent_frame in self._visual_handles:
|
|
87
|
+
handle.opacity = (
|
|
88
|
+
1.0 if parent_frame in highlighted_frames else dim_opacity
|
|
89
|
+
)
|
|
90
|
+
for handle, parent_frame in self._collision_handles:
|
|
91
|
+
handle.visible = parent_frame in highlighted_frames
|
|
92
|
+
|
|
93
|
+
def set_all_collisions_visible(self, visible: bool) -> None:
|
|
94
|
+
"""Set visibility on all individual collision handles."""
|
|
95
|
+
for handle, _ in self._collision_handles:
|
|
96
|
+
handle.visible = visible
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
#
|
|
4
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
Paths to the URDF package and main description for Cookie.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
|
|
12
|
+
# Path to the cookie_description module
|
|
13
|
+
PATH = os.path.dirname(os.path.realpath(__file__))
|
|
14
|
+
|
|
15
|
+
# Path to the meshes folder
|
|
16
|
+
MESHES_PATH = os.path.join(PATH, "meshes")
|
|
17
|
+
|
|
18
|
+
# Path to the robot's URDF
|
|
19
|
+
URDF_PATH = os.path.join(PATH, "urdf", "cookie.urdf")
|
|
20
|
+
|
|
21
|
+
# Path to the robot's Xacro source
|
|
22
|
+
XACRO_PATH = os.path.join(PATH, "xacro", "cookie.xacro")
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"MESHES_PATH",
|
|
26
|
+
"PATH",
|
|
27
|
+
"URDF_PATH",
|
|
28
|
+
"XACRO_PATH",
|
|
29
|
+
]
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
#
|
|
4
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
Load a robot description, specified from the command line, in PyBullet.
|
|
8
|
+
|
|
9
|
+
This example requires PyBullet, which is installed by ``pip install pybullet``.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import math
|
|
13
|
+
import os
|
|
14
|
+
|
|
15
|
+
import loop_rate_limiters
|
|
16
|
+
import pybullet
|
|
17
|
+
import pybullet_data
|
|
18
|
+
|
|
19
|
+
from .paths import PATH, URDF_PATH
|
|
20
|
+
|
|
21
|
+
if __name__ == "__main__":
|
|
22
|
+
pybullet.connect(pybullet.GUI)
|
|
23
|
+
pybullet.configureDebugVisualizer(pybullet.COV_ENABLE_GUI, 0)
|
|
24
|
+
pybullet.configureDebugVisualizer(pybullet.COV_ENABLE_SHADOWS, 0)
|
|
25
|
+
pybullet.setAdditionalSearchPath(PATH)
|
|
26
|
+
pybullet.setAdditionalSearchPath(os.path.dirname(PATH))
|
|
27
|
+
robot = pybullet.loadURDF(URDF_PATH)
|
|
28
|
+
pybullet.setGravity(0, 0, -9.81)
|
|
29
|
+
pybullet.setAdditionalSearchPath(pybullet_data.getDataPath())
|
|
30
|
+
plane = pybullet.loadURDF("plane.urdf")
|
|
31
|
+
pybullet.resetBasePositionAndOrientation(
|
|
32
|
+
robot, [0, 0, 1.5], [0, 0.5, 0.7, 0.3]
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
# Find hip and knee joint indices
|
|
36
|
+
hip_indices = []
|
|
37
|
+
knee_indices = []
|
|
38
|
+
for i in range(pybullet.getNumJoints(robot)):
|
|
39
|
+
joint_info = pybullet.getJointInfo(robot, i)
|
|
40
|
+
joint_name = joint_info[1].decode("utf-8")
|
|
41
|
+
if joint_info[2] != pybullet.JOINT_REVOLUTE:
|
|
42
|
+
continue
|
|
43
|
+
pybullet.setJointMotorControl2(
|
|
44
|
+
robot, i, pybullet.VELOCITY_CONTROL, force=0
|
|
45
|
+
)
|
|
46
|
+
if "hip" in joint_name:
|
|
47
|
+
hip_indices.append(i)
|
|
48
|
+
elif "knee" in joint_name:
|
|
49
|
+
knee_indices.append(i)
|
|
50
|
+
|
|
51
|
+
rate = loop_rate_limiters.RateLimiter(frequency=200.0)
|
|
52
|
+
pybullet.setTimeStep(rate.dt)
|
|
53
|
+
t = 0.0
|
|
54
|
+
while True:
|
|
55
|
+
hip_target = 0.4 * math.sin(2.0 * math.pi * 0.5 * t)
|
|
56
|
+
knee_target = -2.0 * hip_target
|
|
57
|
+
for idx in hip_indices:
|
|
58
|
+
pybullet.setJointMotorControl2(
|
|
59
|
+
robot, idx, pybullet.POSITION_CONTROL,
|
|
60
|
+
targetPosition=hip_target, force=10.0,
|
|
61
|
+
)
|
|
62
|
+
for idx in knee_indices:
|
|
63
|
+
pybullet.setJointMotorControl2(
|
|
64
|
+
robot, idx, pybullet.POSITION_CONTROL,
|
|
65
|
+
targetPosition=knee_target, force=10.0,
|
|
66
|
+
)
|
|
67
|
+
pybullet.stepSimulation()
|
|
68
|
+
t += rate.dt
|
|
69
|
+
rate.sleep()
|