このページの本文へ

マインクラフトで始めるIoT! PHPとArduinoでゲームの世界を監視してみた

2016年08月21日 04時25分更新

文●Christopher Pitt

  • この記事をはてなブックマークに追加
本文印刷

Minecraftと現実世界をボードコンピューターで接続してみよう!』に続き、Minecraft内での行動をもとに、現実世界のアラームを制御するプログラムを作ります。

このシリーズの最初のパートでは、Minecraftとその中で作られる電気回路について少し学習しました。また、マンションのドアが開きっぱなしになっているときにアラートを鳴らす回路も作りました。そして、このバーチャルアラームをリスニング用のPHPスクリプトにつないで、いつドアが開いたかがPHPスクリプトで分かるようにしました。

記事では、Minecraftで作る電気回路で、小さなArduinoベースのアラーム回路を作ります。公式IDE、プログラム言語、Firmata(と呼ばれるもの)を使って、アラームのトリガーを設定する方法について学びます。最後にMinecraftの回路にアラーム回路を接続し、Minecraftのマンションからリアル世界のアラームを聞けるようにします。

なお、この記事のコードは、ここで入手できます。

Arduinoプログラミングの特別演習

Arduinoはさまざまな趣味に使える回路コントローラーの1つです。大きめなUnoや小さめなMicroなど、いくつかデザインの違うものがあります。

共通するのは、異なるコンポーネント(例:ボタン、センサー、LED)に接続するためのポート/ピンがあるということと、一般的なプログラム言語が使えるという点です。とはいえ使うプログラム言語はCやC++といったもので、Arduino学習の最難関ポイントです。

Arduinoボードは小さくてシンプルなコンピューターで、電気回路の基本部分とプログラム用のインターフェイスがあるものと考えてください。

最初にArduino(またはあとで紹介する代替ソフト)と、アラームブザーまたはLEDを入手する必要があります。

ブザー、LEDにはピンが2つあります。1つはグランド(アースのことで「gnd」または「-」と表記されている場合もあります)用で、もう1つはArduinoのポート/ピンとの接続用です。

The illustration of a circuit

図はFritzingで描きました。素晴らしいソフトですから、ぜひ試してみてください!

次に、公式IDEをダウンロードします。ここにアクセスして自分のOSに合ったバージョンをダウンロードしてください。インストールすると、下の画面が表示されます。

A screenshot of the Arduino IDE

Arduinoの一次的なプログラム言語はCとC++です。関数はPHP7に似ていて、戻り値の型は、キーワードの代わりに使用されます。そのためいくつかのメソッドでは「void(なにも戻さないという意味)」が戻される場合があります。

setup関数は、Arduinoスタートアップと呼ばれます。その名のとおり、ボード上での初期インストールに使います。Arduino上でそれぞれのピン/ポートの隣に数字があるのが分かりますか? 数字は入出力(デジタルおよびアナログ)の際に使います。実際の入出力に使う前に、各ピンの機能を定義することをお勧めします。

多くのArduinoボードには、すでにボード上のLEDに接続された13番のピンが付いています。次のようなコードを使って、切り替えられます。

void setup() {
    pinMode(13, OUTPUT);
}

void loop() {
    digitalWrite(13, HIGH);
}

このコードをArduinoにアップロードする前に、アップロード先になるArduinoのデバイス名を知る必要があります。ターミナルウィンドウを開いて、次のコマンドを実行してください。

ls /dev | grep usbmodem

/dev(OS XやほとんどのLinuxシステムでは、システムにプラグインされたUSBデバイスの名前をこれで探せます)で、すべてのデバイス要素をリストアップできます。リストをGrepコマンドに通し、usbmodemという言葉を含むすべてのデバイスを抽出します。

注意:抽出された要素になにもなかったら、Arduinoに問題があるか、ただUSBがちゃんと繋がっていないだけ、という可能性があります。

Arduino IDEに戻り、適合するArduinoポートを「tools」→「Port」メニューから選んでください。ターミナルコマンドを使わなくてもデバイス名を推測できたかもしれませんが、あとで正確な名前が必要になりますから、実際のデバイス名は知っておいた方が良いです。

