twsのアイコン画像
tws 2021年05月16日作成 (2021年05月16日更新)
製作品 製作品 閲覧数 907
tws 2021年05月16日作成 (2021年05月16日更新) 製作品 製作品 閲覧数 907

obnizで宝探しダウジング

obnizで宝探しダウジング

概要

スマホを宝物に見立てて隠し、それをobnizで見つけます。
Bluetoothの電波強度を見て、スマホが近づくとサーボモーターを回し、ダウジングのバーが開くようにします。

デモ動画

ここに動画が表示されます

スマホを遠ざけると、obnizに接続されたサーボモーターが動いて、バーが閉じます。
またスマホを近づけるとバーが開きます。
スマホの隠し場所がわからなくなった場合は、obnizのボタンを押すと、スマホのバイブが少し振動します。
3回obnizのボタンを使うと、ギブアップになり、スマホのバイブが振動し続けます。
その場合はスマホを探し出して、画面にタッチすると振動が止まります。

概略図

ブラウザアプリとして動作させています。
概略図

デバイス 動作
obniz Bluetoothでビーコンを発信します。 スマホ側で検知した電波強度に従い、サーボモーターを駆動します。
スマホ (Android) Bluetoothでビーコンを受け、電波強度を検知し、obniz側へ通知します。 chromeブラウザからWeb Bluetooth APIを利用してビーコンの情報を受信しています。

前準備

試験運用版機能の有効化

Web Bluetooth APIのscan機能を利用しているため、Chromeブラウザの試験的な機能を有効にする必要があります。
chromeブラウザの検索窓から
chrome://flags/#enable-experimental-web-platform-features
を入力し、下記のフラグを有効にします。
記載の通り、試験運用版の機能のため、自己責任でお願いします。

chrome flags

スマホの画面消灯の無効化

スマホのアプリを作成すれば解決するのですが、今回はブラウザを利用しているため、操作をしない状態のままだと画面が消灯し、Bluetoothのビーコンが受けられなくなります。
そのためAndroidの画面消灯の時間を長くするか、画面消灯しなくするアプリを利用してください。

部品

部品 数量 備考
obniz Board 1Y 1 https://obniz.com/ja/doc/reference/board-1y/
サーボモーター 2 TowerProのSG90を使用しました。
電池ボックス 1 100均の乾電池式のスマホ充電器を利用しました。
ストロー 1 適当な長さに切ってサーボモーターに取り付けます。
ブレッドボード 1 手持ちできるようにobniz、サーボ、電池ボックスをはりつけて、配線しています。
ジャンパー線 適量
Androidスマホ 1 BLE対応でChromeがインストールされているもの。BLEビーコンの検知にWeb Bluetooth APIを使用しています。iOSはWeb Bluetooth APIに対応しないため、ブラウザのみでは対応できないようです。別途アプリを作成する必要があると思います。https://webbluetoothcg.github.io/web-bluetooth/

接続図

接続図

ソースコード

obnizのブラウザアプリです。

obnizのコード

