PepperをJavaScriptで動かそう！

# PepperをJavaScriptで動かそう！
執筆／@ExA_DEV 


2014年に登場した感情認識ヒューマノイドロボットPepper（ペッパー）。これを自分で好きに動かすには、Choregrapheと呼ばれる統合開発環境を使用してPepperアプリケーションを開発し、本体にインストールする方法が一般的です。ですが、これをHackするとJavaScriptからPepperを意のままに操ることができます。本記事では、なぜそのようなことが可能なのか、どうすればJavaScriptでPepperを制御できるのかを紹介します。


## どのようなことができるのか
WebブラウザでPepperを制御できます。例えば、Webブラウザの画面にあるボタンを押すとPepperがしゃべり始めたり、前後左右に移動したり、内蔵カメラで撮影したりできます。Webブラウザさえあればいいので、PCだけでなくスマホやタブレットでも使用可能です。


## なぜ、JavaScriptでPepperが制御できるのか
Pepper本体はLinuxで動いていますが、さらにその上にNAOqiというロボット制御OSが搭載されています。NAOqiにはAPIが用意されており、それを通じてPepperに装備されている各種デバイスやメモリの状態の取得や制御ができます。Choregrapheで開発したアプリケーションは内部的にこのAPIをコールすることで種々の動作を実現しています。制御できる対象の1つにPepper胸部に装着されたAndroidタブレットがあります。これは、ユーザに選択肢のボタンを押させたり、商品の説明画像やプロモーションムービーを表示したりする用途を想定して搭載されています。AndroidのWebブラウザが画面を描画しているので、HTML, js, css といったWeb技術が用いられます。Pepper本体側はタブレットに指定のHTMLを表示する機能、タブレット側では画面がタップされたことを検知してPepper本体側に通知する機能が必要です。しかし、タブレットはPepper本体とは完全に切り離され、システム的に独立しています。では、どうやって両者は連携しているのでしょうか。

