nova.types

 1from typing import AsyncIterator, Callable
 2
 3from nova import api
 4from nova.types.motion_settings import MotionSettings
 5from nova.types.pose import Pose
 6from nova.types.state import MotionState, RobotState
 7from nova.types.vector3d import Vector3d
 8
 9LoadPlanResponse = api.models.PlanSuccessfulResponse
10InitialMovementStream = AsyncIterator[api.models.StreamMoveResponse]
11InitialMovementConsumer = Callable[[api.models.StreamMoveResponse], None]
12MovementResponse = api.models.ExecuteTrajectoryResponse | api.models.StreamMoveResponse
13ExecuteTrajectoryRequestStream = AsyncIterator[api.models.ExecuteTrajectoryRequest]
14ExecuteTrajectoryResponseStream = AsyncIterator[api.models.ExecuteTrajectoryResponse]
15MovementControllerFunction = Callable[
16    [ExecuteTrajectoryResponseStream], ExecuteTrajectoryRequestStream
17]
18
19__all__ = [
20    "Vector3d",
21    "Pose",
22    "CollisionScene",
23    "LoadPlanResponse",
24    "InitialMovementStream",
25    "InitialMovementConsumer",
26    "MovementResponse",
27    "MotionState",
28    "RobotState",
29    "MotionSettings",
30    "ExecuteTrajectoryRequestStream",
31    "ExecuteTrajectoryResponseStream",
32    "MovementControllerFunction",
33]
class Vector3d(pydantic.main.BaseModel):
 11class Vector3d(pydantic.BaseModel):
 12    """A vector 3d class
 13    Examples:
 14    >>> Vector3d(x=10, y=20, z=30)
 15    Vector3d(x=10, y=20, z=30)
 16    """
 17
 18    x: float | int
 19    y: float | int
 20    z: float | int
 21
 22    def __eq__(self, other):
 23        if not isinstance(other, Vector3d):
 24            return NotImplemented
 25        return self.x == other.x and self.y == other.y and self.z == other.z
 26
 27    def __neg__(self) -> Vector3d:
 28        return type(self)(x=-self.x, y=-self.y, z=-self.z)
 29
 30    def __add__(self, other: Any) -> Vector3d:
 31        if isinstance(other, (float, int)):
 32            return type(self)(x=self.x + other, y=self.y + other, z=self.z + other)
 33        if isinstance(other, Vector3d):
 34            return type(self)(x=self.x + other.x, y=self.y + other.y, z=self.z + other.z)
 35        return NotImplemented
 36
 37    def __radd__(self, other: Any) -> Vector3d:
 38        return self.__add__(other)
 39
 40    def __sub__(self, other: Any) -> Vector3d:
 41        return self.__add__(-other)
 42
 43    def __rsub__(self, other: Any) -> Vector3d:
 44        if isinstance(other, (float, int)):
 45            return type(self)(x=other - self.x, y=other - self.y, z=other - self.z)
 46        if isinstance(other, Vector3d):
 47            return type(self)(x=other.x - self.x, y=other.y - self.y, z=other.z - self.z)
 48        return NotImplemented
 49
 50    def __mul__(self, other: Any) -> Vector3d:
 51        if isinstance(other, (float, int)):
 52            return type(self)(x=other * self.x, y=other * self.y, z=other * self.z)
 53        return NotImplemented
 54
 55    def __rmul__(self, other: Any) -> Vector3d:
 56        return self * other
 57
 58    def __truediv__(self, other: Any) -> Vector3d:
 59        if not isinstance(other, (float, int)):
 60            return NotImplemented
 61        return (1 / other) * self
 62
 63    def __len__(self):
 64        return 3
 65
 66    def __iter__(self):
 67        """Iterate over the vector
 68
 69        Examples:
 70        >>> v = Vector3d(x=1, y=2, z=3)
 71        >>> list(v)
 72        [1, 2, 3]
 73        >>> tuple(v)
 74        (1, 2, 3)
 75        """
 76        return iter(self.to_tuple())
 77
 78    def __getitem__(self, item):
 79        return self.to_tuple()[item]
 80
 81    @classmethod
 82    def from_tuple(cls, value: tuple[float, float, float]) -> Vector3d:
 83        """Create a new Vector3d from tuple
 84
 85        Examples:
 86        >>> Vector3d.from_tuple((10, 20, 30))
 87        Vector3d(x=10, y=20, z=30)
 88        >>> Vector3d.from_tuple((10.0, 20.5, 30.2))
 89        Vector3d(x=10.0, y=20.5, z=30.2)
 90        """
 91        return cls(x=value[0], y=value[1], z=value[2])
 92
 93    def to_tuple(self) -> tuple[float, float, float]:
 94        """Return the vector as a tuple
 95
 96        Examples:
 97        >>> Vector3d(x=10, y=20, z=30).to_tuple()
 98        (10, 20, 30)
 99        >>> Vector3d(x=10.0, y=20.5, z=30.2).to_tuple()
100        (10.0, 20.5, 30.2)
101        """
102        return self.x, self.y, self.z
103
104    def __array__(self, dtype=None):
105        """Allows numpy to automatically convert Vector3d to a numeric array.
106
107        Examples:
108        >>> v1 = Vector3d(x=1.0, y=2.0, z=3.0)
109        >>> v2 = Vector3d(x=1.001, y=2.0, z=3.0)
110        >>> np.isclose(v1, v2, atol=1e-3)
111        array([ True,  True,  True])
112        """
113        return np.array(self.to_tuple(), dtype=dtype)
114
115    def to_quaternion(self):
116        """Interpret the object as a rotation vector and convert it to a quaternion"""
117        values = np.asarray(self)
118        half_angle = np.linalg.norm(values) / 2
119        return np.concatenate([np.cos(half_angle)[None], values * np.sinc(half_angle / np.pi) / 2])
120
121    @pydantic.model_serializer
122    def serialize_model(self) -> wb.models.Vector3d:
123        """
124        Examples:
125        >>> Vector3d.from_tuple((1, 2, 3)).model_dump()
126        {'x': 1, 'y': 2, 'z': 3}
127        """
128        return wb.models.Vector3d(x=self.x, y=self.y, z=self.z)

