13
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ロボホンとラズベリーパイをFlaskで連携して温度を喋らせてみた

Last updated at Posted at 2019-10-19

目的

ラズベリーパイと連携し、ロボホンに温度を喋らせる

Flaskフロー.png

完成動画

IMAGE ALT TEXT HERE

前提

ラズベリーパイにFlaskをインストールし、温度センサーのデータが取得できるようになっている。
(前回の記事通りに設定されている前提とします)
AndroidStudioの設定やロボホンテンプレートのインストール手順等は割愛する。

Pythonスクリプト修正

前回の手順通りに設定を行った場合、返り値に余計な文字が入ってしまう。
数値のみを返した方が処理しやすいので、ラズベリーパイ(Flask)のPythonスクリプトを修正する。
今回は温度のデータを取り扱うので、compensate_T関数を修正する。

common.py
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変数を定義する。

MainActivity.java
private boolean hascall;

実装中のデバッグ用に発話ボタンの設定を行う。
今回のアプリの場合、アプリが自動起動し、発話後に自動終了する為、必須ではない。

MainActivity.java
//発話ボタンの実装.
        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で使用できるように数値を取得する。

MainActivity.java
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");
        }
    }

新規作成するシーンを有効化する。
新規作成シーンについては後述。

MainActivity.java
// 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);
        }

アプリ終了時にシーンを無効化する。

MainActivity.java
// onPauseメソッド
//Scene無効化.
        VoiceUIManagerUtil.disableScene(mVoiceUIManager, ScenarioDefinitions.SCENE_COMMON);
        VoiceUIManagerUtil.disableScene(mVoiceUIManager, ScenarioDefinitions.SCENE01);
        VoiceUIManagerUtil.disableScene(mVoiceUIManager, ScenarioDefinitions.SCN_TEMP_CALL);

VoiceUIListenerクラスからのコールバックを実装する。
この時点でhascall変数のフラグをtrueにする。
finish()メソッドを呼び出すとアプリが自動的に終了する。

MainActivity.java
@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

シナリオで使用する変数を定義する。

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へアクセスする。

onBtnHttpClicked.java
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

アプリ起動のワードを変更する。
今回は「おんどなんど(温度、何度?)」とする。

home.hvml
<situation priority="78" topic_id="start" trigger="user-word">
            ${Local:WORD_APPLICATION_FREEWORD} eq おんどなんど
</situation>

シナリオ内のセリフも適当に変更する。

home.hvml
<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歳児なので、多めに見ましょう...)

response.hvml
<?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連携)

13
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?