orbita3d

  1from typing import Tuple
  2
  3from ._orbita3d import ffi, lib
  4
  5
  6class KinematicsModel:
  7    """Orbita3d kinematics model"""
  8
  9    def __init__(
 10        self,
 11        alpha: float,
 12        gamma_min: float,
 13        offset: float,
 14        beta: float,
 15        gamma_max: float,
 16        passiv_arms_direct: bool,
 17    ) -> None:
 18        """Create a new Orbita3d kinematics model.
 19
 20        See the [README.md](https://github.com/pollen-robotics/orbita3d_control/orbita3d_kinematics) for more information about the parameters.
 21        """
 22        self.model = ffi.new(
 23            "struct Orbita3dKinematicsModel *",
 24            lib.create_orbita3d_kinematics_model(
 25                alpha,
 26                gamma_min,
 27                offset,
 28                beta,
 29                gamma_max,
 30                passiv_arms_direct,
 31            ),
 32        )
 33
 34    def forward_position(
 35        self, thetas: Tuple[float, float, float]
 36    ) -> Tuple[float, float, float, float]:
 37        """Compute the forward position kinematics of the Orbita3d.
 38
 39        Args:
 40            thetas: The three motors angles (in radians).
 41        Returns:
 42            The quaternion representing the end-effector orientation (qx, qy, qz, qw).
 43        """
 44        thetas = ffi.new("double(*)[3]", tuple(thetas))
 45        q = ffi.new("double(*)[4]")
 46
 47        check(lib.orbita3d_kinematics_forward_position(self.model, thetas, q))
 48
 49        return tuple(q[0])
 50
 51    def forward_velocity(
 52        self,
 53        thetas: Tuple[float, float, float],
 54        thetas_velocity: Tuple[float, float, float],
 55    ) -> Tuple[float, float, float, float]:
 56        """Compute the forward velocity kinematics of the Orbita3d.
 57
 58        Args:
 59            thetas: The three motors angles (in radians).
 60            thetas_velocity: The three motors velocities (in radians per second).
 61        Returns:
 62            Platform output velocity (rad/s)
 63        """
 64        thetas = ffi.new("double(*)[3]", tuple(thetas))
 65        thetas_velocity = ffi.new("double(*)[3]", tuple(thetas_velocity))
 66        q_velocity = ffi.new("double(*)[3]")
 67
 68        check(
 69            lib.orbita3d_kinematics_forward_velocity(
 70                self.model, thetas, thetas_velocity, q_velocity
 71            )
 72        )
 73
 74        return tuple(q_velocity[0])
 75
 76    def forward_torque(
 77        self,
 78        thetas: Tuple[float, float, float],
 79        thetas_torque: Tuple[float, float, float],
 80    ) -> Tuple[float, float, float, float]:
 81        """Compute the forward torque kinematics of the Orbita3d.
 82
 83        Args:
 84            thetas: The three motors angles (in radians).
 85            thetas_torque: The three motors torques (in Newton meters).
 86        Returns:
 87            The quaternion representing the end-effector orientation torque (qx, qy, qz, qw).
 88        """
 89        thetas = ffi.new("double(*)[3]", tuple(thetas))
 90        thetas_torque = ffi.new("double(*)[3]", tuple(thetas_torque))
 91        q_torque = ffi.new("double(*)[4]")
 92
 93        check(
 94            lib.orbita3d_kinematics_forward_torque(
 95                self.model, thetas, thetas_torque, q_torque
 96            )
 97        )
 98
 99        return tuple(q_torque[0])
