Pepperのアプリ開発を3ヶ月やって気づいたこと

# はじめに
Pepperのアプリ開発を3ヶ月やってきて気づいたことを共有します。


# 目的
3ヶ月間開発を行って得られた有益（たぶん）な情報を共有する


# 話の流れ
これまで作ったアプリにはPepper単体で完結するものと、サーバと連携して動作するものがありました。両方開発してきたことにより、Pepper側だけでなくサーバ側の知見もたまってきたのでそれらを紹介します。

話の流れは以下の通りです。Pepper単体に関する部分を主に紹介します。

* 獲得した技術的知見
 * Pepper単体に関する部分
 * サーバ連携に関する部分
* 今やっていること


# Pepper単体に関する部分
まずはPepper単体に関する知見から。ユーザへの応答とPepperらしさとタブレットの使い方の3つに分けて紹介します。

## ユーザへの応答
* 一定時間ユーザの反応がなかったらアプリを終了する
* 想定していない回答に対しても対応する
* 質問に対してはタブレットでも答えられるようにする

### 一定時間ユーザの反応がなかったらアプリを終了する
Pepperのアプリケーションには、ユーザの反応が得られるまでブロックする処理があります。たとえば、質問に対する回答を待つ、QRコードがかざされるのを待つといった処理です。このような処理を行っている最中にユーザがその場を離れてしまうと、Pepperは反応を待ち続けて終了しなくなってしまいます。そのような状況を避けるために、ブロックが行われる処理に対しては必ずタイムアウト時間を設定するようにします。タイムアウト時間を設定するためには、waitボックスを使うことができます。
<img width="1003" alt="スクリーンショット 2015-11-17 15.34.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/77079/d965813f-f443-1940-2571-216e02b81f59.png">

上図では、20秒待って反応が得られなかった場合は終了するようにしています。このように、ブロックする処理に対してはタイムアウトを設定した方が良いと思います。

また、Dialogボックスの場合は以下のようなダイアログスクリプトに、**Dialog/NotSpeaking20**のようなイベントに対する処理を書くとタイムアウトを設定することができます。

```shell-session
u:(e:onStart)野球好き？
  u1:(はい)やったー。$onStopped=1
  u1:(いいえ)しょぼーん。$onStopped=1
u:(e:Dialog/NotSpeaking20) $onStopped=1
```

ちなみに、Dialogボックス中では、待ち時間として以下の4つを設定することができます。

* Dialog/NotSpeaking5
* Dialog/NotSpeaking10
* Dialog/NotSpeaking15
* Dialog/NotSpeaking20


### 想定していない回答に対しても対応する
PepperのDialogボックスには対話のフローを定義することができます。開発者はconceptタグを用いて、聞き取れる単語を増やすことができます。しかしどんなに聞き取れる単語を増やしてもユーザは開発者が想定しない回答をします。そうするとPepperは回答を聞き取ることができないので何も応答しません。その結果、Pepperとユーザとの間に微妙な空気が流れます。そのような状況にしないために、Dialogボックスに**Dialog/NotUnderstood**イベントに対する処理を設定します。これを設定することで、ユーザの発話を聞き取れなかった場合にも対応できるようになります。

```shell-session
concept:(one)   [一人 1人 １人 一名 1名 １名  一 １ 1]
concept:(two)   [二人 2人 ２人 二名 2名 ２名  二 ２ 2]

u:(e:onStart)何名チェックインしますか？
  u1:(~one)一名ですね。わかりました。$peopleNum=1 $onStopped=1
  u1:(~two)二名ですね。わかりました。$peopleNum=2 $onStopped=1
  u1:(e:Dialog/NotUnderstood)ごめんなサイッッ！聞き取れませんでした。何名ですか？^stayInScope
u:(e:Dialog/NotSpeaking20) $onTimeout=1
```
上記の対話で考えてみます。この対話では「何名チェックインするか？」という問いに対して、１名か２名で答えることを期待しています。このとき、３名と答えるとPepperは聞き取れなかったとみなして**Dialog/NotUnderstood**イベントを発生させます。その場合はもう一度聞き直す対応を行っています。

### 質問に対してはタブレットでも答えられるようにする
Pepperの聞き取り精度を向上させるためには、ユーザが言いそうな単語をあらかじめ設定しておく必要があります。しかし、どうしても聞き取れない状況が起きることが考えられます。そのような場合に備えて、タブレットタッチでも回答をできるようにしておくことが望ましいです。

