# CHANGELOG このファイルは本プロジェクトの変更履歴を記録します。 ## v0.1.2 - 2026-09-09 ### Fixed - Dobot MG400 のモーション実行結果判定を修正。 - `JointMovJ` / `MovJ` / `MovL` のコマンド受付成功だけで `move()` を成功扱いしていた問題を修正。 - blocking モーションでは `Sync()` 後にロボットのエラー状態を確認し、実行中にアラームが発生した場合は `False` を返すよう変更。 - Feedback の `ErrorStatus` と `GetErrorID()` を用いて、コマンド受付後に発生した実行エラーを検出するよう変更。 - モーションコマンド自体の応答が失敗した場合についても、従来どおり失敗として扱う。 - Dobot のアラーム情報取得・表示を修正。 - `GetErrorID()` の返却値を単純な整数列へ平坦化せず、Controller / Servo の区分を保持して解析するよう変更。 - Controller と Servo で同一の alarm ID が存在した場合に、alarm 定義が上書きされ得る実装を修正。 - エラー表示に alarm ID と発生元を含めるよう変更。 - alarm 定義の `jp` を優先して日本語表示し、利用できない場合は既存言語へフォールバックするよう変更。 - `description` に加えて `solution` を取得・表示するよう変更。 - alarm 定義に存在しない情報を補完・推測せず、定義されている内容のみ表示する。 - `GetErrorID()` の生レスポンスログを整理。 - 内部解析用の入れ子配列を通常の `INFO` ログへ出力しないよう変更。 - `GetErrorID()` の生レスポンスは `DEBUG` レベルへ変更。 - 通常運用時は、解析・整形済みのアラーム情報を表示する。 ### Refactored - `dobot_tcp.py` に集中していたエラー処理を `dobot_error.py` へ分離。 - `DobotErrorManager` を追加。 - `GetErrorID()` の取得・解析を分離。 - Controller / Servo alarm の識別処理を分離。 - alarm JSON の読み込み・索引処理を分離。 - エラー説明文の生成処理を分離。 - Feedback `ErrorStatus` を利用したモーションエラー判定を分離。 - モーション直後のエラー監視処理を分離。 - `DobotTcp` の公開エラーAPIは互換性を維持。 - `get_error()` - `get_error_code()` - `get_error_count()` - `get_error_info()` - `get_error_description()` - `get_current_error_info()` - `error_code` - `error_description` 上記APIは維持し、内部処理のみ `DobotErrorManager` へ委譲する構成へ変更。 ### Compatibility - メーカー提供の `dobot_api.py` は変更しない。 - 既存の `DobotTcp` 公開インターフェースを維持する。 ## v0.1.1 - 2026-09-09 ### 変更 - MG400 の実機状態取得を整理。 - `current_position` は Dashboard API `GetPose()` から取得。 - `current_angle` は Dashboard API `GetAngle()` から取得。 - `servo_on` は Feedback の `EnableStatus` から取得。 - `busy_status` は Feedback の `RunningStatus` / `JogStatus` から判定。 - `state()` は基本的な running state として Feedback の `RunningStatus` を使用。 - DOBOT 固有の `RobotMode()` は running state と混同せず別扱いとした。 - MG400 の4軸座標と公開6成分座標の変換を整理。 - Cartesian 座標 `[x, y, z, r]` を `[x, y, z, 0, 0, rz]` として扱う。 - 関節値は MG400 の4軸値を6成分I/Fへ変換し、J5/J6を `0.0` とする。 - User / Tool 座標系定義について4軸MG400に合わせた変換を実装。 - Tool 座標系操作を実装。 - `set_tool_define()` / `set_tool()` を実装。 - `get_tool_define()` / `get_tool()` を実装。 - Tool 定義取得時は現在のTool番号を退避し、対象Toolを選択してFeedbackから取得後、元のToolへ復帰する。 - Work 座標系を MG400 の User 座標系として実装・整理。 - User 座標系定義の取得・設定をMG400の座標表現に合わせた。 - 速度関連I/Fを整理。 - 直線移動速度率は `SpeedL` を使用。 - 関節移動速度率は `SpeedJ` を使用。 - グローバル速度倍率は `SpeedFactor` を使用。 - MG400 APIで同義機能を確認できない減速度・拡張加減速度について、ダミー値を返さないよう整理。 - `approach()` を基準座標+オフセットによる移動として実装。 - Digital I/O の役割を整理。 - Digital Input は `DI()` から取得。 - Output と Input の読み出しを混同しないよう修正。 - 未対応I/Fの扱いを整理。 - 実装されていない機能について `None`、`0`、空文字列などのダミー値で実装済みに見せないよう修正。 - MG400 APIで同義機能を確認できないものは明示的に未対応とした。 - DOBOT固有機能と共通I/Fの意味が一致しない場合、名前が近いAPIへ機械的に割り当てないよう整理。 - `take_arm()` / `give_arm()` をMG400用の互換no-opとして修正。 - MG400には独立したアーム制御権取得・解放操作がないため、ロボットへコマンドを送信せず `True` を返す。 - `EnableRobot()` / `DisableRobot()` への誤った読み替えは行わない。 - Dobot実装内のコメント・docstringを整理。 - 他ロボット、他コントローラ、他API固有の名称・説明をDobot実装から除去。 - コメントとdocstringをMG400/Dobot実装自身の仕様・動作だけで説明する形に統一。 ### 方針 - 共通I/Fの名前だけを根拠にDOBOT APIを割り当てず、I/Fが表す意味を維持して実装する。 - MG400で同義の機能が存在しない場合は、別の機能で代用して意味を変えない。 - 意図的な互換no-opと未実装を区別する。 - メーカー提供コードを直接変更せず、Dobot制御層側で必要な実装・変換を行う。 ## v0.1.0 - 2026-09-08 v0.0.0 から、DOBOT MG400 を共通I/Fで制御するための構成整理と、 実機での基本モーション制御確認までを行った。 ### 共通I/Fと実装層 - `DobotCtrl` をロボット制御の共通公開I/Fとして整理。 - MG400固有の実装を `DobotTcp` に分離。 - DOBOT固有機能は `DobotTcp` 側で扱い、`DobotCtrl` の共通I/Fを維持する構成とした。 - Cartesian pose は共通I/Fで `[x, y, z, rx, ry, rz]` とし、 MG400の `[x, y, z, r]` では `r = rz` として変換するよう整理。 - Joint poseについても共通I/FとMG400の4軸表現の変換を整理。 ### DOBOT公式APIと拡張API - ベンダー提供の `dobot_api.py` は変更せず使用。 - `DobotApiExt`、`DobotApiDashboardExt`、`DobotApiMoveExt` を ベンダークラスの継承・拡張層として使用する構成とした。 - `DobotTcp` は拡張API層を経由してDOBOT公式APIを使用。 - Dashboard 29999、Move 30003、リアルタイムステータス 30004 の接続を整理。 - API通信をloggerへ統合し、`[DobotApi][CONN]`、`[DobotApi][TX]`、 `[DobotApi][RX]` として記録するよう整理。 - `DobotTcp` の制御ログとAPIレベルの通信ログを区別。 ### 基本制御 - `EnableRobot()` / `DisableRobot()` による制御を共通I/Fから利用可能にした。 - speed / acceleration 設定をMG400のDashboard APIへ接続。 - PTP / LINE をMG400の `MovJ()` / `MovL()` に対応。 - TCP/IPコマンドの戻り値を処理し、受付結果を上位へ返す構成を整理。 ### Work / User座標系 - 共通I/FのWork座標系とMG400のUser座標系の対応を整理。 - `change_work()` とMG400の `User(index)` の対応を実装。 - MG400のUser座標系定義・取得を共通I/FのWork座標系操作へ対応させた。 ### モーション制御 - `move()` は共通I/Fの6成分poseを受け、MG400の4成分poseへ変換して送信。 - blocking / non-blocking を `is_async` で選択できる構成とした。 - `wait_for_complete()` ではTCP/IP Moveポートの独立した `Sync()` を使用。 ### blocking / non-blocking の最終修正 開発途中で、DobotStudio Proのスクリプト命令にある `SYNC=0` / `SYNC=1` を、TCP/IP 30003ポートの `MovJ()` / `MovL()` の 動的引数として送信する実装が混入した。 実機では `MovJ(...,SYNC=1)` に対してTCP/IP応答が即座に返り、 共通I/Fで要求するblocking動作にならなかったため、この方式を廃止した。 v0.1.0 の実装は次のとおり。 ```text is_async=True MovJ(...) / MovL(...) -> コマンド受付 -> return is_async=False MovJ(...) / MovL(...) -> コマンド受付 -> Sync() -> モーション完了 -> return ``` これにより、DobotStudio Proスクリプト側の `SYNC` オプションと、 TCP/IP API側の独立した `Sync()` コマンドを分離した。 ### v0.1.0 時点の実機確認 - local direct-control の blocking サンプル:動作確認済み。 - local direct-control の non-blocking サンプル:動作確認済み。 - 上記を v0.1.0 の基本モーション制御の基準実装とする。 ## v0.0.0 - 初期開発版。 - DOBOT MG400制御コードの構成、共通I/F、TCP/IP通信、 モーション制御の開発を開始。 ## 2026-09-08 - 初回記録 DOBOT MG400 制御パッケージについて、ここまでに行った設計・実装・修正内容を初回履歴として整理しました。 ### 共通 I/F と MG400 実装を分離 公開制御 I/F を `DobotCtrl`、MG400 固有実装を `DobotTcp` に分離しました。 ```text DobotCtrl 共通公開 I/F | v DobotTcp MG400 固有実装 ``` `DobotCtrl` は共通 I/F の公開だけを担当し、TCP/IP API の呼び分け、座標変換、リアルタイム状態取得などは `DobotTcp` へ委譲します。 DOBOT 固有で共通 I/F に含める必要のない機能は `DobotTcp` 側に置く方針としました。 ### vendor dobot_api.py を直接変更しない構成へ変更 DOBOT が提供する `dobot_api.py` は vendor コードとしてそのまま保持する方針としました。 追加処理は派生クラス側へ置きます。 ```text DobotApiExt DobotApiDashboardExt DobotApiMoveExt ``` 接続処理、logger による TX/RX/CONN 出力などを vendor コードから分離しました。 ### MG400 の 3 ポート接続を実装 `DobotTcp` で次の 3 接続を管理する構成としました。 ```text 29999 Dashboard 30003 Motion 30004 リアルタイムステータス ``` 30004 番ポートは専用スレッドで受信し、1440 byte のフレームを蓄積・解析して最新状態を保持します。 ### ログ出力を logger に統一 制御層からの出力は logger を使用する方針としました。 ```text [DobotApi][CONN] [DobotApi][TX] [DobotApi][RX] [DobotTcp] [DobotStatus] ``` 接続、送信、受信、状態変化、エラーを区別できるようにしました。 ### Motor ON/OFF を MG400 API に対応 共通 I/F のモータ制御を次の MG400 API に対応させました。 ```text turn_on_motor() -> EnableRobot() turn_off_motor() -> DisableRobot() reset_error() -> ClearError() ``` `take_arm()` / `give_arm()` はモータ ON/OFF とは分離しました。 MG400 TCP/IP API には `TakeArm` / `GiveArm` と同じ制御権概念を確認できないため、これらは共通 I/F を保つ no-op としています。 ### 共通座標表現を 6 成分へ統一 Cartesian 座標の共通 I/F を次の 6 成分としました。 ```python [x, y, z, rx, ry, rz] ``` MG400 の 4 成分 ```python [x, y, z, r] ``` とは次のように変換します。 ```text r = rz rx = 0 ry = 0 ``` MG400 から共通 I/F へ返す場合は、 ```python [x, y, z, 0, 0, r] ``` へ展開します。 Joint も共通 I/F では 6 成分とし、MG400 の 4 軸値を ```python [j1, j2, j3, j4, 0, 0] ``` へ展開します。 ### move() の MG400 変換を実装 基本移動について次の変換を実装しました。 ```text P + PTP -> MovJ P + LINE -> MovL J + PTP -> JointMovJ ``` MG400 API の `SYNC` を共通 I/F の `is_async` に対応させました。 ```text is_async=True -> SYNC=0 is_async=False -> SYNC=1 ``` ### motion_mode と path_blend を分離 軌道種別 `PTP` / `LINE` / `CIRCLE` / `SPLINE` と、経路通過条件 `path_blend` を別概念として扱うよう整理しました。 DOBOT の `CP` は共通 I/F の `path_blend` と同じ意味ではないため、機械的な `path_blend -> CP` 変換は行わないこととしました。 ### 動作完了判定を実装 30004 番ポートの実行状態を使用して、 ```text motion_complete() get_motion_complete() wait_for_complete() ``` を実装しました。 移動命令が受付成功したことと、物理動作が完了したことを分離して扱います。 ### 現在位置・現在角度取得を実装 30004 番ポートから、 ```text tool_vector_actual q_actual ``` を読み、共通 I/F の 6 成分へ変換して返すようにしました。 ### 順運動学・逆運動学を実装 MG400 API を使って次を対応させました。 ```text p2j() -> InverseSolution() j2p() -> PositiveSolution() ``` ### Work 座標系を User 座標系として実装 共通 I/F の Work 座標系を MG400 の User 座標系で実装する方針を確定しました。 役割を次のように分離しています。 ```text set_work() User 座標系を定義する change_work() 定義済み User 座標系を選択する get_current_work_no() 現在の User 番号を取得する get_work() User 座標系定義を取得する ``` `change_work()` は既存の ```text User(index) ``` を使用します。 `get_current_work_no()` は 30004 番ポートの ```text userCoordinate ``` を使用します。 `get_work()` は 30004 番ポートの ```text user ``` を使用します。 `set_work()` は MG400 マニュアルに定義されている ```text SetUser(index,{x,y,z,r}) ``` を使用する実装を追加しました。 vendor `dobot_api.py` に `SetUser()` の Python wrapper が存在しなくても vendor ファイルは変更せず、`DobotTcp` から TCP/IP command を送る構成としました。 共通 I/F の 6 成分 Work 定義 ```python [x, y, z, rx, ry, rz] ``` から MG400 の ```text {x,y,z,r} ``` へ変換し、`r = rz` としています。 `rx` / `ry` が 0 でない Work 座標系は 4 軸 MG400 では表現できないため拒否します。 ### Tool 座標系選択を実装 現在の Tool 番号選択と取得を、 ```text Tool(index) toolCoordinate ``` に対応させました。 Tool 定義そのものの取得・変更についてはまだ未実装です。 ### I/O を実装 共通 I/F の I/O を次へ対応させました。 ```text get_IO() -> 30004 digital_input_bits set_IO() -> DO(index,status) ``` ### エラー取得と説明表示を実装 `GetErrorID()` によるエラー ID 取得と、DOBOT 提供 alarm JSON を用いたエラー説明検索を実装しました。 API command の戻り値先頭が `0` でない場合に、エラー ID と説明を logger へ出力します。 ### FastAPI 層の構成を整理 `DobotCtrl` を device class として FastAPI の自動 dispatch へ渡す構成を採用しました。 同期クライアントと非同期クライアントは HTTP 呼び出し方式の違いとして分離し、ロボット移動の `is_async` とは別概念として扱います。 ### テストスクリプトを各 I/F 単位へ分割 各公開メソッド・property を個別に確認する実行スクリプトを用意しました。 PyCharm が `test_*.py` を自動テストとして認識するため、実機確認用途では `check_*.py` 形式へ変更する運用としました。 各スクリプトは共通ヘルパーへ依存せず、単独で実行可能な構成を採用しています。 ### 未実装 I/F を明示 未実装または部分実装の I/F については、メソッド直前のコメントで理由を明示する方針としました。 特に、 - MG400 の物理構造上できないこと - 現在の公開 API に直接対応するものが確認できないこと - 意味変換がまだ実装できていないこと - 単に現時点で未実装であること を区別して記述します。 ### 現在確認されている主な未実装・部分実装 - `halt()` - `hand_stop()` - `path_blend` の MG400 実動作への変換 - 独立 `decel` - 外部軸速度・加速度・減速度 - `dev()` の完全な座標変換意味 - `move()` の `CIRCLE` / `SPLINE` - `approach()` - `rotate()` - `run_script()` の project name 解決 - hand 制御 - `autocal()` - controller / servo log I/F - Tool 定義の取得・設定 - `direct_mode` - `task` オブジェクト - 実機 version 取得 ### 2026-09-08 の実機確認 MG400 `10.170.10.63` への接続、`EnableRobot()`、`SpeedFactor(30)`、`AccL(30)`、`AccJ(30)` の成功を確認しました。 リアルタイムステータスから、例えば次の形式で現在位置を取得できることも確認しました。 ```python [x, y, z, 0.0, 0.0, rz] ``` 従来のローカルサンプルが MG400 ネイティブの 4 成分 ```python [x, y, z, r] ``` を `move()` へ渡していたため、共通 I/F の 6 成分チェックで拒否されることを確認しました。 今後のサンプルでは、 ```python [x, y, z, 0, 0, rz] ``` を使用します。