100
101    def inverse_position(
102        self, q: Tuple[float, float, float, float]
103    ) -> Tuple[float, float, float]:
104        """Compute the inverse position kinematics of the Orbita3d.
105
106        Args:
107            q: The quaternion representing the end-effector orientation (qx, qy, qz, qw).
108        Returns:
109            The three motors angles (in radians).
110        """
111        q = ffi.new("double(*)[4]", tuple(q))
112        thetas = ffi.new("double(*)[3]")
113
114        check(lib.orbita3d_kinematics_inverse_position(self.model, q, thetas))
115
116        return tuple(thetas[0])
117
118    def inverse_velocity(
119        self,
120        thetas: Tuple[float, float, float],
121        output_vel: Tuple[float, float, float],
122    ) -> Tuple[float, float, float]:
123        """Compute the inverse velocity kinematics of the Orbita3d.
124
125        Args:
126            thetas: The three motors angles (in radians).
127            output_vel: The platform velocity (in radians per second).
128        Returns:
129            The three motors velocities (in radians per second).
130        """
131        thetas = ffi.new("double(*)[3]", tuple(thetas))
132        output_vel = ffi.new("double(*)[3]", tuple(output_vel))
133        thetas_velocity = ffi.new("double(*)[3]")
134
135        check(
136            lib.orbita3d_kinematics_inverse_velocity(
137                self.model, thetas, output_vel, thetas_velocity
138            )
139        )
140
141        return tuple(thetas_velocity[0])
142
143    def inverse_torque(
144        self,
145        thetas: Tuple[float, float, float],
146        output_torque: Tuple[float, float, float],
147    ) -> Tuple[float, float, float]:
148        """Compute the inverse torque kinematics of the Orbita3d.
149
150        Args:
151            thetas: The three motors angles (in radians).
152            output_torque: The platform torque (in Newton meters).
153        Returns:
154            The three motors torques (in Newton meters).
155        """
156        thetas = ffi.new("double(*)[3]", tuple(thetas))
157        output_torque = ffi.new("double(*)[3]", tuple(output_torque))
158        thetas_torque = ffi.new("double(*)[3]")
159
160        check(
161            lib.orbita3d_kinematics_inverse_torque(
162                self.model, thetas, output_torque, thetas_torque
163            )
164        )
165
166        return tuple(thetas_torque[0])
167
168
169class Orbita3dController:
170    """Orbita3d controller."""
171
172    def __init__(self, uid: int) -> None:
173        """You should not call this constructor dierctly. Use from_config instead."""
174        self.uid = uid
175
176    @classmethod
177    def from_config(cls, config: str) -> "Orbita3dController":
178        """Create a new Orbita3d controller from a configuration file.
179
180        Args:
181            config: The configuration file path.
182        Returns:
183            A new Orbita3dController.
184        """
185        uid = ffi.new("uint32_t *")
186        check(lib.orbita3d_controller_from_config(config.encode("utf-8"), uid))
187        return cls(uid[0])
188
189    def is_torque_on(self) -> bool:
190        """Check if the torque is on.
191
192        Returns:
193            True if the torque is on, False otherwise.
194        """
195        torque_on = ffi.new("bool *")
196        check(lib.orbita3d_is_torque_on(self.uid, torque_on))
197        return torque_on[0]
198
199    def enable_torque(self, reset_target: bool) -> None:
200        """Enable the torque.
201
202        Args:
203            reset_target (bool): If True, the target position is reset to the current position.
204        """
205        check(lib.orbita3d_enable_torque(self.uid, reset_target))
206
207    def disable_torque(self) -> None:
208        """Disable the torque."""
209        check(lib.orbita3d_disable_torque(self.uid))
210
211    def get_current_orientation(self) -> Tuple[float, float, float, float]:
212        """Get the current orientation of the end-effector.
213
214        Returns:
215            The quaternion representing the end-effector orientation (qx, qy, qz, qw).
216        """
217        q = ffi.new("double(*)[4]")
218        check(lib.orbita3d_get_current_orientation(self.uid, q))
219        return tuple(q[0])
220
221    def get_current_velocity(self) -> Tuple[float, float, float]:
222        """Get the current velocity of the end-effector.
223
224        Returns:
225            The axis-angle representing the end-effector orientation velocity, magnitude is the angular velocity in rad/s and the axis is the rotation axis.
226        """
227        q_velocity = ffi.new("double(*)[3]")
228        check(lib.orbita3d_get_current_velocity(self.uid, q_velocity))
229        return tuple(q_velocity[0])
230
231    def get_current_torque(self) -> Tuple[float, float, float]:
232        """Get the current torque of the end-effector.
233
234        Returns:
235            The axis-angle representing the end-effector torque, magnitude is the torqur magnitude in Nm and the axis is the rotation axis.
236        """
237        q_torque = ffi.new("double(*)[3]")
238        check(lib.orbita3d_get_current_torque(self.uid, q_torque))
239        return tuple(q_torque[0])
240
241    def get_target_orientation(self) -> Tuple[float, float, float, float]:
242        """Get the target orientation of the end-effector.
243
244        Returns:
245            The quaternion representing the end-effector orientation (qx, qy, qz, qw).
246        """
247        q = ffi.new("double(*)[4]")
248        check(lib.orbita3d_get_target_orientation(self.uid, q))
249        return tuple(q[0])
250
251    def set_target_orientation(self, q: Tuple[float, float, float, float]) -> None:
252        """Set the target orientation of the end-effector.
253
254        Args:
255            q: The quaternion representing the end-effector orientation (qx, qy, qz, qw).
256        """
257        q = ffi.new("double(*)[4]", tuple(q))
258        check(lib.orbita3d_set_target_orientation(self.uid, q))
259
260
261    def get_target_rpy_orientation(self) -> Tuple[float, float, float]:
262        """Get the target orientation of the end-effector.
263
264        Returns:
265            The intrinsic Euler representing the end-effector orientation (roll, pitch, yaw).
266        """
267        rpy = ffi.new("double(*)[3]")
268        check(lib.orbita3d_get_target_rpy_orientation(self.uid, rpy))
269        return tuple(rpy[0])
270
271    def set_target_rpy_orientation(self, rpy: Tuple[float, float, float]) -> None:
272        """Set the target orientation of the end-effector. Yaw can be multi-turn.
273
274        Args:
275            rpy: The intrinsic Euler representing the end-effector orientation (roll, pitch, yaw).
276        """
277        rpy = ffi.new("double(*)[3]", tuple(rpy))
278        check(lib.orbita3d_set_target_rpy_orientation(self.uid, rpy))
279
280    def set_target_rpy_orientation_fb(
281        self, rpy: Tuple[float, float, float]
282    ) -> Tuple[float, float, float]:
283        """Set the target orientation of the end-effector. Yaw can be multiturn.
284
285        Args:
286            rpy: The intrinsic Euler representing the end-effector orientation (roll, pitch, yaw).
287        Returns:
288            The current intrinsic Euler orientation  (roll, pitch, yaw)
289        """
290        rpy = ffi.new("double(*)[3]", tuple(rpy))
291        fb = ffi.new("double(*)[3]")
292        check(lib.orbita3d_set_target_rpy_orientation_fb(self.uid, rpy, fb))
293        return tuple(fb[0])
294
295
296
297    def set_target_orientation_fb(
298        self, q: Tuple[float, float, float, float]
299    ) -> Tuple[float, float, float, float]:
300        """Set the target orientation of the end-effector.
301
302        Args:
303            q: The quaternion representing the end-effector orientation (qx, qy, qz, qw).
304        Returns:
305            The current orientation quaternion (qx, qy, qz, qw)
306        """
307        q = ffi.new("double(*)[4]", tuple(q))
308        fb = ffi.new("double(*)[4]")
309        check(lib.orbita3d_set_target_orientation_fb(self.uid, q, fb))
310        return tuple(fb[0])
311
312    def get_raw_motors_velocity_limit(self) -> Tuple[float, float, float]:
313        """Get the raw motors velocity limit.
314
315        Be carfeful, this is not the end-effector velocity limit. But this is the raw velocity limit of the disks!
316
317        Returns:
318            The raw motors velocity limit (in radians per second).
319        """
320        velocity_limit = ffi.new("double(*)[3]")
321        check(lib.orbita3d_get_raw_motors_velocity_limit(self.uid, velocity_limit))
322        return tuple(velocity_limit[0])
323
324    def set_raw_motors_velocity_limit(
325        self, velocity_limit: Tuple[float, float, float]
326    ) -> None:
327        """Set the raw motors velocity limit.
328
329        Be carfeful, this is not the end-effector velocity limit. But this is the raw velocity limit of the disks!
330
331        Args:
332            velocity_limit: The raw motors velocity limit (in radians per second).
333        """
334        velocity_limit = ffi.new("double(*)[3]", tuple(velocity_limit))
335        check(lib.orbita3d_set_raw_motors_velocity_limit(self.uid, velocity_limit))
336
337    def get_raw_motors_torque_limit(self) -> Tuple[float, float, float]:
338        """Get the raw motors torque limit.
339
340        Be carfeful, this is not the end-effector torque limit. But this is the raw torque limit of the disks!
341
342        Returns:
343            The raw motors torque limit (in Newton meters).
344        """
345        torque_limit = ffi.new("double(*)[3]")
346        check(lib.orbita3d_get_raw_motors_torque_limit(self.uid, torque_limit))
347        return tuple(torque_limit[0])
348
349    def set_raw_motors_torque_limit(
350        self, torque_limit: Tuple[float, float, float]
351    ) -> None:
352        """Set the raw motors torque limit.
353
354        Be carfeful, this is not the end-effector torque limit. But this is the raw torque limit of the disks!
355
356        Args:
357            torque_limit: The raw motors torque limit (in Newton meters).
358        """
359        torque_limit = ffi.new("double(*)[3]", tuple(torque_limit))
360        check(lib.orbita3d_set_raw_motors_torque_limit(self.uid, torque_limit))
361
362    def get_raw_motors_pid_gains(
363        self,
364    ) -> Tuple[
365        Tuple[float, float, float],
366        Tuple[float, float, float],
367        Tuple[float, float, float],
368    ]:
369        """Get the raw motors PID gains.
370
371        Be carfeful, this is not the end-effector PID gains. But this is the raw PID gains of the disks!
372
373        Returns:
374            The raw motors PID gains (kp, ki, kd).
375        """
376        pids = ffi.new("double(*)[3][3]")
377        check(lib.orbita3d_get_raw_motors_pid_gains(self.uid, pids))
378        return pids[0]
379
380    def set_raw_motors_pid_gains(
381        self,
382        pids: Tuple[
383            Tuple[float, float, float],
384            Tuple[float, float, float],
385            Tuple[float, float, float],
386        ],
387    ) -> None:
388        """Set the raw motors PID gains.
389
390        Be carfeful, this is not the end-effector PID gains. But this is the raw PID gains of the disks!
391
392        Args:
393            pids: The raw motors PID gains (kp, ki, kd).
394        """
395        pids = ffi.new("double(*)[3][3]", tuple(pids))
396        check(lib.orbita3d_set_raw_motors_pid_gains(self.uid, pids))
397
398    def get_raw_motors_velocity(self) -> Tuple[float, float, float]:
399        """Get the raw motors velocity.
400
401        Be carfeful, this is not the end-effector velocity. But this is the raw velocity of the disks!
402
403        Returns:
404            The raw motors velocity (in radians per second).
405        """
406        velocity = ffi.new("double(*)[3]")
407        check(lib.orbita3d_get_raw_motors_velocity(self.uid, velocity))
408        return tuple(velocity[0])
409    
410    def get_raw_motors_position(self) -> Tuple[float, float, float]:
411        """Get the raw motors position.
412
413        Be carfeful, this is not the end-effector position. But this is the raw position of the disks!
414
415        Returns:
416            The raw motors position (in radians).
417        """
418        position = ffi.new("double(*)[3]")
419        check(lib.orbita3d_get_raw_motors_position(self.uid, position))
420        return tuple(position[0])
421    
422    def get_raw_motors_current(self) -> Tuple[float, float, float]:
423        """Get the raw motors torque.
424
425        Be carfeful, this is not the end-effector torque. But this is the raw torque of the disks!
426
427        Returns:
428            The raw motors torque (in Newton meters).
429        """
430        torque = ffi.new("double(*)[3]")
431        check(lib.orbita3d_get_raw_motors_current(self.uid, torque))
432        return tuple(torque[0])
433    
434
435    def get_raw_axis_sensor(self) -> Tuple[float, float, float]:
436        """Get the raw axis sensor.
437
438        Be carfeful, this is not the end-effector position. But this is the raw position of the disks!
439
440        Returns:
441            The raw axis sensor (in radians).
442        """
443        axis = ffi.new("double(*)[3]")
444        check(lib.orbita3d_get_axis_sensors(self.uid, axis))
445        return tuple(axis[0])
446    
447    def get_raw_axis_zeros(self) -> Tuple[float, float, float]:
448        """Get the raw axis zero.
449
450        Axis sensor value at the mechanical zero position.
451
452        Returns:
453            The raw axis zero (in radians).
454        """
455        axis = ffi.new("double(*)[3]")
456        check(lib.orbita3d_get_axis_sensor_zeros(self.uid, axis))
457        return tuple(axis[0])
458    
459    def get_control_mode(self) -> int:
460        """Get the control mode.
461
462        Returns:
463            The control mode.
464        """
465        mode = ffi.new("uint8_t *")
466        check(lib.orbita3d_get_control_mode(self.uid, mode))
467        return mode[0]
468    
469    def set_control_mode(self, mode: int) -> None:
470        """Set the control mode.
471
472        Args:
473            mode: The control mode.
474        """
475        mode = ffi.new("uint8_t *", mode)
476        check(lib.orbita3d_set_control_mode(self.uid, mode))
477        
478    def set_target_torque(self, torque: Tuple[float, float, float]) -> None:
479        """Set the target torque of the end-effector.
480
481        Args:
482            torque: The quaternion representing the end-effector orientation torque (qx, qy, qz, qw).
483        """
484        torque = ffi.new("double(*)[3]", tuple(torque))
485        check(lib.orbita3d_set_target_torque(self.uid, torque))
486    
487    def set_target_velocity(self, velocity: Tuple[float, float, float]) -> None:
488        """Set the target velocity of the end-effector.
489
490        Args:
491            velocity: The quaternion representing the end-effector orientation velocity (qx, qy, qz, qw).
492        """
493        velocity = ffi.new("double(*)[3]", tuple(velocity))
494        check(lib.orbita3d_set_target_velocity(self.uid, velocity))
495    
496    
497
498def check(err):
499    if err != 0:
500        raise RuntimeError("Error code: {}".format(err))
class KinematicsModel:
  7class KinematicsModel:
  8    """Orbita3d kinematics model"""
  9
 10    def __init__(
 11        self,
 12        alpha: float,
 13        gamma_min: float,
 14        offset: float,
 15        beta: float,
 16        gamma_max: float,
 17        passiv_arms_direct: bool,
 18    ) -> None:
 19        """Create a new Orbita3d kinematics model.
 20
 21        See the [README.md](https://github.com/pollen-robotics/orbita3d_control/orbita3d_kinematics) for more information about the parameters.
 22        """
 23        self.model = ffi.new(
 24            "struct Orbita3dKinematicsModel *",
 25            lib.create_orbita3d_kinematics_model(
 26                alpha,
 27                gamma_min,
 28                offset,
 29                beta,
 30                gamma_max,
 31                passiv_arms_direct,
 32            ),
 33        )
 34
 35    def forward_position(
 36        self, thetas: Tuple[float, float, float]
 37    ) -> Tuple[float, float, float, float]:
 38        """Compute the forward position kinematics of the Orbita3d.
 39
 40        Args:
 41            thetas: The three motors angles (in radians).
 42        Returns:
 43            The quaternion representing the end-effector orientation (qx, qy, qz, qw).
 44        """
 45        thetas = ffi.new("double(*)[3]", tuple(thetas))
 46        q = ffi.new("double(*)[4]")
 47
 48        check(lib.orbita3d_kinematics_forward_position(self.model, thetas, q))
 49
 50        return tuple(q[0])
 51
 52    def forward_velocity(
 53        self,
 54        thetas: Tuple[float, float, float],
 55        thetas_velocity: Tuple[float, float, float],
 56    ) -> Tuple[float, float, float, float]:
 57        """Compute the forward velocity kinematics of the Orbita3d.
 58
 59        Args:
 60            thetas: The three motors angles (in radians).
 61            thetas_velocity: The three motors velocities (in radians per second).
 62        Returns:
 63            Platform output velocity (rad/s)
 64        """
 65        thetas = ffi.new("double(*)[3]", tuple(thetas))
 66        thetas_velocity = ffi.new("double(*)[3]", tuple(thetas_velocity))
 67        q_velocity = ffi.new("double(*)[3]")
 68
 69        check(
 70            lib.orbita3d_kinematics_forward_velocity(
 71                self.model, thetas, thetas_velocity, q_velocity
 72            )
 73        )
 74
 75        return tuple(q_velocity[0])
 76
 77    def forward_torque(
 78        self,
 79        thetas: Tuple[float, float, float],
 80        thetas_torque: Tuple[float, float, float],
 81    ) -> Tuple[float, float, float, float]:
 82        """Compute the forward torque kinematics of the Orbita3d.
 83
 84        Args:
 85            thetas: The three motors angles (in radians).
 86            thetas_torque: The three motors torques (in Newton meters).
 87        Returns:
 88            The quaternion representing the end-effector orientation torque (qx, qy, qz, qw).
 89        """
 90        thetas = ffi.new("double(*)[3]", tuple(thetas))
 91        thetas_torque = ffi.new("double(*)[3]", tuple(thetas_torque))
 92        q_torque = ffi.new("double(*)[4]")
 93
 94        check(
 95            lib.orbita3d_kinematics_forward_torque(
 96                self.model, thetas, thetas_torque, q_torque
 97            )
 98        )
 99
