技術のない人向け　それでも複数台動かしたい

世の中はAzureを使って、とかWebsocketを使って、とか色々な方法でPepperを複数台動かす方法が世にあふれてますが、
「とりあえず動けば何でもいいよ。」という人たちに贈るtipsです。

環境：choregraphe2.4.3.28
------------

#ALProxyについての復習
http://doc.aldebaran.com/2-4/dev/python/making_nao_speak.html
こちらのリンクを見ると

```py
from naoqi import ALProxy
tts = ALProxy("ALTextToSpeech", "<IP of your robot>", 9559)
tts.say("Hello, world!")

```


このような形でロボットのIPとportnumber(9559)をALProxyの引数に入れてあげると、自分の接続しているPepperからほかのPepperのサービスを使うことができます。
要は、ほかのPepperをしゃべらせたり、動かしたりすることができる。という事ですね。

具体的にいうと、Sayボックスをダブルクリックして中にあるSay Textボックスの

```py
    def __init__(self):
        GeneratedClass.__init__(self, False)
        self.tts = ALProxy('ALTextToSpeech')
        self.ttsStop = ALProxy('ALTextToSpeech', True) #Create another proxy as wait is blocking if audioout is remote
```

を

```py
    def __init__(self):
        GeneratedClass.__init__(self, False)
        self.tts = ALProxy('ALTextToSpeech',"192.168.100.xxx",9559)
        self.ttsStop = ALProxy('ALTextToSpeech', True) #Create another proxy as wait is blocking if audioout is remote


```

というように変えてあげればいいだけです。
"192.168.100.xxx"の部分は、自分が接続している機体以外で動かしたいPepperのIPを指定してください。


---------
#session、serviceは無視しよう。
技術がない人向け(自分含む)なので、難しいことは飛ばします。
後で時間があるときにでも調べましょう。

何かというと、Show Imageボックスなどの中身がちょっと前から変わってるんですね。
どういう効果があるのかはいまだによく知らないのですが、

```py
tabletService = self.session().service("ALTabletService")
```

なんていう書き方に変わってます。

なんだか難しそうですね。

ただ、とりあえず

```py
tabletService = ALProxy("ALTabletService")
```

としてしまっても動くんですね。これ。


もっと言うと、

