Google Home の音声命令でルンバにいろんなことをさせてみた

こんにちは。ルンバハック愛好家の kamoc です。 この記事は、おうちハック Advent Calendar 2017 の5日目のエントリーです。

Google Home や Amazon Echo など、各社から AI スピーカーが続々と発売されていますね。かくいう私は「Echo の招待が来てからアドベントカレンダーのネタを作るか〜。」なんて考えていましたが、一向に招待メールが来ず・・・。元々購入する予定は無かったのですが Google Home の購入に至りました。(私が Amazon のファンなだけで、決してガジェットとしてどちらが優秀というわけではないですよ。) この記事では Google Home を用いてルンバにいろいろやらせてみたことについてと、Google Home を使ったりいじったりした感想を紹介します。

作ったもの

ルンバのWifi対応モデルでは、Google Home に標準対応するようになるそうですが、執筆時点ではまだ対応していなかったので、掃除するコマンドを実装するのに加えて無駄な楽しい機能を付け加えてみました! 実装した音声コマンドはこちらです。

  • ルンバ、掃除して!
  • ルンバ、歌って!
  • ルンバ、前進!
  • ルンバ、右へ!
  • ルンバ、左へ!
  • ルンバ、全速前進!
  • ルンバ、とまれ!
  • ルンバ、マグナムトルネード!

今回つくったものを動画にまとめたのでご覧ください。

幼き頃、某ミニ四駆アニメを観ながら、『マシンに向かって話しかけたって反応する訳ないじゃーん。』とか思っていましたが、2017年の今、ついに現実のものになりましたよ! やったよ土屋博士。

さて、技術的にどんな感じで作ったのか紹介していきます。 ここからは実装の詳細の話になるので、興味のない方はGoogle Home を使ってみた感想まで読み飛ばして下さい。

システム構成

システムの全体構成はこんな感じです。

image

音声命令を受け取ってからの処理の流れは以下のようになります。

  1. GoogleHome に入力された音声コマンドを Dialogflow の Intent が処理する
  2. Dialogflow の Fulfillment で Firebase CloudMessage を送る
  3. CloudMessage を受け取った Android 端末がシリアル通信でルンバに命令を送る

各処理について順番に紹介していきます。

GoogleHome に入力された音声コマンドを Dialogflow の Intent が処理する

Dialogflow は自然言語を用いたユーザー体験を実現するためのサービスで、 Google Home アプリを開発するために使用します。 Dialogflow の Intent では、『もし◯◯と言ったら、◯◯を実行。』という動作の定義を行います。具体的な手順については以下の記事を参考にさせていただきました。こちらの記事では api.ai という Dialogflow の旧名称で記載されているので、適宜読み替えてください。

Intent の定義

今回私が設定した Intent はこんな感じです。

image

黄色くハイライトされているのはこの後紹介する Entity で、コマンドのバリエーションを定義します。 コマンドを受け取った時にプログラムでゴニョゴニョするために、忘れずに Use webhook にチェックを入れておきます。

Entity の定義

続いて、Entity の定義です。ここではルンバの動作パターンを定義します。私が作成した Entity はこんな感じです。

image

左側のカラムは日本語でも問題なく動作しますが、この後紹介する Fulfillment でこの値を使用するので半角英数にしました。右カラムは複数のワードを定義することができます。そのため、「前進」の他にも、「走れ」「前へ進め」「パンツァーフォー」といった具合に、いろいろな言い換えを準備しておくことができます。 作ったものを動かしていると、自分が「前進」なのか「進め」なのか、どのワードで設定したか忘れてしまうことがありました。文言レベルで正しく命令しないと解釈してくれないため、固有名詞以外を Entity で定義する場合は、いろんなパターンを準備しておいたほうが快適に使えるようになると思います。

Dialogflow の Fulfillment で Firebase CloudMessage を送る

続いて、Dialogflow の Fulfillment について紹介します。 Fulfillment では、具体的な処理を定義します。 定義するためには以下の2通りの方法を利用することができます。今回は Inline Editor を使用しました。

Webhook

読んでその名の通り、Webhook です。 Webhook の先で実際にやりたいことの処理を実装していくことになります。工夫次第ではなんでもできますね! ただ、音声命令のトリガーで Webhook を叩くちょっとしたデモを作るのであれば、Dialogflow を使うよりも IFTTT を使った方が同じことが簡単に実現できると思います。

Inline Editor

