この記事は ウェブクルー 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にする
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を使えるようにするため、下記のコードを追記
<uses-library android:name="com.google.android.things" />
- リレーモジュールのGPIOの名前取得用関数作成
/**
* 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を追加
<ListView
android:id="@+id/assistantResponsesListView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"/>
- リレー制御処理の追加
まず、105行目の上に、喋った言葉の保存用に変数を作成
private String mResultString = "";
mAssistantResponseObserverの処理で、113行目のRESULTの処理に、「turn on/off swich」と喋ったときに、リレーを制御する処理とリレー制御の履歴出力を追加
さらに、リレー制御をした時は、GoogleAssistantの回答は必要ないので、AUDIO_OUTの処理にリレー制御をした時は、GoogleAssistantの回答を再生しない処理を追加
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行目辺りに宣言
private Gpio mRelay;
リレー制御履歴表示用に、222行目あたりArrayListとArrayAdapterを宣言
private ArrayList<String> mAssistantResponses = new ArrayList<>();
private ArrayAdapter<String> mAssistantResponsesAdapter;
234行目にAdapterの設定追加
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行目辺りに追加
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です。よろしくお願いします。
ウェブクルーでは一緒に働いていただける方を随時募集しております。
お気軽にエントリーくださいませ。