概要
一時流行ったスマートスピーカー。今では家の片隅や押し入れに封印されている方が多いのではないでしょうか。(個人的意見)少なくとも私はその一人です。このまま封印されたままになると思っていましたが、第二回技術書同人博覧会で「スマートスピーカーでおうちハック / 温泉BBA」を購入したのをきっかけに封印を解くことができました!
こちらの書籍でスマートスピーカーのスキルがビジュアルプログラミングできるVoiceflowというツールが紹介されており、スマートスピーカー初心者の私にはぴったりでした。
基本的な操作を理解できたので、音声入力にで実世界の物を動かしてみたいと思い自作のLEGOカーを制御してみました。
デモ
音声で「前進」「後退」「停止」を入力すると、それに応じてLEGOカーが動作します。
【実際の動き】
Voiceflowからの音声入力でゆるメカトロを動かせた!!
— まえぷー (@kmaepu) December 25, 2019
この仕組みを利用しておうちハックやろう。#VUI #voiceflow #obniz #ゆるメカトロ pic.twitter.com/ANVKmChLZQ
構成
Voiceflowで音声入力を受け付け、「前進」「後退」といった入力を定型のURLに変換し、obnizへWebhookを投げています。obnizではWehookで受け取ったコマンドに応じてモータを制御しています。次のような構成となっています。
以降はもう少し詳しく解説していきます。
Voiceflow
定型のコマンドを入力するとWebhookをobnizに投げます。次のURLからサンプルプロジェクトを動かすことができます。
https://creator.voiceflow.com/demo/2897161440721865
【入力部のフロー】
最初のSpeekブロックではスキルが開始したことを知らせています。サンプルプロジェクトでは次の部分です。
最初のSpeekブロックは次のように設定しています。
次にChoiceブロックで入力された音声による分岐を行っています。条件は”前進”、”後退”、”停止”、”その他”です。
Choiceブロックの設定は次のようになっています。これが後退と停止まであります。
分岐したとのSpeekブロックでは何のコマンドを受け付けたか分かるような応答をしています。このブロックの設定は次のようになっています。
その後のSetブロックでは変数にコマンドをセットしています。前進の場合は次のように変数”cmd”に”front”コマンドをセットしています。・
Voiceflowで変数を扱うには予め定義が必要です。次のように画面左のブロック一覧タブから変数タブに切り替え、変数名を入力して定義します。
最後にIntegrationブロックです。このブロックでWebhookを投げています。
URLは次のようにしています。このフォーマットにすることでobnizにWebhookを投げることができます。URLの「0000-0000」部分はobnizのIDです。「data={cmd}」に各コマンドごとの文字列が入ります。
https://obniz.io/obniz/0000-0000/message?data={cmd}
obniz
obnizではWebhookで受け取ったコマンドに応じてモータを制御しています。
Webhook受け取りにはobnizのMessaging機能で実現しています。特定フォーマットのURLにWebhookを投げると、obnizのソースコード内でペイロードのデータを扱うことができます。Messagingについてはこちら。
受け取ったデータをプログラム内で使うには次のようにします。
obniz.onmessage = function(message, from) {
if (message === "front") { // コマンド判定
// コマンドごとの処理を記述
}
};
プログラム
今回のプログラムではMeesagingによる制御と、obnizのWeb画面操作による制御の2系統を用意しています。
<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">
<link rel="stylesheet" href="/css/starter-sample.css">
<script src="https://obniz.io/js/jquery-3.2.1.min.js"></script>
<script src="https://unpkg.com/obniz@2.5.0/obniz.js" crossorigin="anonymous"></script>
</head>
<body>
<div id="obniz-debug"></div>
<div class="wrap">
<div class="print">
<h3 class="text-center">Print words on obniz</h3>
<div>
<input type="text" id="text" value="Hello World" placeholder="Input in freely">
<button class="btn btn-primary" id="showtime">Print on obniz</button>
</div>
</div>
<div class="switch">
<h3 class="text-center"> Swtich </h3>
<span id="print">undefined</span>
</div>
<div class="led">
<h3 class="text-center">Control</h3>
<button class="btn btn-primary" id="front">Front</button>
<button class="btn btn-outline-primary" id="back">Back</button>
<button class="btn btn-outline-primary" id="stop">stop</button>
</div>
</div>
<script>
var obniz = new Obniz("OBNIZ_ID");
obniz.onconnect = async function () {
obniz.display.clear();
obniz.display.print("Hello World");
// Javascript Example
var R_motor = obniz.wired("DCMotor", {forward:0, back:1});
var L_motor = obniz.wired("DCMotor", {forward:10, back:11});
obniz.onmessage = function(message, from) {
console.log(message);
if (message === "front") {
R_motor.reverse();
L_motor.forward();
}
if (message === "back") {
L_motor.reverse();
R_motor.forward();
}
if (message === "stop") {
R_motor.stop();
L_motor.stop();
}
};
$('#front').click(function () {
R_motor.reverse();
L_motor.forward();
obniz.display.clear();
obniz.display.print("Front");
});
$('#back').click(function () {
L_motor.reverse();
R_motor.forward();
obniz.display.clear();
obniz.display.print("Back");
});
$('#stop').click(function () {
R_motor.stop();
L_motor.stop();
obniz.display.clear();
obniz.display.print("stop");
});
};
</script>
</body>
</html>
おわりに
今回は車の制御デモで、実際に車を動かすと考えるとレスポンスや認証などの問題が出てきます。ここを突破できれば面白いものが作れそうですね。