app.cobotta_orin2_ctrl のソースコード

#!/usr/bin/env python
"""
K.NAKADA, kengo.nakada@gmail.com, kengo.nakada@mat.shimane-u.ac.jp
"""
import sys
import traceback
from typing import Any, List, Optional, Sequence
import logging
from pathlib import Path
import time

from cobotta2.server_fastapi import SyncCobottaClient

from x_logger import XLogger

logging.getLogger("httpx").setLevel(logging.WARNING)


[ドキュメント] class CobottaOrin2Ctrl: """ ORiN2 / FastAPI ベースの COBOTTA 制御を行うコントローラクラス。 本クラスは以下の責務を持つ。 - SyncCobottaClient を用いた同期型 COBOTTA 制御の初期化 - モータ ON / OFF 操作の仲介 - アーム Take / Give 操作の実行 - GUI(CobottaCtrl / JoyPad)のボタン状態制御 JoyPad 経由の gRPC 制御とは異なり、本クラスは ORiN2 / FastAPI サーバを I/F とする制御系を担当する。 """ def __init__( self, parent, logger: Optional[XLogger] = None, ): """ CobottaOrin2Ctrl を初期化する。 Args: parent (Any): メイン GUI オブジェクト。 ui 属性を持ち、CobottaCtrl / JoyPad 両方の ボタンウィジェットにアクセス可能であることを前提とする。 logger (XLogger, optional): ログ出力用ロガー。 指定されない場合は本クラス用のデフォルトロガーを生成する。 Notes: - 初期化時に SyncCobottaClient の生成処理を行う - アーム取得状態 (_arm_taken) を内部フラグとして管理する - UI ボタンの初期状態を設定する """ self._parent = parent self._logger = logger or XLogger(logger_name="CobottaOrin2Ctrl") # --- cobotta_client (Sync版) self._client: Optional[SyncCobottaClient] = None self.init() # ------------------------ # UI # ------------------------ self.ui = parent.ui self.ui.CobottaCtrl_button_take_arm.clicked.connect(self._on_take_arm) self.ui.CobottaCtrl_button_give_arm.clicked.connect(self._on_give_arm) try: self.ui.CobottaCtrl_button_take_arm.setEnabled(True) self.ui.CobottaCtrl_button_give_arm.setEnabled(True) except AttributeError: pass self._arm_taken = False
[ドキュメント] def init(self) -> None: """ SyncCobottaClient を生成・初期化する。 Behavior: - Config に定義された SERVER_IP / SERVER_PORT を用いて SyncCobottaClient を生成する - 生成したクライアントを内部に保持する Raises: RuntimeError: Config が未初期化の場合に送出される。 Notes: - 本メソッドは __init__ から自動的に呼び出される - ネットワーク接続自体の成否はここでは判定しない """ self._logger.info("== cobotta_init()") if self._config is None: raise RuntimeError("Config is not initialized") self._logger.info("== Create SyncCobottaClient()") self._logger.info(f"SERVER_IP = {self._config.SERVER_IP}") self._logger.info(f"SERVER_PORT = {self._config.SERVER_PORT}") self._client = SyncCobottaClient( server_ip=self._config.SERVER_IP, server_port=self._config.SERVER_PORT, logger=self._logger, )
[ドキュメント] def trun_off_motor(self) -> bool: """ COBOTTA のモータを停止(OFF)する。 Returns: bool: モータ停止に成功した場合は True、 クライアント未初期化または失敗時は False を返す。 Behavior: - SyncCobottaClient.turn_off_motor() を呼び出す - 失敗時にはエラーログを出力する """ self._logger.info("== turn_off_motor()") if self._client is None: return False ret = self._client.turn_off_motor() if not ret: self._logger.error("***Failed to turn off motor***") return False return True
[ドキュメント] def trun_on_motor(self) -> bool: """ COBOTTA のモータを起動(ON)する。 Returns: bool: モータ起動に成功した場合は True、 クライアント未初期化または失敗時は False を返す。 Behavior: - SyncCobottaClient.turn_on_motor() を呼び出す - 失敗時にはエラーログを出力する """ self._logger.info("== turn_on_motor()") if self._client is None: return False ret = self._client.turn_on_motor() if not ret: self._logger.error("***Failed to turn on motor***") return False return True
[ドキュメント] def give_arm(self) -> bool: """ COBOTTA のアーム制御権を解放する。 Returns: bool: 正常にアーム解放できた場合は True、 失敗または例外発生時は False を返す。 Behavior: - SyncCobottaClient.release_arm() を呼び出す - 成功時は内部フラグ _arm_taken を False に更新する Notes: - クライアント未初期化時は即座に False を返す """ self._logger.info("== give_arm()") if self._client is None: self._logger.error("CobottaClient is not initialized") return False try: ok = self._client.release_arm() if not ok: self._logger.error("Cobotta give_arm returned False") return False except Exception as e: self._logger.error(f"Cobotta give_arm failed: {e}") return False self._arm_taken = False return True
[ドキュメント] def take_arm(self) -> bool: """ COBOTTA のアーム制御権を取得する。 Returns: bool: 正常にアーム取得できた場合は True、 失敗または例外発生時は False を返す。 Behavior: - 一定時間スリープ後に SyncCobottaClient.take_arm() を呼び出す - 成功時は内部フラグ _arm_taken を True に更新する Notes: - ORiN2 側の状態安定を考慮し、呼び出し前に待機時間を挿入している """ self._logger.info("== take_arm()") time.sleep(0.3) if self._client is None: self._logger.error("CobottaClient is not initialized") return False try: ok = self._client.take_arm() if not ok: self._logger.error("Cobotta take_arm returned False") return False except Exception as e: self._logger.error(f"Cobotta take_arm failed: {e}") return False self._arm_taken = True return True
# ----------------------------------------------- # SLOT: cobotta # -----------------------------------------------
[ドキュメント] def _on_give_arm(self) -> None: """ UI の「Give Arm」ボタンが押されたときのスロット。 Behavior: - CobottaCtrl 側の Take / Give ボタン状態を更新する - JoyPad 側の Take / Give ボタン状態を更新する Notes: - 実際のアーム解放処理は本メソッドでは行わない - UI 表示状態の同期のみを担当する """ self._logger.info("== on_give_arm()") try: self.ui.CobottaCtrl_button_take_arm.setEnabled(True) self.ui.CobottaCtrl_button_give_arm.setEnabled(False) except AttributeError: pass try: self.ui.JoyPad_button_take_arm.setEnabled(True) self.ui.JoyPad_button_give_arm.setEnabled(False) except AttributeError: pass
[ドキュメント] def _on_take_arm(self) -> None: """ UI の「Take Arm」ボタンが押されたときのスロット。 Behavior: - CobottaCtrl 側の Take / Give ボタン状態を更新する - JoyPad 側の Take / Give ボタン状態を更新する Notes: - 実際のアーム取得処理は本メソッドでは行わない - UI 操作と制御処理は意図的に分離されている """ self._logger.info("== on_take_arm()") self.ui.CobottaCtrl_button_take_arm.setEnabled(False) self.ui.CobottaCtrl_button_give_arm.setEnabled(True) try: self.ui.JoyPad_button_take_arm.setEnabled(False) self.ui.JoyPad_button_give_arm.setEnabled(False) except AttributeError: pass
pass