A vector 3d class Examples:

>>> Vector3d(x=10, y=20, z=30)
Vector3d(x=10, y=20, z=30)
x: float | int
y: float | int
z: float | int
@classmethod
def from_tuple(cls, value: tuple[float, float, float]) -> Vector3d:
81    @classmethod
82    def from_tuple(cls, value: tuple[float, float, float]) -> Vector3d:
83        """Create a new Vector3d from tuple
84
85        Examples:
86        >>> Vector3d.from_tuple((10, 20, 30))
87        Vector3d(x=10, y=20, z=30)
88        >>> Vector3d.from_tuple((10.0, 20.5, 30.2))
89        Vector3d(x=10.0, y=20.5, z=30.2)
90        """
91        return cls(x=value[0], y=value[1], z=value[2])

Create a new Vector3d from tuple

Examples:

>>> Vector3d.from_tuple((10, 20, 30))
Vector3d(x=10, y=20, z=30)
>>> Vector3d.from_tuple((10.0, 20.5, 30.2))
Vector3d(x=10.0, y=20.5, z=30.2)
def to_tuple(self) -> tuple[float, float, float]:
 93    def to_tuple(self) -> tuple[float, float, float]:
 94        """Return the vector as a tuple
 95
 96        Examples:
 97        >>> Vector3d(x=10, y=20, z=30).to_tuple()
 98        (10, 20, 30)
 99        >>> Vector3d(x=10.0, y=20.5, z=30.2).to_tuple()
100        (10.0, 20.5, 30.2)
101        """
102        return self.x, self.y, self.z

Return the vector as a tuple

Examples:

>>> Vector3d(x=10, y=20, z=30).to_tuple()
(10, 20, 30)
>>> Vector3d(x=10.0, y=20.5, z=30.2).to_tuple()
(10.0, 20.5, 30.2)
def to_quaternion(self):
115    def to_quaternion(self):
116        """Interpret the object as a rotation vector and convert it to a quaternion"""
117        values = np.asarray(self)
118        half_angle = np.linalg.norm(values) / 2
119        return np.concatenate([np.cos(half_angle)[None], values * np.sinc(half_angle / np.pi) / 2])

