reachy2_sdk.parts.tripod

Reachy Tripod module.

Handles all specific methods to the tripod.

  1"""Reachy Tripod module.
  2
  3Handles all specific methods to the tripod.
  4"""
  5
  6import logging
  7from typing import Tuple
  8
  9import grpc
 10import numpy as np
 11from google.protobuf.wrappers_pb2 import FloatValue
 12from reachy2_sdk_api.part_pb2 import PartId
 13from reachy2_sdk_api.tripod_pb2 import Tripod as Tripod_proto
 14from reachy2_sdk_api.tripod_pb2 import TripodCommand, TripodState
 15from reachy2_sdk_api.tripod_pb2_grpc import TripodServiceStub
 16
 17
 18class Tripod:
 19    """The Tripod class represents the fixed tripod of the robot.
 20
 21    The Tripod class is used to update manually the robot tripod's height value.
 22    """
 23
 24    def __init__(
 25        self,
 26        proto_msg: Tripod_proto,
 27        initial_state: TripodState,
 28        grpc_channel: grpc.Channel,
 29    ):
 30        """Initialize the Tripod with its initial state and configuration.
 31
 32        This sets up the tripod by assigning its state based on the provided initial values.
 33
 34        Args:
 35            proto_msg: The protobuf message containing configuration details for the part.
 36            initial_state: The initial state of the tripod's joints.
 37            grpc_channel: The gRPC channel used to communicate with the DynamixelMotor service.
 38        """
 39        self._grpc_channel = grpc_channel
 40        self._stub = TripodServiceStub(grpc_channel)
 41        self._part_id = PartId(id=proto_msg.part_id.id, name=proto_msg.part_id.name)
 42        self._logger = logging.getLogger(__name__)
 43
 44        self._present_position: float
 45        self._goal_position: float
 46        self._update_with(initial_state)
 47
 48    def __repr__(self) -> str:
 49        """Clean representation of the Tripod."""
 50        repr_template = "<Tripod height={height} >"
 51        return repr_template.format(
 52            height=round(self.height, 3),
 53        )
 54
 55    @property
 56    def height(self) -> float:
 57        """Get the current height of the robot torso in meters."""
 58        return float(np.round(self._present_position, 3))
 59
 60    def set_height(self, height: float) -> None:
 61        """Set the height of the tripod.
 62
 63        Args:
 64            height: The height of the tripod in meters.
 65
 66        Raises:
 67            TypeError: If the height is not a float or int.
 68        """
 69        if not isinstance(height, float) and not isinstance(height, int):
 70            raise TypeError(f"height should be a float or int (got {type(height)} instead)!")
 71
 72        limit_min, limit_max = self.get_limits()
 73        if not limit_min <= height <= limit_max:
 74            self._logger.warning(f"Height value {height} is out of bounds. ")
 75            height = np.clip(height, limit_min, limit_max)
 76            self._logger.warning(f"Setting height to {height}.")
 77        command = TripodCommand(
 78            part_id=self._part_id,
 79            height_position=FloatValue(value=height),
 80        )
 81        self._stub.SendCommand(command)
 82
 83    def reset_height(self) -> None:
 84        """Reset the height of the tripod to its default position."""
 85        self._stub.ResetDefaultValues(self._part_id)
 86
 87    def get_limits(self) -> Tuple[float, float]:
 88        """Get the limits of the tripod's height.
 89
 90        Returns:
 91            A tuple containing the minimum and maximum height values.
 92        """
 93        response = self._stub.GetJointsLimits(self._part_id)
 94        return np.round(response.height_limit.min.value, 3), np.round(response.height_limit.max.value, 3)
 95
 96    def _update_with(self, new_state: TripodState) -> None:
 97        """Update the present and goal positions of the joint with new state values.
 98
 99        Args:
100            new_state: A TripodState containing the new state values for the joint. Should include
101                "present_position" and "goal_position", with corresponding FloatValue objects as values.
102        """
103        self._present_position = new_state.height.present_position.value
104        self._goal_position = new_state.height.goal_position.value
class Tripod:
 19class Tripod:
 20    """The Tripod class represents the fixed tripod of the robot.
 21
 22    The Tripod class is used to update manually the robot tripod's height value.
 23    """
 24
 25    def __init__(
 26        self,
 27        proto_msg: Tripod_proto,
 28        initial_state: TripodState,
 29        grpc_channel: grpc.Channel,
 30    ):
 31        """Initialize the Tripod with its initial state and configuration.
 32
 33        This sets up the tripod by assigning its state based on the provided initial values.
 34
 35        Args:
 36            proto_msg: The protobuf message containing configuration details for the part.
 37            initial_state: The initial state of the tripod's joints.
 38            grpc_channel: The gRPC channel used to communicate with the DynamixelMotor service.
 39        """
 40        self._grpc_channel = grpc_channel
 41        self._stub = TripodServiceStub(grpc_channel)
 42        self._part_id = PartId(id=proto_msg.part_id.id, name=proto_msg.part_id.name)
 43        self._logger = logging.getLogger(__name__)
 44
 45        self._present_position: float
 46        self._goal_position: float
 47        self._update_with(initial_state)
 48
 49    def __repr__(self) -> str:
 50        """Clean representation of the Tripod."""
 51        repr_template = "<Tripod height={height} >"
 52        return repr_template.format(
 53            height=round(self.height, 3),
 54        )
 55
 56    @property
 57    def height(self) -> float:
 58        """Get the current height of the robot torso in meters."""
 59        return float(np.round(self._present_position, 3))
 60
 61    def set_height(self, height: float) -> None:
 62        """Set the height of the tripod.
 63
 64        Args:
 65            height: The height of the tripod in meters.
 66
 67        Raises:
 68            TypeError: If the height is not a float or int.
 69        """
 70        if not isinstance(height, float) and not isinstance(height, int):
 71            raise TypeError(f"height should be a float or int (got {type(height)} instead)!")
 72
 73        limit_min, limit_max = self.get_limits()
 74        if not limit_min <= height <= limit_max:
 75            self._logger.warning(f"Height value {height} is out of bounds. ")
 76            height = np.clip(height, limit_min, limit_max)
 77            self._logger.warning(f"Setting height to {height}.")
 78        command = TripodCommand(
 79            part_id=self._part_id,
 80            height_position=FloatValue(value=height),
 81        )
 82        self._stub.SendCommand(command)
 83
 84    def reset_height(self) -> None:
 85        """Reset the height of the tripod to its default position."""
 86        self._stub.ResetDefaultValues(self._part_id)
 87
 88    def get_limits(self) -> Tuple[float, float]:
 89        """Get the limits of the tripod's height.
 90
 91        Returns:
 92            A tuple containing the minimum and maximum height values.
 93        """
 94        response = self._stub.GetJointsLimits(self._part_id)
 95        return np.round(response.height_limit.min.value, 3), np.round(response.height_limit.max.value, 3)
 96
 97    def _update_with(self, new_state: TripodState) -> None:
 98        """Update the present and goal positions of the joint with new state values.
 99
100        Args:
101            new_state: A TripodState containing the new state values for the joint. Should include
102                "present_position" and "goal_position", with corresponding FloatValue objects as values.
103        """
104        self._present_position = new_state.height.present_position.value
105        self._goal_position = new_state.height.goal_position.value