<html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" /> <title>宝探し | obniz App</title> <link rel="stylesheet" href="/css/starter-sample.css" /> <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script> <script src="https://unpkg.com/obniz@3.x/obniz.js" crossorigin="anonymous" ></script> <style> h1 { margin-top: 50px; text-align: center; } #canvas{ display: block; } html, body, #wrapper{ width: 100%; height: 100%; } </style> </head> <body> <div id="wrapper"><canvas id="canvas" width="" height=""></canvas></div> <!--RSSI: <span id="rssi"></span>--> <script> var obniz = new Obniz("OBNIZ_ID_HERE"); //var install_configration = Obniz.App.configs(); var wrapper = null; var canvas = null; var ctx = null; var max_rssi = -100; // 電波強度の最大値 var min_rssi = 0; // 電波強度の最小値 var received = false; var found = false; window.addEventListener("load", function () { wrapper = document.getElementById("wrapper"); canvas = document.getElementById("canvas"); ctx = canvas.getContext("2d"); draw_treasure_chest(); canvas.addEventListener("click", function () { // スマホを見つけて、タッチした時 hint_disp(3); max_rssi = -100; min_rssi = 0; found = true; }); }); window.addEventListener("resize", function () { draw_treasure_chest(); }); function draw_treasure_chest() { canvas.width = wrapper.offsetWidth; canvas.height = wrapper.offsetHeight; // 宝箱 ctx.strokeStyle = "#ff0"; ctx.fillStyle = "#800"; ctx.lineWidth = 70; ctx.beginPath(); ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.strokeRect(0, 0, canvas.width, canvas.height); ctx.moveTo(0, canvas.height / 2); ctx.lineTo(canvas.width, canvas.height / 2); ctx.closePath(); ctx.stroke(); ctx.fill(); ctx.fillStyle = "#ff0"; ctx.beginPath(); ctx.fillRect(canvas.width / 2 - 100, canvas.height / 2, 200, 100); ctx.closePath(); // 鍵穴 ctx.strokeStyle = "#000"; ctx.fillStyle = "#000"; ctx.lineWidth = 5; ctx.beginPath(); ctx.moveTo(canvas.width / 2, canvas.height / 2); ctx.arc(canvas.width / 2, canvas.height / 2, 30, 0.7 * Math.PI, 0, true); ctx.arc(canvas.width / 2, canvas.height / 2, 30, 0, 0.4 * Math.PI, true); ctx.lineTo(canvas.width / 2 + 20, canvas.height / 2 + 60); ctx.lineTo(canvas.width / 2 - 20, canvas.height / 2 + 60); ctx.closePath(); ctx.fill(); } obniz.onconnect = async function () { // サーボモーターをobnizに接続 const servo1 = obniz.wired("ServoMotor", { gnd: 0, vcc: 1, signal: 2 }); // 左サーボ const servo2 = obniz.wired("ServoMotor", { gnd: 3, vcc: 4, signal: 5 }); // 右サーボ servo1.angle(10); servo2.angle(170); // 残りヒント数表示 hint_disp(3); // ボタンを押したときの動作 obniz.switch.onchange = async function (state) { if (state === "push") { // ヒント window.navigator.vibrate([200, 200, 200, 200, 200]); hint = hint - 1; hint_disp(hint); if (hint < 1) { // 降参 hint = 0; found = false; while ((obniz.connectionState === "connected") & (found == false)) { try { window.navigator.vibrate([200, 200, 200, 200, 200]); await obniz.wait(500); await obniz.pingWait(); } catch (e) { break; } } } } }; // obniz側からBLEビーコンを出す await obniz.ble.initWait(); var service = new obniz.ble.service({ uuid: "0b32" }); // このUUIDで判別 var characteristic = new obniz.ble.characteristic({ uuid: "7777", data: [1, 2, 3], }); service.addCharacteristic(characteristic); obniz.ble.peripheral.addService(service); obniz.ble.advertisement.setAdvData(service.advData); obniz.ble.advertisement.setScanRespData({ localName: "obniz BLE", }); obniz.ble.advertisement.start(); // スマホ側でobnizのBLEビーコンを受ける navigator.bluetooth .requestLEScan({ //acceptAllAdvertisements:true, filters: [{ services: [0x0b32] }], // このUUIDを探す keepRepeatedDevices: true, }) .then(() => { navigator.bluetooth.addEventListener("advertisementreceived", (event) => { console.log( "Advertisement received. Device Name: " + event.device.name + ", Device ID: " + event.device.id + ", RSSI: " + event.rssi + ", TX Power: " + event.txPower + ", UUIDs: " + event.uuids ); //obniz.display.print("rssi: " + event.rssi); received = true; max_rssi = Math.max(max_rssi, event.rssi); min_rssi = Math.min(min_rssi, event.rssi); var angle = ((event.rssi - min_rssi) / (max_rssi - min_rssi)) * 90 + 10; servo1.angle(angle); servo2.angle(180 - angle); }); }); var count = 0; obniz.onloop = async function () { if (received == false) { count++; if (count > 40) { // ビーコンが一定時間来なかったら元の位置に戻す servo1.angle(10); servo2.angle(170); count = 0; console.log("beacon not found"); } } else { count = 0; } received = false; }; }; // 残りヒントの数の表示 var hint = 3; function hint_disp(h) { var fill = true; obniz.display.clear(); for (let i = 0; i < 3; i++) { if (i + 1 > h) fill = false; obniz.display.circle(i * 30 + 15, 10, 10, fill); } hint = h; } </script> </body> </html>

遊び方

ソフトを実行するとBluetoothの機能を使う旨のメッセージが出るので、許可してください。
スマホを宝箱と見立てて、どこかに隠します。
obnizを使って、スマホを探し、スマホが近くにあるとバーが開きます。
隠し場所がわからない場合は、obnizのボタンを押すとスマホ側のバイブが一定時間、動作します。
3回obnizのボタンを使ってしまうと、ギブアップになり、バイブが動作しっぱなしになります。
その場合はスマホを探し出して、スマホ側の画面をタッチすると止まります。

おわりに

サーボの動きをダウジングっぽく、もう少し滑らかにしたい。
Bluetoothのアドバタイズパケットではなく、接続した状態の方がもう少し頻繁に電波強度の情報が取れるかもしれない。
obniz Boardはスマホとobnizとの通信を意識せずに連携して動作することができ、とても使いやすかった。

ログインしてコメントを投稿する

投稿者の人気記事