ちょっといきぬき

vimとかpythonとかロボットとかMLとか環境構築とかの興味ある技術のことを書きたいだけの人生だった。

NAOqi Dialog(QiChat)について

教える時用のメモ

基本NAO寄りだけどPepperもおんなじなはず。

※ 2017年10月30日現在

出てくる用語

  • Dialog Topic
    Dialogのメインであるシナリオを記述するテキストファイル。
    シナリオの記述にはQiChatという独自の文法を使用する。
    拡張子は .top
    DialogディレクトリがBehaviorに含まれている場合もあるが、
    基本的なプロジェクトの構成は以下のようになる。
ProjectDirectory
├── ProjectName.pml
├── behavior_1
│   └── behavior.xar
├── manifest.xml
└── Dialog
    ├── Dialog.dlg
    └── Dialog.top
  • Dialog 設定ファイル(仮)
    ドキュメント見てもいまいち正式名称が見つからないので仮。
    Dialogの対応言語やトピックファイルを協調的対話(Collaborative Dialog)として使用するかの情報を格納する。
    拡張子は .dlg で、このファイルをフローダイアグラムにドラッグアンドドロップすることでもDialog Boxを作成できる。

  • Dialog Box
    Behavior上でDialogを扱いたい場合に利用する。
    ボックスの作成方法によってはサンプルのトピックファイルが自動生成されたりするが、
    ボックスの編集画面で任意のトピックに設定可能。

  • Collaborative Dialog
    端的にいうと、オートノーマスライフの対話内容を拡張するオプション。
    Dialog 設定ファイルの「協調的対話としてパッケージコンテンツを追加」にチェックマークを付けたあと、
    Dialogのファイル2種が含まれたプロジェクトをロボットにインストールすることで対話が拡張される。

補足として、オートノーマスライフのDialogを実行している部分はNAOだとrun_dialog_devアプリ。
Pepperは分からぬ。

QiChat Syntaxの用語

広く浅くは色んなサイトやドキュメントで書かれているので割愛。
ハマりポイントやより詳細な挙動を記述するためのTips集。

  • ユーザルール
    文法の基本は u:(Human Imput) Robot Output
    Human Imputには対話テキスト以外にメモリイベントも使用可能。

例えば u:(e:MyEvent) はろー と記述されたDialogの実行中に
ALMemory::raiseEvent('MyEvent', 1); でイベントを発行するとロボットが「はろー」と喋る。

Robot Outputは対話テキストのほか、ルール関数やプロパティを記述できます。

  • ユーザサブルール ユーザルールの先頭の uu1u9 と記述することで
    ユーザルールでは実現が厳しかった対話の流れを記述できる。
    インデントは無くても動く。
u:(こんにちは) こんちわ。

u:(りんごの色は) そんなの簡単、赤ですよ。じゃあ、バナナの色は?
    u1:(黄色) まあ、当然だよね。
    u1:(e:Dialog/NotUnderstood) あれ、難しかったかな?
この時注目したいのがそれぞれのルールのスコープ。  

Dialog実行時のアクティブなスコープは以下の2つ。

u:(こんにちは) こんちわ。
u:(りんごの色は) そんなの簡単、赤ですよ。じゃあ、バナナの色は?

ここで「黄色」と話し掛けてもスコープの範囲外なのでロボットは反応しない。

次に、「りんごの色は」と話し掛けた後にアクティブになるスコープが以下。

    u1:(黄色) まあ、当然だよね。
    u1:(e:Dialog/NotUnderstood) あれ、難しかったかな?

ここにきて「黄色」だったり、いずれのルールにも当てはまらない言葉が入力されるとロボットが反応する。

注意点として、このスコープ時に「こんにちは」と話し掛けるとロボットが「こんちは。」と反応する。
するとスコープもサブルールを抜けた状態になり「黄色」などに反応しなくなる。

例えば、デモンストレーション時など、1個1個のセリフを飛ばさず、順番に、確実に進行したい場合はユーザルール&ユーザサブルールのみでは実現が難しい。

そこでよく利用しているのがProposalだったりする。

  • Proposal
    宣言は proposal: で、機能を要約するとシナリオを関数化することができる。

というと語弊があるが、自分の場合は上記で説明したスコープの管理でよく使います。

通常のユーザルール u はそのトピックが実行している間、常にアクティブになります。