100        return tuple(q_torque[0])
101
102    def inverse_position(
103        self, q: Tuple[float, float, float, float]
104    ) -> Tuple[float, float, float]:
105        """Compute the inverse position kinematics of the Orbita3d.
106
107        Args:
108            q: The quaternion representing the end-effector orientation (qx, qy, qz, qw).
109        Returns:
110            The three motors angles (in radians).
111        """
112        q = ffi.new("double(*)[4]", tuple(q))
113        thetas = ffi.new("double(*)[3]")
114
115        check(lib.orbita3d_kinematics_inverse_position(self.model, q, thetas))
116
117        return tuple(thetas[0])
118
119    def inverse_velocity(
120        self,
121        thetas: Tuple[float, float, float],
122        output_vel: Tuple[float, float, float],
123    ) -> Tuple[float, float, float]:
124        """Compute the inverse velocity kinematics of the Orbita3d.
125
126        Args:
127            thetas: The three motors angles (in radians).
128            output_vel: The platform velocity (in radians per second).
129        Returns:
130            The three motors velocities (in radians per second).
131        """
132        thetas = ffi.new("double(*)[3]", tuple(thetas))
133        output_vel = ffi.new("double(*)[3]", tuple(output_vel))
134        thetas_velocity = ffi.new("double(*)[3]")
135
136        check(
137            lib.orbita3d_kinematics_inverse_velocity(
138                self.model, thetas, output_vel, thetas_velocity
139            )
140        )
141
142        return tuple(thetas_velocity[0])
143
144    def inverse_torque(
145        self,
146        thetas: Tuple[float, float, float],
147        output_torque: Tuple[float, float, float],
148    ) -> Tuple[float, float, float]:
149        """Compute the inverse torque kinematics of the Orbita3d.
150
151        Args:
152            thetas: The three motors angles (in radians).
153            output_torque: The platform torque (in Newton meters).
154        Returns:
155            The three motors torques (in Newton meters).
156        """
157        thetas = ffi.new("double(*)[3]", tuple(thetas))
158        output_torque = ffi.new("double(*)[3]", tuple(output_torque))
159        thetas_torque = ffi.new("double(*)[3]")
160
161        check(
162            lib.orbita3d_kinematics_inverse_torque(
163                self.model, thetas, output_torque, thetas_torque
164            )
165        )
166
167        return tuple(thetas_torque[0])

