IoT
Raspberrypi3
AndroidThings
GoogleAssistant

Google Assistant SDK+ラズパイでIoTっぽいことしてみた

More than 1 year has passed since last update.

この記事は ウェブクルー Advent Calendar 2017の16日目の記事です。

昨日は@WCSakuraiさんの「業務で使えそうなScalaz」でした。


はじめに

16日目は@eclair-rougeが担当します。

本記事では、GoogleAssistantSDKのサンプルをもとに、「オッケーグーグル!~~のスイッチ入れて」的なことをやってみた時の内容を書かせていただきました。


概要


  • GoogleAssistantのサンプルを動かしてみる

  • リレーモジュール使い、電化製品のスイッチを声で操作してみる


今回使ったもの


  • RaspberryPi3 Model B

  • microSD 32GB(UHSスピードクラス3)

  • ブレッドボード

  • タクトスイッチ

  • LED

  • ジャンパワイヤ

  • 抵抗(470Ω、10kΩ)

  • リレーモジュール(1ch)

  • USBキーボード、USBマウス、USBヘッドセット(マイクとスピーカー)

  • HDMIケーブルとHDMI接続できるモニタ

  • microUSBケーブルとUSB電源(2.4A)

  • LANケーブル


開発環境


  • Windows 10 Pro

  • Android Studio 2.3.3

  • JDK8

  • python3(pip使うだけ)


GoogleAssistantのサンプルを動かす


Android Thingsのセットアップ

公式の手順の通りにインストールするだけのため説明は省略します。

すごく簡単に説明すると、ダウンロードしたイメージを、Win32DiskImagerを使って書き込むだけです。


ハードウェアの設定


  • ブレッドボードの接続

    まずは、こちらを参考にLED、タクトスイッチ、抵抗を配置します。

    この後クローンする、サンプルのソースコード(BoardDefaults.java)を見るとわかりますが、ラズパイで使用しているGPIOのピンが違うのでそれを繋ぎ直してください。

    BCM21→BCM23、BCM6→BCM25にそれぞれ繋ぎ直す

    ラズパイのピン配はこちら


  • 周辺機器接続

    ラズパイにHDMIケーブル、USBのキーボード、マウス、ヘッドセット、LANケーブルを繋いで、プログラム転送元のPCと同じネットワーク上にLANケーブルを繋ぐ


  • microUSBの電源を入れる

    電源を入れると、AndroidThingsが自動で立ち上がります。(電源ボタンとかは無い)

    AndroidThingsの画面が表示したら、画面の中央下に表示しているIPアドレスをひかえておいてください。



Googleの設定


  • Google Assistant APIの認証情報を作成する

    こちらの手順で認証情報のjsonを作成する



  • アクティビティの設定

    Googleのアカウント設定の、アクティビティ管理で以下の項目をONにする


    • ウェブとアプリのアクティビティ

    • ロケーション履歴

    • 端末情報

    • 音声アクティビティ



  • google-auth-oauthlibのインストール

    コマンドプロンプトを起動し、下記のコマンドを実行


> pip install google-auth-oauthlib


アプリケーション実行


  • adbコマンドでデバイスに接続

    コマンドプロンプトを起動し、下記のコマンドを実行

> adb connect 3のIPアドレス

adbコマンドが叩けない場合は、以下の環境変数を設定してください

C:¥Users¥{ユーザーネーム}¥AppData¥Local¥Android¥sdk¥platform-tools


  • サンプルプログラムのソースコード取得

    こちらからサンプルプログラムをクローンする


  • OAuth認証

    コマンドプロンプトを起動し、下記のコマンドでOAuth認証をかける

    client_secret_****.jsonはGoogleの設定で作成したjson


google-oauthlib-tool --client-secrets client_secret_****.json --credentials app/src/main/res/raw/credentials.json --scope https://www.googleapis.com/auth/assistant-sdk-prototype --save


  • プログラム修正

    Andorid Studio起動を起動し、クローンしたサンプルのプロジェクトをインポートする

    今回は、USBのヘッドセット(マイク、スピーカー)を使用するため、I2SはOFFにする


AssistantActivity.java

private static final boolean AUDIO_USE_I2S_VOICEHAT_IF_AVAILABLE = true;


private static final boolean AUDIO_USE_I2S_VOICEHAT_IF_AVAILABLE = false;


  • プログラム起動

    ツールバーのRun(▶)をクリックするとデバイスの選択ができ、その中にラズパイ(rpi3_IoT)があるので、それを選択し、実行する


タクトスイッチを押している間の音声を録音し、放すと録音していた音声データに対する応答が返ってきます

音声を録音している時(タクトスイッチを押している時)は、LEDが点灯します


電化製品のスイッチを声で操作


ハードウェアの設定


  • ブレッドボードの接続

    サンプルで作成した回路にリレーモジュールを追加する

    まず、リレーモジュールをブレッドボードに載せ、基板上の+の印(電源)に5v、基板上の-の印にGround、残った一つにBCM21をそれぞれ繋ぐ


  • 電化製品の接続

    100vの何かしらの電化製品の電源ケーブルの中央を2つに裂いて片側を切断する

    切断したそれぞれを、リレーモジュールの両端にそれぞれ接続する

    繋ぐ電化製品は、壊れてもいいものかつ、スイッチが無いもの(コンセント差したら電源入るもの)が良いです

    また、ワット数が高いものは避けてください

    私は、要らなくなったネットワークHUBでやりました