必ず順番通りに喋って欲しい、とか、会場のノイズでスコープがハズレてほしくない等、利用シーンは限られるがこういった場合に便利。

例えば以下のようなシナリオを組んでみます。

イベント利用でロボットを動かしたい。
Dialogが実行されたらMCとの掛け合いを行う。

MC「こんにちは」
ロボット「こんにちは」
MC「今日は暑いですね」
ロボット「そうですね、肩関節のモーターも結構温まっちゃってます」
〜会場ノイズ発生〜
ロボット「ごめんなさい、認識できません」
MC「早速ロボット君に◯◯について説明してもらいましょう」
ロボット「わかりました。〜〜」
MC「◯◯の特徴って何かな?」
ロボット「これには〜」
...

ここで想定したいのがイベント会場のノイズで、NAOもPepperもコミュニケーションロボットなので人の生活シーンにおいて、そばにいる人同時の会話や、環境音などのノイズ入力への対策を行う必要があります。

ユーザルールとユーザサブルールで作るとどんな具合になるでしょうか。

u:(こんにちは) こんにちは
    u1:(今日は暑いですね) そうですね、肩関節のモーターも結構温まっちゃってます
        u2:({早速ロボット君に}◯◯について説明して{もらいましょう}) わかりました。〜〜
            u3:(◯◯の特徴{って何かな}) これには〜
                ...
            u3:(e:Dialog/NotUnderstood)
        u2:(e:Dialog/NotUnderstood) ごめんなさい、認識できません
    u1:(e:Dialog/NotUnderstood) ごめんなさい、認識できません

上記は適当に作ってみましたが、多分上手く動きません。

u u1 u2 と順番に繋げることが出来れば問題ありませんが、 誤って「こんにちは」といった入力が行われるとスコープが u1 に戻ります。

また、e:Dialog/NotUnderstood以降のシナリオが記述されていないためノイズの入力が発生すると途中で対話が止まってしまうはずです。

この設計では、e:Dialog/NotUnderstoodが実行されるたびにユーザサブルールを入れ子のように増やす必要があり、可読性も損なわれます。

では、proposalを利用するとどうなるでしょうか。

u:(e:onStart) ^nextProposal
u:(e:Dialog/NotUnderstood) ごめんなさい、認識できません ^sameProposal

proposal:
    u1:(こんにちは) こんにちは ^nextProposal

proposal:
    u1:(今日は暑いですね) そうですね、肩関節のモーターも結構温まっちゃってます ^nextProposal

proposal:
    u1:({早速ロボット君に}◯◯について説明して{もらいましょう}) わかりました。〜〜 ^nextProposal

proposal:
    u1:(◯◯の特徴{って何かな}) これには〜 ^nextProposal

proposal:
    ...

シナリオが1個1個まとめられていて見やすくないですか(?)

Proposalの宣言文の次に u1と書けば、スコープがProposalにフォーカスされている時のみアクティブなユーザサブルールが作成できます。

最初の u:(e:onStart) はDialogボックスのonStart入力にシグナルが到達すると実行されるイベントで、まあボックスが実行されたらまず最初に行いたい処理を掛けばおkです。

Collaborative Dialogでまずはじめに行いたい処理がある場合は一応 u:(in:onActivation) と書けば動きますが、ドキュメントに載ってなくいつ仕様が変わるか分からないのでオススメできません。

^nextProposal^sameProposal はProposal用のルール関数で、以下のような意味合いです。

・^nextProposal - 次のproposalにフォーカスを移す
・^sameProposal - 同じトピック内で最後に実行されたProposalを繰り返す

^nextProposalはProposalの記述した順に、呼ぶたびに次のProposalへとフォーカスを移します。

u:(e:Dialog/NotUnderstood) ^sameProposalはグローバルスコープで例外をキャッチして元のProposalにフォーカスを戻してるような感じですね。

その他色々なルール関数があるので暇な時にドキュメント読んだりシミュレータで試すのがおすすめです。

NAO用
QiChat - Introduction — Aldebaran 2.1.4.13 documentation http://doc.aldebaran.com/2-1/naoqi/audio/dialog/dialog.html

Pepper用
QiChat - Introduction — Aldebaran 2.4.3.28 documentation http://doc.aldebaran.com/2-4/naoqi/interaction/dialog/dialog.html

その他必須じゃないけどDialogの内部動作を理解するために必要な用語

作成予定

BNFとかコンパイルとかファイルパスとかトラブルシューティングとか