Source code for uppaal2jetracer.controller.hardware_controller

"""Hardware controller

This module contains the hardware controller class for the JetRacer.

This file can be imported and contains the following classes:

    * HardwareController:   Controls a specific hardware.
    * HardwareResult:       Contains result of hardware accesses.
    * HardwareState:        State of the hardware.
    * JRHardwareController: Controls a NVIDIA JetRacer ROS AI Kit.
"""

from __future__ import annotations

from abc import ABC, abstractmethod
from enum import Enum
import logging

from uppaal2jetracer.jetracerros2.jetracerros2.turn_controller import TurnController
from uppaal2jetracer.jetracerros2.jetracerros2.speed_controller import SpeedController
from uppaal2jetracer.jetracerros2.jetracerros2.collision_controller import CollisionController

logger = logging.getLogger("controller")


[docs] class HardwareController(ABC): """ A class to represent a hardware controller. Each method should return a :class:`HardwareResult` with a correct :class:`HardwareState`. This allows the hardware command system to savely handle hardware errors. """
[docs] @abstractmethod def shutdown(self): """ Shut down the hardware controller and associated hardware. """
[docs] @abstractmethod def stop(self): """ Stops running hardware. """
[docs] class HardwareResult[T]: """ A class to represent a hardware result. :ivar _hardware_state: The state of the hardware. :vartype _hardware_state: HardwareState :ivar _result: The result of the hardware operation. :vartype _result: T """ __slots__ = ("_hardware_state", "_result") def __init__(self, hardware_state: HardwareState, result: T): self._hardware_state = hardware_state self._result = result @property def hardware_state(self) -> HardwareState: """ Get the state of the hardware. :return: The state of the hardware. :rtype: HardwareState """ return self._hardware_state @property def result(self) -> T: """ Get the result of the hardware operation. :return: The result of the hardware operation. :rtype: T """ return self._result
[docs] class HardwareState(Enum): """ This enum represents the state of underlying hardware. """ OK = 0 ERROR = 1
[docs] class JRHardwareController(HardwareController): """ A class to represent a hardware controller for the JetRacer. """ __slots__ = ("_turn_controller", "_speed_controller", "_collision_controller") def __init__(self): """ Initialize the hardware controller. """ self._turn_controller = TurnController() self._speed_controller = SpeedController() self._collision_controller = CollisionController() logger.debug("Initialized hardware controller.")
[docs] def shutdown(self): """ Shut down ROS 2 and rclpy. """ self._turn_controller.shutdown() self._speed_controller.shutdown() self._collision_controller.shutdown() logger.debug("Shutting down hardware controller.")
[docs] def stop(self): """ Stop the JetRacer. """ self.set_speed(0.0)
[docs] def turn(self, theta: float) -> HardwareResult[None]: """ Turn the JetRacer by a given angle. :param theta: The angle to turn the JetRacer in radians. :type theta: float :return: The result of the turn operation. :rtype: HardwareResult[None] """ self._turn_controller.turn(theta) logger.debug("Turned JetRacer by %f radians.", theta) return HardwareResult(HardwareState.OK, None)
[docs] def set_speed(self, speed: float) -> HardwareResult[None]: """ Set the speed of the JetRacer. :param speed: The speed to set the JetRacer to in m/s. Range: [-1.2, 1.2] :type speed: float :return: The result of the set speed operation. :rtype: HardwareResult[None] """ self._speed_controller.set_speed(speed) logger.debug("Set JetRacer speed to %f m/s.", speed) return HardwareResult(HardwareState.OK, None)
[docs] def potential_collision(self) -> HardwareResult[bool]: """ Check if there is a potential collision ahead. :return: True if there is a potential collision ahead, False otherwise. :rtype: HardwareResult[bool] """ result = self._collision_controller.potential_collision logger.debug("Checked for potential collision ahead. Result: %s", result) return HardwareResult(HardwareState.OK, result)
[docs] def free_ahead(self) -> HardwareResult[bool]: """ Check if there is enough free space ahead. :return: True if there is enough free space ahead, False otherwise. :rtype: HardwareResult[bool """ result = self._collision_controller.free_ahead logger.debug("Checked for free space ahead. Result: %s", result) return HardwareResult(HardwareState.OK, result)