はじめに
プログラミング歴が浅いが、IoTデバイスを触ってみたいと思い切ってMESHの人感センサーを購入しました。
人感センサーなので反応する度何か喋ってほしいなと考えていました。
さらに、__喋るならゆっくりに喋ってほしい…__と思いでカスタムタグを作成したので、備忘録として載せます。
そもそもMESHってなに?
MESHとは「無線でつながるIoTデバイス」であり、主な特徴としては以下が挙げられます。(MESH公式サイト)
-
ビジュアルプログラミングアプリがあり、プログラミングが分からなくても簡単にMESHの挙動フロー(MESHレシピ)が作成できる
これはアプリで作成したMESHレシピになるのですが、タグと呼ばれるものを繋げて挙動を決定します。
-
SDKがあり、独自のコード(カスタムタグ)を作成できる
-
MESH HubによりRaspberry Piからコードを動かすことができる
MESHに反応があるとゆっくりに喋るようになるまで
MESH Hubを使ってMESHの人感センサーに反応があるたびにRaspberry Piからゆっくりが喋るカスタムタグを作成してみました。
ざっくりとした流れはこちら
- Raspberry PiからWebAPIサーバを起動する
- MESHのカスタムタグからWebAPIへHTTPリクエストを発行する
- WebAPIの中でsubprocessによりAquesTalkコマンドを実行する
主にSony MESH Hubでミクさんにおかえりを言ってもらったを参考にしています。
ゆっくりに喋ってもらいたかったので、OpenJTalkを使う所はAquesTalkに変えています。
ラズパイからゆっくりに喋ってもらう部分はRaspberry pi で音声会話をするを参考にしました。
# !/usr/bin/perl
# -*- coding:utf-8 -*-
import subprocess
from flask import Flask, request
app = Flask(__name__)
def aquestalk(speech):
cmd = '/home/pi/aquestalkpi/AquesTalkPi -s 80 ' + speech.decode('utf-8') + '| aplay';
// コマンドを実行する
// 実行が成功すると0が返り、失敗するとCalledProcessErrorが生じる
// 詳しくは https://docs.python.jp/3/library/subprocess.html
output = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True)
print(str(output))
return True
def say(speech):
aquestalk(speech)
return speech
// ルーティングをしてURLとPOSTメソッドを紐づける
@app.route('/talk', methods=['POST'])
def handleSay():
speech = request.form['speech'].encode('utf-8')
return say(speech)
def main():
// WebAPIサーバーを起動する
app.run('127.0.0.1')
if __name__ == '__main__':
main()
カスタムタグの作り方はSony MESH Hubでミクさんにおかえりを言ってもらったが詳しいため割愛。
Executeメソッドの実装時に__routeデコレーターの引数とPropertyの設定__を合わせる必要があります。
カスタムタグのExecuteメソッド
// AjaxでアクセスするURL
// routeデコレーターの引数と合わせる
var url = "http://localhost:5000/talk";
// URLに送信したいデータオブジェクト
// PropatyのRefarence Nameと合わせる
var speech = {
"speech" : properties.talk,
};
// Ajaxで非同期通信を行う
// 詳しくは https://meshprj.com/sdk/doc/ja/
ajax({
url: url,
type: 'post',
data: speech,
timeout: 5000,
success: function(success) {
log(success);
callbackSuccess({
resultType: 'continue' // 次のメソッドを呼ぶ
});
},
error: function(request, error) {
log(error);
callbackSuccess({
resultType: 'continue' // 次のメソッドを呼ぶ
});
}
});
// Ajaxは非同期通信であるためイベントハンドラが実行されるまで待つ
return {
resultType: 'pause' // 次のメソッドを呼ばない
};
レシピはお試しでシンプルに喋るだけにしました。
Propertyを設定しておくことでレシピのタグから喋る内容が変えられるようになります。
以下のコマンドを叩いてMESHの人感センサーを反応させるとゆっくりが喋ります。ヤッター!
$ python start.py
MESHとラズパイを使ってゆっくりを喋らせてみた pic.twitter.com/lE7cWc2Mhx
— nori (@nori0__) 2018年10月14日
ハマった点
- MESH HubはRaspbian(Stretch)でしか動かない
(久々ラズパイを動かしたのでRaspbian Jessieで止まっていていたためsudo apt-get update
を何度も実行しました…) - MESH Hubを使う場合、iOS版のMESHアプリでしか対応していない(2018/9/12現在)
-
subprocess.check_output
の引数をリストにした場合、CalledProcessErrorが生じる
# CalledProcessError:Command return non-zero exit status 154が発生
cmd = '/home/pi/aquestalkpi/AquesTalkPi -s 80 ' + speech.decode('utf-8') + '| aplay';
output = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT, shell=True)
subprocess で shell=True でリストを与えたときの挙動によると、shell=Trueを指定した場合、リストではなく文字列を指定しないと適切に引数が渡らないようです。
課題
- 「python start.py」を打ってWebAPIを起動させるのは面倒くさい問題
- ゆっくりが最初の4文字分ほどを喋ってくれない問題
(PropertyのValueに「ゆっくりしていってね」と入れると「していってね」と聞こえてしまい、ラズパイがゆっくりしてくれない)
よって、PropertyのValueが「ゆっくりゆっくりしていってね」にすると「ゆっくりしていってね」と聞こえる。
自身の環境の問題かもしれないが解決策が分からない。