Pepper を複数台連携する方法 - 特大ペッパソン2016 より

# はじめに

この記事は、昨年行われた[特大ペッパソン2016](https://mashupawards.doorkeeper.jp/events/53065)で発表した「フードコート Pepper 」というアプリ内でPepper を複数台連携して動かした方法を基に、記事としてまとめたものです。
このアプリ、特大ペッパソンではエーアイ賞とグローリー賞、Mashup Awards 2016 では Pepperコラボ賞をいただきました。

# Pepper を複数台連携して動かしたい！
Pepper を複数台連携して動かす、とはどんなものなのでしょうか。
発売された直後は品薄状態で、いたとしてもポツンと１台だけだった Pepper。（アトリエ秋葉原にはすでに数台いましたが）
最近では街中でもよく見かけるようになり、一箇所に数台いる光景も少しずつ増えてきています。
そんな中、昨年はこんなイベントが行われました。

[[11/26] 2台以上Pepperを使ったアプリ縛り！Pepperハッカソン@アトリエ秋葉原](https://pepper.doorkeeper.jp/events/54289)
イベントのレポートは[こちら](http://pepper-atelier-akihabara.jp/archives/1778)


また、昨年行われた9台の Pepper によるロボライブも各所で話題になりましたね。

[アキバハロウィンでロボライブオンステージが開催されました](https://robotstart.info/2016/11/06/2525pepper_on_stage.html)


徐々に Pepper が複数台いる環境ができてきた印象です。
こういう取り組みを見ていると、自分でもやってみたくなるものですよね？
ということで、昨年特大ペッパソン2016に参加した際にチャレンジしてみました。
当日の様子は[こちら](http://mashupaward.jp/2016/11/hackathon-pepper/)です。

本記事では、連携する2つの方法と、どのような時に使い分けた方がよいかを紹介していきます。

また、以下の例ではPepper がこのような IP アドレスである場合を対象の例を記載しています。
皆さんの環境に応じて適宜書き換えてください。

Pepper A: 192.168.10.10
Pepper B: 192.168.10.20


# 前提
- Mac OSX El Capitan
- Choregraphe 2.4.3.28 
- Pepper A と Pepper B は同一の LAN に接続


# さっそく連携をしてみよう
## 先達の記事
他にも連携方法をまとめていただいている記事もあるので合わせて参考にしてください。

[技術のない人向け　それでも複数台動かしたい](http://qiita.com/UMasaU/items/36edfc5781cdcb9a718c)

## その１：ボックスで直接IPアドレスとポート番号を指定して実行する
一番シンプルかつ、他の Pepper が動作を行ったことも検知できるので使いやすい方法です。

さっそく Animated Say ボックスで試してみましょう。
Animated Say ボックス をダブルクリックして、さらにその中の Animated Say Text ボックスをダブルクリックします。
`ALProxy('ALAnimatedSpeech')`の部分を以下のように書き換えてみてください。

```python:Animated_Say_Text
import time

class MyClass(GeneratedClass):
    def __init__(self):
        GeneratedClass.__init__(self, False)
        # self.animSpeech = ALProxy('ALAnimatedSpeech')
        self.animSpeech = ALProxy('ALAnimatedSpeech', '192.168.10.20', 9559)

    def onLoad(self):
        self.bIsRunning = False
        self.ids = []
```

ボックスの配置はこんな感じです。

<img width="700" alt="スクリーンショット 2017-03-30 21.02.27.png" src="https://qiita-image-store.s3.amazonaws.com/0/172685/2ca3fb4d-7f89-7d4b-e800-189c5fd35eec.png">

さて、このアプリを **Pepper A で動かしてみる**と…
Pepper B がしゃべります！

この時点でちょっとした感動を覚える訳ですが、そのまま続けていきましょう。

もう一つ Animated Say ボックスを追加して先ほどのボックスと繋げてみましょう。
今度は特に Script をいじることなく、Pepper B がしゃべったことをに対する返答をしゃべらせてみます。

ボックスの配置はこんな感じです。
(わかりやすいようにボックスの名前を変えてあります)

<img width="700" alt="スクリーンショット 2017-03-30 21.11.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/172685/dfb404a3-66cd-2c7c-ac8a-bffb74a92e0b.png">

すると、Pepper B がしゃべった後に　Pepper A がしゃべる、会話（のようなもの）が出来ました！

さて、ここで重要なのは、
**Pepper A で動かしたプロジェクトで Pepper B の動作の終了(onStopped 出力)が取得できる**
ということです。

この方法を用いることで、別の Pepper の動作が終了したあとで次の処理に移ることが出来ます。



## その２：イベントを介して動作を制御する
連携方法その２は、その１の応用です。

こちらの方法では Pepper A と Pepper B それぞれでアプリを起動する必要があって若干面倒ですが、
それなりのメリットもあるので参考にしてみてください。

それではまず、 Pepper A で起動するアプリからです。

Raise Event ボックスを連携方法その１と同じ要領で修正します。

```py
class MyClass(GeneratedClass):
    def __init__(self):
        GeneratedClass.__init__(self)
        pass

    def onLoad(self):
        # self.memory = ALProxy("ALMemory")
        self.memory = ALProxy("ALMemory", '192.168.10.20', 9559)

    def onUnload(self):
        self.memory = None

```

そして、修正した Raise Event の後に Subscribe to Event ボックスを繋げて、
Pepper A をしゃべらせるボックスを置きます。

【Pepper A のアプリ】
<img width="700" alt="スクリーンショット 2017-03-30 21.42.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/172685/1039aea6-4551-0a86-544a-0b06801f5a7b.png">

これは

- 最初に　Pepper B へイベントを飛ばして(Pepper B Raise Event)、
- その後 Pepper B から返ってくるイベントを監視(Subscribe to Event)、
- イベントを取得したら Pepper A がセリフをしゃべる(Pepper A Ani Say)、

という流れになっています。
Pepper B Raise Event ボックスが Script の修正を行ったボックスです。

次に Pepper B のアプリです。
Pepper A で起動したアプリと同様に、以下のように修正した Raise Event ボックスを使用します。

```py
class MyClass(GeneratedClass):
    def __init__(self):
        GeneratedClass.__init__(self)
        pass

    def onLoad(self):
        # self.memory = ALProxy("ALMemory")
        self.memory = ALProxy("ALMemory", '192.168.10.10', 9559)

    def onUnload(self):
        self.memory = None

```

ボックス全体図はこんな感じです。

【Pepper B のアプリ】
<img width="700" alt="スクリーンショット 2017-03-30 21.49.01.png" src="https://qiita-image-store.s3.amazonaws.com/0/172685/d3855eaf-cc92-8e03-8f44-3461befae93b.png">

これは

- 最初に Pepper A からのイベントを監視(Subscribe to Event)、
- イベントを取得したら Pepper B がセリフをしゃべる(Pepper B Ani Say)、
- セリフを終えたら Pepper A にイベントを飛ばす(Pepper A Raise Event)、

という流れになっています。
Pepper A Raise Event ボックスが Script の修正を行ったボックスです。


さて、これで準備が整いました。
まず Pepper B のアプリを起動して、その後 Pepper A のアプリを起動してみましょう。
すると、Pepper B がしゃべった後に　Pepper A がしゃべる、会話（のようなもの）が出来ました！

全体の流れは以下のようになります。

1. 【Pepper B】: Pepper A からのイベントを監視開始
1. 【Pepper A】: Pepper B へイベントを発火、Pepper B からのイベントを監視開始
1. 【Pepper B】: Pepper A からのイベントを取得してセリフを発話、Pepper A へイベント発火
1. 【Pepper A】: Pepper B からのイベントを取得してセリフを発話

つまり、
**各処理のトリガーをイベントを介して行っている**
ということになります。


# ２つの方法の使い分け
方法その１と方法その２、どちらも動かすと、
Pepper B がしゃべる => Pepper A がしゃべる という順序になっており、
一見するとその１の方が簡単でいいのではないか、という気がしてきます。

実際、２体だけ制御する場合では、方法その１の方が作りもシンプルで開発も早いことが多いかと思います。

しかし、今回のサンプルではしゃべらせるのみでしたが、実際は各 Pepper それぞれ動きつつ、しゃべりながら、タブレットにも何かを表示して…といったことを他の Pepper と連携して行うことなるので、
制御する台数が 3台、４台、と増えていくと、制御する側の Pepper のボックス数はそれはそれはスゴイことになってしまいます。

メインとなる Pepper がイベントを各 Pepper に飛ばしてその先の処理は各 Pepper に任せ、
サブの Pepper は処理を終了を通知する、という作りにしておけば、その点はだいぶ解消されます。

まだ試行錯誤中ですが、参考にしていただければ幸いです。

# 最後に
昨年の特大ペッパソン2016では　Pepper 3台で行いましたが、連携する Pepper の台数を若干増やした動画を載せていますのでぜひご覧ください。
大型商業施設やショッピングモールのフードコートなど、複数の店舗が集まっている場所でやれたらいいな、と思っています。

[![Pepper 5台でルーレット](http://img.youtube.com/vi/fz4T0qGjzRU/0.jpg)](http://www.youtube.com/watch?v=fz4T0qGjzRU)