2015/11/12
15:22

Choregraphe Pepperアプリ開発 JavaScript連携(1)

ChoregrapheとJavaScriptによるPepperアプリ開発
テックだ。
ひとまずPepper App Challengeの一次審査応募が終わって一息ついている所だ。
今後は、今回のアプリ開発を経て得た技術の整理もかねて、皆さんへ共有していくぞ。
今回は、タブレットのJavaScriptとPepper(ペッパー)の連携について紹介する。
紹介に入る前に、PepperのNaoQi OSと、タブレットで実行したJavaScriptがお互いどのような関係性となっているかは、以下の記事を参考にしていただきたい。

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

こちらの記事を参考にした上で、本記事では実際にPepperのアプリに組み込む際の実践的な方法を紹介する。

そして前置きとして、JavaScriptとPepperの連携に関しては、大きく分けて二つ方法がある。
一つはPepper側からJavaScriptのイベントを呼ぶ方法、もう一つはJavaScript側からPepperのイベントを呼ぶ方法だ。
二回に分けて、この二つの方法を解説していくぞ。


Pepper⇒JavaScript

今回は、Pepper側からJavaScriptのイベントを呼ぶ方法をやってみよう。
ここでは例として、以下のようなアプリを作るぞ。
○左手を触ると画面に「左手触ったね」と表示
○右手を触ると画面に「右手触ったね」と表示
プロジェクト名は"Test01"として進めていく。


1.HTMLファイルのインポート

まず初めに、タブレットに表示するHTMLをインポートする所から始める。
下図のように、画面左側のプロジェクトファイルのスペースから、+ボタンを押して"新規フォルダを追加"を押してくれ。

ChoregrapheとJavaScriptによるPepperアプリ開発

次にディレクトリの作成ウィンドウが表示されるので、名前を"html"にする。

ChoregrapheとJavaScriptによるPepperアプリ開発

これでプロジェクトファイル内にhtmlフォルダが作成されたぞ。

ChoregrapheとJavaScriptによるPepperアプリ開発

今度は同じく、+ボタンを押して"ファイルをインポート"を押してくれ。

ChoregrapheとJavaScriptによるPepperアプリ開発

インポートするファイルを選択出来るので、以下の内容のHTMLを作成してインポートしてほしい。

test01.html

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <title>Test01 Pepper⇒JS</title>
    <script src="/libs/qimessaging/1.0/qimessaging.js"></script>
    <script>
      var session = new QiSession();

      /** PepperからTablet */
      function startSubscribe() {
        session.service("ALMemory").done(function (ALMemory) {
          ALMemory.subscriber("test01/fromLHand").done(function(subscriber) {
            subscriber.signal.connect(message01);
          });
          ALMemory.subscriber("test01/fromRHand").done(function(subscriber) {
            subscriber.signal.connect(message02);
          });
        });
      }

      function message01() {
        document.getElementById("message").innerHTML = "左手触ったね";
      }

      function message02() {
        document.getElementById("message").innerHTML = "右手触ったね";
      }
    </script>
  </head>

  <body onLoad="startSubscribe();">
    <div style="font-size: 6em" id="message">
      ここにメッセージが表示されるよ
    </div>
  </body>
</html>

プロジェクトファイルに"test01.html"がインポートされたら、今度はそれをhtmlフォルダに移動させる。

ChoregrapheとJavaScriptによるPepperアプリ開発


2.コレグラフでボックスを用意する

次に、コレグラフのボックスライブラリから、以下のボックスを用意してくれ。
・Show Image
・Tactile L.Hand
・Tactile R.Hand
・Raise Event (2つ)

ChoregrapheとJavaScriptによるPepperアプリ開発

ChoregrapheとJavaScriptによるPepperアプリ開発

ChoregrapheとJavaScriptによるPepperアプリ開発


3."Show Image"ボックスを修正する

PepperのタブレットにHTMLを表示する際は"Show App"というボックスを用いる方法が簡単なのだが、このボックスでは"index.html"という名前のHTMLファイルしか表示が出来ない。
そこで、今回は"Show Image"ボックスに少し手を加える事で、任意の名前のHTMLファイルを表示出来るようにする方法も紹介しよう。
まずは、"Show Image"ボックスを開いて、下図のようにスクリプトエディタを表示する。

ChoregrapheとJavaScriptによるPepperアプリ開発

中には、"Show Image"ボックスのPythonコードが記述されているが、最初に以下に示す箇所を見てほしい。

def _getAppName

def _getAppName(self):
  import os
  if self.frameManager:
    behaviorPath = 
      os.path.normpath(self.frameManager.getBehaviorPath(self.behaviorId))
    appsFolderFragment = os.path.join("PackageManager", "apps")
    if not (appsFolderFragment in behaviorPath):
      self.logger.error("appsFolderFragment is not in behaviorPath")
    fragment = behaviorPath.split(appsFolderFragment, 1)[1]
    fragment = fragment.split('/')[1]
    return fragment.lstrip("\\/")
  else:
    self.logger.warning("No ALFrameManager")

"_getAppName"関数の中身に黄色で示したコードを追加だ。
これはコレグラフのパス指定問題を回避するためなのだが、参考記事に詳しく記述されているので、説明は割愛させていただく。
今度はこちらを見て頂きたい。