正しいポートに設定し、適切なArduinoタイプ(「Tools」から「Board」メニュー)を選択したら、ボードにサンプルをアップロードできるはずです。

An animated image of the IDE in use

Arduino IDEは、CまたはC++で書いたコードで、ボードが理解できるようなバイトコードにコンパイルしいます。ライティング、コンパイル、Arduinoへのコードのアップロードという一連のプロセスは、PHPユーザーにとっては我慢できないほど遅いのです。このあとすぐ、より簡単なアプローチを紹介します。

「File」→「Examples」メニューを通して、Arduinoプログラムのたくさんのサンプルが見られます。C言語の構文やボード能力と格闘しているときには大変助かります!

実際、Arduinoがうまく機能して正しく接続されているかどうかをチェックするためのより簡単な方法は、「Blink」サンプルのアップロードです。

ブザーまたはLEDに正しく接続されていれば、スクリプトを変えて、使うポートをHIGH/Lowから選択できるようになります。しかし、C言語を習得することと、絶えずArduinoへのコードをアップロードし続けなければならないことから、時間がかかってイライラしてしまう手順です。

たまに、コンポーネントの違う動き方を理解するのが難しいときがあります。そこで、スムーズに始められるようなガイドがこれです!

いつものPHPで

ちょっと違う方法を試してみます。Arduinoの世界では、コミュニケーションのための共通言語が存在します。Firmataと呼ばれるプロトコルで、Firmataのおかげでどのような言語でも使えるようになり、自身の技術を飛躍的に拡張できます。

「Examples」→「Firmata」→「Standard Firmata」サンプルと進み、サンプルをArduinoにアップロードしてください。アップロードすると標準的なシリアルインターフェイスでやりとりができるようになります。

今回は『Minecraftと現実世界をボードコンピューターで接続してみよう!』のコードを土台に作業をするので、ここからダウンロードしてください。

以前のコードに、次のように新しいライブラリーを加える必要があります。

composer require carica/firmata

このライブラリーは、Arduinoにアップロードしたばかりの標準的なFirmataプロコルのコードのクライアントとして動作します。Arduinoに接続するために、index.phpに次のコードを加えます。

use Carica\Io;
use Carica\Firmata;

$board = new Firmata\Board(
    Io\Stream\Serial\Factory::create(
        "/dev/cu.usbmodem14141", 57600
    )
);

このコードを実行する前には必ずArduinoのポートを閉じておく必要があります。このコードでArduinoへ接続できますが、ArduinoはPHPスクリプトによってこの接続をブロックしてしまいます。いつまでたってもArduinoに接続できない場合、接続を解除し、同じUSBポートへArduinoを再接続してください。これで、適切な接続のブロックしている空いたポートをすべて閉じられます。

次に、ターミナルコマンド(またはIDEの「Tools」→「ポート」メニューで見つかったもの)から分かったデバイスネームを、cu.usbmodem14141に変更する必要があります。

PHPスクリプトが最終的にArduinoに接続されたときに、次のイベントリスナを加えてください。

$board
    ->activate()
    ->done(
        function() use ($board, $loop, $watcher) {
            $pin = $board->pins[9];
            $pin->mode = Firmata\Pin::MODE_PWM;

            print "connected to Arduino";
        }
    );

$loop->run();

最終的にPHPスクリプトがボードに接続されたあとに実行するためのコールバックを追加します。ここで、『PHP, Arduino, And… Minecraft? Connecting an Arduino to PHP!』でArduino IDからCコードに設定したように、Arduinoのピン/ポートのモードを設定する必要があります。9番のピンをPWM(Pulse-Width Modulation)モードに設定します。

ほとんどのArduinoのピンは、HIGHLOWに設定できます。HIGHに設定されたデバイスのスイッチをオンにするとLEDが光ります。LOWに設定するとスイッチはオフになります。PWMはインクリメンタル・モードで、接続されたデバイスに対して、0から255の間の細かい値で設定してチャージできます。技術的には、PWMは与えられた時間の255分のxのタイミングでHIGHLOWを素早く切り替えられ、切り替えができない場合は自動的にHIGHにセットされます。しかし、見る限りでは、効果に違いは見られません。

