目的
ラズベリーパイと連携し、ロボホンに温度を喋らせる
完成動画
前提
ラズベリーパイにFlaskをインストールし、温度センサーのデータが取得できるようになっている。
(前回の記事通りに設定されている前提とします)
AndroidStudioの設定やロボホンテンプレートのインストール手順等は割愛する。
Pythonスクリプト修正
前回の手順通りに設定を行った場合、返り値に余計な文字が入ってしまう。
数値のみを返した方が処理しやすいので、ラズベリーパイ(Flask)のPythonスクリプトを修正する。
今回は温度のデータを取り扱うので、compensate_T関数を修正する。
def compensate_T(adc_T):
global t_fine
v1 = (adc_T / 16384.0 - digT[0] / 1024.0) * digT[1]
v2 = (adc_T / 131072.0 - digT[0] / 8192.0) * (adc_T / 131072.0 - digT[0] / 8192.0) * digT[2]
t_fine = v1 + v2
temperature = t_fine / 5120.0
- return "temp : %-6.2f " % (temperature)
+ return "%-6.2f " % (temperature)
ロボホンアプリの実装
テンプレートから変更する箇所を列挙していく。
values/string.xml等、記載がないものも適宜変更している。
MainActivity.java
初回起動の判定の為、hascall変数を定義する。
private boolean hascall;
実装中のデバッグ用に発話ボタンの設定を行う。
今回のアプリの場合、アプリが自動起動し、発話後に自動終了する為、必須ではない。
//発話ボタンの実装.
Button Button = (Button) findViewById(R.id.accost);
Button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
access_to_flask();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
if (mVoiceUIManager != null) {
VoiceUIVariableListHelper helper = new VoiceUIVariableListHelper().addAccost(ScenarioDefinitions.ACC_HELLO);
VoiceUIManagerUtil.updateAppInfo(mVoiceUIManager, helper.getVariableList(), true);
}
}
});
Flaskにアクセスし、hvmlで使用できるように数値を取得する。
protected void access_to_flask() throws ExecutionException, InterruptedException {
String temp = null;
ExecutorService exec = Executors.newSingleThreadExecutor();
Future<String> stringFuture = exec.submit(new onBtnHttpClicked());
temp = stringFuture.get();
Log.d("変数", temp);
int ret = VoiceUIVariableUtil.setVariableData(mVoiceUIManager, ScenarioDefinitions.MEM_TEMP, temp);
if(ret == VoiceUIManager.VOICEUI_ERROR){
Log.d(TAG, "setVariableData:VARIABLE_REGISTER_FAILED");
}
}
新規作成するシーンを有効化する。
新規作成シーンについては後述。
// onResumeメソッド
//Scene有効化.
VoiceUIManagerUtil.enableScene(mVoiceUIManager, ScenarioDefinitions.SCENE_COMMON);
VoiceUIManagerUtil.enableScene(mVoiceUIManager, ScenarioDefinitions.SCENE01);
VoiceUIManagerUtil.enableScene(mVoiceUIManager, ScenarioDefinitions.SCN_TEMP_CALL);
if (mVoiceUIManager != null && !hascall) {
try {
access_to_flask();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
VoiceUIVariableListHelper helper = new VoiceUIVariableListHelper().addAccost(ScenarioDefinitions.ACC_TEMP_CALL);
VoiceUIManagerUtil.updateAppInfo(mVoiceUIManager, helper.getVariableList(), true);
}
アプリ終了時にシーンを無効化する。
// onPauseメソッド
//Scene無効化.
VoiceUIManagerUtil.disableScene(mVoiceUIManager, ScenarioDefinitions.SCENE_COMMON);
VoiceUIManagerUtil.disableScene(mVoiceUIManager, ScenarioDefinitions.SCENE01);
VoiceUIManagerUtil.disableScene(mVoiceUIManager, ScenarioDefinitions.SCN_TEMP_CALL);
VoiceUIListenerクラスからのコールバックを実装する。
この時点でhascall変数のフラグをtrueにする。
finish()メソッドを呼び出すとアプリが自動的に終了する。
@Override
public void onExecCommand(String command, List<VoiceUIVariable> variables) {
Log.v(TAG, "onExecCommand() : " + command);
switch (command) {
case ScenarioDefinitions.FUNC_TEMP_CALL:
hascall =true;
Log.d("TEST", "温度トリガー");
finish();
break;
case ScenarioDefinitions.FUNC_END_APP:
finish();
break;
case ScenarioDefinitions.FUNC_START_PROJECTOR:
//TODO プロジェクタマネージャの開始(プロジェクター利用時のみ).
//if(!isProjected) {
// startService(getIntentForProjector());
//}
break;
default:
break;
}
}
ScenarioDefinitions.java
シナリオで使用する変数を定義する。
//温度測定シナリオの定数
public static final String SCN_TEMP_CALL = PACKAGE + ".temp.response";
public static final String ACC_TEMP_CALL = ScenarioDefinitions.PACKAGE + ".temp.response";
public static final String FUNC_TEMP_CALL = "temp_response";
public static final String MEM_TEMP = ScenarioDefinitions.TAG_MEMORY_PERMANENT + ScenarioDefinitions.PACKAGE + ".temp";
public static final String ACC_GET_MEMORYP = ScenarioDefinitions.PACKAGE + ".get_memoryp.t1";
onBtnHttpClicked.java
新規作成する。
HttpURLConnectionメソッドでFlaskのURLへアクセスする。
public class onBtnHttpClicked implements Callable<String> {
@Override
public String call(){
try {
URL url = new URL("http://IPアドレス:80/temp");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
String str = InputStreamToString(con.getInputStream());
Log.d("Flask_caller", str);
return str;
} catch (Exception ex) {
Log.d("Exception Error", String.valueOf(ex));
return "";
}
}
static String InputStreamToString(InputStream is) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
br.close();
return sb.toString();
}
}
XXX_home.hvml
アプリ起動のワードを変更する。
今回は「おんどなんど(温度、何度?)」とする。
<situation priority="78" topic_id="start" trigger="user-word">
${Local:WORD_APPLICATION_FREEWORD} eq おんどなんど
</situation>
シナリオ内のセリフも適当に変更する。
<action index="2">
<speech>温度を測定するね</speech>
<behavior id="assign" type="normal" />
<control function="start_activity" target="home">
<data key="package_name" value="jp.co.anyplus.temp_check" />
<data key="class_name" value="jp.co.anyplus.temp_check.MainActivity" />
</control>
</action>
XXX_response.hvml
温度を読み上げるhvmlを新規作成する。
ちなみに「25℃」のように記載すると、「25たび」と読まれてしまった。
平仮名で「25ど」に修正すると、想定通りにしゃべってくれた。
(5歳児なので、多めに見ましょう...)
<?xml version="1.0" ?>
<hvml version="2.0">
<head>
<producer>jp.co.anyplus.temp_check</producer>
<description>温度測定のシナリオ</description>
<scene value="jp.co.anyplus.temp_check.temp.response" />
<version value="1.0" />
<accost priority="74" topic_id="response" word="jp.co.anyplus.temp_check.temp.response" />
</head>
<body>
<topic id="response" listen="false">
<action index="1">
<speech>温度は${memory_p:jp.co.anyplus.temp_check.temp}ど、みたいだよ</speech>
<behavior id="assign" type="normal" />
<control function="temp_response" target="jp.co.anyplus.temp_check" />
</action>
</topic>
</body>
</hvml>
参考
今回はこちらの記事を参考にさせて頂きました。
「私、いくつに見える?」への返答機能をRoBoHoNに実装する(AWS Rekognition連携)