こんにちは、クリエイティブラボのイシイです。

2017年より続けている、体験を通じて未来のクリエイターを育てるワークショップ「FUTURE FACTORY」では、現在はSONYのMESHを使ったテーマが2つあり、ワークショプ開催時にはMESHアプリケーションを動かすためのiPadをレンタルするなどして機材を揃えていますが、制作物をワークショップの場だけでなく、常設のような形で別の場所に設置し続けるとなると、設置用の端末を購入するか、設置期間中ずっと端末のレンタルをし続けるということになってしまいます。

そのため、Raspberry Pi上でMESHのレシピを実行できるというMESHハブアプリケーションを使うことで、こうした課題を解決できないか調査してみることにしました。

MESHハブアプリケーション活用時の問題点

MESHハブアプリケーションを利用するにあたっての問題点として、iOS用/Android用のMESHアプリにある「カメラブロック」「マイクブロック」「スピーカーブロック」などのスマートフォン・タブレット付属の機能が、MESHハブアプリケーションにはないことが挙げられます。

ワークショップのテーマでは「日用品を使ってオリジナルのモンスターをつくる」「あたらしいあそびをつくってみる」などがありますが、これらのワークショップで作った作品を常設するにあたって、これらの不足分のブロックをどう補うのかを考える必要がありました。

カメラ・通知・ミュージックのブロック

これら3つのブロックは、「日用品を使ってオリジナルのモンスターをつくる」「あたらしいあそびをつくってみる」のワークショップテーマでは使用しないようにしています。そのため、常設時にMESHハブアプリケーションに機能がなくても特に問題はないため、別の対応方法は検討しないことにしました。

マイクのブロック

マイクのブロックについては、主に自分の声を録音したり、音の検知に使用したりすることが想定されますが、録音する必要があるのは制作を行うワークショップの時間のときのみであり、常設展示する頃には音は録り終えているので、別途音声ファイルとして用意できれば問題なさそうです。また現状では音の検知によるアクションを起こすものは生まれていません。音の検知によるものが生まれたときは、おそらくGPIOブロックなどを使った対応をする必要になると想定されますが、現状ではまだ不要であるため、マイクのブロックの代替方法の検討は今回は見送ることにしました。

スピーカーのブロック

スピーカーのブロックは、音や声を出したりするのに使われるため、MESHハブアプリケーションを使って常設展示を行おうとするのであれば、スピーカーのブロックの代替が必須になります。そのため、今回はこのスピーカーのブロックの対応を考えてみました。

Raspberry Piでスピーカー機能を再現させる方法の検討

MESHには、MESH SDKというオリジナルのカスタムブロックを作成する機能が提供されているようです。機能の作成にあたってはJavascriptでコードを書けるようなので、こちらでスピーカーの代わりにカスタムブロックを作っていってみることにしました。音そのものの出力には、Raspberry Pi 3の3.5mmオーディオジャックが利用できる小型スピーカーを用意し、そこから音を出すようにしてみます。

仕組みの検討

MESH SDKではJavascriptが書けますが、requireで他のモジュールの読み込みなどをすることができなそうで、音の再生方法をどうするか悩みましたが、MESH SDKのリファレンスマニュアルの提供されているライブラリを見てみる限りだと、Ajaxを使った非同期通信は使えそうだったので、レシピを実行するRaspberry Pi自身にローカルサーバーを立てて、自身からこのAjaxの機能経由で音を再生する仕組みにしてみることにしました。

今回準備したもの

以上から、Raspberry Piでレシピを実行でき、かつスピーカー機能を実現させるために、下記のものを準備してみます。

・ Raspberry Pi 3 Model B
・ MicroSDカード
・ USB ミニスピーカー (DAISOで¥300で購入)

なお、MicroSDカードにはRaspberry Pi公式サイトのRaspbian Stretchがインストールされていて、必要な設定は終わっているものとします。