Orbita3d kinematics model

KinematicsModel( alpha: float, gamma_min: float, offset: float, beta: float, gamma_max: float, passiv_arms_direct: bool)
10    def __init__(
11        self,
12        alpha: float,
13        gamma_min: float,
14        offset: float,
15        beta: float,
16        gamma_max: float,
17        passiv_arms_direct: bool,
18    ) -> None:
19        """Create a new Orbita3d kinematics model.
20
21        See the [README.md](https://github.com/pollen-robotics/orbita3d_control/orbita3d_kinematics) for more information about the parameters.
22        """
23        self.model = ffi.new(
24            "struct Orbita3dKinematicsModel *",
25            lib.create_orbita3d_kinematics_model(
26                alpha,
27                gamma_min,
28                offset,
29                beta,
30                gamma_max,
31                passiv_arms_direct,
32            ),
33        )

Create a new Orbita3d kinematics model.

See the README.md for more information about the parameters.

model
def forward_position( self, thetas: Tuple[float, float, float]) -> Tuple[float, float, float, float]:
35    def forward_position(
36        self, thetas: Tuple[float, float, float]
37    ) -> Tuple[float, float, float, float]:
38        """Compute the forward position kinematics of the Orbita3d.
39
40        Args:
41            thetas: The three motors angles (in radians).
42        Returns:
43            The quaternion representing the end-effector orientation (qx, qy, qz, qw).
44        """
45        thetas = ffi.new("double(*)[3]", tuple(thetas))
46        q = ffi.new("double(*)[4]")
47
48        check(lib.orbita3d_kinematics_forward_position(self.model, thetas, q))
49
50        return tuple(q[0])

Compute the forward position kinematics of the Orbita3d.

Args: thetas: The three motors angles (in radians). Returns: The quaternion representing the end-effector orientation (qx, qy, qz, qw).

def forward_velocity( self, thetas: Tuple[float, float, float], thetas_velocity: Tuple[float, float, float]) -> Tuple[float, float, float, float]:
52    def forward_velocity(
53        self,
54        thetas: Tuple[float, float, float],
55        thetas_velocity: Tuple[float, float, float],
56    ) -> Tuple[float, float, float, float]:
57        """Compute the forward velocity kinematics of the Orbita3d.
58
59        Args:
60            thetas: The three motors angles (in radians).
61            thetas_velocity: The three motors velocities (in radians per second).
62        Returns:
63            Platform output velocity (rad/s)
64        """
65        thetas = ffi.new("double(*)[3]", tuple(thetas))
66        thetas_velocity = ffi.new("double(*)[3]", tuple(thetas_velocity))
67        q_velocity = ffi.new("double(*)[3]")
68
69        check(
70            lib.orbita3d_kinematics_forward_velocity(
71                self.model, thetas, thetas_velocity, q_velocity
72            )
73        )
74
75        return tuple(q_velocity[0])

Compute the forward velocity kinematics of the Orbita3d.

Args: thetas: The three motors angles (in radians). thetas_velocity: The three motors velocities (in radians per second). Returns: Platform output velocity (rad/s)

def forward_torque( self, thetas: Tuple[float, float, float], thetas_torque: Tuple[float, float, float]) -> Tuple[float, float, float, float]:
 77    def forward_torque(
 78        self,
 79        thetas: Tuple[float, float, float],
 80        thetas_torque: Tuple[float, float, float],
 81    ) -> Tuple[float, float, float, float]:
 82        """Compute the forward torque kinematics of the Orbita3d.
 83
 84        Args:
 85            thetas: The three motors angles (in radians).
 86            thetas_torque: The three motors torques (in Newton meters).
 87        Returns:
 88            The quaternion representing the end-effector orientation torque (qx, qy, qz, qw).
 89        """
 90        thetas = ffi.new("double(*)[3]", tuple(thetas))
 91        thetas_torque = ffi.new("double(*)[3]", tuple(thetas_torque))
 92        q_torque = ffi.new("double(*)[4]")
 93
 94        check(
 95            lib.orbita3d_kinematics_forward_torque(
 96                self.model, thetas, thetas_torque, q_torque
 97            )
 98        )
 99
100        return tuple(q_torque[0])

Compute the forward torque kinematics of the Orbita3d.

Args: thetas: The three motors angles (in radians). thetas_torque: The three motors torques (in Newton meters). Returns: The quaternion representing the end-effector orientation torque (qx, qy, qz, qw).

def inverse_position(self, q: Tuple[float, float, float, float]) -> Tuple[float, float, float]:
102    def inverse_position(
103        self, q: Tuple[float, float, float, float]
104    ) -> Tuple[float, float, float]:
105        """Compute the inverse position kinematics of the Orbita3d.
106
107        Args:
108            q: The quaternion representing the end-effector orientation (qx, qy, qz, qw).
109        Returns:
110            The three motors angles (in radians).
111        """
112        q = ffi.new("double(*)[4]", tuple(q))
113        thetas = ffi.new("double(*)[3]")
114
115        check(lib.orbita3d_kinematics_inverse_position(self.model, q, thetas))
116
117        return tuple(thetas[0])

Compute the inverse position kinematics of the Orbita3d.

Args: q: The quaternion representing the end-effector orientation (qx, qy, qz, qw). Returns: The three motors angles (in radians).

def inverse_velocity( self, thetas: Tuple[float, float, float], output_vel: Tuple[float, float, float]) -> Tuple[float, float, float]:
119    def inverse_velocity(
120        self,
121        thetas: Tuple[float, float, float],
122        output_vel: Tuple[float, float, float],
123    ) -> Tuple[float, float, float]:
124        """Compute the inverse velocity kinematics of the Orbita3d.
125
126        Args:
127            thetas: The three motors angles (in radians).
128            output_vel: The platform velocity (in radians per second).
129        Returns:
130            The three motors velocities (in radians per second).
131        """
132        thetas = ffi.new("double(*)[3]", tuple(thetas))
133        output_vel = ffi.new("double(*)[3]", tuple(output_vel))
134        thetas_velocity = ffi.new("double(*)[3]")
135
136        check(
137            lib.orbita3d_kinematics_inverse_velocity(
138                self.model, thetas, output_vel, thetas_velocity
139            )
140        )
141
142        return tuple(thetas_velocity[0])

Compute the inverse velocity kinematics of the Orbita3d.

Args: thetas: The three motors angles (in radians). output_vel: The platform velocity (in radians per second). Returns: The three motors velocities (in radians per second).

def inverse_torque( self, thetas: Tuple[float, float, float], output_torque: Tuple[float, float, float]) -> Tuple[float, float, float]:
144    def inverse_torque(
145        self,
146        thetas: Tuple[float, float, float],
147        output_torque: Tuple[float, float, float],
148    ) -> Tuple[float, float, float]:
149        """Compute the inverse torque kinematics of the Orbita3d.
150
151        Args:
152            thetas: The three motors angles (in radians).
153            output_torque: The platform torque (in Newton meters).
154        Returns:
155            The three motors torques (in Newton meters).
156        """
157        thetas = ffi.new("double(*)[3]", tuple(thetas))
158        output_torque = ffi.new("double(*)[3]", tuple(output_torque))
159        thetas_torque = ffi.new("double(*)[3]")
160
161        check(
162            lib.orbita3d_kinematics_inverse_torque(
163                self.model, thetas, output_torque, thetas_torque
164            )
165        )
166
167        return tuple(thetas_torque[0])