![Pepper本体と胸部タブレットの関係](https://qiita-image-store.s3.amazonaws.com/0/128323/26f34403-ad1a-3df1-93b9-179a7754ff0d.png)

Pepper本体はタブレットのブラウザを起動し、指定のHTMLファイルを開かせることができます。タブレット側はそのままでは本体にタップなどのイベントを通知できません。そこで、タブレットのブラウザが表示するHTMLファイルにNAOqiのAPIをコールできるオブジェクトを生成する`qimessaging.js`を読み込ませます。そうして、タブレット上のイベントを本体側に通知できる環境が整います。

```
<script src="/libs/qimessaging/1.0/qimessaging.js"></script>
```

Pepper内部では、Webサーバのnginxが立ち上がっています。タブレットブラウザがHTTPリクエストを出すと、Pepperのnginxは`/var/www/`ディレクトリを参照します。このjsファイルは`/var/www/libs/qimessaging/1.0/`ディレクトリに存在します。

`qimessaging.js`を引っこ抜けば、Pepperに装着されているタブレット以外のブラウザからでもPepperを制御できるはず。というわけで実際に試してみたら見事に動いたというわけです。


## PepperをJavaScriptで動かすには
何はともあれ、`qimessaging.js`を手に入れる必要があります。幸い、開発元のAldebaranがGitHubで公開しているので、ありがたくそれを拝借します。version 1.0 のみを使用します。

> aldebaran/libqi-js
> <https://github.com/aldebaran/libqi-js>

以下のようなディレクトリ構成でファイルを配置します。

```
pepper/
  ├── index.html
  ├── js/
  │    └── pepper.js
  └── libs/
       └── qimessaging/
              └── 1.0/
                   ├── qimessaging.js
                   ├── socket.io.min.js
                   └── jquery.min.js
```


続いて、以下のような`index.html`と`pepper.js`を作成します。

```index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8" />
	<title>PepperのJavaScriptサンプル</title>
	<script src="libs/qimessaging/1.0/jquery.min.js"></script>
	<script src="libs/qimessaging/1.0/qimessaging.js"></script>
	<script src="js/pepper.js"></script>
</head>
<body>
	<input type="text" id="ip"></input>
	<button type="button" id="connect-btn">接続</button>
	<button type="button" id="test-btn">テスト</button>
</body>
</html>
```

```pepper.js
$(function(){
	var qis, ip;

	// 接続ボタンclickイベント
	$('#connect-btn').on('click', function(){
		// 入力IP取得
		ip = $('#ip').val();
		// NAOqi Session 生成
		qis = new QiSession(ip);
		// 接続
		qis.socket()
		.on('connect', function(){
			// 接続成功
			console.log('[CONNECTED]');
		})
		.on('disconnect', function(){
			// 接続断
			console.log('[DISCONNECTED]');
		})
		.on('error', function(){
			// 接続エラー
			console.log('[CONNECTION ERROR]');
		});
	});

	// テストボタンclickイベント
	$('#test-btn').on('click', function(){
		// TODO: ここに動作確認のコードを書く
		console.log('[TEST]');
	});
});
```

`index.html`をブラウザで開き、PepperのIPアドレスをテキストボックスに入力して[接続]をクリックします。問題がなければ、ブラウザの開発者ツールに付属するコンソールに「[CONNECTED]」と出るはずです。なお、PepperのIPアドレスは本体に装着されているタブレットの裏側にある電源ボタンを1回押して、「インターネットアドレスは \*.\*.\*.\* デス」と音声で読み上げさせるか、タブレットから設定画面を開いてネットワーク設定で調べます。これで最低限、Pepperとブラウザ間の通信が確保されました。ではいよいよ、NAOqiのAPIを用いてPepperをコントロールしてみましょう。


## NAOqi APIをコールする
Pepperの各種機能をロードするには、以下のように記述します。

```sample01.js
qis.service('<モジュール名>').done(function(ins){
	// TODO: ここにモジュールを使ったコードを書く
});
```

例えば、単純にしゃべらせたい場合は以下の通り。

```sample02.js
qis.service('ALTextToSpeech').done(function(tts){
	tts.say('こんにちは、僕はペッパー！');
});
```

ALTextToSpeechをロードした後、`say`メソッドでしゃべらせています。これらを全て盛り込んだ`pepper.js`は次のようになります。

```pepper.js
$(function(){
	var qis, ip, als = {};

	// 接続ボタンclickイベント
	$('#connect-btn').on('click', function(){
		// 入力IP取得
		ip = $('#ip').val();
		// NAOqi Session 生成
		qis = new QiSession(ip);
		// 接続
		qis.socket()
		.on('connect', function(){
			// 接続成功
			console.log('[CONNECTED]');
			// ALTextToSpeechを使う
			qis.service('ALTextToSpeech').done(function(ins){
				als.alTextToSpeech = ins;
			});
		})
		.on('disconnect', function(){
			// 接続断
			console.log('[DISCONNECTED]');
		})
		.on('error', function(){
			// 接続エラー
			console.log('[CONNECTION ERROR]');
		});
	});

	// テストボタンclickイベント
	$('#test-btn').on('click', function(){
		// Pepperにしゃべらせる
		console.log('[TEST]');
		if(als.alTextToSpeech) als.alTextToSpeech.say('こんにちは、僕はペッパー！');
	});
});
```

## NAOqi内のイベントを監視する
Pepperには多数のセンサが搭載されています。NAOqiは、センサを通して得られたデータを元にイベントを発生させます。例えば、Pepperの前に人が通ればHumanDetected、顔を認識すればFaceDetected、左手の甲を触られたらHandLeftBackTouchedがイベントとして発火します。JavaScriptでこのようなイベントを監視して、イベント駆動なプログラムを組むことができます。イベント監視にはALMemoryを使用します。以下は、左手の甲に触れられたイベントを検知するコードです。

```sample03.js
qis.service('ALMemory').done(function(alMemory){
	alMemory.subscriber('HandLeftBackTouched').done(function(subscriber){
        subscriber.signal.connect(function(val){
        	// イベントが発生すると呼び出される
        	console.log('[EVENT]HandLeftBackTouched:' + val);
        });
    });
});
```


## モジュールの紹介
Pepperにはどのようなモジュールがあるのか、簡単ではありますが表にまとめました。全てを網羅しているわけではありませんが、ここに掲載されているものだけでもいろいろできそうです。さらに詳細を知りたい場合は、Aldebaranの公式APIドキュメントを参照してください。

> NAOqi APIs
> <http://doc.aldebaran.com/2-1/naoqi/>

**JavaScript制御で使えそうなNAOqiモジュール一覧**

| モジュール名 | 機能 | 使えそうなメソッド |
|:-----------|:------------|:------------|
| ALMemory　| NAOqiは key, value の組み合わせで内部状態をメモリ管理しています。ALMemory を使うとそれらの値にアクセスできるようになります。| <nobr>`insertData`</nobr><br />メモリに値を登録<br /><nobr>`getData`</nobr><br />メモリの値を取得<br /><nobr>`raiseEvent`</nobr><br />イベントを発火させる |
| ALBehaviorManager     | Pepperにインストールされたアプリケーション（Behaviorと呼ばれています）の起動や停止を行います。 | <nobr>`stopAllBehaviors`</nobr><br />起動中のBehaviorを全て終了<br /><nobr>`runBehavior`</nobr><br />指定IDのBehaviorを起動する    |
| ALAutonomousLife | Pepperはオートノマスライフと呼ばれる動作モードがあり、デフォルトではsolitaryモードになっています。ALAutonomousLifeはこのモードを制御します。 | <nobr>`getState`</nobr><br />現在のモードを取得する<br /><nobr>`setState`</nobr><br />モードを設定する     |
| ALTabletService | Pepperに装着されているタブレットを制御します。 | <nobr>`showWebview`</nobr><br />ブラウザを起動する<br /><nobr>`enableWifi`</nobr><br />タブレットのwifiを有効化<br /><nobr>`loadUrl`</nobr><br />指定URLを開く<br /><nobr>`showImage`</nobr><br />画像を表示する<br /><nobr>`showInputDialog`</nobr><br />入力欄付きダイアログの表示<br /><nobr>`hideWebview`</nobr><br />ブラウザを閉じる |
| ALMotion       | Pepperにポーズを取らせたり、移動させたりと物理的な動きを制御するほか、スリープモードに切り替えたりできます。 | <nobr>`rest`</nobr><br />スリープモードにする<br /><nobr>`wakeUp`</nobr><br />スリープモードから復帰する<br /><nobr>`robotIsWakeUp`</nobr><br />起きていればtrueを返す<br /><nobr>`moveTo`</nobr><br />移動・回転を行う<br /><nobr>`setAngles`</nobr><br />関節を動かす |
| ALAnimatedSpeech    | 身振り手振りを伴いつつしゃべらせます。 | <nobr>`say`</nobr><br />身振り手振りしつつしゃべる<br /> |
| ALAudioDevice    | 音声の設定を行います。 |  <nobr>`getOutputVolume`</nobr><br />声の大きさを取得する<br /><nobr>`setOutputVolume`</nobr><br />声の大きさを設定する<br /> |
| ALSpeechRecognition    | 簡易的な音声認識を行います。予め登録された語彙に反応します。 | <nobr>`setVocabulary`</nobr><br />認識する語彙を設定する<br /><nobr>`subscribe`</nobr><br />聞き取り開始<br /><nobr>`unsubscribe`</nobr><br />聞き取り停止<br /> |
| ALTextToSpeech    | しゃべらせます。 | <nobr>`say`</nobr><br />しゃべらせる |
| ALBattery    | 内蔵バッテリーの状態を取得します。 |   <nobr>`getBatteryCharge`</nobr><br />バッテリー残量を取得する<br /> |


## まとめ
以上がPepperをJavaScriptで制御する方法でした。実際にPepper開発をしていると動いたり動かなかったりするエラーに見舞われたり、なぜかいきなりPepperが再起動をし始めたりと普通のプログラミング以上に苦労が絶えませんが、思い通りに動くとなかなか楽しいものです。本記事があなたのPepper開発のお役に立てば幸いです。