Newer
Older
RobotCar / src / pc / gui / manual_controller.py
"""
manual_controller
キー入力から手動操作の throttle / steer を計算するモジュール
"""

from PySide6.QtCore import Qt
from PySide6.QtGui import QKeyEvent

# 手動操作の throttle / steer 量
MANUAL_THROTTLE: float = 0.5
MANUAL_STEER: float = 0.4


class ManualController:
    """キー入力を throttle / steer に変換する

    Qt のキーイベントを受け取り,
    押下中のキーセットから操舵量を計算する
    """

    def __init__(self) -> None:
        self._pressed_keys: set[int] = set()
        self.throttle: float = 0.0
        self.steer: float = 0.0

    def reset(self) -> None:
        """状態をリセットする"""
        self._pressed_keys.clear()
        self.throttle = 0.0
        self.steer = 0.0

    def handle_key_press(self, event: QKeyEvent) -> bool:
        """キー押下を処理する

        Args:
            event: Qt のキーイベント

        Returns:
            操舵量が更新された場合 True
        """
        if event.isAutoRepeat():
            return False
        self._pressed_keys.add(event.key())
        self._update()
        return True

    def handle_key_release(self, event: QKeyEvent) -> bool:
        """キー離上を処理する

        Args:
            event: Qt のキーイベント

        Returns:
            操舵量が更新された場合 True
        """
        if event.isAutoRepeat():
            return False
        self._pressed_keys.discard(event.key())
        self._update()
        return True

    def is_emergency_stop(self) -> bool:
        """Space キーによる緊急停止が発生したか判定する

        緊急停止の場合は状態をリセットする

        Returns:
            緊急停止が発生した場合 True
        """
        if Qt.Key.Key_Space in self._pressed_keys:
            self.reset()
            return True
        return False

    def _update(self) -> None:
        """押下中のキーから throttle と steer を計算する"""
        keys = self._pressed_keys

        # Space で緊急停止
        if Qt.Key.Key_Space in keys:
            self.reset()
            return

        # throttle: W/↑ で前進,S/↓ で後退
        forward = (
            Qt.Key.Key_W in keys or Qt.Key.Key_Up in keys
        )
        backward = (
            Qt.Key.Key_S in keys
            or Qt.Key.Key_Down in keys
        )
        if forward and not backward:
            self.throttle = MANUAL_THROTTLE
        elif backward and not forward:
            self.throttle = -MANUAL_THROTTLE
        else:
            self.throttle = 0.0

        # steer: A/← で左,D/→ で右
        left = (
            Qt.Key.Key_A in keys
            or Qt.Key.Key_Left in keys
        )
        right = (
            Qt.Key.Key_D in keys
            or Qt.Key.Key_Right in keys
        )
        if left and not right:
            self.steer = -MANUAL_STEER
        elif right and not left:
            self.steer = MANUAL_STEER
        else:
            self.steer = 0.0