Compute the inverse torque kinematics of the Orbita3d.

Args: thetas: The three motors angles (in radians). output_torque: The platform torque (in Newton meters). Returns: The three motors torques (in Newton meters).

class Orbita3dController:
170class Orbita3dController:
171    """Orbita3d controller."""
172
173    def __init__(self, uid: int) -> None:
174        """You should not call this constructor dierctly. Use from_config instead."""
175        self.uid = uid
176
177    @classmethod
178    def from_config(cls, config: str) -> "Orbita3dController":
179        """Create a new Orbita3d controller from a configuration file.
180
181        Args:
182            config: The configuration file path.
183        Returns:
184            A new Orbita3dController.
185        """
186        uid = ffi.new("uint32_t *")
187        check(lib.orbita3d_controller_from_config(config.encode("utf-8"), uid))
188        return cls(uid[0])
189
190    def is_torque_on(self) -> bool:
191        """Check if the torque is on.
192
193        Returns:
194            True if the torque is on, False otherwise.
195        """
196        torque_on = ffi.new("bool *")
197        check(lib.orbita3d_is_torque_on(self.uid, torque_on))
198        return torque_on[0]
199
200    def enable_torque(self, reset_target: bool) -> None:
201        """Enable the torque.
202
203        Args:
204            reset_target (bool): If True, the target position is reset to the current position.
205        """
206        check(lib.orbita3d_enable_torque(self.uid, reset_target))
207
208    def disable_torque(self) -> None:
209        """Disable the torque."""
210        check(lib.orbita3d_disable_torque(self.uid))
211
212    def get_current_orientation(self) -> Tuple[float, float, float, float]:
213        """Get the current orientation of the end-effector.
214
215        Returns:
216            The quaternion representing the end-effector orientation (qx, qy, qz, qw).
217        """
218        q = ffi.new("double(*)[4]")
219        check(lib.orbita3d_get_current_orientation(self.uid, q))
220        return tuple(q[0])
221
222    def get_current_velocity(self) -> Tuple[float, float, float]:
223        """Get the current velocity of the end-effector.
224
225        Returns:
226            The axis-angle representing the end-effector orientation velocity, magnitude is the angular velocity in rad/s and the axis is the rotation axis.
227        """
228        q_velocity = ffi.new("double(*)[3]")
229        check(lib.orbita3d_get_current_velocity(self.uid, q_velocity))
230        return tuple(q_velocity[0])
231
232    def get_current_torque(self) -> Tuple[float, float, float]:
233        """Get the current torque of the end-effector.
234
235        Returns:
236            The axis-angle representing the end-effector torque, magnitude is the torqur magnitude in Nm and the axis is the rotation axis.
237        """
238        q_torque = ffi.new("double(*)[3]")
239        check(lib.orbita3d_get_current_torque(self.uid, q_torque))
240        return tuple(q_torque[0])
241
242    def get_target_orientation(self) -> Tuple[float, float, float, float]:
243        """Get the target orientation of the end-effector.
244
245        Returns:
246            The quaternion representing the end-effector orientation (qx, qy, qz, qw).
247        """
248        q = ffi.new("double(*)[4]")
249        check(lib.orbita3d_get_target_orientation(self.uid, q))
250        return tuple(q[0])
251
252    def set_target_orientation(self, q: Tuple[float, float, float, float]) -> None:
253        """Set the target orientation of the end-effector.
254
255        Args:
256            q: The quaternion representing the end-effector orientation (qx, qy, qz, qw).
257        """
258        q = ffi.new("double(*)[4]", tuple(q))
259        check(lib.orbita3d_set_target_orientation(self.uid, q))
260
261
262    def get_target_rpy_orientation(self) -> Tuple[float, float, float]:
263        """Get the target orientation of the end-effector.
264
265        Returns:
266            The intrinsic Euler representing the end-effector orientation (roll, pitch, yaw).
267        """
268        rpy = ffi.new("double(*)[3]")
269        check(lib.orbita3d_get_target_rpy_orientation(self.uid, rpy))
270        return tuple(rpy[0])
271
272    def set_target_rpy_orientation(self, rpy: Tuple[float, float, float]) -> None:
273        """Set the target orientation of the end-effector. Yaw can be multi-turn.
274
275        Args:
276            rpy: The intrinsic Euler representing the end-effector orientation (roll, pitch, yaw).
277        """
278        rpy = ffi.new("double(*)[3]", tuple(rpy))
279        check(lib.orbita3d_set_target_rpy_orientation(self.uid, rpy))
280
281    def set_target_rpy_orientation_fb(
282        self, rpy: Tuple[float, float, float]
283    ) -> Tuple[float, float, float]:
284        """Set the target orientation of the end-effector. Yaw can be multiturn.
285
286        Args:
287            rpy: The intrinsic Euler representing the end-effector orientation (roll, pitch, yaw).
288        Returns:
289            The current intrinsic Euler orientation  (roll, pitch, yaw)
290        """
291        rpy = ffi.new("double(*)[3]", tuple(rpy))
292        fb = ffi.new("double(*)[3]")
293        check(lib.orbita3d_set_target_rpy_orientation_fb(self.uid, rpy, fb))
294        return tuple(fb[0])
295
296
297
298    def set_target_orientation_fb(
299        self, q: Tuple[float, float, float, float]
300    ) -> Tuple[float, float, float, float]:
301        """Set the target orientation of the end-effector.
302
303        Args:
304            q: The quaternion representing the end-effector orientation (qx, qy, qz, qw).
305        Returns:
306            The current orientation quaternion (qx, qy, qz, qw)
307        """
308        q = ffi.new("double(*)[4]", tuple(q))
309        fb = ffi.new("double(*)[4]")
310        check(lib.orbita3d_set_target_orientation_fb(self.uid, q, fb))
311        return tuple(fb[0])
312
313    def get_raw_motors_velocity_limit(self) -> Tuple[float, float, float]:
314        """Get the raw motors velocity limit.
315
316        Be carfeful, this is not the end-effector velocity limit. But this is the raw velocity limit of the disks!
317
318        Returns:
319            The raw motors velocity limit (in radians per second).
320        """
321        velocity_limit = ffi.new("double(*)[3]")
322        check(lib.orbita3d_get_raw_motors_velocity_limit(self.uid, velocity_limit))
323        return tuple(velocity_limit[0])
324
325    def set_raw_motors_velocity_limit(
326        self, velocity_limit: Tuple[float, float, float]
327    ) -> None:
328        """Set the raw motors velocity limit.
329
330        Be carfeful, this is not the end-effector velocity limit. But this is the raw velocity limit of the disks!
331
332        Args:
333            velocity_limit: The raw motors velocity limit (in radians per second).
334        """
335        velocity_limit = ffi.new("double(*)[3]", tuple(velocity_limit))
336        check(lib.orbita3d_set_raw_motors_velocity_limit(self.uid, velocity_limit))
337
338    def get_raw_motors_torque_limit(self) -> Tuple[float, float, float]:
339        """Get the raw motors torque limit.
340
341        Be carfeful, this is not the end-effector torque limit. But this is the raw torque limit of the disks!
342
343        Returns:
344            The raw motors torque limit (in Newton meters).
345        """
346        torque_limit = ffi.new("double(*)[3]")
347        check(lib.orbita3d_get_raw_motors_torque_limit(self.uid, torque_limit))
348        return tuple(torque_limit[0])
349
350    def set_raw_motors_torque_limit(
351        self, torque_limit: Tuple[float, float, float]
352    ) -> None:
353        """Set the raw motors torque limit.
354
355        Be carfeful, this is not the end-effector torque limit. But this is the raw torque limit of the disks!
356
357        Args:
358            torque_limit: The raw motors torque limit (in Newton meters).
359        """
360        torque_limit = ffi.new("double(*)[3]", tuple(torque_limit))
361        check(lib.orbita3d_set_raw_motors_torque_limit(self.uid, torque_limit))
362
363    def get_raw_motors_pid_gains(
364        self,
365    ) -> Tuple[
366        Tuple[float, float, float],
367        Tuple[float, float, float],
368        Tuple[float, float, float],
369    ]:
370        """Get the raw motors PID gains.
371
372        Be carfeful, this is not the end-effector PID gains. But this is the raw PID gains of the disks!
373
374        Returns:
375            The raw motors PID gains (kp, ki, kd).
376        """
377        pids = ffi.new("double(*)[3][3]")
378        check(lib.orbita3d_get_raw_motors_pid_gains(self.uid, pids))
379        return pids[0]
380
381    def set_raw_motors_pid_gains(
382        self,
383        pids: Tuple[
384            Tuple[float, float, float],
385            Tuple[float, float, float],
386            Tuple[float, float, float],
387        ],
388    ) -> None:
389        """Set the raw motors PID gains.
390
391        Be carfeful, this is not the end-effector PID gains. But this is the raw PID gains of the disks!
392
393        Args:
394            pids: The raw motors PID gains (kp, ki, kd).
395        """
396        pids = ffi.new("double(*)[3][3]", tuple(pids))
397        check(lib.orbita3d_set_raw_motors_pid_gains(self.uid, pids))
398
399    def get_raw_motors_velocity(self) -> Tuple[float, float, float]:
400        """Get the raw motors velocity.
401
402        Be carfeful, this is not the end-effector velocity. But this is the raw velocity of the disks!
403
404        Returns:
405            The raw motors velocity (in radians per second).
406        """
407        velocity = ffi.new("double(*)[3]")
408        check(lib.orbita3d_get_raw_motors_velocity(self.uid, velocity))
409        return tuple(velocity[0])
410    
411    def get_raw_motors_position(self) -> Tuple[float, float, float]:
412        """Get the raw motors position.
413
414        Be carfeful, this is not the end-effector position. But this is the raw position of the disks!
415
416        Returns:
417            The raw motors position (in radians).
418        """
419        position = ffi.new("double(*)[3]")
420        check(lib.orbita3d_get_raw_motors_position(self.uid, position))
421        return tuple(position[0])
422    
423    def get_raw_motors_current(self) -> Tuple[float, float, float]:
424        """Get the raw motors torque.
425
426        Be carfeful, this is not the end-effector torque. But this is the raw torque of the disks!
427
428        Returns:
429            The raw motors torque (in Newton meters).
430        """
431        torque = ffi.new("double(*)[3]")
432        check(lib.orbita3d_get_raw_motors_current(self.uid, torque))
433        return tuple(torque[0])
434    
435
436    def get_raw_axis_sensor(self) -> Tuple[float, float, float]:
437        """Get the raw axis sensor.
438
439        Be carfeful, this is not the end-effector position. But this is the raw position of the disks!
440
441        Returns:
442            The raw axis sensor (in radians).
443        """
444        axis = ffi.new("double(*)[3]")
445        check(lib.orbita3d_get_axis_sensors(self.uid, axis))
446        return tuple(axis[0])
447    
448    def get_raw_axis_zeros(self) -> Tuple[float, float, float]:
449        """Get the raw axis zero.
450
451        Axis sensor value at the mechanical zero position.
452
453        Returns:
454            The raw axis zero (in radians).
455        """
456        axis = ffi.new("double(*)[3]")
457        check(lib.orbita3d_get_axis_sensor_zeros(self.uid, axis))
458        return tuple(axis[0])
459    
460    def get_control_mode(self) -> int:
461        """Get the control mode.
462
463        Returns:
464            The control mode.
465        """
466        mode = ffi.new("uint8_t *")
467        check(lib.orbita3d_get_control_mode(self.uid, mode))
468        return mode[0]
469    
470    def set_control_mode(self, mode: int) -> None:
471        """Set the control mode.
472
473        Args:
474            mode: The control mode.
475        """
476        mode = ffi.new("uint8_t *", mode)
477        check(lib.orbita3d_set_control_mode(self.uid, mode))
478        
479    def set_target_torque(self, torque: Tuple[float, float, float]) -> None:
480        """Set the target torque of the end-effector.
481
482        Args:
483            torque: The quaternion representing the end-effector orientation torque (qx, qy, qz, qw).
484        """
485        torque = ffi.new("double(*)[3]", tuple(torque))
486        check(lib.orbita3d_set_target_torque(self.uid, torque))
487    
488    def set_target_velocity(self, velocity: Tuple[float, float, float]) -> None:
489        """Set the target velocity of the end-effector.
490
491        Args:
492            velocity: The quaternion representing the end-effector orientation velocity (qx, qy, qz, qw).
493        """
494        velocity = ffi.new("double(*)[3]", tuple(velocity))
495        check(lib.orbita3d_set_target_velocity(self.uid, velocity))