Interpret the object as a rotation vector and convert it to a quaternion

@pydantic.model_serializer
def serialize_model(self) -> wandelbots_api_client.models.vector3d.Vector3d:
121    @pydantic.model_serializer
122    def serialize_model(self) -> wb.models.Vector3d:
123        """
124        Examples:
125        >>> Vector3d.from_tuple((1, 2, 3)).model_dump()
126        {'x': 1, 'y': 2, 'z': 3}
127        """
128        return wb.models.Vector3d(x=self.x, y=self.y, z=self.z)

Examples:

>>> Vector3d.from_tuple((1, 2, 3)).model_dump()
{'x': 1, 'y': 2, 'z': 3}
model_config: ClassVar[pydantic.config.ConfigDict] = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class Pose(pydantic.main.BaseModel, typing.Sized):
 40class Pose(pydantic.BaseModel, Sized):
 41    """A pose (position and orientation)
 42
 43    Example:
 44    >>> Pose(position=Vector3d(x=10, y=20, z=30), orientation=Vector3d(x=1, y=2, z=3))
 45    Pose(position=Vector3d(x=10, y=20, z=30), orientation=Vector3d(x=1, y=2, z=3))
 46    """
 47
 48    position: Vector3d
 49    orientation: Vector3d
 50
 51    def __init__(self, *args, **kwargs):
 52        """Parse a tuple into a dict
 53
 54        Examples:
 55        >>> Pose((1, 2, 3, 4, 5, 6))
 56        Pose(position=Vector3d(x=1, y=2, z=3), orientation=Vector3d(x=4, y=5, z=6))
 57        >>> Pose((1, 2, 3))
 58        Pose(position=Vector3d(x=1, y=2, z=3), orientation=Vector3d(x=0, y=0, z=0))
 59        >>> Pose(wb.models.Pose(position=wb.models.Vector3d(x=1, y=2, z=3), orientation=wb.models.Vector3d(x=4, y=5, z=6)))
 60        Pose(position=Vector3d(x=1, y=2, z=3), orientation=Vector3d(x=4, y=5, z=6))
 61        >>> Pose(wb.models.TcpPose(position=wb.models.Vector3d(x=1, y=2, z=3), orientation=wb.models.Vector3d(x=4, y=5, z=6), coordinate_system=None, tcp='Flange'))
 62        Pose(position=Vector3d(x=1, y=2, z=3), orientation=Vector3d(x=4, y=5, z=6))
 63        >>> Pose(wb.models.Pose2(position=[1, 2, 3], orientation=[4, 5, 6]))
 64        Pose(position=Vector3d(x=1, y=2, z=3), orientation=Vector3d(x=4, y=5, z=6))
 65        >>> pose = Pose((1, 2, 3, 4, 5, 6))
 66        >>> new_pose = Pose.model_validate(pose.model_dump())
 67        >>> pose == new_pose
 68        True
 69
 70        """
 71        if args:
 72            values = _parse_args(*args)
 73            super().__init__(**values)
 74        else:
 75            super().__init__(**kwargs)
 76
 77    def __str__(self):
 78        return str(round(self).to_tuple())
 79
 80    def __eq__(self, other):
 81        if not isinstance(other, Pose):
 82            return NotImplemented
 83        return self.position == other.position and self.orientation == other.orientation
 84
 85    def __round__(self, n=None):
 86        if n is not None:
 87            raise NotImplementedError("Setting precision is not supported yet")
 88        pos_and_rot_vector = self.to_tuple()
 89        return Pose(
 90            tuple(
 91                [round(a, 1) for a in pos_and_rot_vector[:3]]
 92                + [round(a, 3) for a in pos_and_rot_vector[3:]]
 93            )
 94        )
 95
 96    def __len__(self):
 97        return 6
 98
 99    def __iter__(self):
