ビーコンとArduinoで宝探し! — 神山電子工作クラブ

こんにちは!またまた山下です。徳島もめっきり寒くなってきました。

最近は仕事ではIoTの基礎研究をしながら、木曜日の午後は実践編ということで電子工作をやっています。

おかげさまで弊社とダンクソフト様が主催する放課後電子工作クラブは順調に回を重ね、ご参加いただけるお子さんも増えてきました。

昨日、12/3の回では、iBeacon,パソコン,Arduinoを使った宝探しゲームをしました。総勢6名で組織した探検隊で、地野のあちこちに隠されたお菓子のビンを探知機を頼りに捜索しました。

テストプレイの様子です。この後、もっと遠くからでも光るように調整しました。

パソコンの画面に表示されたストーリーは、ビーコンに近づいたり、ビーコンを取得することで進んでいきます。

パソコンの画面例
パソコンの画面例

今回のシナリオはこんな感じです。

・ 「クマのしゅつぼつするはたけ」にいけ!
・ よくやった!次は「小さなイドのそこ」だぞ!
・ よしいいぞ!最後のお宝のありかを教えてやろう。「ほたるのすみか」だ!
・ おめでとう!お宝は君たちのものだ。次は君たちで宝を隠してみよう!

盛り上がりすぎて写真撮るの忘れました。

このブログは技術ブログなので、仕組みを簡単に書いておきます。

・ ジャム瓶にビーコンとお菓子を入れて、方々に設置する。瓶のフタをしめると、BLEが弱るのでできれば開けておく。
・ ビーコンスキャナーはNodeで書いた。node-bleaconでビーコンをスキャンし、websocketでクライアント(ブラウザ)に送信する。
・ クライアントはストーリー進行を担当する。ストーリーの各所(例:ビーコンに近づいた)でwebsocketを通してNodeサーバに通知する。
・ NodeサーバはFirmataでArduinoと通信し、LEDを点滅させる。

Screen Shot 2015-12-04 at 14.47.15

サーバのコード:


var Bleacon = require("bleacon");
var us      = require("underscore");
var express = require("express");
var app     = express();
var http    = require("http").Server(app);
var io      = require("socket.io")(http);
var five = require("johnny-five");
var board = new five.Board();

app.use(express.static("."));

var interval = {
    far: 1000,
    near: 300,
    immediate: 100
};

function nop () {}

var led = {blink: nop, off: nop};

board.on("ready", function () {
    led = new five.Led(6);
    led.stop().off();
});

io.on("connection", function (socket) {
    console.log("connect " + socket.id);

    socket.on("beacon-near", function (proximity) {
        console.log(proximity);
        led.blink(interval[proximity]);
    });
    socket.on("beacon-acquired", function () {
        console.log("found");
        led.stop().off();
    });
});

Bleacon.on("discover", function (beacon) {
    io.emit("beacon", beacon);
});

Bleacon.startScanning();

http.listen(3000);

クライアントのコード:


      var socket = io();
      var beacons = [{
        major: 0,
        minor: 0,
        far:  "すぐ近くだ!",
        near: "近いぞ!クマに襲われないように探すんだ!",
        immediate:  "よくやった!次のヒントは「ちいさなイドのそこ」だ!",
        next_hint: "ちいさなイドのそこ",
        discovered: false
      }, {
        major: 1,
        minor: 1,
        far:  "見えてきたぞ!",
        near: "近いぞ!イドに落ちるなよ!",
        immediate:  "よくやった!おたからの場所のヒントをおしえよう。「ほたるのすみか」だ。",
        next_hint: "ほたるのすみか",
        discovered: false
      }, {
        major: 0,
        minor: 3,
        far:  "あとひといきだ!",
        near: "よし!お宝はすぐ近くにあるぞ!",
        immediate:  "おめでとう!おたからは君たちのものだ!",
        next_hint: "次は君たちでおたからを隠してみよう",
        discovered: false
      }];

      var msg = document.getElementById("message");

      var timer = null;
      socket.on("beacon", function (beacon) {
        var b = _.find(beacons, function (b) {
          return b.major === beacon.major
              && b.minor === beacon.minor
              && ! b.discovered;
        });
        if (b) {
          clearTimeout(timer);
          socket.emit("beacon-near", beacon.proximity);
          msg.innerHTML = b[beacon.proximity];
          if (beacon.proximity === "immediate") {
            b.discovered = true;
            setTimeout(function () {
              socket.emit("beacon-acquired");
              msg.innerHTML = "ヒント:" + b.next_hint;
            }, 1000 * 5);
          }
        }
        timer = setTimeout(function () {
          socket.emit("beacon-acquired");
        }, 5000);
      });

使った技術

・ Node.js
・ Socket.IO
・ jhonny-five
・ Arduino
・ node-bleacon

課題

・ 当日の朝思いついたものなので、パソコンで作ったが、ほんとはスマホとかの方がスマート。クライアントはHTMLなので、WebsocketサーバとFirmataサーバさえ書けば移植はそんなに難しくないはず。

今後とも神山電子工作クラブにご期待ください。

LISPing at the end of time.