Orbita3d controller.

Orbita3dController(uid: int)
173    def __init__(self, uid: int) -> None:
174        """You should not call this constructor dierctly. Use from_config instead."""
175        self.uid = uid

You should not call this constructor dierctly. Use from_config instead.

uid
@classmethod
def from_config(cls, config: str) -> Orbita3dController:
177    @classmethod
178    def from_config(cls, config: str) -> "Orbita3dController":
179        """Create a new Orbita3d controller from a configuration file.
180
181        Args:
182            config: The configuration file path.
183        Returns:
184            A new Orbita3dController.
185        """
186        uid = ffi.new("uint32_t *")
187        check(lib.orbita3d_controller_from_config(config.encode("utf-8"), uid))
188        return cls(uid[0])

Create a new Orbita3d controller from a configuration file.

Args: config: The configuration file path. Returns: A new Orbita3dController.

def is_torque_on(self) -> bool:
190    def is_torque_on(self) -> bool:
191        """Check if the torque is on.
192
193        Returns:
194            True if the torque is on, False otherwise.
195        """
196        torque_on = ffi.new("bool *")
197        check(lib.orbita3d_is_torque_on(self.uid, torque_on))
198        return torque_on[0]

Check if the torque is on.

Returns: True if the torque is on, False otherwise.

def enable_torque(self, reset_target: bool) -> None:
200    def enable_torque(self, reset_target: bool) -> None:
201        """Enable the torque.
202
203        Args:
204            reset_target (bool): If True, the target position is reset to the current position.
205        """
206        check(lib.orbita3d_enable_torque(self.uid, reset_target))

Enable the torque.

Args: reset_target (bool): If True, the target position is reset to the current position.

def disable_torque(self) -> None:
208    def disable_torque(self) -> None:
209        """Disable the torque."""
210        check(lib.orbita3d_disable_torque(self.uid))

Disable the torque.

def get_current_orientation(self) -> Tuple[float, float, float, float]:
212    def get_current_orientation(self) -> Tuple[float, float, float, float]:
213        """Get the current orientation of the end-effector.
214
215        Returns:
216            The quaternion representing the end-effector orientation (qx, qy, qz, qw).
217        """
218        q = ffi.new("double(*)[4]")
219        check(lib.orbita3d_get_current_orientation(self.uid, q))
220        return tuple(q[0])

Get the current orientation of the end-effector.

Returns: The quaternion representing the end-effector orientation (qx, qy, qz, qw).

def get_current_velocity(self) -> Tuple[float, float, float]:
222    def get_current_velocity(self) -> Tuple[float, float, float]:
223        """Get the current velocity of the end-effector.
224
225        Returns:
226            The axis-angle representing the end-effector orientation velocity, magnitude is the angular velocity in rad/s and the axis is the rotation axis.
227        """
228        q_velocity = ffi.new("double(*)[3]")
229        check(lib.orbita3d_get_current_velocity(self.uid, q_velocity))
230        return tuple(q_velocity[0])

