Source code for j5.components.servo

"""Classes for supporting Servomotors."""

from abc import abstractmethod
from typing import Type, Union

from j5.components.component import Component, Interface

# A servo can be powered down by setting its position to None.
ServoPosition = Union[float, None]

class ServoInterface(Interface):
    """An interface containing the methods required to control a Servo."""

    def get_servo_position(self, identifier: int) -> ServoPosition:
        Get the position of a servo.

        :param identifier: Port of servo to check.
        :returns: Position of servo.
        raise NotImplementedError  # pragma: no cover

    def set_servo_position(
        identifier: int,
        position: ServoPosition,
    ) -> None:
        Set the position of a servo.

        :param identifier: Port of servo to set position.
        :param position: Position to set the servo to.
        raise NotImplementedError  # pragma: no cover

[docs]class Servo(Component): """A standard servomotor.""" def __init__(self, identifier: int, backend: ServoInterface) -> None: self._backend = backend self._identifier = identifier @staticmethod def interface_class() -> Type[ServoInterface]: """ Get the interface class that is required to use this component. :returns: interface class. """ return ServoInterface @property def identifier(self) -> int: """ An integer to identify the component on a board. :returns: component identifier. """ return self._identifier @property def position(self) -> ServoPosition: """ Get the current position of the Servo. :returns: current position of the Servo """ return self._backend.get_servo_position(self._identifier) @position.setter def position(self, new_position: ServoPosition) -> None: """ Set the position of the Servo. :param new_position: new position for the servo. :raises ValueError: invalid servo position """ if new_position is not None: if not -1 <= new_position <= 1: raise ValueError self._backend.set_servo_position(self._identifier, new_position)