```py
tabletService = ALProxy("ALTabletService","192.168.100.xxx",9559)
````

としてしまっても動きます。

とりあえずほかの人が開発してるPepperのタブレットをガンガン動かしてみましょう。
たぶん、すごく怒られます。


----------
#他のロボットのALMemoryをのぞいてみたい
とはいっても、先ほどまでのALProxyにIPを足す方法では難しいようです。
Raise Eventは可能なのですが、Subscribe to EventやGet Dataができないようです。
このあたりは、非同期処理に対応してないんじゃないかな、とか思いますが、正直、プログラミングの知識がないんでよくわからないですね。
なので、とりあえず小細工で何とかします。

要は
・Pepper AからPepper BのALMemoryが覗ければよい。
・Subscribe to EventやGet DataはできないがRaise Eventは可能。

ということなので、
Pepper Bが自分のALMemoryの内容をPepper AのALMemoryに書き込んであげれば、よさそうですね。
そうすれば、Pepper Aは自身のALMemoryをsubscribeするだけでPepper BのALMemoryを覗くことができそうです。

まずは、例として、Pepper AにPepper Bの首関節のモーターの温度を言ってもらいましょう。

Pepper A
　①Raise Eventボックス：レンチマークを押してeventのところにtestと記入。pythonスクリプトを編集。ALProxy の引数にPepper BのIPを記入
　②Subscribe to Eventボックス：レンチマークを押してeventのところにother/testと記入
　③Say Textボックス：Subscribe to EventボックスのonEvent端子(グレーの出力端子)に入力を接続
![image](https://qiita-image-store.s3.amazonaws.com/0/60999/a0da6df9-0fc4-bdb4-7340-19629da5f0bc.png)


Pepper B
　④Subscribe to Eventボックス：レンチマークを押してeventのところにtestと記入。
　⑤Get Dataボックス：レンチマークを押してeventのところに「Device/SubDeviceList/HeadYaw/Temperature/Sensor/Value」と記入
　⑥Raise Eventボックス：レンチマークを押してeventのところにother/testと記入。pythonスクリプトを編集。ALProxy の引数にPepper AのIPを記入
![image](https://qiita-image-store.s3.amazonaws.com/0/60999/28f3b9eb-d733-b055-e7c9-0c28d1481e79.png)

Pepper Bに接続したChoregrapheで実行した後にPepper Aに接続したChoregrapheで実行してみましょう。

これで「340」とか言ったら成功です。
pepperは小数点を飛ばして発音するので3桁の数字を言ってますが、Pepper Aのダイアログビューなどを見て確認すれば、納得できる数字のはずです。

流れとしては
①で作ったPepper AのRaise EventボックスがPepper BのALMemory の「test」にevent をRaiseします。
④のPepper BのSubscribe to Event ボックスがPepper AからのRaise Eventを検知します。
⑤のGetData ボックスがPepper Bの頭の関節の温度データを取得します。
⑥のRaise EventボックスがPepper AのALMemory「other/test」にeventをRaiseします。
②のPepper AのSubscribe to EventボックスがPepper BからのRaise Eventを検知します。
③Pepper AのALMemory「other/test」の内容を発話します。

というものになります。


------------
#他のロボットで発生したeventを検知してみたい。
たとえば、Pepperを防犯に使ってみる。みたいなデモをするときによいかもしれません。

Pepper Aで実行することは変わりませんが
Pepper Bでは
　④Basic Awarenessボックスを配置。
　⑤ALMemoryからのイベントを追加。「ALBasicAwareness/HumanTracked」
![image](https://qiita-image-store.s3.amazonaws.com/0/60999/5a277c2b-5920-8221-3901-ae2844d3129e.png)
![image](https://qiita-image-store.s3.amazonaws.com/0/60999/43177fbb-4492-0d08-1519-47ce541642c1.png)
　⑥ifボックスの出力端子を右クリックで編集。数値へ。レンチマークを押して「value to compare」を-1に。
![image](https://qiita-image-store.s3.amazonaws.com/0/60999/4d6d7609-cf14-9cbd-819d-4e736e12a566.png)
pythonスクリプトも変更。入力された数値を出力するように改造する。

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

    def onLoad(self):
        #~ puts code for box initialization here
        pass

    def onUnload(self):
        #~ puts code for box cleanup here
        pass

    def onInput_onData(self, p):
        param = self.getParameter("Value to compare")
        try:
            p = float(p)
            param = float(param)
        except:
            p = str(p)
            param = str(param)
        operator = self.getParameter("Condition operator")
        if( operator == "<" ):
            self.outputTrueOrFalse( p < param ,p)
        elif( operator == "< or =" ):
            self.outputTrueOrFalse( p <= param ,p)
        elif( operator == "=" ):
            self.outputTrueOrFalse( p == param ,p)
        elif( operator == "> or =" ):
            self.outputTrueOrFalse( p >= param ,p)
        elif( operator == ">" ):
            self.outputTrueOrFalse( p > param ,p)
        elif( operator == "≠" ):
            self.outputTrueOrFalse( p != param ,p)
        else:
            raise Exception( "Operator not known: " + str(operator) )
        
    def outputTrueOrFalse(self, condition,p):
        if( condition ):
            self.output_then(p)
        else:
            self.output_else(p)

```

![image](https://qiita-image-store.s3.amazonaws.com/0/60999/370e87e0-c209-dd28-7083-08b9552a8af1.png)
ちなみに、ifボックスの追加や、改造は、BasicAwarenessがHumanLostした時などに、「-1」を連発してうるさいから、というだけで、
発生するイベントによっては不要です。



-----------
ちなみに、この複数台、というのは「実機複数台」だけでなく「バーチャルロボット＋実機」でもできる。というのがポイント。
モーションとALMemory周りを人工夫してPEpper開発の最大の障害「複数人がChoregrapheでつなげない」が何とかできないかなー。と
思う今日この頃。