Pepperのアプリ開発でタブレットを使用しなければならないときに、まず困るのは仕組みが違うことです。Choregrapheのボックスでもできるのですが、タブレットの座標値で制御するのは面倒ですし、もう1つの手段として、HTML/CSS/JavaScriptで作るにも1からだと大変です。
何かいい資料はないかと探していたらアトリエ秋葉原さんの過去のイベント【アトリエ秋葉原】ディスプレイ(タブレット)技術勉強会の株式会社ヘッドウォータースさんの資料にTapperというフレームワークが紹介されていましたので、今回使用してみました。
参考
こちらの資料を参考にさせていただきました。
株式会社ヘッドウォータースさんの資料 Pepperディスプレイのちょっとしたコツ
注意事項
ソフトバンクロボティクス株式会社のPepperを活用し、独自開発したものです。
環境について
今回使用した環境です。
MacOS Sierra 10.12.2
Choregraphe 2.4.3.28
Pepper
Tapper 0.3
Python 2.7.10
Tapperについて
pepper-devさんが公開されている。ディスプレイ側の開発用フレームワークです。
BSD-Licenceの下でライセンスされています。
http://pepper-dev.github.io/tapper/
ドキュメントも充実しています。
インストール
次のコマンドでTapperコマンドをインストールします。
sudo pip install tapper
テンプレートの作成
TapperはPepperのタブレット用のテンプレートを生成してくれます。
tapper create を実行すると、カレントディレクトリにテンプレートが生成されます。
以下は3画面のテンプレートの作成例です。
-sceneオプションに画面数を指定します。
tapper create --scene 3
Tapper create.
Scene 3
mkdir: ./html
mkdir: ./html/css
mkdir: ./html/js
mkdir: ./html/img
mkdir: ./html/img/preloads
create: ./html/index.html
create: ./html/css/contents.css
create: ./html/css/normalize.css
create: ./html/js/tapper.js
create: ./html/js/contents.js
Succeeded.
プロジェクトへの組み込み
Choregrapheのプロジェクトに組み込みます。
ビヘイビアの位置はルートに変更しておいてください。
sceneについて
Tapperでは画面のことをsceneと呼びます。
先ほどのコマンドで生成されたhtmlがこちらです。idがscene1からscene3までのsectionが作成されていますす。 また、最初に表示されるのは、scene1です。
<body>
<section id="scene1" style="display: block;">
</section>
<section id="scene2" style="display: none;">
</section>
<section id="scene3" style="display: none;">
</section>
</body>
sceneの切り替え方法
scene2に切り替える場合、Pythonでは次のように行います。
self.memory = ALProxy("ALMemory")
self.memory.raiseEvent("Tapper/View/ChangeScene", "2")
タッチイベントについて
初期化時にhtml内のdata-btn-id属性を持つ全てのノード対して、touchstart、touchendのイベントが自動で割り当てられます。
Tapper.view = {
init: function(){
$(document).on('touchstart', '[data-btn-id]', function(){
var node = $(this);
node.addClass('touched');
}).on('touchend', '[data-btn-id]', function(){
var node = $(this);
node.removeClass('touched');
node.addClass('selected');
Tapper.utl.raiseEvent("Tapper/View/ButtonTouched", node.attr('data-btn-id'));
});
},
:
また、touchend時にTapper/View/ButtonTouchedのイベントが発火するので、このイベントに対しての処理を記述することで、画面がタッチされたとか、ボタンが押されたとかの処理に対応することができます。
画像のプレロードについて
画像のプレロード機能もあります。html/img/preloads配下にhtmlで使用する画像を配置し、tapper updateコマンドを実行すると、tapper.jsが書き換えられ、プレロードの処理が追加されます。
tapper update
Tapper update.
load: omocha_robot.png
create: ./html/js/tapper.js
Succeeded.
Tapper.core = function($) {
// T.B.D
var PROXY_LEN = 2;
// image preload
var _preload_img = function() {
var image = [
'img/preloads/omocha_robot.png'
];
$.each(image, function(i, src) {
$('<img>').attr('src', src);
});
}
初期データについて
タブレット側に渡す初期データをALMemoryのTapper/InitData経由で渡すことができます。htmlロード時(Tapper.coreの初期化時)に行われるため、Show Appボックスの実行前にセットする必要があります。値はTapper.init_dataに保持されます。
fileName = self.framemanager.getBehaviorPath(self.behaviorId) + "/init_data.json"
try:
import json
with open(fileName, 'r') as f:
init_data = json.load(f)
self.memory.insertData("Tapper/InitData", json.dumps(init_data))
:
contents.js
tapper.jsはtapperコマンドで置き換わってしまうので、基本的にはcontents.jsに処理を記述することになります。自動生成されたコードには、onLoad、onStart、onScene_[n]_の関数が用意されています。それぞれのイベント時にこれらの関数が実行されれるようになっていますので、画面表示時に何か動的に表示させたいなどといったことが記述できます。
// pepper contents
Tapper.contents = {
onLoad: function() {
console.log("onLoad.");
},
onStart: function() {
console.log("onStart.");
},
onScene1: function() {
console.log("onScene1");
},
onScene2: function() {
console.log("onScene2");
},
onScene3: function() {
console.log("onScene3");
}
}
例:メニューボタンの文字列をinit_dataから設定する
onScene2: function() {
console.log("onScene2");
$("#s2-menu1").append("<p>" + Tapper.init_data["scene2"]["menu1"]["title"]+ "</p>");
$("#s2-menu2").append("<p>" + Tapper.init_data["scene2"]["menu2"]["title"]+ "</p>");
},
contents.css
スタイルシートです。テンプレート生成時は、html, body, sectionの定義しかないので、作成するコンテンツに合わせて追加する必要があります。
/* contents.css */
html, body, section {
height: 100%;
width: 100%;
}
サンプル
実際にTapperを使用して作成したサンプルアプリがこちらです。
https://github.com/piroku/TapperSample
(HTML/CCS/JavaScriptは得意ではないので、あくまで参考ということで・・)
sceneごとの処理はそれぞれのボックスに分けた方が良いです。
scene1がタイトル、scene2がメニュー、scene3がメッセージを表示するような画面といったサンプルを作りました。
sceneのボックスの例がこちらです。scene2はメニュー画面としています。Tapper/View/ButtonTouchedが発火したら、対応するメッセージを発話して、次のボックスに遷移します。
def onInput_onStart(self):
import json
#データの取得
data = self.memory.getData("Tapper/InitData")
self.initdata = json.loads(data)
#シーン2:メニュー画面の開始
self.memory.raiseEvent("Tapper/View/ChangeScene", "2")
def onInput_onTapperButton(self, p):
if(p == "btn-menu1"):
sayText = self.initdata['scene2']['menu1']['say'].encode('utf-8')
self.onMenu1(sayText)
self.onStopped()
elif(p == "btn-menu2"):
sayText = self.initdata['scene2']['menu2']['say'].encode('utf-8')
self.onMenu2(sayText)
self.onStopped()
また、ボタンの表現ですが、data-btn-id属性のノードには selected, touchedクラスが自動付与されるので、メニューの押した感じを少し表現してみました。
#scene2 .selected, #scene3 .selected {
background-color:#4d639f;
}
#scene2 .touched, #scene3 .touched{
position: absolute;
top: 20px;
}
感想
Tapperを使用することで、HTML/CCS/JavaScriptが苦手な私でも、Pepperのタブレット連携をあれこれ悩まずに開発することができました。Choregraphe(Python)側との切り分けが明確なので、タブレット側と、Choregraphe側の分担開発もしやすいのではと思います。
Tapperは、素晴らしいフレームワークですので、ぜひ一度使用してみてください。