100        """Iterate over the pose
101
102        Examples:
103        >>> p = Pose((1, 2, 3, 0, 0, 0))
104        >>> list(p)
105        [1, 2, 3, 0, 0, 0]
106        >>> tuple(p)
107        (1, 2, 3, 0, 0, 0)
108        """
109        return iter(self.to_tuple())
110
111    def __invert__(self) -> Pose:
112        """
113        Return the inverse of this pose.
114        In terms of 4x4 homogeneous matrices, this is T^-1 where T = R|p
115                                                                     0|1
116        i.e. T^-1 = R^T | -R^T p
117                     0  |   1
118
119        Returns:
120            Pose: the inverse of the current pose
121
122        Examples:
123        >>> p = Pose((1, 2, 3, 0, 0, np.pi/2))  # rotate 90° about Z
124        >>> inv_p = ~p
125        >>> identity_approx = p @ inv_p
126        >>> np.allclose(identity_approx.position.to_tuple(), (0, 0, 0), atol=1e-7)
127        True
128        """
129        # Invert the homogeneous transformation matrix
130        inv_matrix = np.linalg.inv(self.matrix)
131        # Convert back to a Pose
132        return self._matrix_to_pose(inv_matrix)
133
134    def to_tuple(self) -> tuple[float, float, float, float, float, float]:
135        """Return the pose as a tuple
136
137        Example:
138        >>> Pose(position=Vector3d(x=10, y=20, z=30), orientation=Vector3d(x=1, y=2, z=3)).to_tuple()
139        (10, 20, 30, 1, 2, 3)
140        """
141        return self.position.to_tuple() + self.orientation.to_tuple()
142
143    def __getitem__(self, item):
144        return self.to_tuple()[item]
145
146    def __matmul__(self, other):
147        """
148        Pose concatenation combines two poses into a single pose that represents the cumulative effect of both
149        transformations applied sequentially.
150
151        Args:
152            other: can be a Pose, or an iterable with 6 elements
153
154        Returns:
155            Pose: the result of the concatenation
156
157        Examples:
158        >>> Pose((1, 2, 3, 0, 0, 0)) @ Pose((1, 2, 3, 0, 0, 0))
159        Pose(position=Vector3d(x=2.0, y=4.0, z=6.0), orientation=Vector3d(x=0.0, y=0.0, z=0.0))
160        >>> Pose((1, 2, 3, 0, 0, 0)) @ [1, 2, 3, 0, 0, 0]
161        Pose(position=Vector3d(x=2.0, y=4.0, z=6.0), orientation=Vector3d(x=0.0, y=0.0, z=0.0))
162        >>> Pose((1, 2, 3, 0, 0, 0)) @ (1, 2, 3, 0, 0, 0)
163        Pose(position=Vector3d(x=2.0, y=4.0, z=6.0), orientation=Vector3d(x=0.0, y=0.0, z=0.0))
164        >>> def as_iterator(data):
165        ...     for d in data:
166        ...         yield d
167        >>> Pose((1, 2, 3, 0, 0, 0)) @ as_iterator([1, 2, 3, 0, 0, 0])
168        Pose(position=Vector3d(x=2.0, y=4.0, z=6.0), orientation=Vector3d(x=0.0, y=0.0, z=0.0))
169        >>> Pose((1, 2, 3, 0, 0, 0)) @ Vector3d.from_tuple((1, 2, 3))
170        Pose(position=Vector3d(x=2.0, y=4.0, z=6.0), orientation=Vector3d(x=0.0, y=0.0, z=0.0))
171        """
172        if isinstance(other, Pose):
173            transformed_matrix = np.dot(self.matrix, other.matrix)
174            return self._matrix_to_pose(transformed_matrix)
175        if isinstance(other, Iterable):
176            seq = tuple(other)
177            return self.__matmul__(Pose(seq))
178
179        raise ValueError(f"Cannot multiply Pose with {type(other)}")
180
181    def __array__(self, dtype=None):
182        """Convert Pose to a 6-element numpy array: [pos.x, pos.y, pos.z, ori.x, ori.y, ori.z].
183
184        Examples:
185        >>> p1 = Pose((1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
186        >>> p2 = Pose((1.001, 2.0, 3.0, 3.9995, 5.0, 6.0))
187        >>> np.isclose(p1, p2, atol=1e-3)
188        array([ True,  True,  True,  True,  True,  True])
189        """
190        # The `to_tuple()` method already returns (x, y, z, rx, ry, rz)
191        return np.array(self.to_tuple(), dtype=dtype)
192
193    def transform(self, other) -> Pose:
194        return self @ other
195
196    def _to_wb_pose(self) -> wb.models.Pose:
197        """Convert to wandelbots_api_client Pose
198
199        Examples:
200        >>> Pose(position=Vector3d(x=10, y=20, z=30), orientation=Vector3d(x=1, y=2, z=3))._to_wb_pose()
201        Pose(position=Vector3d(x=10, y=20, z=30), orientation=Vector3d(x=1, y=2, z=3), coordinate_system=None)
202        """
203        return wb.models.Pose(
204            position=wb.models.Vector3d(**self.position.model_dump()),
205            orientation=wb.models.Vector3d(**self.orientation.model_dump()),
206        )
207
208    def _to_wb_pose2(self) -> wb.models.Pose2:
209        """Convert to wandelbots_api_client Pose
210
211        Examples:
212        >>> Pose(position=Vector3d(x=10, y=20, z=30), orientation=Vector3d(x=1, y=2, z=3))._to_wb_pose2()
213        Pose2(position=[10, 20, 30], orientation=[1, 2, 3])
214        """
215        return wb.models.Pose2(
216            position=list(self.position.to_tuple()), orientation=list(self.orientation.to_tuple())
217        )
218
219    @pydantic.model_serializer
220    def serialize_model(self):
221        """
222        Examples:
223        >>> Pose(position=Vector3d(x=10, y=20, z=30), orientation=Vector3d(x=1, y=2, z=3)).model_dump()
224        {'position': [10, 20, 30], 'orientation': [1, 2, 3]}
225        """
226        return self._to_wb_pose2().model_dump()
227
228    @pydantic.model_validator(mode="before")
229    @classmethod
230    def model_validator(cls, data):
231        """Transform the data that is passed into model validator to match what we return in the model_dump"""
232        if not isinstance(data, dict):
233            raise ValueError("model_validator only accepts dicts")
234        pos = data["position"]
235        ori = data["orientation"]
236        return {
237            "position": Vector3d(x=pos[0], y=pos[1], z=pos[2]),
238            "orientation": Vector3d(x=ori[0], y=ori[1], z=ori[2]),
239        }
240
241    def _to_homogenous_transformation_matrix(self):
242        """Converts the pose (position and rotation vector) to a 4x4 homogeneous transformation matrix."""
243        rotation_vec = [self.orientation.x, self.orientation.y, self.orientation.z]
244        rotation_matrix = Rotation.from_rotvec(rotation_vec).as_matrix()
245        mat = np.eye(4)
246        mat[:3, :3] = rotation_matrix
247        mat[:3, 3] = [self.position.x, self.position.y, self.position.z]
248        return mat
249
250    def _matrix_to_pose(self, matrix: np.ndarray) -> Pose:
251        """Converts a homogeneous transformation matrix to a Pose."""
252        rotation_matrix = matrix[:3, :3]
253        position = matrix[:3, 3]
254        rotation_vec = Rotation.from_matrix(rotation_matrix).as_rotvec()
255        return Pose(
256            (
257                position[0],
258                position[1],
259                position[2],
260                rotation_vec[0],
261                rotation_vec[1],
262                rotation_vec[2],
263            )
264        )
265
266    def orientation_to_quaternion(self):
267        values = np.asarray(self.orientation)
268        half_angle = np.linalg.norm(values) / 2
269        return np.concatenate([np.cos(half_angle)[None], values * np.sinc(half_angle / np.pi) / 2])
270
271    @property
272    def matrix(self) -> np.ndarray:
273        """Returns the homogeneous transformation matrix."""
274        return self._to_homogenous_transformation_matrix()