プログラム修正


  • Things Support Libraryを使えるようにするため、下記のコードを追記


AndroidManifest.xml

<uses-library android:name="com.google.android.things" />



  • リレーモジュールのGPIOの名前取得用関数作成


BoardDefaults.java

/**

* Return the GPIO pin for the Relay Module trigger.
*/

public static String getGPIOForRelayModule() {
switch (getBoardVariant()) {
case DEVICE_RPI3:
return "BCM21";
default:
throw new IllegalStateException("Unknown Build.DEVICE " + Build.DEVICE);
}
}


  • リレー制御を行った履歴表示用にListViewを追加


activity_main.xml

<ListView

android:id="@+id/assistantResponsesListView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"/>


  • リレー制御処理の追加


まず、105行目の上に、喋った言葉の保存用に変数を作成


AssistantActivity.java

private String mResultString = "";


mAssistantResponseObserverの処理で、113行目のRESULTの処理に、「turn on/off swich」と喋ったときに、リレーを制御する処理とリレー制御の履歴出力を追加

さらに、リレー制御をした時は、GoogleAssistantの回答は必要ないので、AUDIO_OUTの処理にリレー制御をした時は、GoogleAssistantの回答を再生しない処理を追加


AssistantActivity.java

case RESULT:

final String spokenRequestText = value.getResult().getSpokenRequestText();
if (!spokenRequestText.isEmpty()) {
mResultString = spokenRequestText;
Log.i(TAG, "assistant request text: " + spokenRequestText);
mMainHandler.post(new Runnable() {
@Override
public void run() {
mAssistantRequestsAdapter.add(spokenRequestText);
try
{
if (spokenRequestText.equals("turn on switch"))
{
mRelay.setDirection(Gpio.DIRECTION_OUT_INITIALLY_HIGH); // GPIOをハイで出力
mAssistantResponsesAdapter.add("power on");
}
else if (spokenRequestText.equals("turn off switch"))
{
mRelay.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW); // GPIOをローで出力
mAssistantResponsesAdapter.add("power off");
}
}catch(Exception e){
Log.w(TAG, "error toggling RelayModule:", e);
}
}
});
}
break;
case AUDIO_OUT:
final ByteBuffer audioData =
ByteBuffer.wrap(value.getAudioOut().getAudioData().toByteArray());
Log.d(TAG, "converse audio size: " + audioData.remaining());
if (!(mResultString.equals("turn on switch") || mResultString.equals("turn off switch")))
{
mAudioTrack.write(audioData, audioData.remaining(), AudioTrack.WRITE_BLOCKING);
if (mLed != null)
{
try
{
mLed.setValue(!mLed.getValue());
}
catch (IOException e)
{
Log.w(TAG, "error toggling LED:", e);
}
}
}
break;

リレー制御用のGpio変数をを169行目辺りに宣言


AssistantActivity.java

private Gpio mRelay;


リレー制御履歴表示用に、222行目あたりArrayListとArrayAdapterを宣言


AssistantActivity.java

private ArrayList<String> mAssistantResponses = new ArrayList<>();

private ArrayAdapter<String> mAssistantResponsesAdapter;

234行目にAdapterの設定追加


AssistantActivity.java

ListView assistantResponsesListView = (ListView)findViewById(R.id.assistantResponsesListView);

mAssistantResponsesAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mAssistantResponses);
assistantResponsesListView.setAdapter(mAssistantResponsesAdapter);

GPIOのオープンと初期状態設定処理を、265行目辺りに追加


AssistantActivity.java

mRelay = pioService.openGpio(BoardDefaults.getGPIOForRelayModule());

mRelay.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);


アプリケーション実行


  • プログラム起動

    サンプルの時と同じように、実行する


サンプルの時と同じように、タクトスイッチを押している間の音声を録音し、放すと録音していた音声データに対する応答が返ってきますが、今回は「ターン オン スイッチ」「ターン オフ スイッチ」と喋ると、リレーモジュールが切り替わり、電化製品のスイッチが、声で制御できるようになります。


参考にした記事

Android ThingsでGoogle Assistantのサンプルを動かすまで

Android ThingsをRaspberry Pi3で使ってみた


最後に

今回、久しぶりにGPIOの制御などをやってみましたが、OSの無いカスタムCPUの制御とは違って、非常に簡単に制御を行う事ができました。組込制御の開発を行ったことがない人でも、結構簡単にできてしまうのでは?と感じました。(OSが載っているからかもしれませんが・・・)

アプリケーション開発も面白いですが、現実世界でモノが動く、デバイス制御は違った楽しさがあります。

明日は@wc-keisuke_tokunagaです。よろしくお願いします。

ウェブクルーでは一緒に働いていただける方を随時募集しております。

お気軽にエントリーくださいませ。

開発エンジニアの募集

フロントエンドエンジニアの募集

データベースエンジニアの募集