ここで、$watcher$loopを使ったことに気づきましたか? $loopはイベントループのインスタンスで、PHPのアプリケーションではまったく一般的ではありません。イベントループやイベントループの仕組みにあまり詳しくない場合は、以前SitePointに投稿した記事『An Introduction into Event Loops in PHP』でイベントループや仕組みを勉強してみてください。

イベントループにコールバックを追加すると、JavaScriptのsetInterval関数に似た考え方が使えます。

print "connecting.";

$board
    ->activate()
    ->done(
        function() use ($board, $loop, $watcher) {
            print "connected.";

            $pin = $board->pins[9];
            $pin->mode = Firmata\Pin::MODE_PWM;

            $loop->setInterval(
                function() use ($pin, $watcher) {
                    // this is called about every second
                },
                1000
            );
        }
    );

JavaScriptのsetInterval関数に似た考え方が使えるため、ログファイルの変更点を調べる目的では、無限ループを使う代わりにイベントループタイマーを使用できます。以下に示す残りのスクリプトを加えれば、9番のピンを0から255の間の値に設定できます。

$loop->setInterval(
    function() use ($pin, $watcher) {
        print "check.";

        $watcher->findChanges();
        $changes = $watcher->getUpdatedResources();

        if (count($changes) > 0) {
            $first = $changes[0];

            $lines = file($first);

            for ($i = count($lines) - 1; $i > -1; $i--) {
                if (stristr($lines[$i], "CHAT")) {
                    if (stristr($lines[$i], "closed")) {
                        print "open.";

                        $pin->analog = 0; // 0/255
                    }

                    if (stristr($lines[$i], "open")) {
                        print "closed.";

                        $pin->analog = 0.5; // 127/255
                    }

                    break;
                }
            }
        }
    },
    1000
);

おおまかに言うなら使っているのは『Minecraftと現実世界をボードコンピューターで接続してみよう!』で作ったものと同じです。今回は、ターミナルに対してopenまたはclosedと書く代わりに、9番目のピンに対して、『Minecraftと現実世界をボードコンピューターで接続してみよう!』でPWM設定で使ったanalog値を設定します。よりシンプルなHIGHまたはLOWの値を使いたい場合、次のようにピンモードをデジタルに設定します。

$pin->mode = Pin::MODE_OUTPUT;

そして、ピンのdigital値をセットします。

if (stristr($lines[$i], "closed")) {
    $pin->digital = 0;
}

if (stristr($lines[$i], "open")) {
    $pin->digital = 1;
}

Gorillaを取り入れる

この作業を通して、ときどきArduino、Firmata、OS Xのリンクが不安定になることがありました。Carica Firmataライブラリーはいくつか異なるメソッド(どのエクステンションが使えるかによります)を使いますし、デフォルトはネイティブなストリームソケットです。都合の悪いことに、新しく接続したあとに自動的にリセットしたバージョンのArduinoとFirmataは、Arduinoと通信する前に短い遅延時間が必要になります。

Carica Firmata内でネイティブなストリームソケットを実行する際、ボードとの間のやりとりがあまりに速いため、起動サイクルを妨害してしまいます。そして、その結果としてトラブルが発生します。

しかし、Carica Firmataがサポートしているエクステンション、Gorillaのインストールによって回避できました。Gorillaの使い方はここにあります。Gorillaを使えるような環境を構築すれば、安定性の問題で苦労をせずにすみます。

同じように使える別のマイクロコントローラーがたくさんあるにもかかわらず、Arduinoにフォーカスしたのは、手元にあったからです。Firmataに対応する別のマイクロコントローラーを持っているなら、今回紹介したコードは役に立つはずです。ただし、ブザーまたはLEDとマイクロコントローラーとの接続方法は自分で見つけないといけませんが…

記事では、回路の半分をMinecraftに、あとの半分はArduinoにうまく実装できました。加えて、PHPを通じてその両方を接続する方法も1つ発見できました。がんばればやり方は見つかるものですね!

(原文:PHP, Arduino, And… Minecraft? Connecting an Arduino to PHP!

[翻訳:島田理彩]
[編集:Livit

Web Professionalトップへ

この記事の編集者は以下の記事をオススメしています