MESHハブアプリケーションのインストール

まずはRaspberry Pi上でMESHのレシピを実行できるように、Raspberry PiにMESHハブアプリケーションをインストールします。インストールにあたっては、MESH公式サイトに掲載されている「MESHハブのインストールと起動」を参考に、インストールを行います。無事インストール後、

mesh start

でMESHハブアプリケーションが起動するので、初期セットアップを参考に進め、iOS端末からRaspberry Piのレシピを作成できる環境にします。

MESH SDKでカスタムブロックを作成

ここまででMESHのレシピをRaspberry Pi上で実行する環境が整ったので、ここからはスピーカーのブロックの代わりになるものを作っていきます。

MESH SDKで、音声出力用のカスタムブロックを準備してみます。カスタムブロックでは、「音声出力用のカスタムブロックの設定で再生したいファイル名を指定し、カスタムブロックへのなんらかのインプットをトリガーにして、Raspberry Piに格納してある音声をAjax経由で再生させる」という機能を実装してみました。

まず、カスタムブロックへのインプットをトリガーにするため、Connectorの「Input Connector」を1つ設置します。次に、再生したいファイル名をブロック内で設定できるように、Propertyを1つ追加し、Javascript内での参照用の名前(Reference Name)、変数タイプ(Type)、初期値(Default Value)をそれぞれ設定します。

カスタムブロック1

続けて、カスタムブロックのコードの部分を作っていきます。カスタムブロックでは、リファレンスマニュアルの「コードについて」の部分を見ると、Initialize, Receive, Execute, Resultの4つのメソッドに分けられており、動作タイミングに応じて、記述していくようです。

今回作成するカスタムブロックでは、カスタムブロックへのインプットをトリガーにして指定URLにアクセスするだけで、入力の受け取り判別やスケジュール機能などは利用せず、出力の振り分けなども行わないため、上記4つのメソッドのうち、Executeのみに記載していきます。

カスタムブロック2

実際にExecuteに記述したコードは下記になります。

    
var fileName = properties.SoundFileName

var apiURL = "http://localhost:8080/soundplay?filename=" + fileName;
 
ajax ({
    url : apiURL,
    type : "get",
    timeout : 1000,
    success : function ( contents ) {
        log("Sound played.");
        callbackSuccess( {
            resultType : "continue"
        } );
    },
    error : function ( request, errorMessage ) {
        log("API request error occured");
        callbackSuccess( {
            resultType : "continue"
        } );
    }
});
 
return {
    resultType : "pause"
};

これで、ブロック内で設定したファイル名を引数として、レシピを実行しているRaspberry Piのローカルサーバーにアクセスする機能まではできあがりました。

Raspberry Piで音声出力するWeb APIを作成

続けて、Raspberry Piにローカルサーバーを立てて、アクセスしてきた引数を元に音声ファイルを再生する仕組みを作ります。今回はローカルサーバー環境構築のためにNode.jsとExpressを使うことにし、まずはNode.jsのインストールを行います。とりあえず今回はNodeのバージョンは10.xでインストールしてみました。

curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
sudo apt-get install -y nodejs

続けて、npmのアドオンをインストールするためのツールも入れておきます。

sudo apt-get install -y build-essential

Node.jsのインストールが終わったら、今度は今回のプロジェクト用のディレクトリを作成し、Expressと音声ファイル再生用のplay-soundをnpmでインストールします。

mkdir meshhubSoundPlay
cd meshhubSoundPlay
npm init
npm install
npm install express --save
npm install play-sound

インストールが終わったら、音声ファイル格納用のディレクトリも作成しておき、テスト用の音声を入れておきます。

mkdir soundData
cp /usr/share/sounds/alsa/Front_Right.wav soundData/
cp /usr/share/sounds/alsa/Front_Left.wav soundData/

あとは実際に、アクセスしてきた引数を元に音声ファイルを再生する仕組みの構築です。app.jsを作って、下記のようにコードを書いてみました。

    
var express = require("express");
var app = express();

