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.
Files changed (36) hide show
  1. cookie_description/__init__.py +17 -0
  2. cookie_description/__main__.py +30 -0
  3. cookie_description/collision_viser_visualizer.py +96 -0
  4. cookie_description/meshes/ankle_stator.stl +0 -0
  5. cookie_description/meshes/knee_bumper.stl +0 -0
  6. cookie_description/meshes/knee_stator.stl +0 -0
  7. cookie_description/meshes/mj5208_rotor.stl +0 -0
  8. cookie_description/meshes/mj5208_stator.stl +0 -0
  9. cookie_description/meshes/oak_d_lite.stl +0 -0
  10. cookie_description/meshes/qdd100_rotor.stl +0 -0
  11. cookie_description/meshes/qdd100_stator.stl +0 -0
  12. cookie_description/meshes/rotor_connector.stl +0 -0
  13. cookie_description/meshes/torso.stl +0 -0
  14. cookie_description/meshes/wheel_hub.stl +0 -0
  15. cookie_description/meshes/wheel_tire.stl +0 -0
  16. cookie_description/paths.py +29 -0
  17. cookie_description/simulation.py +69 -0
  18. cookie_description/urdf/cookie.urdf +1187 -0
  19. cookie_description/visualizer.py +469 -0
  20. cookie_description/xacro/cookie.xacro +19 -0
  21. cookie_description/xacro/leg.xacro +228 -0
  22. cookie_description/xacro/materials.xacro +40 -0
  23. cookie_description/xacro/torso.xacro +148 -0
  24. cookie_description/xacro/utils/box_collision_inertial.xacro +17 -0
  25. cookie_description/xacro/utils/box_inertial.xacro +18 -0
  26. cookie_description/xacro/utils/bumper_segment.xacro +20 -0
  27. cookie_description/xacro/utils/cylinder_collision_inertial.xacro +18 -0
  28. cookie_description/xacro/utils/cylinder_inertial.xacro +18 -0
  29. cookie_description/xacro/utils/mj5208_joint.xacro +54 -0
  30. cookie_description/xacro/utils/qdd100_joint.xacro +51 -0
  31. cookie_description/xacro/utils/virtual_link.xacro +19 -0
  32. cookie_description-1.0.0.dist-info/METADATA +86 -0
  33. cookie_description-1.0.0.dist-info/RECORD +36 -0
  34. cookie_description-1.0.0.dist-info/WHEEL +4 -0
  35. cookie_description-1.0.0.dist-info/entry_points.txt +3 -0
  36. 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
@@ -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()