naoki86star

インターネットの片隅でなにかしら書いてみる

com.google.android.apps.simplepedometerのこと

https://github.com/google/simple-pedometer

まるまる同じコードでなくクラスをコピーして動かしてみたのです。

Andoroidの加速度センサーを使うところから初めての経験です。*1

コードの内容を自分の言葉で説明してみます。

  • SensorFusionMath.java

数学の関数:Σ,内積,正規化,ベクトル積*2

  • SimplePedometerActivity.java

AndroidのUI部分+加速度センサーの準備

センサーサービスのオブジェクト準備

    // Get an instance of the SensorManager
    sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
    accel = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

判定処理を別クラス(SimpleStepDetector)に定義しそれの生成と、その結果はこのクラスで受け取るという手続き

    simpleStepDetector = new SimpleStepDetector();
    simpleStepDetector.registerListener(this);

onResume():UIがアクティブになったときに、センサーサービスの通知を受け取りを開始している

    sensorManager.registerListener(this, accel, SensorManager.SENSOR_DELAY_FASTEST);

onPause():UIがひっこんだときにセンサーサービスの通知を解除している

    sensorManager.unregisterListener(this);

コールバックインタフェースの定義、判定が1歩ごとにコールしてくれるという構造。

  • SimpleStepDetector.java

ここが歩数判定のロジック。

SimplePedometerActivity::onResume()でsensorManager.registerListener()を呼び出した以降センサーオブジェクト側の任意のタイミングでupdateAccel()を呼び出してくるという構造です。
まず、この呼び出し間隔がどのくらい?かというのが自分の知っておきたい点です。adbでながめていたら、KYF35は10msec程度、zteは20msecの間隔であがってきていました。

updateAccel()に3方向の加速度が渡されてきて、横置きにしているとどれかひとつ例えばz軸方向が、昔物理の時間とかで見覚えある数字9.8に近い数字(つまり重力加速度ですな)なのでセンサーの加速度たしかにとれてそれがプログラムに通知されているみたいです。

この加速度ををまずリングバッファにいれて、軸ごとに和をとってデータのサイズで割る、つまり平均をとっているようです。*3

センサーからの数値を平滑化した加速度と最新の加速度の内積をとって、平滑化した加速度の正規化した値を引いてます。(currentZ)

    // Next step is to figure out the component of the current acceleration
    // in the direction of world_z and subtract gravity's contribution

normalization_factorを引いているのは重力の寄与分を引いているとのことみたいです。

currentZをリングバッファにいれて合計をとっているのは、積分にあたるのかなぁ、velocityEstimate:速度見積もりといってるので、このサンプルは加速度の通知間隔を100msecと想定しているのかもしれない(VEL_RING_SIZE=10で、10個足したのをそのままvelocityとするなら)

最後以下の条件がなりたったら親クラスに通知というはこび。

    if (velocityEstimate > STEP_THRESHOLD && oldVelocityEstimate <= STEP_THRESHOLD
        && (timeNs - lastStepTimeNs > STEP_DELAY_NS)) {
      listener.step(timeNs);
      lastStepTimeNs = timeNs;
    }

____________________________


で、ほぼこのままのコードで実測した結果ですが、なにがしかの数字はでてきます。

動いていないときには0カウント、カウントが出る場合、だいたい300秒のあいだに20~50カウント、といった数字で、全然実態を表現していない感じではあるのです。
でもそれは加速度の通知間隔としきい値の定義がマッチしていないからであり、簡易な判定ロジックでももう少し改善できると思うのでさらに調べる*4つもりでいます。
____________________________
(9/19追記)

夜中にほんの30秒ほど外を歩いて得られる値を実測してみました。
プログラムで30秒間の加速度(ax,ay,az)をログに吐いて、それをExcelで同じ計算式でvelocityEstimateの値を求めてプロットしています。一回ずつしかデータとれてません。2つ同時でなく、順番に測った結果です。*5それでもとりあえず、ふーん、という感想。

  • この結果からするとしきい値50fは大き4fは小さすぎると思われる。うまいこととるとzteのほうは歩数計としても結構期待できる。
  • KYF35のプロットがばらついていることについて。KYF35のtimeNSが精度が悪いようにみえた。もしくは加速度の通知が欠落しているかもしれない。


(ZTE/BladeSlight)
f:id:naoki86star:20170919211314p:plain


(KYF35)
f:id:naoki86star:20170919211342p:plain
____________________________

*1:もう10年くらい前シリアルポート出力の2軸のいわゆる電子工作キットで遊んだことはあります。積分すれば移動距離わからねとか最初思ったのが出力のノイズというか変動をみてこりゃ動いている止まっているがわかれば恩の字ぢゃ、という記憶。

*2:ベクトル積というのはまったく使ったことない・分からない

*3:正確にminでリングバッファサイズか入れた数かで割ってますけど、10msecで通知してくるから起動してからあっというまにリングバッファサイズに到達してしまいますな

*4:実態は試行錯誤

*5:実験が雑ですけどAndroidでとろうとするのは結構大変で結果についてまだまずいところあるかもしれない。