The Tripod class represents the fixed tripod of the robot.

The Tripod class is used to update manually the robot tripod's height value.

Tripod( proto_msg: tripod_pb2.Tripod, initial_state: tripod_pb2.TripodState, grpc_channel: grpc.Channel)
25    def __init__(
26        self,
27        proto_msg: Tripod_proto,
28        initial_state: TripodState,
29        grpc_channel: grpc.Channel,
30    ):
31        """Initialize the Tripod with its initial state and configuration.
32
33        This sets up the tripod by assigning its state based on the provided initial values.
34
35        Args:
36            proto_msg: The protobuf message containing configuration details for the part.
37            initial_state: The initial state of the tripod's joints.
38            grpc_channel: The gRPC channel used to communicate with the DynamixelMotor service.
39        """
40        self._grpc_channel = grpc_channel
41        self._stub = TripodServiceStub(grpc_channel)
42        self._part_id = PartId(id=proto_msg.part_id.id, name=proto_msg.part_id.name)
43        self._logger = logging.getLogger(__name__)
44
45        self._present_position: float
46        self._goal_position: float
47        self._update_with(initial_state)

Initialize the Tripod with its initial state and configuration.

This sets up the tripod by assigning its state based on the provided initial values.

Arguments:
  • proto_msg: The protobuf message containing configuration details for the part.
  • initial_state: The initial state of the tripod's joints.
  • grpc_channel: The gRPC channel used to communicate with the DynamixelMotor service.
height: float
56    @property
57    def height(self) -> float:
58        """Get the current height of the robot torso in meters."""
59        return float(np.round(self._present_position, 3))

Get the current height of the robot torso in meters.

def set_height(self, height: float) -> None:
61    def set_height(self, height: float) -> None:
62        """Set the height of the tripod.
63
64        Args:
65            height: The height of the tripod in meters.
66
67        Raises:
68            TypeError: If the height is not a float or int.
69        """
70        if not isinstance(height, float) and not isinstance(height, int):
71            raise TypeError(f"height should be a float or int (got {type(height)} instead)!")
72
73        limit_min, limit_max = self.get_limits()
74        if not limit_min <= height <= limit_max:
75            self._logger.warning(f"Height value {height} is out of bounds. ")
76            height = np.clip(height, limit_min, limit_max)
77            self._logger.warning(f"Setting height to {height}.")
78        command = TripodCommand(
79            part_id=self._part_id,
80            height_position=FloatValue(value=height),
81        )
82        self._stub.SendCommand(command)

Set the height of the tripod.

Arguments:
  • height: The height of the tripod in meters.
Raises:
  • TypeError: If the height is not a float or int.
def reset_height(self) -> None:
84    def reset_height(self) -> None:
85        """Reset the height of the tripod to its default position."""
86        self._stub.ResetDefaultValues(self._part_id)

Reset the height of the tripod to its default position.

def get_limits(self) -> Tuple[float, float]:
88    def get_limits(self) -> Tuple[float, float]:
89        """Get the limits of the tripod's height.
90
91        Returns:
92            A tuple containing the minimum and maximum height values.
93        """
94        response = self._stub.GetJointsLimits(self._part_id)
95        return np.round(response.height_limit.min.value, 3), np.round(response.height_limit.max.value, 3)

Get the limits of the tripod's height.

Returns:

A tuple containing the minimum and maximum height values.