今回お世話になったのはこちらの Inline Editor です。 実態は Firebase の Cloud Functions で、ブラウザ上で手軽にプログラムを書くことができます。 デフォルトの index.js にちょろっと変更を加えただけです。変更点について紹介していきます。 まず、CloudMessageを送信するためにモジュールの読み込みと初期設定を、 index.js の先頭で行います。

  const functions = require('firebase-functions'); // Cloud Functions for Firebase library
  const DialogflowApp = require('actions-on-google').DialogflowApp; // Google Assistant helper library
  const admin = require('firebase-admin');
  admin.initializeApp({
    credential: admin.credential.applicationDefault(),
    databaseURL: "https://roomba-********.firebaseio.com/"
  });

このデモでは Firebase DB は使用しませんが、firebase-admin の初期化のために必要になるので、Firebase コンソールで DB を作成して URL をセットしてあげてください。

次に、音声入力されたコマンドを CloudMessage として送信する部分を実装します。 processV1Requestメソッド内の、actionHandlersを拡張します。

    'input.roomba': () => {
        const token = "************************************************************************************************************************************************";
        console.log("action", action);
        console.log("parameters", parameters);
        console.log("inputContexts", inputContexts);
        console.log("requestSource", requestSource);
        const payload = {
            data: {
                command: parameters.roomba_command
            }
        };
        
        admin.messaging().sendToDevice(token, payload)
            .then(pushResponse => {
                sendResponse("はい");
                console.log("success", pushResponse);
            })
            .catch(error => {
                sendResponse("失敗しました。");
            });
    },

今回はデモなので、Firebase の token はソースにべた書きしてしまっています。 parameters から Entity で定義したルンバコマンドを取得し、CloudMessageに乗せてお家の Android 端末に通知を飛ばします。

Dialogflow のソースコードは Gist にあげておきました。 [blogcard url=“https://gist.github.com/kamomc/e827c84fbee201bef417cf71b8bec64d”]

CloudMessage を受け取った Android 端末がシリアル通信でルンバに命令を送る

あとは、 Android 側で PUSH 通知を受け取り、コマンドに合わせてルンバを動かしてあげれば完成です。 この部分については、ルンバと Android 端末をつなぐケーブルを自作する必要があったりして長くなるので、具体的な説明は割愛します。 Android アプリのソースコードも GitHub にあげておいたので、興味がある方は見てみて下さい。

Google Home を使ってみた感想

この記事では Google Home を使ってルンバに音声で色々なことをさせてみました。 最後に、Google Home を触ったり、使ってみた感想を紹介します。

音声で操作する体験が素晴らしい

音声で家電を制御する体験は、想像以上に快適なものでした。 ルンバに掃除をさせる場合、従来は

  • iRobot App を立ち上げてクリーンボタンを押す
  • ルンバ本体のクリーンボタンを押す

といったように、ワンアクションする必要がありましたが、「ルンバ、掃除して」と一声かけるだけで良いのはとても快適です。Google Home からの掃除命令は公式でサポートされると発表されています。しかし、執筆時点では、まだ自分で拡張しないと利用できない模様です。)(2017/12/15 追記: ついに公式でも対応しました!) ほんの一手間の節約なのですが、毎日やることなので長期的に見ればそれなりの時間の節約になります。 また、 Google Home に話しかけるという行為が、日常生活から大きく乖離したアクションでないことも良い点だと思います。私の場合、日常から飛躍しすぎると、すぐに飽きてしまい使わなくなってしまうのですが、これなら日常生活に溶け込んで行きそうです。

現状、自分で拡張しない限りできることが少ない

ちょっとデフォルト状態だとできることが少ないかなーと思います。 私の場合、 Google Play Music や Spotify などの対応サービスに契約していないこともあり、自分で拡張した機能以外における恩恵はあまり感じませんでした。ただ、この記事で紹介したように、簡単に拡張ができるため、今後さまざまなコンテンツが登場することを期待しています。

IFTTT で言うところの IF だけでなく THAT も担えてほしい

私が調べた限りでは、 「もし◯◯なら、☓☓を実行する。」ということを実現したい時に、Google Home は前半部の「もし◯◯なら」の部分しか担えない点が残念でした。例えば、自分が管理しているサーバーがダウンしたら Google Home が通知するようなものを作れたら便利なのにな〜と思いました。

2017/12/07 追記 以下の記事で Google Home 外部トリガーで喋らせる方法が紹介されていました! https://qiita.com/sitopp/items/89add216c500de5ace4e

現状ではまだ物足りなさを感じる Google Home ですが、手軽に対応アプリを開発できることもあり、今後の発展がとても楽しみです! また、 Amazon Echo が入手できたらいろいろ試してみようと思います!