グーグルの携帯電話を手に入れてから、私の頭の中を定期的にさまよっています。「この携帯電話で何をするのがとても楽しいだろうか?」 もちろん、加速度を測定してください! そして、結果として、速度と移動距離を計算します。 もちろん、加速度計のみを使用すると、測定にいくつかの制限が課せられます。まず、動きが直線的である必要があり、次に、空間内の装置の向きが変わらないようにし、第三に、測定を開始する前にセンサーを較正することをお勧めします。 すぐに言わなければならない-これらの要件を緩和する方法がありますが、それについては後で詳しく説明します。
主な質問は、いつものように、「なぜ?」です。 GPSがあるのはなぜですか? まあ、本当のポイント。 ただし、GPSはどこでも機能しませんが、加速度計です-電話であなたと一緒です。 たとえば、地下鉄で衛星をキャッチしようとしましたか?..
「理由」がわかったら、「方法」に進みます...
加速の変化に対応するには、SensorEventListenerインターフェースをどこかに実装する必要があります。 どうすればいいかまだわかっていないので、抽象クラスを作成します
public abstract class Accelerometer implements SensorEventListener { protected float lastX; protected float lastY; protected float lastZ; public abstract Point getPoint(); public void onAccuracyChanged(Sensor arg0, int arg1) { } }
同時に、センサー
カウンターの読み取り値を保存するクラス:
public class Point { private float x = 0; private float y = 0; private float z = 0; private int cnt = 1; public float getX() { return x/(float)cnt; } public float getY() { return y/(float)cnt; } public float getZ() { return z/(float)cnt; } public Point(float x, float y, float z, int cnt) { this.x = x; this.y = y; this.z = z; this.cnt = cnt; } }
そして次に何をすべきかを考えてください。 SENSOR_DELAY_GAMEモードでセンサーからの情報を更新する期間は約20ミリ秒です。 多くの場合、これで十分です。タスクではこれは必要ありません。 一方、測定値の取得頻度を減らすと、「放出」に陥り、精度が低下するリスクがあります。 たとえば、最後の1秒間に何らかの形で平均加速度値を定期的に受信することは論理的です。 配列を保存して平均値を計算するのは費用がかかります。取得したすべての値を加算して数で割るのははるかに簡単です。 また、まだ実装されていないキャリブレーションであるdX、dY、dZも提供しています。
結果は次のとおりです。
public class XYZAccelerometer extends Accelerometer { private static final int BUFFER_SIZE = 500;
許可を得て、センサーのキャリブレーション方法の説明をスキップします。 しばらくの間悔い改めを取り除いてから、XYZ加速度計で適切なdX、dY、dZを設定する必要があると言うだけで十分です。 この手順を無視することはできません。
私たちが寝ている間 、重力の加速度は絶えず作用しており、センサーがそれを測定します。
最も重要なのは、インターバルのモーションパラメータを保存および計算するためのクラスを取得することです。
public class MeasurePoint { private float x; private float y; private float z; private float speedBefore; private float speedAfter; private float distance; private float acceleration; private long interval; public MeasurePoint(float x, float y, float z, float speedBefore, long interval) { this.x = x; this.y = y; this.z = z; this.speedBefore = speedBefore; this.interval = interval; speedAfter = 0; calc(); } private void calc(){
そして、実験全体に関する情報を保存するクラス:
public class MeasureData {
すべてがシンプルで明確だと思います。 アクティビティでこれを使用するだけです...ところで、まだありません。 レイアウトから始めましょう:
<serviceLinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <serviceButton android:id="@+id/btn" android:text="TEST" android:layout_width="300px" android:layout_height="200px" android:onClick="onButtonTest" /> <serviceTextView android:id = "@+id/txt" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text=":" /> <service/LinearLayout>
そしてコード:
public class TestActivity extends Activity { static final int TIMER_DONE = 2; static final int START = 3; private StartCatcher mStartListener; private XYZAccelerometer xyzAcc; private SensorManager mSensorManager; private static final long UPDATE_INTERVAL = 500; private static final long MEASURE_TIMES = 20; private Timer timer; private TextView tv; private Button testBtn; int counter; private MeasureData mdXYZ; Handler hRefresh = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case TIMER_DONE: onMeasureDone(); String es1 = Float.toString(Math.round(mdXYZ.getLastSpeedKm()*100)/100f); tv.append(" END SPEED " + es1 + " \n"); enableButtons(); break; case START: tv.append(" START"); timer = new Timer(); timer.scheduleAtFixedRate( new TimerTask() { public void run() { dumpSensor(); } }, 0, UPDATE_INTERVAL); break; } } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); tv = (TextView) findViewById(R.id.txt); testBtn = (Button) findViewById(R.id.btn); } @Override protected void onResume() { super.onResume(); tv.append("\n .."); mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); setAccelerometer(); setStartCatcher(); mSensorManager.registerListener(xyzAcc, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_GAME); } @Override protected void onPause() { mSensorManager.unregisterListener(xyzAcc); super.onPause(); } public void onButtonTest(View v) { disableButtons(); mdXYZ = new MeasureData(UPDATE_INTERVAL); counter = 0; tv.setText(""); hRefresh.sendEmptyMessage(START); } void dumpSensor() { ++counter; mdXYZ.addPoint(xyzAcc.getPoint()); if (counter > MEASURE_TIMES) { timer.cancel(); hRefresh.sendEmptyMessage(TIMER_DONE); } } private void enableButtons() { testBtn.setEnabled(true); } private void setAccelerometer() { xyzAcc = new XYZAccelerometer(); mSensorManager.registerListener(xyzAcc, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_UI); } private void disableButtons() { testBtn.setEnabled(false); } private void onMeasureDone() { mdXYZ.process(); } }
以上です。 驚くべきことに、平坦な経路では、この方法は非常に優れた測定精度を提供します。
1つの実験のグラフを囲みます。青い線は加速度計によって計算された速度、赤い線はGPSから最大周波数で取得された速度です。 ブラックブロット-実験終了時の速度計の速度。
