QiMessagingでiOSとPepperを相互にやりとりするサンプル
概要
QiMessagingJavaScriptとWebViewJavascriptBridgeを利用しiOSからPepperに命令を送る
& Pepperで発火したイベントの通知をiOSで受け取る
を実装したサンプルです。
iOS側のサンプルはObjCで実装を行っています。
JavaScriptでのpepperとやりとりする部分は先にAndroidで実装していたものを参考にさせて頂きました。感謝です。
注意点
- Pepperと同じネットワークに接続している必要あり
- XcodeのATSの設定を無効にする必要あり
- 実機で検証しました。
Pepper側
今回Pepper側で実装するのはイベントを発火させるだけの処理です。 advancedボックスライブラリ > Memory > Raise Eventボックス
を配置し、適当な変数名「PepperQiMessaging/test」を設定します。この変数名に紐づくPepperのメモリイベントをiOS側のJavaScriptで監視することによってイベントを受け取ることが可能になります。
iOS側
WebViewでJavaScriptが記述してあるHTMLファイルを読み込んでやりとりを行います。細かい手順は以下です。
QiMessaging JavaScript
ライブラリを読み込んであるHTMLファイルをUIWebViewで開くWebViewJavascriptBridge
を利用してObjCとjavascriptをbridgeさせる- JavaScriptの命令を実行することでPepperのNAOqiのAPIに対して操作コマンドを送る、またはpepperのイベントを受け取ってObjCの処理を呼び出す
ExampleApp.html 読み込んでいるjsライブラリ
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript" src="socket.io.min.js"></script>
<script type="text/javascript" src="qi.js"></script>
JavaScriptCore.frameworkで外部ライブラリは利用できない模様なのでWebView主体の方法で実装しています。
iOSからPepperに命令を送る
- QiSessionを生成してpepperとリアルタイムチャット接続を確立する
- pepperに命令を送るためにALProxyのインスタンスを保持
- 登録したメソッドをObjCで呼び出す
InterfaceBuilderで適当にボタンを配置し、押したときの connect
メソッドの中身を以下のように実装します。
ViewController
/**
* pepperと接続開始コマンドを送る
*
* @param sender
*/
- (IBAction)connect:(UIButton *)sender
{
[self.bridge callHandler:@"startConnect" data:PepperIPAddress responseCallback:^(id response) {
NSLog(@"接続するためのjsを叩いたコールバック: %@", response);
}];
}
接続成功時にinit()
とobserve()
を呼び出し、ALProxyのインスタンスを保持、ALMemoryのイベントの監視を開始します(後述)
ExampleApp.html
// pepperと通信を開始する
bridge.registerHandler('startConnect', function(data, responseCallback) {
log('Call Connnect to Pepper With IPAddress : ', data)
qiSession = new QiSession(data);
qiSession.socket().on('connect', function(){
qiSession.service("ALTextToSpeech").done(function(tts){tts.say("接続しました。");})
init();
observe();
var responseData = { 'Javascript Says':'Right back atcha!' }
log('connect Success !!', responseData)
responseCallback(responseData)
})
})
接続に成功したら、あとは命令を送るだけです。ViewControllerでボタンを押したら挨拶する処理を追記します。
ViewController.m
/**
* 挨拶コマンドを送る
*
* @param sender
*/
- (IBAction)hello:(UIButton *)sender
{
[self.bridge callHandler:@"hello" data:@"こんにちは、ペッパーです。" responseCallback:^(id response) {
NSLog(@"挨拶するためのjsを叩いたコールバック: %@", response);
}];
}
ExampleApp.html
// 挨拶コマンドを送る
bridge.registerHandler('hello', function(data, responseCallback) {
log('Call Send Command to next ')
self.textToSpeech.say(data);
responseCallback("コールバックあれば渡す")
})
ボタン押したらpepperがしゃべるはず!
pepperで発火したイベントの通知をiOSで受け取る
- QiSessionを生成してpepperとリアルタイムチャット接続を確立する
- iOS側のjsでイベントを受け取るためにALMemoryのイベントの監視する
- Choregrapheでアプリケーションを再生させてイベントを発火させる
- 対応する処理に通知されiOS側で処理を実行する
手順1. はiOSからPepperに命令を送る
の初期化処理です。接続成功時にobserve()
を呼び出しALMemory.subscriber
によるイベントの監視登録を行っています。
ExampleApp.html
function observe(){
log('イベントコールバック登録')
qiSession.service("ALMemory").done(function(am){
// コレグラフの「RaiseEvent」ボックスで登録した「PepperQiMessaging/test」イベントが発火したときに呼ばれるメソッド
am.subscriber("PepperQiMessaging/test").done(function(subscriber){
subscriber.signal.connect(function(value){
/* 発火時に実行したい処理 */
bridge.callHandler('pepperEvent', {'foo': 'bar'}, function(response) {
log('ペッパーイベント発火時のresponse', response)
})
});
});
});
};
ViewControllerでペッパーが発火させたイベントのコールバックを受け取る処理をViewDidLoadあたりで呼び出して登録しておきます。
ViewController.m
[self.bridge registerHandler:@"pepperEvent" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"ペッパーが発火したイベントをObjCで受け取るサンプル %@", data);
responseCallback(@"ObjCで受け取ったかどうかはNSLogで確認");
}];
Choregrapheでアプリケーションの再生ボタンを押したらiPhoneシュミレータとXcodeにログがでるはず!
TODO
- Choregrapheのバーチャルロボットと繋ぐ方法
- iOSのWebViewで読み込むHTMLファイルのJS部分がネストしてて色々キツイのでどうにかしたい