A pose (position and orientation)

Example:

>>> Pose(position=Vector3d(x=10, y=20, z=30), orientation=Vector3d(x=1, y=2, z=3))
Pose(position=Vector3d(x=10, y=20, z=30), orientation=Vector3d(x=1, y=2, z=3))
position: Vector3d
orientation: Vector3d
def to_tuple(self) -> tuple[float, float, float, float, float, float]:
134    def to_tuple(self) -> tuple[float, float, float, float, float, float]:
135        """Return the pose as a tuple
136
137        Example:
138        >>> Pose(position=Vector3d(x=10, y=20, z=30), orientation=Vector3d(x=1, y=2, z=3)).to_tuple()
139        (10, 20, 30, 1, 2, 3)
140        """
141        return self.position.to_tuple() + self.orientation.to_tuple()

Return the pose as a tuple

Example:

>>> Pose(position=Vector3d(x=10, y=20, z=30), orientation=Vector3d(x=1, y=2, z=3)).to_tuple()
(10, 20, 30, 1, 2, 3)
def transform(self, other) -> Pose:
193    def transform(self, other) -> Pose:
194        return self @ other
@pydantic.model_serializer
def serialize_model(self):
219    @pydantic.model_serializer
220    def serialize_model(self):
221        """
222        Examples:
223        >>> Pose(position=Vector3d(x=10, y=20, z=30), orientation=Vector3d(x=1, y=2, z=3)).model_dump()
224        {'position': [10, 20, 30], 'orientation': [1, 2, 3]}
225        """
226        return self._to_wb_pose2().model_dump()

