app.cobotta_bcap_arm のソースコード

#!/usr/bin/env python
"""
K.NAKADA, kengo.nakada@gmail.com, kengo.nakada@mat.shimane-u.ac.jp
"""
from typing import Any, Union, List, Dict, Tuple, Callable, Optional, Sequence

# grpc
from cobotta2.server_grpc import JoyPadClient

from x_logger import XLogger


[ドキュメント] class CobottaBcapArm: """ b-CAP 制御された COBOTTA のアーム占有状態(Take / Give)のみを管理するクラス。 本クラスは以下の責務のみを持つ。 - JoyPadClient を通じてアームの取得 / 解放要求を送信する - 「このクライアントがアームを保持しているか」という状態を内部に保持する - アーム状態に応じて UI ボタンの有効 / 無効を切り替える 実際のロボット運動制御や座標制御は一切行わない。 本クラスは「状態管理 + UI 反映」に限定された薄い制御層である。 """ def __init__( self, parent: Any, client: JoyPadClient, # JoyPadClient logger: XLogger = None, ): """ CobottaBcapArm を初期化する。 Args: parent (Any): 親オブジェクト。 UI(Qt Designer で生成された ui 属性)を保持していることを前提とする。 client (JoyPadClient): gRPC 経由でサーバ側の ctrl に接続するクライアント。 take_arm / give_arm RPC の呼び出しのみを行う。 logger (XLogger, optional): ログ出力用ロガー。 指定されない場合は本クラス専用の logger を内部生成する。 Notes: - 初期状態ではアームは未取得(_arm_taken = False)とする - UI が存在しない実行環境(テスト等)でも動作するよう、 UI 操作部分は AttributeError を握りつぶす設計になっている - Take / Give ボタンの signal-slot 接続もここで行う """ self._parent = parent self._client = client self._logger = logger or XLogger(logger_name="CobottaArmCtrl") self._arm_taken = False # ------------------ # UI # ------------------ self.ui = self._parent.ui self.ui.JoyPad_button_take_arm.clicked.connect(self._on_take_arm) self.ui.JoyPad_button_give_arm.clicked.connect(self._on_give_arm) # 初期ボタン状態 try: self.ui.JoyPad_button_take_arm.setEnabled(True) self.ui.JoyPad_button_give_arm.setEnabled(True) except AttributeError: pass
[ドキュメント] def take_arm(self): """ アームの取得(Take Arm)を要求する。 Returns: bool: True : アーム取得に成功、または既に取得済み False : 取得要求が失敗した場合 Behavior: - すでにアームを保持している場合は RPC を呼ばず True を返す - JoyPadClient.take_arm() を呼び出し、成功時のみ内部状態を更新する - 内部状態 _arm_taken は UI 状態制御の判断材料としてのみ使用される """ if self._arm_taken: return True ok = self._client.take_arm() if ok: self._arm_taken = True return True else: return False
[ドキュメント] def give_arm(self) -> bool: """ アームの解放(Give Arm)を要求する。 Returns: bool: True : アーム解放に成功、または元々保持していない False : 解放要求が失敗した場合 Behavior: - アームを保持していない場合は RPC を呼ばず True を返す - JoyPadClient.give_arm() を呼び出し、成功時のみ内部状態を更新する """ if not self._arm_taken: return True ok = self._client.give_arm() if ok: self._arm_taken = False return True else: return False
@property def arm_taken(self) -> bool: """ 現在このクライアントがアームを保持しているかを返す。 Returns: bool: True : アームを保持している False : アームを保持していない Notes: - 実機の状態を直接問い合わせるものではない - 本クラス内で管理している状態フラグの参照のみを行う """ return self._arm_taken # ----------------------------------------------- # SLOT # JoyPad Take/Give Arm buttons # -----------------------------------------------
[ドキュメント] def _on_take_arm(self) -> None: """ UI の「Take Arm」ボタンが押されたときのスロット。 Behavior: - take_arm() を呼び出してアーム取得を試みる - 失敗した場合はログを出力して終了する - 成功した場合は UI ボタンの有効 / 無効状態を更新する Notes: - UI の存在を前提としないため、AttributeError は無視される - JoyPad 側 / CobottaCtrl 側の両方のボタン状態を同時に制御する """ self._logger.info("== on_take_arm()") ok = self.take_arm() if not ok: self._logger.error("take_arm() failed") return try: self.ui.JoyPad_button_take_arm.setEnabled(False) self.ui.JoyPad_button_give_arm.setEnabled(True) self.ui.CobottaCtrl_button_take_arm.setEnabled(False) self.ui.CobottaCtrl_button_give_arm.setEnabled(False) except AttributeError: pass
[ドキュメント] def _on_give_arm(self) -> None: """ UI の「Give Arm」ボタンが押されたときのスロット。 Behavior: - give_arm() を呼び出してアーム解放を試みる - 失敗した場合はログを出力して終了する - 成功した場合は UI ボタンの有効 / 無効状態を更新する Notes: - Take Arm と対称な状態遷移を UI に反映する - UI 非存在環境でも例外を出さない設計になっている """ self._logger.info("== on_give_arm()") ok = self.give_arm() if not ok: self._logger.error("give_arm() failed") return try: self.ui.JoyPad_button_take_arm.setEnabled(True) self.ui.JoyPad_button_give_arm.setEnabled(False) self.ui.CobottaCtrl_button_take_arm.setEnabled(True) self.ui.CobottaCtrl_button_give_arm.setEnabled(False) except AttributeError: pass