Device Class と Device Proxy を用いたコボッタクライアントの概略
cobotta を SUSANOO で用いるには、Device Class と Device Proxy が必要となる。 Device Class は、cobotta を実際に制御している Class である。
現在は backend として b-CAP もしくは ORiN2 を選択可能な形で、 上位の I/F Class として CobottaCtrl() を用意している。
この CobottaCtrl() を用いて、通信を介さずに cobotta を制御する場合は、
from cobotta2 import CobottaCtrl
client = CobottaCtrl()
client.move("P100")
のように記述する。 ここでは簡略化した例を示しているため、このままでは動作しないが、 概ねイメージは掴めるはずである。
これを、分散型制御フレームワークである ese774_frame 上で記述すると、 クライアント側は
import asyncio
from ese774_frame import DeviceProxy
async def main():
client = DeviceProxy("CobottaCtrl")
await client.move("P100")
asyncio.run(main())
として記述できるようにしてある。
また、sync 形式で書く場合は
import asyncio
from ese774_frame import DeviceProxy
client = DeviceProxy("CobottaCtrl", async_mode=False)
client.move("P100")
と記述することで動作する。
これは Factory デザインパターンで構成してあり、たとえば電子天秤であれば、
import asyncio
from ese774_frame import DeviceProxy
client = DeviceProxy("AanddReader", async_mode=False)
client.meas()
として記述可能である。
ポイントは、DeviceProxy に渡す Device Class の選択を、 実クラスではなく文字列で記述している点にある。
初歩的なプログラムの話で恐縮だが、
import asyncio
from ese774_frame import DeviceProxy
device_class = "AanddReader"
client = DeviceProxy(device_class, async_mode=False)
client.meas()
のように書くことで、client を 動的に切り替え 可能となる。
これは非常に Python 的な設計であり、 Python でプログラムを行う上では、非常に重要なデザインパターンの一つである。

少し脱線したが、SUSANOO フレームワーク・プロジェクトとしてのミソは、 DeviceClass がデバイス装置側に存在しているにもかかわらず、 通信を介したクライアント PC 側に、DeviceProxy を通して 透過的に 存在しているように見える点にある。
実体はサーバ側に存在しているが、フレームワーク側で自動的に透過されることで、 クライアント側へ再現される。
つまり、利用者は通信そのものをほとんど意識せずに扱うことができる。 これが DeviceProxy 形式(透過型)の特徴である。
また、デバイスクラスを実クラスで直接扱う場合は、
import asyncio
from cobotta2.server import AsyncCobottaClient
client = AsyncCobottaClient()
client.move("P100")
ただし、この書き方は Python 的にはやや冗長であり、
import asyncio
from cobotta2.server import SyncCobottaClient
client = SyncCobottaClient()
client.move("P100")
のように、実クラス側には Sync 版と Async 版が存在するため、 少々煩雑になる。
一方で、こちらの方が動作実態としては理解しやすい、という考え方もある。 どちらの記述形式も利用可能である。
DeviceProxy へ DeviceClass を登録する
DeviceClass (DeviceClient) を DeviceProxy へ登録する
from cobotta2.server import AsyncCobottaClient,SyncCobottaClient
from cobotta2.server import cobotta_ctrl_api_spec
from ese774_frame.clients import register_device_proxy
register_device_proxy(
"CobottaCtrl",
async_client_cls=AsyncCobottaClient,
sync_client_cls=SyncCobottaClient,
api_spec=cobotta_ctrl_api_spec,
default_async_mode=True,
aliases=["cobotta"],
)
作者
Kengo NAKADA