先日イベントで「Subscribe to EventボックスがonStop入力後もイベントを出力してしまう」みたいな指摘があったのですが、Record Videoを直してみたみたいな投稿にもある通り、Choregrapheに添付されたボックスライブラリ群は簡単にAPIの機能などにアクセスできる一方、少々扱いが面倒な部分があります。
今回は、Subscribe to Eventボックスの現在の動きの確認と、所望の動きをする(onStopされたらunsubscribeされる)ボックスへとどのように修正すべきかを個人的に考えてみたのでそのメモ。
Subscribe to Eventボックスの現在の動き
動作確認用ビヘイビアを作りました。動作確認は Choregraphe 2.3.1.25 とバーチャルロボットでおこなっています。
また、今回作成したChoregrapheプロジェクトは、GitHub https://github.com/yacchin1205/pepper-subscribe-to-event に置いてあります。
動作確認用プロジェクトは test で、ビヘイビアの構成はこんな感じ。
Testボックス内でSubscribe to Eventボックスを実行しています。
Subscribe to Eventボックスはテスト用のイベント TestKey1
を購読するよう設定しています。
Raise Eventボックスにより、以下の3つのタイミングで TestKey1
のイベントを発火し、それぞれにSubscribe to Eventボックスがどう反応するかを見ています。
なお、Subscribe to EventボックスがどのRaise Eventボックスに反応したかをわかりやすくするため、それぞれタイミングによりイベントに与える値を変えています。
- Subscribe to EventボックスにonStartが入力された後 - Raise Eventにより
Expected
を発火 - Subscribe to EventボックスにonStopを入力された後(停止状態) -
Unexpected
を発火 - Subscribe to Eventボックスの親ボックスが停止し、ボックスがアンロードされた後 -
Unload
を発火
挙動の確認はログビューアにより行っています。Subscribe to Eventボックスには以下のような接続、修正をおこなっています。
-
Subscribe to EventボックスにLogボックスを接続(Message textは
Test
) -
Subscribe to Eventボックスの
onEventCallback
に以下の行を追加def onEventCallback(self, key, value, message): # テストのため追加-ここから self.logger.info('Called: key=%s value=%s' % (key, value)) # テストのため追加-ここまで self.onEvent(value)
このように、動作確認した内容もビヘイビアとして残しておくことで、テストした内容を残しておくことができ、「以前はどんな動きしてたんだっけ」といったことを確認しやすくなります。
出力されたログ
バーチャルロボットで実行したところ、以下のようなログが得られました。
[INFO ] behavior.box :onInput_message:26 ...__Test_9__Log_1: Test: Expected
[INFO ] behavior.box :onEventCallback:21 ...__Test_9__SubscribetoEvent_7: Called: key=TestKey1 value=Expected
[INFO ] behavior.box :onInput_message:26 ...__Test_9__Log_1: Test: Unexpected
[INFO ] behavior.box :onEventCallback:21 ...__Test_9__SubscribetoEvent_7: Called: key=TestKey1 value=Unexpected
[INFO ] behavior.box :onUnload:10 ...__Test_9__Log_1: Unloaded: Test box
[INFO ] behavior.box :onEventCallback:21 ...__Test_9__SubscribetoEvent_7: Called: key=TestKey1 value=Unloaded
簡単にまとめるとこんな感じ。
状況 | Subscribe to Eventに続くボックスの反応 | onEventCallbackの反応 |
---|---|---|
onStartが入力された後 | あり | あり |
onStopが入力された後 | あり | あり |
アンロードされた後 | なし | あり |
Testボックス内のLogボックスはアンロードされていることをログから確認しているので、Subscribe to Eventボックスがアンロードされなかったということは考えにくそう。
ということは、アンロードされた後も onEventCallback
が呼ばれているような・・・
現在のSubscribe to Eventボックスの停止・アンロード処理における課題
以上からわかった挙動と、Subscribe to Eventボックスのコードを考慮すると、以下の2つの課題がありそうです。
- Subscribe to EventボックスはonStop入力がされても、onStopped出力を発火するだけで、特に購読の停止処理をおこなうことはない
- Subscribe to Eventボックスはアンロードされても購読の停止処理をおこなわず、onEventCallbackの呼び出し自体は継続される
実際の利用上は、Subscribe to Eventボックスがアンロードされるのに合わせて、onEvent出力の出力先のボックスもアンロードされるため、購読自体はアンロードにともない停止されたように見える。ということなのかなと思います。
Subscribe to Eventボックスの修正例
Subscribe to Eventボックスは、現在の実装でも、回避策(適切に他のボックスをアンロードする)をとればまあ利用できないわけではないわけですが、アプリ中での予期しない挙動を防ぐためにも、単純に、
- onStart入力がされると、イベント発生に応じてonEvent出力がされる(開始状態)
- onStop入力がされると、イベントが発生してもonEvent出力がなされなくなる(停止状態)
みたいにしておきたいよね、となるのが開発者の心情です。
そこで、以下のような修正をすることにします。
-
onStop入力がされた際にアンロード相当の処理を実行する
def onInput_onStop(self): # 修正: onStop時にonUnloadを呼び出す self.onUnload() self.onStopped()
-
onUnload時に
ALMemory.unsubscribeToEvent()
を実行するdef onUnload(self): # 修正: unsubscribeToEventを実行する if self.memory is not None: self.memory.unsubscribeToEvent(self.getParameter("key"), self.getName()) self.memory = None
まあ、新規作成直後のPythonボックスの onStop
の記述にも self.onUnload() #it is recommended to reuse the clean-up as the box is stopped
って書いてあることだし・・・ということと、ハンドラを追加したら、適切に削除しましょう。ということで。
修正例の動作確認
testプロジェクトのうち、Subscribe to Eventボックスを上記のような修正をしたバージョンに置き換えたのが、GitHubにおいたコード中の fixed プロジェクトです。
これを実行すると、以下のように期待した動作(Unexpected, Unloadイベントは無視)をするようになります。
[INFO ] behavior.box :onEventCallback:26 ...__Test_9__SubscribetoEvent_7: Called: key=TestKey1 value=Expected
[INFO ] behavior.box :onInput_message:26 ...__Test_9__Log_1: Test: Expected
[INFO ] behavior.box :onUnload:10 ...__Test_9__Log_1: Unloaded: Test box
このように修正したボックスを、 独自ボックスライブラリの作成と管理 などを参考に管理していくと、よりボックスでのアプリ作成が楽になるのでは・・・と思います。
ちなみに、このようなテストや、問題発生時の修正は、独自ボックスでも同じように必要になってくる作業です。他にも個人的におこなっているトライアルがあるので、キリがいいところで投稿していこうと考え中・・・