From 55fc18d0276daa74f3ab3c5de144441997601f42 Mon Sep 17 00:00:00 2001 From: Ember Chow <emberchow.businiess@iu.edu> Date: Fri, 22 Jul 2022 14:04:01 -0400 Subject: [PATCH 1/5] fix some docstrings --- forcedimension/__init__.py | 88 ++++++++++++++++++++++---------------- 1 file changed, 51 insertions(+), 37 deletions(-) diff --git a/forcedimension/__init__.py b/forcedimension/__init__.py index 088ad8a..d8017de 100644 --- a/forcedimension/__init__.py +++ b/forcedimension/__init__.py @@ -238,8 +238,9 @@ def pos(self) -> Optional[ImmutableWrapper[MutFSeq]]: :rtype: Optional[MutableSequence[float]] - :returns: A mutable sequence of [x, y, z] where x, y, and z are the - end-effector's position given in [m]. + :returns: + A mutable sequence of [x, y, z] where x, y, and z are the + end-effector's position given in [m]. """ self.check_threadex() return self._pos_view @@ -266,8 +267,9 @@ def v(self) -> Optional[ImmutableWrapper[MutFSeq]]: :rtype: Optional[MutableSequence[float]] - :returns: A mutable sequence of [vx, vy, vz] where vx, vy, and vz are - the end-effector's linear velocity given in [m/s]. + :returns: + A mutable sequence of [vx, vy, vz] where vx, vy, and vz are + the end-effector's linear velocity given in [m/s]. """ self.check_threadex() return self._v_view @@ -280,8 +282,9 @@ def w(self) -> Optional[ImmutableWrapper[MutFSeq]]: :rtype: Optional[MutableSequence[float]] - :returns: A mutable sequence of [wx, wy, wz] where wx, wy, and wz are - the end-effector's linear velocity given in [rad/s]. + :returns: + A mutable sequence of [wx, wy, wz] where wx, wy, and wz are + the end-effector's linear velocity given in [rad/s]. """ self.check_threadex() return self._w_view @@ -294,8 +297,9 @@ def t(self) -> Optional[ImmutableWrapper[MutFSeq]]: :rtype: Optional[MutableSequence[float]] - :returns: A mutable sequence of [tx, ty, tz] where tx, ty, and tz are - the torque experienced by the end-effector in [Nm] + :returns: + A mutable sequence of [tx, ty, tz] where tx, ty, and tz are + the torque experienced by the end-effector in [Nm] """ self.check_threadex() return self._t_view @@ -308,8 +312,9 @@ def f(self) -> Optional[ImmutableWrapper[MutFSeq]]: :rtype: Optional[MutableSequence[float]] - :returns: A mutable sequence of [fx, fy, fz] where fx, fy, and fz are - the torque experienced by the end-effector in [N] + :returns: + A mutable sequence of [fx, fy, fz] where fx, fy, and fz are + the torque experienced by the end-effector in [N] """ self.check_threadex() @@ -692,11 +697,12 @@ def get_max_force(self) -> Optional[float]: Retrieve the current limit (in N) to the force magnitude that can be applied by the haptic device. - :returns: The current limit (in N) to the force magnitude that can be - applied by the haptic device to the end-effector. If there is no limit, - None is returned instead. + :returns: + The current limit (in N) to the force magnitude that can be + applied by the haptic device to the end-effector. If there is no + limit, None is returned instead. - rtype: Optional[float] + :rtype: Optional[float] """ limit = dhd.getMaxForce(ID=cast(int, self._id)) @@ -708,9 +714,9 @@ def set_max_force(self, limit: Optional[float]) -> None: Define or disable a limit (in N) to the force magnitude that can be applied by the haptic device. - :param Optional[float] limit: The desired limit (in N) to the force - magnitude that can be applied. If the limit is None, the force limit is - disabled. + :param Optional[float] limit: + The desired limit (in N) to the force magnitude that can be + applied. If the limit is None, the force limit is disabled. """ if limit is None: err = dhd.setMaxForce(ID=cast(int, self._id), limit=-1.0) @@ -728,9 +734,10 @@ def get_max_torque(self) -> Optional[float]: Retrieve the current limit (in Nm) to the torque magnitude that can be applied by the haptic device. - :returns: The current limit (in Nm) to the force magnitude that can be - applied by the haptic device to the end-effector. If there is no limit, - None is returned instead. + :returns: + The current limit (in Nm) to the force magnitude that can be + applied by the haptic device to the end-effector. If there is no + limit, None is returned instead. rtype: Optional[float] """ @@ -744,9 +751,9 @@ def set_max_torque(self, limit: Optional[float]) -> None: Define or disable a limit (in N) to the force magnitude that can be applied by the haptic device. - :param Optional[float] limit: The desired limit (in N) to the force - magnitude that can be applied. If the limit is None, the force limit is - disabled. + :param Optional[float] limit: + The desired limit (in N) to the force magnitude that can be + applied. If the limit is None, the force limit is disabled. """ if limit is None: err = dhd.setMaxTorque(ID=cast(int, self._id), limit=-1.0) @@ -785,7 +792,7 @@ def get_button(self, button_id: int = 0) -> bool: See Also -------- - :class:forcedimension.dhd.dhd.constants.NovintButtonID + :class:forcedimension.dhd.constants.NovintButtonID """ return bool(self._buttons & cast(int, 1 << button_id)) @@ -811,6 +818,12 @@ class Gripper: case, a Gripper object will be instantiated as well containing methods to get kinematic information about the Gripper. """ + _enc: int + _angle: float + _gap: float + _v: float + _w: float + _fg: float def __init__( self, @@ -827,12 +840,12 @@ def __init__( VecType = vecgen - self._enc: int = 0 - self._angle: float = nan - self._gap: float = nan - self._v: float = nan - self._w: float = nan - self._fg: float = nan + self._enc = 0 + self._angle = nan + self._gap = nan + self._v = nan + self._w = nan + self._fg = nan self._thumb_pos: MutFSeq = VecType() self._finger_pos: MutFSeq = VecType() @@ -883,11 +896,12 @@ def get_max_force(self) -> Optional[float]: Retrieve the current limit (in N) to the force magnitude that can be applied by the haptic device. - :returns: The current limit (in N) to the force magnitude that can be - applied by the haptic device to the end-effector. If there is no limit, - None is returned instead. + :returns: + The current limit (in N) to the force magnitude that can be + applied by the haptic device to the end-effector. If there is no + limit, None is returned instead. - rtype: Optional[float] + :rtype: Optional[float] """ limit = dhd.getMaxGripperForce(ID=cast(int, self._id)) @@ -899,9 +913,9 @@ def set_max_force(self, limit: Optional[float]) -> None: Define or disable a limit (in N) to the force magnitude that can be applied by the haptic device. - :param Optional[float] limit: The desired limit (in N) to the force - magnitude that can be applied. If the limit is None, the force limit is - disabled. + :param Optional[float] limit: + The desired limit (in N) to the force magnitude that can be + applied. If the limit is None, the force limit is disabled. """ if limit is None: err = dhd.setMaxGripperForce(ID=cast(int, self._id), limit=-1.0) From 9934edae8ae11cf0d0d4bf34b8617f884f396516 Mon Sep 17 00:00:00 2001 From: Ember Chow <emberchow.businiess@iu.edu> Date: Fri, 22 Jul 2022 14:41:40 -0400 Subject: [PATCH 2/5] another couple docstrings tweaks --- forcedimension/__init__.py | 22 +++++++++++++++------- forcedimension/dhd/os_independent.py | 8 -------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/forcedimension/__init__.py b/forcedimension/__init__.py index d8017de..041594a 100644 --- a/forcedimension/__init__.py +++ b/forcedimension/__init__.py @@ -1,3 +1,10 @@ +""" +.. module::forcedimension + :platform: Windows, Unix + :synopsis: ForceDimensionSDK high level wrappers. + +.. moduleauthor:: Ember "Emmy" Chow <emberchow.business@gmail.com> +""" from math import nan from threading import Condition, Lock, Thread from time import monotonic, sleep @@ -558,7 +565,7 @@ def submit(self): See Also -------- - :func:HapticDevice.req + :func:`HapticDevice.req` """ self._req = False @@ -739,7 +746,7 @@ def get_max_torque(self) -> Optional[float]: applied by the haptic device to the end-effector. If there is no limit, None is returned instead. - rtype: Optional[float] + :rtype: Optional[float] """ limit = dhd.getMaxTorque(ID=cast(int, self._id)) @@ -785,14 +792,15 @@ def get_button(self, button_id: int = 0) -> bool: """ See if the button on the device is being pressed. + See Also + -------- + :class:`forcedimension.dhd.constants.NovintButtonID` + + :param int button_id: The button to check :rtype: bool - :returns: True if the button is being pressed, False otherwise. - - See Also - -------- - :class:forcedimension.dhd.constants.NovintButtonID + :returns: True if the button is being pressed, False otherwise """ return bool(self._buttons & cast(int, 1 << button_id)) diff --git a/forcedimension/dhd/os_independent.py b/forcedimension/dhd/os_independent.py index 3e04744..7a316ec 100644 --- a/forcedimension/dhd/os_independent.py +++ b/forcedimension/dhd/os_independent.py @@ -1,11 +1,3 @@ -""" -.. module::expert - :platform: Windows, Unix - :synopsis: libdhd "OS Independent SDK" Python libdhd - -.. moduleauthor:: Ember "Emmy" Chow <emberchow.business@gmail.com> -""" - from ctypes import c_bool, c_byte, c_double from forcedimension import runtime From e260bd0af19bcd1f5d5a4711a3e7e8f1cb264d08 Mon Sep 17 00:00:00 2001 From: Ember Chow <emberchow.businiess@iu.edu> Date: Tue, 16 May 2023 20:39:46 -0700 Subject: [PATCH 3/5] Patch dhdSleep --- forcedimension/__init__.py | 2 +- forcedimension/dhd/os_independent.py | 5 ++--- pyproject.toml | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/forcedimension/__init__.py b/forcedimension/__init__.py index 088ad8a..d3a79b3 100644 --- a/forcedimension/__init__.py +++ b/forcedimension/__init__.py @@ -23,7 +23,7 @@ ) -__version__ = '0.1.5' +__version__ = '0.1.6' DefaultVecType = EuclidianVector diff --git a/forcedimension/dhd/os_independent.py b/forcedimension/dhd/os_independent.py index 3e04744..7276ee9 100644 --- a/forcedimension/dhd/os_independent.py +++ b/forcedimension/dhd/os_independent.py @@ -68,7 +68,7 @@ def getTime() -> float: _libdhd.dhdSleep.argtypes = [c_double] -_libdhd.dhd.restype = None +_libdhd.dhdSleep.restype = None def sleep(sec: float) -> None: @@ -81,5 +81,4 @@ def sleep(sec: float) -> None: def startThread(): - # TODO implement startThread - pass + raise NotImplementedError() diff --git a/pyproject.toml b/pyproject.toml index 7b26c38..d8651fc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta" [project] name = "forcedimension" -version = "0.1.5" -authors = [ +version = "0.1.6" +authors = [ { name="Ember Chow", email="emberchow.business@gmail.com" }, ] description = "Python Bindings for the ForceDimension SDK" From d8ed1a219bfa8fda77d60e5de7e2561bd313f6d1 Mon Sep 17 00:00:00 2001 From: Ember Chow <emberchow.businiess@iu.edu> Date: Tue, 20 Jun 2023 15:52:58 -0700 Subject: [PATCH 4/5] Added getForceAndTorqueAndGripperForce --- forcedimension/dhd/__init__.py | 97 ++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/forcedimension/dhd/__init__.py b/forcedimension/dhd/__init__.py index 57b2d8a..7a8f129 100644 --- a/forcedimension/dhd/__init__.py +++ b/forcedimension/dhd/__init__.py @@ -2536,6 +2536,103 @@ def setForceAndTorqueAndGripperForce(f: FloatVectorLike, ) +_libdhd.dhdGetForceAndTorqueAndGripperForce.argtypes = [ + c_double, + c_double, + c_double, + c_double, + c_double, + c_double, + c_double, + c_byte +] +_libdhd.dhdGetForceAndTorqueAndGripperForce.restype = c_int + +def getForceAndTorqueAndGripperForce( + ID: int = -1, + f_out: Optional[MutableFloatVectorLike] = None, + t_out: Optional[MutableFloatVectorLike] = None +) -> Tuple[ + Union[MutableFloatVectorLike, List[float]], + Union[MutableFloatVectorLike, List[float]], + float, + int +]: + """ + Retrieve the force and torque vectors applied to the device end-effector. + + :param int ID: + Device ID (see multiple devices section for details), defaults to -1. + + :param Optional[MutableFloatVectorLike] f_out: + An output buffer to store the applied forces on the end-effector. If + specified, the return will contain a reference to this buffer rather to + a newly allocated list, optional. + + :param Optional[MutableFloatVectorLike] t_out: + An output buffer to store the applied torques on the end-effector. If + specified, the return will contain a reference to this buffer rather to + a newly allocated list, optional. + + :raises ValueError: + If ``ID`` is not implicitly convertible to C char. + + :returns: + A tuple in the form ``([fx, fy, fz], [tx, ty, tz], fg, err)``. + ``[fx, fy, fz]`` are translation forces applied to the end-effector + (in [N]) about the X, Y, and Z axes, respectively. ``[tx, ty, tz]`` + refers to the torques applied to the end-effector (in [Nm]) about + the X, Y, and Z axes. ``fg`` refers to the gripper force (in [Nm]). + ``err`` is 0, on success, -1 otherwise. + + :rtype: + Tuple + [ + Union[MutableFloatVectorLike, List[float]], + Union[MutableFloatVectorLike, List[float]], + int + ] + + """ + + fx = c_double() + fy = c_double() + fz = c_double() + + tx = c_double() + ty = c_double() + tz = c_double() + + fg = c_double() + + err = _libdhd.dhdGetForceAndTorqueAndGripperForce( + byref(fx), byref(fy), byref(fz), + byref(tx), byref(ty), byref(tz), + byref(fg), + ID + ) + + if f_out is None: + f_ret = [fx.value, fy.value, fz.value] + else: + f_ret = f_out + + f_out[0] = fx.value + f_out[1] = fy.value + f_out[2] = fz.value + + if t_out is None: + t_ret = [tx.value, ty.value, tz.value] + else: + t_ret = t_out + + t_out[0] = tx.value + t_out[1] = ty.value + t_out[2] = tz.value + + return (f_ret, t_ret, fg.value, err) + + _libdhd.dhdConfigLinearVelocity.argtypes = [c_int, c_int, c_byte] _libdhd.dhdConfigLinearVelocity.restype = c_int From 2174f53dbf1d76e5451d689c59f67d34aff3ec7f Mon Sep 17 00:00:00 2001 From: Ember Chow <emberchow.businiess@iu.edu> Date: Tue, 20 Jun 2023 16:00:20 -0700 Subject: [PATCH 5/5] fix typing of getForceAndTorqueAndGripperForce --- forcedimension/dhd/__init__.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/forcedimension/dhd/__init__.py b/forcedimension/dhd/__init__.py index 7a8f129..dd13672 100644 --- a/forcedimension/dhd/__init__.py +++ b/forcedimension/dhd/__init__.py @@ -2537,13 +2537,13 @@ def setForceAndTorqueAndGripperForce(f: FloatVectorLike, _libdhd.dhdGetForceAndTorqueAndGripperForce.argtypes = [ - c_double, - c_double, - c_double, - c_double, - c_double, - c_double, - c_double, + POINTER(c_double), + POINTER(c_double), + POINTER(c_double), + POINTER(c_double), + POINTER(c_double), + POINTER(c_double), + POINTER(c_double), c_byte ] _libdhd.dhdGetForceAndTorqueAndGripperForce.restype = c_int