Help us understand the problem. What is going on with this article?

音声入力(Voiceflow)で自作LEGOカーを制御する

概要

 一時流行ったスマートスピーカー。今では家の片隅や押し入れに封印されている方が多いのではないでしょうか。(個人的意見)少なくとも私はその一人です。このまま封印されたままになると思っていましたが、第二回技術書同人博覧会で「スマートスピーカーでおうちハック / 温泉BBA」を購入したのをきっかけに封印を解くことができました!

 こちらの書籍でスマートスピーカーのスキルがビジュアルプログラミングできるVoiceflowというツールが紹介されており、スマートスピーカー初心者の私にはぴったりでした。

 基本的な操作を理解できたので、音声入力にで実世界の物を動かしてみたいと思い自作のLEGOカーを制御してみました。

デモ

 音声で「前進」「後退」「停止」を入力すると、それに応じてLEGOカーが動作します。

【実際の動き】

構成

 Voiceflowで音声入力を受け付け、「前進」「後退」といった入力を定型のURLに変換し、obnizへWebhookを投げています。obnizではWehookで受け取ったコマンドに応じてモータを制御しています。次のような構成となっています。
 image.png

以降はもう少し詳しく解説していきます。

Voiceflow

 定型のコマンドを入力するとWebhookをobnizに投げます。次のURLからサンプルプロジェクトを動かすことができます。
https://creator.voiceflow.com/demo/2897161440721865

入力部のフロー
image.png
 最初のSpeekブロックではスキルが開始したことを知らせています。サンプルプロジェクトでは次の部分です。
image.png
 最初のSpeekブロックは次のように設定しています。
image.png
 次にChoiceブロックで入力された音声による分岐を行っています。条件は”前進”、”後退”、”停止”、”その他”です。
image.png
 Choiceブロックの設定は次のようになっています。これが後退と停止まであります。
image.png
 分岐したとのSpeekブロックでは何のコマンドを受け付けたか分かるような応答をしています。このブロックの設定は次のようになっています。
image.png
 その後のSetブロックでは変数にコマンドをセットしています。前進の場合は次のように変数”cmd”に”front”コマンドをセットしています。・
image.png
 Voiceflowで変数を扱うには予め定義が必要です。次のように画面左のブロック一覧タブから変数タブに切り替え、変数名を入力して定義します。
image.png

 最後にIntegrationブロックです。このブロックでWebhookを投げています。
 image.png
 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>

おわりに

今回は車の制御デモで、実際に車を動かすと考えるとレスポンスや認証などの問題が出てきます。ここを突破できれば面白いものが作れそうですね。

kmaepu
自由気ままにものづくりをする組込みソフトエンジにゃ~。
iotlt
IoT縛りの勉強会です。 毎月イベントを実施しているので是非遊びに来てください! 登壇者を中心にQiitaでも情報発信していきます。 https://iotlt.connpass.com
https://iotlt.connpass.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした