Edited at

スマホのセンサーとManticoreのクルマのデータを使ったSDLアプリを作ってみた


SDLアプリコンテストって?

SDLアプリコンテスト2019は、SDLの普及を目的としたSDLコンソーシアム日本分科会の協力で実施するもので、今回が2回目の開催となります。

本コンテストでは、四輪と二輪の両方を対象に、SDLに対応するアプリ(Android、iOSアプリ)を広く募集します。年齢、性別、国籍等は不問で、個人・チームどちらでも応募可能です。

SDLアプリコンテスト2019の応募締切は2019年10月31日までですので、リンク先を確認して、急いで応募しよう(来年にも期待!)


SDLとは?

SDLアプリコンテスト2019の「SDLとは」のページを確認しよう!


今回のサンプル「フェード現象の警告」


フェード現象とは?

自動車やオートバイでの走行中に摩擦ブレーキを連続使用した結果、ブレーキの効き(制動力)が低下すること。

Wikipediaより

初心者の時、こんな感じの思い出はないでしょうか?(事故まではないかw)

スクリーンショット 2019-10-23 19.39.31.png


一定の角度以上で下っていたら警告したい

以下の画像をクルマの車載モニターだとしよう。一定の角度で一定時間以上下っている場合、シフトレバー操作をエンジンブレーキがかかるポジションにしているか注意したい

image.png


【今回未実装】警告が出ていたポイントをクラウドに収集

今回は、スマホのセンサーとManticoreのクルマのデータを使ったサンプルの説明に特化したい為、実装は省略しています。

しかし、検出ポイントをクラウドで収集して、他のドライバにシェアすることにより、

・下っている最中ではなく、付近に近づいたら事前に警告したり

・警告が発生するポイントって、案外走り屋としては面白い?

などの使い道が出てくると考えている。


今回のソースと前提の資料

今回のサンプルは、Githubに格納しています。

SDLアプリとAndroidアプリの違いや基本的なサンプルについては、SDLアプリコンテスト広島 SDLハンズオンの資料で確認していただきたい。


サンプルの動作ムービー

リンクの動画をご確認ください。


スマホのセンサーデータを取得するには?

SDLServiceは、android.app.Serviceクラスを継承しています。なので、シンプルにSensorEventListenerをimplementsしてあげるだけです。


SDLService.javaの77行目付近

public class SdlService extends Service implements SensorEventListener {

private static final String TAG = "SDL Vehicle";
public static final String PORT_NAME = "port";

さらに、Activityの場合は、onCreateに記載しますが、Seviceクラスの場合は、onStartCommandにSensorManagerの定義を記述します。


SDLService.javaの159行目付近

    public int onStartCommand(Intent intent, int flags, int startId) {

if (null == intent || intent.equals(null) || intent.getData() == null){Log.e("Log", "the intent in onStartCommand is null");}
Bundle bundle = intent.getExtras();
if (bundle != null)
{
TCP_PORT = bundle.getInt(PORT_NAME);
}
sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
rotationSensor = sensorManager.getDefaultSensor(Sensor.TYPE_GAME_ROTATION_VECTOR);
sensorManager.registerListener(this, rotationSensor,
SensorManager.SENSOR_DELAY_NORMAL);
startProxy();

return START_STICKY_COMPATIBILITY;
//return START_STICKY;
}


余談ですが、160行目付近のintentのNullチェックを行っている部分は、MainActivityからパラメータ渡しで情報を受け取っている部分です。

MainActivityで画面に入力されたManticoreのポート番号をSDLSeviceに渡して、Manticoreに接続するために使っています。


SDLService.javaの160行目付近


if (null == intent || intent.equals(null) || intent.getData() == null){Log.e("Log", "the intent in onStartCommand is null");}
Bundle bundle = intent.getExtras();
if (bundle != null)
{
TCP_PORT = bundle.getInt(PORT_NAME);
}


センサーをの値を実際に取得しているのは、SDLService.javaの546行目付近からです。

サンプルなので超適当で、シフトレバーの状態がオートマ車はDRIVEの状態で、超雑ですが、50Hzくらいの周期でセンサーデータが飛んできているので、だいたい10秒くらい20度くらい傾いたら警告を表示するだけのサンプルになっています。


SDLService.javaの546行目付近

    public final void onSensorChanged(SensorEvent event) {

if(event.sensor.getType() == Sensor.TYPE_GAME_ROTATION_VECTOR){
//シフトがドライブの時だけ
if(prndl != null) {
if ("DRIVE".equals(prndl.toString())) {
float[] rotMatrix = new float[9];
float[] rotVals = new float[3];

SensorManager.getRotationMatrixFromVector(rotMatrix, event.values);
SensorManager.remapCoordinateSystem(rotMatrix,
SensorManager.AXIS_X, SensorManager.AXIS_Y, rotMatrix);

SensorManager.getOrientation(rotMatrix, rotVals);
float azimuth = (float) Math.toDegrees(rotVals[0]);
float pitch = (float) Math.toDegrees(rotVals[1]);
float roll = (float) Math.toDegrees(rotVals[2]);

if (pitch < -20) {
counter++;
} else if (pitch > 20) {
counter++;
} else {
counter = 0;
}

if (counter > 20) {
showAlert("マニュアル車なら2~3速のギアで、オートマ車も2レンジか3レンジで速度調整してください");
counter = 0;
}
}
}
}
}


Manticoreで警告表示するWindowを出すのは、SDLService.javaの423行目付近のshowAlertメソッドを使っています。

これだけで、警告表示ができるとはすごくシンプル!alert.setDuration(5000);で5秒だけ表示するようにしています。


SDLService.javaの423行目付近

    public void showAlert(String text){

Alert alert = new Alert();
alert.setAlertText1(text);
alert.setDuration(5000);
sdlManager.sendRPC(alert);
}

さらに、ManticoreからText to Speechで音声を再生した場合(英語のみ)、以下のコードをコピペして"Test"の部分をしゃべらせたいワードに変更すれば音声での警告も行えます


SDLService.java

sdlManager.sendRPC(new Speak(TTSChunkFactory.createSimpleTTSChunks("TEST")));



Manticoreからクルマのデータ(擬似データ)を取得する

Manticoreからクルマの擬似データをSDLアプリに送信することができます。送信するための画面はManticoreの右側にあるVEHICLE DATAの部分です。

image.png

今回はシフトレバーの値が取りたいので、「Prndl」の項目を選択して、シフトの状態を選択します。

image.png

変更された都度データを受信するプログラムは、SDLService.javaの244行目付近になります。

シフトレバーの状態は、onVehicleDataNotification.getPrndl();で取得できます。

ここで書かれているNotificationListenerは、定期的にデータが送信されるわけではなく、Manticoreで値を変更した都度データが飛んでくると思ってください


SDLService.javaの244行目付近

                    sdlManager.addOnRPCNotificationListener(FunctionID.ON_VEHICLE_DATA, new OnRPCNotificationListener() {

@Override
public void onNotified(RPCNotification notification) {
OnVehicleData onVehicleDataNotification = (OnVehicleData) notification;

sdlManager.getScreenManager().beginTransaction();

prndl = onVehicleDataNotification.getPrndl();



最後に

今回開発に使った環境については、SDLアプリコンテスト広島 ハンズオン事前資料に記載しています。

まだまだSDLについては、情報が少ないですが、どんどん情報公開してサンプルを充実できるようにがんばっていきます!

今回記事やハンズオンの資料を作りにあたり、田中さんの記事が非常に参考になりました。こちらも合わせて読んでいただければと思います。