Get the current velocity of the end-effector.

Returns: The axis-angle representing the end-effector orientation velocity, magnitude is the angular velocity in rad/s and the axis is the rotation axis.

def get_current_torque(self) -> Tuple[float, float, float]:
232    def get_current_torque(self) -> Tuple[float, float, float]:
233        """Get the current torque of the end-effector.
234
235        Returns:
236            The axis-angle representing the end-effector torque, magnitude is the torqur magnitude in Nm and the axis is the rotation axis.
237        """
238        q_torque = ffi.new("double(*)[3]")
239        check(lib.orbita3d_get_current_torque(self.uid, q_torque))
240        return tuple(q_torque[0])

Get the current torque of the end-effector.

Returns: The axis-angle representing the end-effector torque, magnitude is the torqur magnitude in Nm and the axis is the rotation axis.

def get_target_orientation(self) -> Tuple[float, float, float, float]:
242    def get_target_orientation(self) -> Tuple[float, float, float, float]:
243        """Get the target orientation of the end-effector.
244
245        Returns:
246            The quaternion representing the end-effector orientation (qx, qy, qz, qw).
247        """
248        q = ffi.new("double(*)[4]")
249        check(lib.orbita3d_get_target_orientation(self.uid, q))
250        return tuple(q[0])

Get the target orientation of the end-effector.

Returns: The quaternion representing the end-effector orientation (qx, qy, qz, qw).

def set_target_orientation(self, q: Tuple[float, float, float, float]) -> None:
252    def set_target_orientation(self, q: Tuple[float, float, float, float]) -> None:
253        """Set the target orientation of the end-effector.
254
255        Args:
256            q: The quaternion representing the end-effector orientation (qx, qy, qz, qw).
257        """
258        q = ffi.new("double(*)[4]", tuple(q))
259        check(lib.orbita3d_set_target_orientation(self.uid, q))

Set the target orientation of the end-effector.

Args: q: The quaternion representing the end-effector orientation (qx, qy, qz, qw).

def get_target_rpy_orientation(self) -> Tuple[float, float, float]:
262    def get_target_rpy_orientation(self) -> Tuple[float, float, float]:
263        """Get the target orientation of the end-effector.
264
265        Returns:
266            The intrinsic Euler representing the end-effector orientation (roll, pitch, yaw).
267        """
268        rpy = ffi.new("double(*)[3]")
269        check(lib.orbita3d_get_target_rpy_orientation(self.uid, rpy))
270        return tuple(rpy[0])

Get the target orientation of the end-effector.

Returns: The intrinsic Euler representing the end-effector orientation (roll, pitch, yaw).

def set_target_rpy_orientation(self, rpy: Tuple[float, float, float]) -> None:
272    def set_target_rpy_orientation(self, rpy: Tuple[float, float, float]) -> None:
273        """Set the target orientation of the end-effector. Yaw can be multi-turn.
274
275        Args:
276            rpy: The intrinsic Euler representing the end-effector orientation (roll, pitch, yaw).
277        """
278        rpy = ffi.new("double(*)[3]", tuple(rpy))
279        check(lib.orbita3d_set_target_rpy_orientation(self.uid, rpy))

Set the target orientation of the end-effector. Yaw can be multi-turn.

Args: rpy: The intrinsic Euler representing the end-effector orientation (roll, pitch, yaw).

def set_target_rpy_orientation_fb(self, rpy: Tuple[float, float, float]) -> Tuple[float, float, float]:
281    def set_target_rpy_orientation_fb(
282        self, rpy: Tuple[float, float, float]
283    ) -> Tuple[float, float, float]:
284        """Set the target orientation of the end-effector. Yaw can be multiturn.
285
286        Args:
287            rpy: The intrinsic Euler representing the end-effector orientation (roll, pitch, yaw).
288        Returns:
289            The current intrinsic Euler orientation  (roll, pitch, yaw)
290        """
291        rpy = ffi.new("double(*)[3]", tuple(rpy))
292        fb = ffi.new("double(*)[3]")
293        check(lib.orbita3d_set_target_rpy_orientation_fb(self.uid, rpy, fb))
294        return tuple(fb[0])

Set the target orientation of the end-effector. Yaw can be multiturn.

Args: rpy: The intrinsic Euler representing the end-effector orientation (roll, pitch, yaw). Returns: The current intrinsic Euler orientation (roll, pitch, yaw)

def set_target_orientation_fb( self, q: Tuple[float, float, float, float]) -> Tuple[float, float, float, float]:
298    def set_target_orientation_fb(
299        self, q: Tuple[float, float, float, float]
300    ) -> Tuple[float, float, float, float]:
301        """Set the target orientation of the end-effector.
302
303        Args:
304            q: The quaternion representing the end-effector orientation (qx, qy, qz, qw).
305        Returns:
306            The current orientation quaternion (qx, qy, qz, qw)
307        """
308        q = ffi.new("double(*)[4]", tuple(q))
309        fb = ffi.new("double(*)[4]")
310        check(lib.orbita3d_set_target_orientation_fb(self.uid, q, fb))
311        return tuple(fb[0])

Set the target orientation of the end-effector.

Args: q: The quaternion representing the end-effector orientation (qx, qy, qz, qw). Returns: The current orientation quaternion (qx, qy, qz, qw)

def get_raw_motors_velocity_limit(self) -> Tuple[float, float, float]:
313    def get_raw_motors_velocity_limit(self) -> Tuple[float, float, float]:
314        """Get the raw motors velocity limit.
315
316        Be carfeful, this is not the end-effector velocity limit. But this is the raw velocity limit of the disks!
317
318        Returns:
319            The raw motors velocity limit (in radians per second).
320        """
321        velocity_limit = ffi.new("double(*)[3]")
322        check(lib.orbita3d_get_raw_motors_velocity_limit(self.uid, velocity_limit))
323        return tuple(velocity_limit[0])

Get the raw motors velocity limit.

Be carfeful, this is not the end-effector velocity limit. But this is the raw velocity limit of the disks!

Returns: The raw motors velocity limit (in radians per second).

def set_raw_motors_velocity_limit(self, velocity_limit: Tuple[float, float, float]) -> None:
325    def set_raw_motors_velocity_limit(
326        self, velocity_limit: Tuple[float, float, float]
327    ) -> None:
328        """Set the raw motors velocity limit.
329
330        Be carfeful, this is not the end-effector velocity limit. But this is the raw velocity limit of the disks!
331
332        Args:
333            velocity_limit: The raw motors velocity limit (in radians per second).
334        """
335        velocity_limit = ffi.new("double(*)[3]", tuple(velocity_limit))
336        check(lib.orbita3d_set_raw_motors_velocity_limit(self.uid, velocity_limit))

Set the raw motors velocity limit.

Be carfeful, this is not the end-effector velocity limit. But this is the raw velocity limit of the disks!

Args: velocity_limit: The raw motors velocity limit (in radians per second).

def get_raw_motors_torque_limit(self) -> Tuple[float, float, float]:
338    def get_raw_motors_torque_limit(self) -> Tuple[float, float, float]:
339        """Get the raw motors torque limit.
340
341        Be carfeful, this is not the end-effector torque limit. But this is the raw torque limit of the disks!
342
343        Returns:
344            The raw motors torque limit (in Newton meters).
345        """
346        torque_limit = ffi.new("double(*)[3]")
347        check(lib.orbita3d_get_raw_motors_torque_limit(self.uid, torque_limit))
348        return tuple(torque_limit[0])

Get the raw motors torque limit.

Be carfeful, this is not the end-effector torque limit. But this is the raw torque limit of the disks!

Returns: The raw motors torque limit (in Newton meters).

