PepperタブレットにおけるJavaScript活用コンテンツ(QiMessaging JavaScript)

Pepperのタブレットで[画像や動画を表示](http://qiita.com/Atelier-Akihabara/items/87def938b6553ee9c1e9)する方法についてみてきましたが、JavaScriptなどを含むHTMLコンテンツをタブレットで実行することで、よりリッチなコミュニケーションを実現することができます。
ここでは、HTMLコンテンツの基本的な表示方法と、**QiMessaging JavaScript**ライブラリによる、HTMLコンテンツとビヘイビアとを連携する方法について紹介します。

なお、**このサンプルはバーチャルロボットでの動作確認手段はなく、Pepper実機が必要になります。**アルデバラン・アトリエ秋葉原などでPepper実機を使って実験などおこなってみていただければと思います。 (予約URL：http://pepper.doorkeeper.jp/events)

#Pepperとタブレット

Pepperでタブレットアプリケーションを作成するにあたり、Pepperで動作している**NAOqi OS**とタブレットで動作しているソフトウェアの関係を簡単に説明していきます。

##NAOqiでのアプリケーション実行

これまで紹介してきたサンプルの多くが、Choregraphe上でボックスをつないで振る舞いを作成し、実行する形式のサンプルでした。
これらの実行時には、接続されているPepperのNAOqi OS上にアプリケーションのファイル一式がアップロードされたのち、NAOqi OS上でアプリケーションのビヘイビアが実行されるという処理がおこなわれています。

![choregraphe-app.png](https://qiita-image-store.s3.amazonaws.com/0/54394/97d55b36-e298-a958-86c0-00368bc025dd.png)

ビヘイビアは、その中に配置されたボックスが**NAOqi API**([ALMemory](http://qiita.com/Atelier-Akihabara/items/4162192129f366da1240#almemory%E3%82%92%E4%BB%8B%E3%81%97%E3%81%9F%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E5%80%A4%E3%81%AE%E5%8F%96%E5%BE%97), [ALTextToSpeech](http://qiita.com/Atelier-Akihabara/items/3289e60985586b8da709#%E7%B0%A1%E5%8D%98%E3%81%AA%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B) など)にアクセスすることで、さまざまな処理を実現することができます。
このように、Choregrapheで作成したアプリケーションはPepper上で実行される形になります。

##タブレットでの画像や動画の表示

PepperのタブレットではAndroid OSが動作しており、Pepperで動作しているNAOqi OSとは独立したものとして動作しています。 

![choregraphe-web-resources.png](https://qiita-image-store.s3.amazonaws.com/0/54394/5108eb2d-67af-8de1-c186-67da95840086.png)

NAOqi OSとAndroid OSは内部的なネットワークで接続されており、ビヘイビアからは **ALTabletService API** を通じてタブレットに対してブラウザを起動するなどの指示を出したり、タッチイベントを取得したりといったことが可能になっています。
たとえば、[tabletボックスライブラリ](http://qiita.com/Atelier-Akihabara/items/87def938b6553ee9c1e9#%E3%83%9C%E3%83%83%E3%82%AF%E3%82%B9%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9%E3%82%B3%E3%83%B3%E3%83%86%E3%83%B3%E3%83%84%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B)はこれらのAPIを用いることで、NAOqi上からタブレットへの画像表示や動画表示を指示している形になります。

また、タブレット内のブラウザは`ALTabletService`経由で受けた指示に従い、アプリケーションの画像ファイルやHTMLファイルを取得し、表示をおこないます。
これまで「タブレットに表示したいコンテンツはプロジェクト中の `html` ディレクトリに配置する」と説明してきましたが、これはNAOqiが、タブレットのようなNAOqi外のシステムに対しては`html`ディレクトリ内のファイルにのみアクセスを許可するような構造になっているためです。

##QiMessaging JavaScript

タブレットのブラウザでは、通常のWebのコンテンツと同様にJavaScriptを記述し、実行させることができます。
加えて、NAOqiが提供する**QiMessaging JavaScript**ライブラリをHTMLコンテンツ内で読み込むことで、JavaScriptからNAOqiのAPIに対して操作をおこなうことが可能になります。

![qimessaging.png](https://qiita-image-store.s3.amazonaws.com/0/54394/19aa7023-a1bb-c215-ecdf-80425206f7c1.png)


つまり、**QiMessaging JavaScriptを用いることで、HTMLコンテンツからもNAOqiの各機能にアクセスできる**ようになります。
今回は例として、`ALMemory` を介したビヘイビアとHTMLコンテンツの連携についてみていきます。

#試してみる

ここでは、ChoregrapheでのHTMLコンテンツの作成方法から、QiMessaging JavaScriptの利用までを、簡単な例を追ってみていきます。

##プロジェクトファイルの入手方法

このチュートリアルに関するプロジェクトファイルはGitHub https://github.com/Atelier-Akihabara/pepper-qimessaging-examples にて公開しています。
GitHubにあるコードの取得方法にはいくつかありますが、[Download ZIP]リンクからアーカイブを取得するのが簡単な方法のひとつです。他にもgit関連ツールを利用する方法などさまざまな方法がありますので、状況に応じて調べてみてください。

##簡単なHTMLをタブレットに表示

まずは、プロジェクト内に**HTMLで単純なコンテンツを作成し、タブレットに表示**させてみます。

サンプルプロジェクトは **show-app** です。GitHubから取得したファイルのうち、 `show-app` フォルダ内の `show-app.pml` をダブルクリックするなどして開くことができます。

1. `html`ディレクトリを作成する
    プロジェクトの内容パネルの追加ボタンをクリックし、**[ディレクトリの作成...]** をクリックします。
    ![make-directory.png](https://qiita-image-store.s3.amazonaws.com/0/54394/5317a12f-0588-2030-90e0-7235baeaeff0.png)

    名前を `html` として作成すると、プロジェクトファイルとして `html` ディレクトリが作成されます。
    ![html-directory.png](https://qiita-image-store.s3.amazonaws.com/0/54394/4d1eed84-ec23-6080-ef76-fae1ea4f5d5e.png)

2. `index.html`ファイルを作成する
    以下のようなファイルをテキストエディタで作成し、適当な場所に保存します。なお、保存する際の文字コードは**UTF-8**を指定してください。

    ```html
    <!DOCTYPE html>
    <html lang="ja">
      <head>
        <meta charset="UTF-8">
        <title>タブレットに表示したいページ</title>
      </head>
      <body>
        <div style="font-size: 6em">
          タブレットに表示したいページ
        </div>
      </body>
    </html>
    ```

3. `index.html`ファイルをインポートし、`html`ディレクトリ内に配置します
    プロジェクトの内容パネルの追加ボタンをクリックし、**[ファイルのインポート...]** をクリックします。
    ![import-file.png](https://qiita-image-store.s3.amazonaws.com/0/54394/17e138d4-8688-dcbd-35c7-91298bad36b5.png)

    インポートするファイルを問い合わせるダイアログが開きますので、2.で作成した `index.html` を選択します。すると、プロジェクトファイルに `index.html` がインポートされます。
    ![index-html-root.png](https://qiita-image-store.s3.amazonaws.com/0/54394/f2e53c25-5bd1-7c45-2650-582a2716cbef.png)
    
    `index.html`を`html`ディレクトリにマウスドラッグして移動します。
    ![index-html-html.png](https://qiita-image-store.s3.amazonaws.com/0/54394/ba006e9a-af56-88db-adc0-215d84cef8ae.png)

    これでHTMLコンテンツの準備は完了です。


3. ビヘイビアにShow Appボックスを配置する
    **tabletボックスライブラリ > Show Appボックス**をフローダイアグラムにドラッグ＆ドロップし、以下のように接続します。
    ![show-app-flow.png](https://qiita-image-store.s3.amazonaws.com/0/54394/23273484-9fd8-e0b6-e9b6-14d53cd8f52d.png)

4. Show Appボックスを修正する
    Show Appボックスは[Show Imageボックスと同様のパス問題](http://qiita.com/Atelier-Akihabara/items/87def938b6553ee9c1e9#%E8%A3%9C%E8%B6%B3show-image%E3%83%9C%E3%83%83%E3%82%AF%E3%82%B9%E3%81%AE%E5%AE%9F%E8%A3%85%E3%82%92%E3%81%BF%E3%81%A6%E3%81%BF%E3%82%8B)を持っています。そのため、Show Appボックスの `_getAppName` 関数のコードを修正します。

    ```py
            fragment = behaviorPath.split(appsFolderFragment, 1)[1]
            # 以下の1行を追加
            fragment = fragment.split("/")[1]
            return fragment.lstrip("\\/")
    ```

これで、`index.html`の内容をタブレットに表示するアプリケーションの完成です。

###実行する

ChoregrapheでPepperに接続し、**[ロボットにアップロードして再生]**をおこないます。
以下のようにタブレットに `index.html` の内容が表示されれば成功です。

![show-app-pepper.png](https://qiita-image-store.s3.amazonaws.com/0/54394/a958a179-1403-3826-b75d-b1f7cf746917.png)

##簡単なJavaScriptを実行

次に、HTML中に簡単なJavaScriptを記述してみます。JavaScriptの例として、**HTMLコンテンツ上のボタンが押されたらログメッセージを表示する**ことをおこなってみます。

一般にブラウザ上のJavaScriptでは `console.log` APIを用いてログ出力をおこなうことができますが、PepperのタブレットでもこのAPIが提供されており、出力したログメッセージは`ALMemory`のメモリイベント `ALTabletService/message` から取得することが可能です。

サンプルプロジェクトは **simple-js** です。GitHubから取得したファイルのうち、 `simple-js` フォルダ内の `simple-js.pml` をダブルクリックするなどして開くことができます。

1. 先ほど作成した [簡単なHTMLをタブレットに表示] と同じ手順で`html`ディレクトリ、Show Appボックスを準備する
2. 以下のような `index.html` ファイルを作成する
    先と同様の手順で `html`ディレクトリ内に配置します。

    ```html
    <!DOCTYPE html>
    <html lang="ja">
      <head>
        <meta charset="UTF-8">
        <title>単純なJavaScript (ログ出力)</title>
        <script>
          // ログを出力するだけの関数
          // <button>が押されると、onclick属性に指定されたスクリプトが実行され、この関数が
          // 実行されます。
          function sampleButtonClicked() {
            console.log("sampleButtonClicked")
          }
        </script>
      </head>
      <body>
        <div style="font-size: 6em">
          単純なJavaScript (ログ出力)
        </div>
        <button style="font-size: 6em" type="button" onclick="sampleButtonClicked();">ログ出力</button>
      </body>
    </html>    
    ```

    `script` 要素に関数 `sampleButtonClicked` を記述し、これを[ログ出力]ボタンクリック時に実行(`onclick`属性で指定)する形にしています。

2. `ALTabletService/message` メモリイベントをLogボックスにつなぐ
    **メモリイベント追加[+]ボタンをクリック[A]**し、フィルターに**ALTabletServiceと入力[B]**し、**ALTabletService/messageをチェック[C]** し[OK]ボタンを押します。
    ![add-message-event.png](https://qiita-image-store.s3.amazonaws.com/0/54394/ee29695e-e42d-4839-a49c-15f2596d3ccf.png)

    **standardボックスライブラリ > System > Logボックス**をフローダイアグラムに配置し、以下のように **ALTabletService/message 入力とつなぎ[A]**ます。また、ログがタブレットからのものとわかりやすいように、**パラメータのMessage prefixをTabletに変更[B]**します。
    ![message-log.png](https://qiita-image-store.s3.amazonaws.com/0/54394/94e686f3-d2e4-6794-a86e-693a0f527f7b.png)


このようにして、HTMLで呼び出した `console.log` によるメッセージをメモリイベントとして取得し、Choregrapheのログ出力で確認することが可能になります。

###実行する

[ログビューア](http://qiita.com/Atelier-Akihabara/items/7a898f5e4d878b1ad889#-%E5%8F%82%E8%80%83%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%AE%E8%A1%A8%E7%A4%BA%E3%81%A8%E3%83%AD%E3%82%B0%E3%83%93%E3%83%A5%E3%83%BC%E3%82%A2)を開いてログが確認可能な状態にして、プロジェクトを実行してみてください。

まず、タブレットでのブラウザの起動処理などが動作し、以下のようなログが表示されます。

```
[INFO ] behavior.box :onInput_message:27 _Behavior__lastUploadedChoregrapheBehaviorbehavior_11027515016__root__Log_1: Tablet: [INFO] TabletService : Loading application .lastUploadedChoregrapheBehavior
[INFO ] behavior.box :onInput_message:27 _Behavior__lastUploadedChoregrapheBehaviorbehavior_11027515016__root__Log_1: Tablet: [INFO] TabletService : Loading url: 'http://198.18.0.1/apps/.lastUploadedChoregrapheBehavior'
[INFO ] behavior.box :onInput_message:27 _Behavior__lastUploadedChoregrapheBehaviorbehavior_11027515016__root__Log_1: Tablet: [INFO] TabletService : Ping url : http://198.18.0.1/apps/.lastUploadedChoregrapheBehavior response : 200
[INFO ] behavior.box :onInput_onStart:56 _Behavior__lastUploadedChoregrapheBehaviorbehavior_11027515016__root__ShowApp_2: Successfully set application: .lastUploadedChoregrapheBehavior
[INFO ] behavior.box :onInput_message:27 _Behavior__lastUploadedChoregrapheBehaviorbehavior_11027515016__root__Log_1: Tablet: [INFO] TabletService : Show web view
```

この後、タブレットに **[ログ出力]** というボタンがあらわれますので、タブレットをタッチしてボタンを押してみてください。以下のようなログメッセージが表示されるはずです。

```
[INFO ] behavior.box :onInput_message:27 _Behavior__lastUploadedChoregrapheBehaviorbehavior_11027515016__root__Log_1: Tablet: [INFO] WebView : onConsoleMessage : sampleButtonClicked
```

これは、Pepperのタブレット内でJavaScriptが実行され、そこで実行された `console.log` の内容が `ALTabletService/message` メモリイベントを通じてログに出力されたことを意味しています。
JavaScriptでの開発の際は、`console.log`を活用することでスクリプトの動作の把握がしやすくなります。

##アプリケーションとの連携

JavaScriptが動作することが確認できたので、QiMessaging JavaScriptを用いてJavaScriptからNAOqi APIにアクセスしてみましょう。
今回は `ALMemory` を介して、ビヘイビアとHTMLコンテンツを連携させてみます。

###タブレット→アプリケーション

まず、タブレットのJavaScript側からイベントを発行し、これをビヘイビア側で取得してみます。
簡単な例として、**タブレットのボタンが押されたら独自メモリイベント PepperQiMessaging/fromtablet を発行し、ビヘイビア側で渡された値をしゃべる** ということをやってみます。

サンプルプロジェクトは **memory-from-tablet** です。GitHubから取得したファイルのうち、 `memory-from-tablet` フォルダ内の `memory-from-tablet.pml` をダブルクリックするなどして開くことができます。

1. 先ほど作成した [簡単なJavaScriptを実行] と同じ手順で`html`ディレクトリ、Show Appボックス、`console.log`の確認用Logボックスを配置する
2. `PepperQiMessaging/fromtablet` メモリイベント入力を作成する
    今回は独自のキーを持つメモリイベントを利用します。フローダイアグラム上でメモリイベント追加[+]ボタンをクリックし、[メモリイベントの選択]ダイアログを開き、**[新しいキーの追加...]**をクリックします。
    ![add-new-key.png](https://qiita-image-store.s3.amazonaws.com/0/54394/54fdbe49-156b-13f9-1c77-3609d38e5f61.png)

    新しいメモリキー名として、**PepperQiMessaging/fromtabletを入力**します。
    ![new-memory-key.png](https://qiita-image-store.s3.amazonaws.com/0/54394/5c38fb59-84f1-02b0-f38f-d797e74eabe4.png)

    メモリキーの一覧に `PepperQiMessaging/fromtablet` が追加されるので、**これをチェック**します。
    ![custom-key.png](https://qiita-image-store.s3.amazonaws.com/0/54394/f7b00bab-d0e6-7b6c-81ea-e5758fd06426.png)


3. `PepperQiMessaging/fromtablet`メモリイベント入力をSay Textボックスに出力する
    **advancedボックスライブラリ > Audio > Voice > Say Textボックス**を配置し、以下のように接続します。
    ![custom-say.png](https://qiita-image-store.s3.amazonaws.com/0/54394/a3a69300-a872-b69f-c472-1e3eda3470de.png)

4. `index.html`を修正する
    今回は以下のようなHTMLを記述します。

    ```html
    <!DOCTYPE html>
    <html lang="ja">
      <head>
        <meta charset="UTF-8">
        <title>QiMessaging (メモリに出力)</title>
        <script src="/libs/qimessaging/1.0/qimessaging.js"></script>
        <script>
          var session = new QiSession();
          
          function sampleButtonClicked() {
            session.service("ALMemory").done(function (ALMemory) {
              console.log("ALMemory取得成功");
              ALMemory.raiseEvent("PepperQiMessaging/fromtablet", "押したね");
            });
          }
        </script>
      </head>
      <body>
        <div style="font-size: 6em">
          QiMessaging (メモリに出力)
        </div>
        <button style="font-size: 6em" type="button" onclick="sampleButtonClicked();">メモリイベント発生</button>
      </body>
    </html>
    ```

    重要なのは以下の3点です。
    * `qimessaging.js`の読み込み
        以下の`script`要素により、タブレットに`qimessaging.js`をダウンロード・実行します。

        ```html
        <script src="/libs/qimessaging/1.0/qimessaging.js"></script>
        ```
    * `QiSession`オブジェクトの作成
        ページのロード時に、`qimessaging.js`に定義された`QiSession`オブジェクトを初期化しています。JavaScriptは、このオブジェクトを介してNAOqi APIにアクセスできるようになります。

        ```javascript
        var session = new QiSession();
        ```
    * `QiSession`からの`ALMemory`取得、`ALMemory.raiseEvent`呼び出し
        ボタンが押された際の処理で、`session`オブジェクトに対して`service`関数を通じて `ALMemory` へのアクセス用オブジェクトを要求します。
        この取得処理は非同期的に実行され、取得完了時に `function (ALMemory) { ... }` 関数がアクセス用オブジェクト `ALMemory` をともなって呼び出されます。

        ```javascript
            session.service("ALMemory").done(function (ALMemory) {
              console.log("ALMemory取得成功");
              ALMemory.raiseEvent("PepperQiMessaging/fromtablet", "押したね");
            });
        ```
        
このようにして、JavaScript側でボタンが押された際に、`ALMemory.raiseEvent` を実行することで、独自メモリイベント `PepperQiMessaging/fromtablet` に `押したね` という値をつけて発火させています。
ビヘイビア側では`PepperQiMessaging/fromtablet`の値をSay Textボックスに入力することで、JavaScriptで指定された文字列(押したね)をしゃべらせています。

####実行する

このアプリケーションをPepperで再生してみてください。
タブレットに[メモリイベント発生]ボタンが表示されるので、これを押すとPepperが「押したね」としゃべります。

このように、`ALMemory.raiseEvent` により、メモリイベントを介してタブレットからビヘイビアへと処理を伝達することができます。

###アプリケーション→タブレット

今度は逆に、アプリケーションで発火したイベントをJavaScript側で取得してみます。
簡単な例として、**Basic Awarenessで得られた人のIDをメモリイベントを介してタブレットに渡す** ということをやってみます。

サンプルプロジェクトは **memory-to-tablet** です。GitHubから取得したファイルのうち、 `memory-to-tablet` フォルダ内の `memory-to-tablet.pml` をダブルクリックするなどして開くことができます。

1. [簡単なJavaScriptを実行] と同じ手順で`html`ディレクトリ、Show Appボックス、`console.log`の確認用Logボックスを配置する
2. Basic Awarenessボックスを配置する
    **standardボックスライブラリ > Trackers > Basic Awarenessボックス**をドラッグ＆ドロップします。

3. Raise Eventボックスを配置する
    ビヘイビア側でイベントを発火させるため、 **advancedボックスライブラリ > Memory > Raise Eventボックス**を配置し、**パラメータkeyにPepperQiMessaging/totabletを設定**します。
    ![raise-event-box.png](https://qiita-image-store.s3.amazonaws.com/0/54394/9e413f13-6594-4694-5da8-cb0c06322a92.png)

4. ボックスをつなげる
    以下のようにボックスをつなげます。なお、Show AppボックスとBasic Awarenessボックスの間は3秒程度のWaitボックスを挿入しています。今回の例では、タブレットでのコンテンツがロードされたのちにBasic Awarenessが起動するように制御する必要があったのですが、例として単純化するためにWaitで実現しています。
    ![raise-event-flow.png](https://qiita-image-store.s3.amazonaws.com/0/54394/56704d50-cb9c-85af-b625-94c835d907b8.png)
    
4. `index.html`を修正する
    HTMLは以下のようにします。

    ```html
    <!DOCTYPE html>
    <html lang="ja">
      <head>
        <meta charset="UTF-8">
        <title>QiMessaging (メモリを監視)</title>
        <script src="/libs/qimessaging/1.0/qimessaging.js"></script>
        <script>
          var session = new QiSession();
          
          function toTabletHandler(value) {
            console.log("PepperQiMessaging/totabletイベント発生: " + value);
            document.getElementById("memory").innerHTML = value;
          }
          
          function startSubscribe() {
            session.service("ALMemory").done(function (ALMemory) {
              console.log("ALMemory取得成功");
              ALMemory.subscriber("PepperQiMessaging/totablet").done(function(subscriber) {
                subscriber.signal.connect(toTabletHandler);
              });
            });
          }
        </script>
      </head>
      <body onLoad="startSubscribe();">
        <div style="font-size: 6em">
          QiMessaging (メモリを監視)
        </div>
        <div style="font-size: 4em">
          現在のPepperQiMessaging/totabletの値: <span id="memory">不明</span>
        </div>
      </body>
    </html>
    ```

    先の例に加えて重要なのは `ALMemory.subscriber`によるイベントの監視部分です。以下の処理により、`PepperQiMessaging/totablet`メモリイベントが発生した際にJavaScriptで定義した `toTabletHandler` 関数が呼び出されるように設定しています。

    ```javascript
              ALMemory.subscriber("PepperQiMessaging/totablet").done(function(subscriber) {
                subscriber.signal.connect(toTabletHandler);
              });
    ```


####実行する

このアプリケーションをPepperで再生してみて、Pepperに近づいたり、離れたりしてみてください。
Pepperのビヘイビア内、Basic Awarenessボックスが検出した人のIDがタブレットに表示されるはずです。

![basic-awareness.png](https://qiita-image-store.s3.amazonaws.com/0/54394/1e8c578d-8e76-2b2e-edbb-f266247c2bf1.png)

このように、`ALMemory.subscriber` により、ビヘイビアからタブレットへとメモリイベントを伝達することができるようになります。


以上のように、QiMessaging JavaScriptを利用することで、Choregrapheのボックスとタブレットを密接に連携させたアプリケーションを実現することが可能になります。
また、QiMessaging JavaScriptでは、`ALMemory`以外に他にも`ALMotion`などのさまざまなAPIにアクセスすることが可能です。今後は、QiMessagingからAPIへとアクセスする例も扱っていく予定です。