たとえば、ユーザに「はい、いいえ」形式で回答してもらいたい場合には、以下のようにタブレットに表示します。
![yesno.001.jpeg](https://qiita-image-store.s3.amazonaws.com/0/77079/e7be9d46-0c3b-1013-411a-e7d00904df21.jpeg)



## Pepperらしさ
* しゃべり
 * イントネーション（当て字で自然な発話）
 * 抑揚（メリハリつける）
* モーション
 * Animated Say
 * タイムラインボックス

### イントネーションと抑揚
Pepperにしゃべらせるときには、いくつかのパラメータを設定することができます。パラメータを設定することで、Pepperらしさが増します。Sayボックスにはvct=135、rspd=110と設定するとPepperらしいはつらつとした声になります。ここで、vctはピッチ、rspdはしゃべる速さを表しています。
<img width="360" alt="スクリーンショット 2015-11-17 16.30.22.png" src="https://qiita-image-store.s3.amazonaws.com/0/77079/8c326bbd-a4be-63d8-c38c-05b29aa0955b.png">

しかしこれだけでは十分ではありません。Sayボックスに文章を入力して読ませてみても、イントネーションがおかしい場合が多々あります。そこでイントネーションを調整する必要があります。イントネーションを調整するには、以下のように当て字をします。地道な作業ですがこれを行うと見違えるようによくなります。

```
やったー! -> ヤッ田--------ッ
```

抑揚を調整するには、rspdやvctといったパラメータを単語レベル・文字レベルで調整すればいいです。これもまた地道な作業ですが、この作業を行うと見違えるように自然な発話になります。

```
やったー! -> \rspd=100\\vct=160\ヤッ田--------ッ
```

ちなみに、イントネーションや抑揚を調整する時はロボットウェブページから音声を再生して行うのが良いと思います。

### モーション
モーションを全く入れないと、Pepperは棒立ちのままなのでPepperらしさが半減します。Pepperらしいアプリにするには、話しているときはPepperを動かし続けるのがいいです。動かすためには、Animated Sayかタイムラインボックスにモーションを設定します。タイムラインボックスは、決めポーズなどの大きな動作を行うときに使えば良いと思います。


## タブレットの使い方
* コントラストを高く
* 画像のプリロード

### コントラストを高く
タブレットは屋外だと意外と見えにくいことがあります。そのようなときは設定画面からタブレットの輝度を上げるのに加えて、ボタンやその背景色をよく考えて選ぶ必要があります。

### 画像のプリロード
実はPepperはタブレットの部分と本体の部分が分かれています。アプリをインストールするとPepper本体の部分に格納されます。そのため、タブレットにコンテンツを表示するときにはPepper本体からタブレットに転送されてから表示されます。このような仕様のため、アプリケーションが画像の表示命令を出しても転送に時間がかかるのですぐに表示されません。その結果として、表示して欲しいタイミングで画像や動画が表示されないという問題が起こります。それに対する対策として、必要な時に必要なだけ呼び出すのではなく、あらかじめ使うと思われる画像や動画などをタブレットにプリロードしておきます。こうすることで、必要な時に転送しなくて済むようになるので表示がすぐに行われるようになります。


# サーバとの連携に関する部分
## サーバとの連携
基本的にはPepper単体で処理が完結するのですが、時にはサーバで処理を行ってその結果を取得することもあります。

実際にサーバを利用するまでには、以下のような手順を踏むことが多かったです。
1. サーバ側の開発
2. AWSのEC2でインスタンスを作成
3. デプロイ
4. サーバ実行

# 今やっていること
EC2にサーバを用意する方法は、自由度は高いですが色々と面倒くさいです。やりすぎ感があります。たとえば以下のような問題があります。

* Webフレームワークの学習が必要
* 一時間に100アクセスもしないのに、Elastic IP振ってインスタンスを立ち上げっぱなしなのでコストが高い
* サーバ作るので、開発に時間がかかる

AWSに用意されている機能をうまく使って、QCDを高めようと思っています。特にAPI GatewayとLambdaの組み合わせはいい感じです。

* API Gateway、Lambda、DynamoDB、（ElasticBeanStalk）、（S3）

**料金**

* [EC2](https://aws.amazon.com/jp/ec2/pricing/)
* [API Gateway](https://aws.amazon.com/jp/api-gateway/pricing/)
* [Lambda](https://aws.amazon.com/jp/lambda/pricing/)
* [DynamoDB](https://aws.amazon.com/jp/dynamodb/pricing/)
* [S3](https://aws.amazon.com/jp/s3/pricing/)

**AWSの使い方**

* [AWSのAPI GatewayとLambdaを使ってRest APIを書いてみた](http://qiita.com/Hironsan/items/de5dcd42e1c6f6a9b5c7)
* [Amazon API GatewayでAWS Lambda関数にクエリ文字列をパラメータとして渡す](http://qiita.com/yuyakato/items/89fcef9746afbf48977a)

# おわりに
今回は３ヶ月間開発を行ってわかったことをまとめてみました。参考になれば幸いです。