def set_raw_motors_torque_limit(self, torque_limit: Tuple[float, float, float]) -> None:
350    def set_raw_motors_torque_limit(
351        self, torque_limit: Tuple[float, float, float]
352    ) -> None:
353        """Set the raw motors torque limit.
354
355        Be carfeful, this is not the end-effector torque limit. But this is the raw torque limit of the disks!
356
357        Args:
358            torque_limit: The raw motors torque limit (in Newton meters).
359        """
360        torque_limit = ffi.new("double(*)[3]", tuple(torque_limit))
361        check(lib.orbita3d_set_raw_motors_torque_limit(self.uid, torque_limit))

Set the raw motors torque limit.

Be carfeful, this is not the end-effector torque limit. But this is the raw torque limit of the disks!

Args: torque_limit: The raw motors torque limit (in Newton meters).

def get_raw_motors_pid_gains( self) -> Tuple[Tuple[float, float, float], Tuple[float, float, float], Tuple[float, float, float]]:
363    def get_raw_motors_pid_gains(
364        self,
365    ) -> Tuple[
366        Tuple[float, float, float],
367        Tuple[float, float, float],
368        Tuple[float, float, float],
369    ]:
370        """Get the raw motors PID gains.
371
372        Be carfeful, this is not the end-effector PID gains. But this is the raw PID gains of the disks!
373
374        Returns:
375            The raw motors PID gains (kp, ki, kd).
376        """
377        pids = ffi.new("double(*)[3][3]")
378        check(lib.orbita3d_get_raw_motors_pid_gains(self.uid, pids))
379        return pids[0]

Get the raw motors PID gains.

Be carfeful, this is not the end-effector PID gains. But this is the raw PID gains of the disks!

Returns: The raw motors PID gains (kp, ki, kd).

def set_raw_motors_pid_gains( self, pids: Tuple[Tuple[float, float, float], Tuple[float, float, float], Tuple[float, float, float]]) -> None:
381    def set_raw_motors_pid_gains(
382        self,
383        pids: Tuple[
384            Tuple[float, float, float],
385            Tuple[float, float, float],
386            Tuple[float, float, float],
387        ],
388    ) -> None:
389        """Set the raw motors PID gains.
390
391        Be carfeful, this is not the end-effector PID gains. But this is the raw PID gains of the disks!
392
393        Args:
394            pids: The raw motors PID gains (kp, ki, kd).
395        """
396        pids = ffi.new("double(*)[3][3]", tuple(pids))
397        check(lib.orbita3d_set_raw_motors_pid_gains(self.uid, pids))

Set the raw motors PID gains.

Be carfeful, this is not the end-effector PID gains. But this is the raw PID gains of the disks!

Args: pids: The raw motors PID gains (kp, ki, kd).

def get_raw_motors_velocity(self) -> Tuple[float, float, float]:
399    def get_raw_motors_velocity(self) -> Tuple[float, float, float]:
400        """Get the raw motors velocity.
401
402        Be carfeful, this is not the end-effector velocity. But this is the raw velocity of the disks!
403
404        Returns:
405            The raw motors velocity (in radians per second).
406        """
407        velocity = ffi.new("double(*)[3]")
408        check(lib.orbita3d_get_raw_motors_velocity(self.uid, velocity))
409        return tuple(velocity[0])

Get the raw motors velocity.

Be carfeful, this is not the end-effector velocity. But this is the raw velocity of the disks!

Returns: The raw motors velocity (in radians per second).

def get_raw_motors_position(self) -> Tuple[float, float, float]:
411    def get_raw_motors_position(self) -> Tuple[float, float, float]:
412        """Get the raw motors position.
413
414        Be carfeful, this is not the end-effector position. But this is the raw position of the disks!
415
416        Returns:
417            The raw motors position (in radians).
418        """
419        position = ffi.new("double(*)[3]")
420        check(lib.orbita3d_get_raw_motors_position(self.uid, position))
421        return tuple(position[0])

Get the raw motors position.

Be carfeful, this is not the end-effector position. But this is the raw position of the disks!

Returns: The raw motors position (in radians).

def get_raw_motors_current(self) -> Tuple[float, float, float]:
423    def get_raw_motors_current(self) -> Tuple[float, float, float]:
424        """Get the raw motors torque.
425
426        Be carfeful, this is not the end-effector torque. But this is the raw torque of the disks!
427
428        Returns:
429            The raw motors torque (in Newton meters).
430        """
431        torque = ffi.new("double(*)[3]")
432        check(lib.orbita3d_get_raw_motors_current(self.uid, torque))
433        return tuple(torque[0])

Get the raw motors torque.

Be carfeful, this is not the end-effector torque. But this is the raw torque of the disks!

Returns: The raw motors torque (in Newton meters).

def get_raw_axis_sensor(self) -> Tuple[float, float, float]:
436    def get_raw_axis_sensor(self) -> Tuple[float, float, float]:
437        """Get the raw axis sensor.
438
439        Be carfeful, this is not the end-effector position. But this is the raw position of the disks!
440
441        Returns:
442            The raw axis sensor (in radians).
443        """
444        axis = ffi.new("double(*)[3]")
445        check(lib.orbita3d_get_axis_sensors(self.uid, axis))
446        return tuple(axis[0])

Get the raw axis sensor.

Be carfeful, this is not the end-effector position. But this is the raw position of the disks!

Returns: The raw axis sensor (in radians).

def get_raw_axis_zeros(self) -> Tuple[float, float, float]:
448    def get_raw_axis_zeros(self) -> Tuple[float, float, float]:
449        """Get the raw axis zero.
450
451        Axis sensor value at the mechanical zero position.
452
453        Returns:
454            The raw axis zero (in radians).
455        """
456        axis = ffi.new("double(*)[3]")
457        check(lib.orbita3d_get_axis_sensor_zeros(self.uid, axis))
458        return tuple(axis[0])

Get the raw axis zero.

Axis sensor value at the mechanical zero position.

Returns: The raw axis zero (in radians).

def get_control_mode(self) -> int:
460    def get_control_mode(self) -> int:
461        """Get the control mode.
462
463        Returns:
464            The control mode.
465        """
466        mode = ffi.new("uint8_t *")
467        check(lib.orbita3d_get_control_mode(self.uid, mode))
468        return mode[0]

Get the control mode.

Returns: The control mode.

def set_control_mode(self, mode: int) -> None:
470    def set_control_mode(self, mode: int) -> None:
471        """Set the control mode.
472
473        Args:
474            mode: The control mode.
475        """
476        mode = ffi.new("uint8_t *", mode)
477        check(lib.orbita3d_set_control_mode(self.uid, mode))

Set the control mode.

Args: mode: The control mode.

def set_target_torque(self, torque: Tuple[float, float, float]) -> None:
479    def set_target_torque(self, torque: Tuple[float, float, float]) -> None:
480        """Set the target torque of the end-effector.
481
482        Args:
483            torque: The quaternion representing the end-effector orientation torque (qx, qy, qz, qw).
484        """
485        torque = ffi.new("double(*)[3]", tuple(torque))
486        check(lib.orbita3d_set_target_torque(self.uid, torque))

Set the target torque of the end-effector.

Args: torque: The quaternion representing the end-effector orientation torque (qx, qy, qz, qw).

def set_target_velocity(self, velocity: Tuple[float, float, float]) -> None:
488    def set_target_velocity(self, velocity: Tuple[float, float, float]) -> None:
489        """Set the target velocity of the end-effector.
490
491        Args:
492            velocity: The quaternion representing the end-effector orientation velocity (qx, qy, qz, qw).
493        """
494        velocity = ffi.new("double(*)[3]", tuple(velocity))
495        check(lib.orbita3d_set_target_velocity(self.uid, velocity))

Set the target velocity of the end-effector.

Args: velocity: The quaternion representing the end-effector orientation velocity (qx, qy, qz, qw).

def check(err):
499def check(err):
500    if err != 0:
501        raise RuntimeError("Error code: {}".format(err))