onInput_onStart 変更前

def onInput_onStart(self):
  tabletService = self._getTabletService()
  if tabletService:
    try:
      url = self.getParameter("ImageUrl")
      if url == '':
        self.logger.error("URL of the image is empty")
      if not url.startswith('http'):
        url = self._getAbsoluteUrl(url)
      tabletService.showImage(url)
    except Exception as err:
      self.logger.error("Error during ShowImage : %s " % err)
      self.onStopped()
  else:
    self.logger.warning("No ALTabletService, can't display the image.")
    self.onStopped()

変更前の"onInput_onStart"関数の内容だが、黄色で示した箇所を以下のように変更してほしい。

onInput_onStart 変更後

def onInput_onStart(self):
  tabletService = self._getTabletService()
  if tabletService:
    try:
      url = self.getParameter("ImageUrl")
      if url == '':
        self.logger.error("URL of the image is empty")
      if not url.startswith('http'):
        url = self._getAbsoluteUrl(url)
      tabletService.loadUrl(url)
      tabletService.showWebview()
    except Exception as err:
      self.logger.error("Error during ShowImage : %s " % err)
      self.onStopped()
  else:
    self.logger.warning("No ALTabletService, can't display the image.")
    self.onStopped()

これで準備は完了だ。
使い方も簡単で、"Show Image"で表示したい画像を指定する時と同じように、左下のスパナマークをクリックし、表示したいHTMLファイルの名前を指定するだけだ。
今回は、"test01.html"という名前で指定すれば良いぞ。

ChoregrapheとJavaScriptによるPepperアプリ開発


4."Raise Event"ボックスの設定をする

次に、"Raise Event"ボックス左下のスパナマークをクリックしてほしい。
ここで発火させたいイベント名を任意に設定する事が出来る。
参考までに、我々がアプリ開発をする時は以下のようなルールで設定しているぞ。

○○(HTMLファイル名)/□□(どのようなイベントか識別しやすい名前)

このようにイベント名を設定する事で、混乱が生まれにくくしている。
今回の例では、
"Raise Event 1"の"key"を"test01/fromLHand"、
"Raise Event 2"の"key"を"test01/fromRHand"、
とするぞ。

ChoregrapheとJavaScriptによるPepperアプリ開発

ChoregrapheとJavaScriptによるPepperアプリ開発


5.ボックスを接続して動作確認をする

最後にボックスを下図のように接続すれば完成だ。

ChoregrapheとJavaScriptによるPepperアプリ開発

Pepperにアップロードして、動作を確認してみよう。
"Show Image"ボックスによって、インポートした"test01.html"の内容が表示されているかと思う。

ChoregrapheとJavaScriptによるPepperアプリ開発

次に、Pepperの左手を触ってみよう。
下図のように、「左手触ったね」と表示される事が確認できるだろうか。

ChoregrapheとJavaScriptによるPepperアプリ開発

続けて、右手を触ったら「右手触ったね」と表示されれば成功だ。

ChoregrapheとJavaScriptによるPepperアプリ開発

ここまでで、上手くいかない方は、以下の問題が考えられる。

○タブレットに画面が表示されない
 →作成したフォルダの名前が"html"になっているか、"Show Image"ボックスでファイル名を正しく指定しているか確認してみてくれ。

○手を触っても文字が切り替わらない
 →各"Raise Event"ボックスに設定した値が正しいか、再度確認してみてほしい。また、Pepperは手の甲でしかタッチ検出をしないので、必ず"backTouched"から線を繋ぐ事。


HTMLファイル解説

無事に動作確認が出来たら、改めてインポートしてもらったHTMLを見てみよう。
まず、こちらを見てほしい。

/** PepperからTablet */
  function startSubscribe() {
    session.service("ALMemory").done(function (ALMemory) {
      ALMemory.subscriber("test01/fromLHand").done(function(subscriber) {
        subscriber.signal.connect(message01);
      });
      ALMemory.subscriber("test01/fromRHand").done(function(subscriber) {
       subscriber.signal.connect(message02);
      });
    });
  }

この"startSubscribe()"関数では、"ALMemory.subscriber()"内で決めたイベントが発火されると、それに対応した関数を呼び出すという処理を行っている。
ちなみにイベント名は任意で決める事が出来るが、"ALMemory.subscriber()"で決めたイベント名とコレグラフ側の"Raise Event"に設定するイベント名は対応させる必要があるぞ。
簡単にまとめるとここでは、
○"Raise Event 1"で"test01/fromLHand"が発火されると"message01"関数を呼ぶ
○"Raise Event 2"で"test01/fromRHand"が発火されると"message02"関数を呼ぶ
という処理を行っているのだ。
呼び出された"message01"関数、"message02"関数では何を行っているかというと、

  function message01() {
    document.getElementById("message").innerHTML = "左手触ったね";
  }

  function message02() {
    document.getElementById("message").innerHTML = "右手触ったね";
  }

id属性で"message"を指定した箇所にそれぞれ「左手触ったね」、「右手触ったね」という文字列を表示しているのだ。


解説は以上だ。
今回はPepper側からJavaScriptを呼び出す方法を紹介したが、いかがだっただろうか。
次回は、JavaScriptからPepperのイベントを呼び出す方法を紹介するぞ。
楽しみにしていてくれ。