Examples:

>>> Pose(position=Vector3d(x=10, y=20, z=30), orientation=Vector3d(x=1, y=2, z=3)).model_dump()
{'position': [10, 20, 30], 'orientation': [1, 2, 3]}
@pydantic.model_validator(mode='before')
@classmethod
def model_validator(cls, data):
228    @pydantic.model_validator(mode="before")
229    @classmethod
230    def model_validator(cls, data):
231        """Transform the data that is passed into model validator to match what we return in the model_dump"""
232        if not isinstance(data, dict):
233            raise ValueError("model_validator only accepts dicts")
234        pos = data["position"]
235        ori = data["orientation"]
236        return {
237            "position": Vector3d(x=pos[0], y=pos[1], z=pos[2]),
238            "orientation": Vector3d(x=ori[0], y=ori[1], z=ori[2]),
239        }

Transform the data that is passed into model validator to match what we return in the model_dump

def orientation_to_quaternion(self):
266    def orientation_to_quaternion(self):
267        values = np.asarray(self.orientation)
268        half_angle = np.linalg.norm(values) / 2
269        return np.concatenate([np.cos(half_angle)[None], values * np.sinc(half_angle / np.pi) / 2])
matrix: numpy.ndarray
271    @property
272    def matrix(self) -> np.ndarray:
273        """Returns the homogeneous transformation matrix."""
274        return self._to_homogenous_transformation_matrix()

Returns the homogeneous transformation matrix.

CollisionScene
LoadPlanResponse = <class 'wandelbots_api_client.models.plan_successful_response.PlanSuccessfulResponse'>
InitialMovementStream = typing.AsyncIterator[wandelbots_api_client.models.stream_move_response.StreamMoveResponse]
InitialMovementConsumer = typing.Callable[[wandelbots_api_client.models.stream_move_response.StreamMoveResponse], NoneType]
MovementResponse = wandelbots_api_client.models.execute_trajectory_response.ExecuteTrajectoryResponse | wandelbots_api_client.models.stream_move_response.StreamMoveResponse
class MotionState(pydantic.main.BaseModel):
14class MotionState(pydantic.BaseModel):
15    """Collection of information on the current state of the robot"""
16
17    motion_group_id: str
18    path_parameter: float
19    state: RobotState

Collection of information on the current state of the robot

motion_group_id: str
path_parameter: float
state: RobotState
model_config: ClassVar[pydantic.config.ConfigDict] = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class RobotState(pydantic.main.BaseModel):
 7class RobotState(pydantic.BaseModel):
 8    """Collection of information on the current state of the robot"""
 9
10    pose: Pose
11    joints: tuple[float, ...] | None = None

Collection of information on the current state of the robot

