AndroidWearの加速度センサ値をスマホでリアルタイムにグラフ描画する!(前編)

  • このエントリーをはてなブックマークに追加
  • Pocket
  • LINEで送る

AndroidWearで取得した加速度をスマホに送信して、リアルタイムにグラフ描画するアプリを作って見ます。
この(前編)では、AndroidWear側の処理のみ紹介します。

(後編)では、mobile側のプログラムを紹介します。
グラフ描画はMPAndroidChartという便利なライブラリがあるので、こちらを利用します。
githubのライブラリを使うので、開発環境はAndroidStudioになります。

実際に作成したアプリです。

手順

wear側(前編)

1.加速度データ取得

2.加速度データ送信

mobile側(後編)

3.加速度データ受信

4.加速度をグラフにプロット

大雑把ですが、こんな流れです。

1.加速度データ取得

まずはwearで加速度を取得します。

1-1.センサーマネージャの取得

//センサーマネージャーを取得 
manager = (SensorManager)getSystemService(SENSOR_SERVICE); 
//センサマネージャに TYPE_ACCELEROMETER(加速度センサ) を指定します。 
sensor_h = manager_h.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

1-2 .SensorEventListenerインタフェースの実装

public class MainActivity extends Activity implements SensorEventListener{}
onSensorChanged

加速度センサの値に変化があると、ここの部分が実行されます。

なので、この部分に加速度データを送信するプログラムを書きます。

onAccuracyChanged

センサの精度に変更があったときに実行されます。

1-3.値の取得(onSensorChanged)

加速度を取得した時にデータ送信したいので、onSensorChanged内に送信処理を書きます。

@Override
public void onSensorChanged(SensorEvent event) {
    if(count>= 10) {
        count = 0;
        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
            //x = (x * GAIN + event.values[0] * (1 - GAIN));
            //y = (y * GAIN + event.values[1] * (1 - GAIN));
            //z = (z * GAIN + event.values[2] * (1 - GAIN));
            x = event.values[0];
            y = event.values[1];
            z = event.values[2];
            mTextView.setText(String.format("X : %f\nY : %f\nZ : %f" , x, y, z));
        }
    }else count++;
}

引数のevent.values[]に加速度が格納されています。
加速度はXYZの3方向で出力されるので、それぞれevent.values[0], event.values[1], event.values[2]から取り出します。

ちなみに、心拍数のような要素が一つのデータの場合はevent.values[0]のみ用います。

3行目に注目してください。

if(count>= 10)

加速度を取得しても10回に一度だけ送信するようにしています。
これは加速度を全て送信するとmobileとwearの通信帯域が圧迫されて処理が追いつかなくなるからです。
この処理は簡単ですが、他にも数回分の加速度をまとめて送信する方法や、一定間隔で送信する方法もあります。
デバイスのセンサーによって検出頻度が変わってくるので、様子を見て変更してください。
冒頭の動画で使っているスマートウォッチはHUAWEI WATCH初代です。

2.加速度データ送信

//転送セット
String SEND_DATA = x + "," + y + "," + z;
    if (mNode != null) {
        Wearable.MessageApi.sendMessage(mGoogleApiClient, mNode, SEND_DATA, null).setResultCallback(new ResultCallback<MessageApi.SendMessageResult>() {
          @Override
            public void onResult(MessageApi.SendMessageResult result) {
            if (!result.getStatus().isSuccess()) {
            Log.d(TAG, "ERROR : failed to send Message" + result.getStatus());
        }
    }
    });
}

wearで加速度を取得したので、それを整形してmobileに送信します。

wearとmobileのデータ通信にはDataLayerAPIを使います。
DataLayerAPIが持つクラスにはData Item,Messageがあります。
Data Itemは同期通信、Messageは非同期通信です。
画像などの大きなデータを送るときは、Data ItemにAssetを付加します。

MainActvity.java(wear)

package yokohama.mio.sensorplot;

import android.app.Activity;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.support.wearable.view.WatchViewStub;
import android.util.Log;
import android.view.WindowManager;
import android.widget.TextView;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.wearable.MessageApi;
import com.google.android.gms.wearable.NodeApi;
import com.google.android.gms.wearable.Wearable;

import java.util.Date;

public class MainActivity extends Activity implements SensorEventListener {
    private final String TAG = MainActivity.class.getName();
    private TextView mTextView;
    private SensorManager mSensorManager;
    private GoogleApiClient mGoogleApiClient;
    private String mNode;
    private float x,y,z;
    int count = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
        stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
            @Override
            public void onLayoutInflated(WatchViewStub stub) {
                mTextView = (TextView) stub.findViewById(R.id.text);
                mTextView.setTextSize(36.0f);
            }
        });

        mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);

        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addApi(Wearable.API)
                .addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
                    @Override
                    public void onConnected(Bundle bundle) {
                        Log.d(TAG, "onConnected");
                        Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).setResultCallback(new ResultCallback<NodeApi.GetConnectedNodesResult>() {
                            @Override
                            public void onResult(NodeApi.GetConnectedNodesResult nodes) {
                                if (nodes.getNodes().size() > 0) {
                                    mNode = nodes.getNodes().get(0).getId();
                                }
                            }
                        });
                    }

                    @Override
                    public void onConnectionSuspended(int i) {
                        Log.d(TAG, "onConnectionSuspended");

                    }
                })
                .addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
                    @Override
                    public void onConnectionFailed(ConnectionResult connectionResult) {
                        Log.d(TAG, "onConnectionFailed : " + connectionResult.toString());
                    }
                })
                .build();
    }

    @Override
    protected void onResume() {
        super.onResume();

        Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL);
        mGoogleApiClient.connect();
    }

    @Override
    protected void onPause() {
        super.onPause();
        mSensorManager.unregisterListener(this);
        mGoogleApiClient.disconnect();
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        if(count>= 10) {
            count = 0;
            if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
                x = event.values[0];
                y = event.values[1];
                z = event.values[2];
                mTextView.setText(String.format("X : %f\nY : %f\nZ : %f" , x, y, z));
                String SEND_DATA = x + "," + y + "," + z;
                if (mNode != null) {
                    Wearable.MessageApi.sendMessage(mGoogleApiClient, mNode, SEND_DATA, null).setResultCallback(new ResultCallback<MessageApi.SendMessageResult>() {
                        @Override
                        public void onResult(MessageApi.SendMessageResult result) {
                            if (!result.getStatus().isSuccess()) {
                                Log.d(TAG, "ERROR : failed to send Message" + result.getStatus());
                            }
                        }
                    });
                }
            }
        }else count++;
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
    }
}

 

次回

次回は後編です。

mobileに送信した加速度データを受信して、グラフにプロットします。

参考

Android Wear開発まとめ|ngsw_taro

Android WearのData Layer APIを試してみた|bati11 の 日記

コールバック関数 (callback function)|「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典

SensorManager|AndroidDeveloper

  • このエントリーをはてなブックマークに追加
  • Pocket
  • LINEで送る

SNSでもご購読できます。

コメント

  1. komaru より:

    後編はいつになりますか?

  2. matu_mio より:

    記事をご覧いただきありがとうございます。
    後編を掲載しました。
    更新が遅くなり申し訳ございません。
    またわからない点などありましたら、ご連絡ください。

    AndroidWearの加速度センサ値をスマホでリアルタイムにグラフ描画する!(後編)|mio.yokohama
    http://mio.yokohama/?p=461

コメントを残す

*