var server = app.listen(8080, function(){
    //console.log("Server port number : " + server.address().port);
});

const player = require('play-sound')();

app.get("/soundplay", function(req, res){

    var soundFilePath = __dirname + "/soundData/";
    var soundFileName = req.query.filename + ".wav";

    if(req.query.filename){
    
        player.play(soundFilePath + soundFileName, err => {
             //console.log(soundFileName);
             if(err) console.log("soundFile not found");      
        });

    } else {
         //console.log("Set soundFileName");
    }
    
});

これで、

node app.js

で実行し、待受状態にしておくことで、カスタムブロックからアクセスしてきたときに、設定したファイル名がsoundDataディレクトリに存在する場合に、音声ファイルを再生することができるようになりました。

foreverでWeb APIをdaemon化

上記まででnodeを実行することで音声ファイルの再生まではできるようになりましたが、なんらかの問題でnodeのプロセスが落ちてしまった場合などに、再度コマンド実行を手動で行い、待受状態にしなければならないため、永続的にプロセスが実行できるようにforeverで起動するようにします。まずはforeverをインストールします。

sudo npm install forever -g

foreverがインストールできたら、実行してみます。

forever start app.js

foreverで実行できているかどうかを、forever listで確認してみます。

forever list
info:    Forever processes running
data:        uid  command       script                           forever pid  id logfile                    uptime                    
data:    [0] fxcA /usr/bin/node /home/pi/meshhubSoundPlay/app.js 919     1096    /home/pi/.forever/fxcA.log 38:7:38:37.35499999998137 

app.jsが動いていることが確認できました。foreverでの実行を止めたいときは、実行しているリストの[]内の番号を引数として

forever stop 0

で止められます。

Raspberry Pi起動時の設定

最後の仕上げです。foreverを使ってプロセス自体は永続的に実行されるようになりましたが、そもそもこのforeverコマンド自体を自動で実行させなければ、毎回Raspberry Piに電源を入れる度にログインしてコマンドを実行しなければならないため、運用するにはかなり不便です。そのため、Raspberry Pi起動時にforeverが実行されるように、cronに設定します。

which forever

で、foreverがインストールされた場所を確認しておき、

crontab -e

でcronの設定画面を開き、起動時に実行される@rebootを使って

@reboot /usr/bin/sudo -u pi /usr/bin/forever start /home/pi/meshhubSoundPlay/app.js

のように設定しておきます。

これで、Raspberry Pi起動時にforeverコマンドで音声ファイル再生用のサーバーとスクリプトが実行される環境が作れました。

動作テスト

iPhone端末からRaspberry PiのMESHハブアプリケーションにアクセスし、カスタムブロックを追加して、ボタンブロックとつないで指定した音声ファイル名を再生させるレシピを作るところまでの流れをやってみました。

動画はMESHハブアプリケーションの操作画面キャプチャのため、スピーカー再生音は含まれていませんが、カスタムブロック内で指定したファイル名.wavの音声ファイルがスピーカーから再生されています。

ひとまずこれで常設展示のRaspberry Pi活用ができそうなので、今後は複数台を設置したときにどのような問題が起こるのか、2.4GHzの電波が多い環境では遅延などはどうなるのか、などの検証を進めていければと思っています。

おまけ

MESHハブアプリケーションをRaspberry Piで実行している場合、MESHハブアプリケーションが正しく実行されている状況なのかがひと目ではわからないので、運用してうまく動いていないときなどに、レシピが正しく実行されているのかどうかがわかると、問題解決が早まります。そんなツールとして、スイッチサイエンスさんからMESH ハブ用 Status boardというものが出ていて、Raspberry PiのGPIOピンに挿しておくと、MESHハブのステータスやネットワーク接続状況などが簡単に確認できるようなので、実運用時にはこういったものを併用するのが良さそうです。