pose: Pose
joints: tuple[float, ...] | None
model_config: ClassVar[pydantic.config.ConfigDict] = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class MotionSettings(pydantic.main.BaseModel):
  6class MotionSettings(pydantic.BaseModel):
  7    """
  8    Settings for an action. This is closely related to the `MotionCommand` in the API.
  9    See planTrajectory.motion_commands for more information.
 10
 11    Motion settings are immutable; if you need to change a setting, create a copy and update the new object.
 12
 13    Attributes:
 14        min_blending_velocity:
 15            A minimum velocity for blending, in percent. Cannot be used if `blending` is set.
 16
 17        position_zone_radius:
 18            Defines the position zone radius.
 19
 20        joint_velocity_limits:
 21            Maximum joint velocities
 22
 23        joint_acceleration_limits:
 24            Maximum joint accelerations
 25
 26        tcp_velocity_limit:
 27            Maximum TCP velocity
 28
 29        tcp_acceleration_limit:
 30            Maximum TCP acceleration
 31
 32        tcp_orientation_velocity_limit:
 33            Maximum TCP orientation velocity
 34
 35        tcp_orientation_acceleration_limit:
 36            Maximum TCP orientation acceleration
 37    """
 38
 39    min_blending_velocity: int | None = pydantic.Field(default=None)
 40    position_zone_radius: float | None = pydantic.Field(default=None)
 41    joint_velocity_limits: tuple[float, ...] | None = pydantic.Field(default=None)
 42    joint_acceleration_limits: tuple[float, ...] | None = pydantic.Field(default=None)
 43    tcp_velocity_limit: float | None = pydantic.Field(default=50)
 44    tcp_acceleration_limit: float | None = pydantic.Field(default=None)
 45    tcp_orientation_velocity_limit: float | None = pydantic.Field(default=None)
 46    tcp_orientation_acceleration_limit: float | None = pydantic.Field(default=None)
 47
 48    class Config:
 49        frozen = True
 50
 51    @classmethod
 52    def field_to_varname(cls, field):
 53        return f"__ms_{field}"
 54
 55    @pydantic.model_validator(mode="after")
 56    def validate_blending_settings(self) -> "MotionSettings":
 57        if self.min_blending_velocity and self.position_zone_radius:
 58            raise ValueError("Can't set both min_blending_velocity and blending")
 59        return self
 60
 61    def has_blending_settings(self) -> bool:
 62        return any([self.min_blending_velocity, self.position_zone_radius])
 63
 64    def has_limits_override(self) -> bool:
 65        return any(
 66            [
 67                self.tcp_velocity_limit,
 68                self.tcp_acceleration_limit,
 69                self.tcp_orientation_velocity_limit,
 70                self.tcp_orientation_acceleration_limit,
 71                self.joint_velocity_limits,
 72                self.joint_acceleration_limits,
 73            ]
 74        )
 75
 76    def as_limits_settings(self) -> wb.models.LimitsOverride:
 77        return wb.models.LimitsOverride(
 78            joint_velocity_limits=wb.models.Joints(joints=self.joint_velocity_limits)  # type: ignore
 79            if self.joint_velocity_limits
 80            else None,
 81            joint_acceleration_limits=wb.models.Joints(joints=self.joint_acceleration_limits)  # type: ignore
 82            if self.joint_acceleration_limits
 83            else None,
 84            tcp_velocity_limit=self.tcp_velocity_limit,
 85            tcp_acceleration_limit=self.tcp_acceleration_limit,
 86            tcp_orientation_velocity_limit=self.tcp_orientation_velocity_limit,
 87            tcp_orientation_acceleration_limit=self.tcp_orientation_acceleration_limit,
 88        )
 89
 90    def as_blending_setting(self) -> wb.models.MotionCommandBlending:
 91        if self.position_zone_radius:
 92            return wb.models.MotionCommandBlending(
 93                wb.models.BlendingPosition(
 94                    position_zone_radius=self.position_zone_radius, blending_name="BlendingPosition"
 95                )
 96            )
 97        return wb.models.MotionCommandBlending(
 98            wb.models.BlendingAuto(
 99                min_velocity_in_percent=self.min_blending_velocity, blending_name="BlendingAuto"
100            )
101        )

Settings for an action. This is closely related to the MotionCommand in the API. See planTrajectory.motion_commands for more information.

Motion settings are immutable; if you need to change a setting, create a copy and update the new object.

Attributes:
  • min_blending_velocity: A minimum velocity for blending, in percent. Cannot be used if blending is set.
  • position_zone_radius: Defines the position zone radius.
  • joint_velocity_limits: Maximum joint velocities
  • joint_acceleration_limits: Maximum joint accelerations
  • tcp_velocity_limit: Maximum TCP velocity
  • tcp_acceleration_limit: Maximum TCP acceleration
  • tcp_orientation_velocity_limit: Maximum TCP orientation velocity
  • tcp_orientation_acceleration_limit: Maximum TCP orientation acceleration
min_blending_velocity: int | None
position_zone_radius: float | None
joint_velocity_limits: tuple[float, ...] | None
joint_acceleration_limits: tuple[float, ...] | None
tcp_velocity_limit: float | None
tcp_acceleration_limit: float | None
tcp_orientation_velocity_limit: float | None
tcp_orientation_acceleration_limit: float | None
@classmethod
def field_to_varname(cls, field):
51    @classmethod
52    def field_to_varname(cls, field):
53        return f"__ms_{field}"
@pydantic.model_validator(mode='after')
def validate_blending_settings(self) -> MotionSettings:
55    @pydantic.model_validator(mode="after")
56    def validate_blending_settings(self) -> "MotionSettings":
57        if self.min_blending_velocity and self.position_zone_radius:
58            raise ValueError("Can't set both min_blending_velocity and blending")
59        return self
def has_blending_settings(self) -> bool:
61    def has_blending_settings(self) -> bool:
62        return any([self.min_blending_velocity, self.position_zone_radius])
def has_limits_override(self) -> bool:
64    def has_limits_override(self) -> bool:
65        return any(
66            [
67                self.tcp_velocity_limit,
68                self.tcp_acceleration_limit,
69                self.tcp_orientation_velocity_limit,
70                self.tcp_orientation_acceleration_limit,
71                self.joint_velocity_limits,
72                self.joint_acceleration_limits,
73            ]
74        )
def as_limits_settings(self) -> wandelbots_api_client.models.limits_override.LimitsOverride:
76    def as_limits_settings(self) -> wb.models.LimitsOverride:
77        return wb.models.LimitsOverride(
78            joint_velocity_limits=wb.models.Joints(joints=self.joint_velocity_limits)  # type: ignore
79            if self.joint_velocity_limits
80            else None,
81            joint_acceleration_limits=wb.models.Joints(joints=self.joint_acceleration_limits)  # type: ignore
82            if self.joint_acceleration_limits
83            else None,
84            tcp_velocity_limit=self.tcp_velocity_limit,
85            tcp_acceleration_limit=self.tcp_acceleration_limit,
86            tcp_orientation_velocity_limit=self.tcp_orientation_velocity_limit,
87            tcp_orientation_acceleration_limit=self.tcp_orientation_acceleration_limit,
88        )
def as_blending_setting( self) -> wandelbots_api_client.models.motion_command_blending.MotionCommandBlending:
 90    def as_blending_setting(self) -> wb.models.MotionCommandBlending:
 91        if self.position_zone_radius:
 92            return wb.models.MotionCommandBlending(
 93                wb.models.BlendingPosition(
 94                    position_zone_radius=self.position_zone_radius, blending_name="BlendingPosition"
 95                )
 96            )
 97        return wb.models.MotionCommandBlending(
 98            wb.models.BlendingAuto(
 99                min_velocity_in_percent=self.min_blending_velocity, blending_name="BlendingAuto"
100            )
101        )
model_config: ClassVar[pydantic.config.ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class MotionSettings.Config:
48    class Config:
49        frozen = True
frozen = True
ExecuteTrajectoryRequestStream = typing.AsyncIterator[wandelbots_api_client.models.execute_trajectory_request.ExecuteTrajectoryRequest]
ExecuteTrajectoryResponseStream = typing.AsyncIterator[wandelbots_api_client.models.execute_trajectory_response.ExecuteTrajectoryResponse]
MovementControllerFunction = typing.Callable[[typing.AsyncIterator[wandelbots_api_client.models.execute_trajectory_response.ExecuteTrajectoryResponse]], typing.AsyncIterator[wandelbots_api_client.models.execute_trajectory_request.ExecuteTrajectoryRequest]]