2016-10-05 45 views
7

我只是想知道是否可以/從哪裏開始測量Android設備的向上和向下移動。我需要它儘可能準確。是否有可能測量手機垂直移動的距離

我完全迷失了方向的在哪裏看我已經看到有一些方法here,看着these old questions他們提到這是相當困難的,但我想知道如果從那時開始,曾出現過任何改進的Android的新版本。

下面的圖片是方向的一個額外的例子,我想手機在移動。

enter image description here

+0

更準確地說,我知道這是可以做到的,儘管我真的在尋找一個如何完成的例子。 – jackdh

回答

4

臨睡前的解決方案,我會分裂成小資產的解決方案,並把這一難題的解決方案

  1. 我們需要聽電話傳感器
  2. 我們需要檢查手機處於垂直位置或不
  3. 我們需要做的是垂直註冊電話時間計數器計數
  4. 我們需要在屏幕上

顯示時間爲第一步,我將實現SensorEventListener給我們班,這樣可以讓我們用onSensorChanged的方法。

@Override 
public void onSensorChanged(SensorEvent event) { 
    if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { 
     listenToSensors(event); 
    } 
} 

private void listenToSensors(SensorEvent event) { 
    if (isPhoneVertical(event)) { 
     timeCounter(); 
     if (mStatus) { 
      mStartTime = getStartTime(); 
      mStatus = false; 
     } 
    } else { 
     if (!mStatus) { 
      mTotalTime = getDiffTime() + mTotalTime; 
      mStatus = true; 
     } 
    } 
} 

對於第二步,我建立了一個叫isPhoneVertical檢查,如果我們的電話是垂直的方式或不方法,它主要是檢查y軸。您可以通過更改maxVertical來改變陡度。 價值不那麼陡峭,0意味着手機應該幾乎100%垂直。對於我的測試設置爲3

private boolean isPhoneVertical(SensorEvent event) { 
    float[] values = event.values; 
    double y = values[1]; 
    // do not change this value 
    double yAxisInitValue = 10.0; 
    double verMargin = yAxisInitValue - maxVertical; 

    return y >= verMargin; 
} 

3步我做了幾個方法來檢查開始時間和結束時間,並更新一個全局變量,在秒跟蹤時間。

private long getStartTime() { 
    return System.currentTimeMillis()/1000; 
} 

private long getDiffTime() { 
    return getStartTime() - mStartTime; 
} 

第4步我已經做了常規runOnUiThread更新屏幕上的時間。

private void timeCounter() { 
    runOnUiThread(new Runnable() { 
     @Override 
     public void run() { 
      mView1.setText("Phone has been vertical for: " + getDiffTime() + " seconds"); 
      mView2.setText("The total time: " + (mTotalTime + getDiffTime()) + ""); 
     } 
    }); 
} 

認爲這方案是爲了說明這一目標如何能夠達成,我相信這是可以做到不同的方式。但我想展示解決方案背後的邏輯。

這裏是一個應用程序的屏幕截圖,用於計算每次手機垂直時間和垂直時間的總時間。

enter image description here

的解決方案,包括一些說明:

MainActivity。java的

public class MainActivity extends Activity implements SensorEventListener { 
    private SensorManager mSensorManager; 
    private Sensor mAccelerometer; 
    private TextView mView1, mView2; 
    private long mStartTime; 
    private long mTotalTime; 
    private boolean mStatus = true; 
    // less value her less steep, 0 means the phone should almost be 100% vertical 
    // try it out 
    private double maxVertical = 3.0; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     requestWindowFeature(Window.FEATURE_NO_TITLE); 
     getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 
       WindowManager.LayoutParams.FLAG_FULLSCREEN); 

     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     mView1 = (TextView) findViewById(R.id.textView1); 
     mView2 = (TextView) findViewById(R.id.textView2); 

     mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); 
     mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); 
    } 

    @Override 
    public void onSensorChanged(SensorEvent event) { 
     if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { 
      listenToSensors(event); 
     } 
    } 

    private void listenToSensors(SensorEvent event) { 
     if (isPhoneVertical(event)) { 
      timeCounter(); 
      if (mStatus) { 
       mStartTime = getStartTime(); 
       mStatus = false; 
      } 
     } else { 
      if (!mStatus) { 
       mTotalTime = getDiffTime() + mTotalTime; 
       mStatus = true; 
      } 
     } 
    } 

    // This method return true only for specific phone orientation 
    // y axis for vertical orientation 
    private boolean isPhoneVertical(SensorEvent event) { 
     float[] values = event.values; 
     double y = values[1]; 
     // do not change this value 
     double yAxisInitValue = 10.0; 
     double verMargin = yAxisInitValue - maxVertical; 

     return y >= verMargin; 
    } 

    private long getStartTime() { 
     return System.currentTimeMillis()/1000; 
    } 

    private long getDiffTime() { 
     return getStartTime() - mStartTime; 
    } 

    // update steps in user interface 
    private void timeCounter() { 
     runOnUiThread(new Runnable() { 
      @Override 
      public void run() { 
       mView1.setText("Phone has been vertical for: " + getDiffTime() + " seconds"); 
       mView2.setText("The total time: " + (mTotalTime + getDiffTime()) + ""); 
      } 
     }); 
    } 

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

    } 

    @Override 
    protected void onResume() { 
     super.onResume(); 
     mSensorManager.registerListener(this, 
       mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), 
       SensorManager.SENSOR_DELAY_NORMAL); 
    } 

    @Override 
    protected void onPause() { 
     super.onPause(); 
     // if you want to collect data while mobile screen off, just disable the 
     // following line, the app will still collecting sensor data 
     mSensorManager.unregisterListener(this); 
    } 
} 

activity_main.xml中

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:id="@+id/activity_main" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:paddingBottom="@dimen/activity_vertical_margin" 
    android:paddingLeft="@dimen/activity_horizontal_margin" 
    android:paddingRight="@dimen/activity_horizontal_margin" 
    android:paddingTop="@dimen/activity_vertical_margin" 
    tools:context="com.example.maytham.verticaltravels.MainActivity"> 

    <TextView 
     android:id="@+id/textView1" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:layout_alignParentLeft="true" 
     android:layout_alignParentStart="true" 
     android:layout_alignParentTop="true" 
     android:textSize="20sp" 
     android:text="TextView1" /> 

    <TextView 
     android:id="@+id/textView2" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:layout_alignParentLeft="true" 
     android:layout_alignParentStart="true" 
     android:layout_below="@+id/textView1" 
     android:layout_marginTop="57dp" 
     android:textSize="20sp" 
     android:text="TextView2" /> 
</RelativeLayout> 

我會留下一些鏈接,閱讀也是如此。

如果你認爲我會添加更多的Infor mation可以幫助你進一步解決你的問題,請讓我知道。目前還不清楚你是否在尋找步行檢測/計數器,如果這是你感興趣的事情,請看下面的答案/鏈接。

和GitHub的源代碼

+1

謝謝你,這是多優秀! – jackdh

+0

不客氣;) –

+0

如何計算行程距離,因爲您知道設備有多長時間垂直? – geo

3

之前,我們必須瞭解傳感器API,它是我們使用。

的Android傳感器API

的Android傳感器API提供了許多類和接口。是重要的接口傳感器API的如下:

1)的SensorManager類

android.hardware.SensorManager類提供了一些方法:

to get sensor instance, 
to access and list sensors, 
to register and unregister sensor listeners etc. 

你可以得到的SensorManager實例通過調用方法getSystemService()並傳遞其中的SENSOR_SERVICE常量。

SensorManager sm = (SensorManager)getSystemService(SENSOR_SERVICE); 

2)傳感器類

android.hardware.Sensor類提供的方法來得到傳感器如傳感器名稱,傳感器類型,傳感器的分辨率,傳感器類型等的信息。

3)SensorEvent類

它的實例是由系統創建的。它提供有關傳感器的信息。

4)SensorEventListener接口

它提供了兩個回調的方法來獲取信息時的傳感器值(x,y和z)的變化或傳感器精度的變化。 公共抽象方法描述

void onAccuracyChanged(Sensor sensor, int accuracy) 

    //it is called when sensor accuracy is changed. 

    *void onSensorChanged(SensorEvent event)* 

    //it is called when sensor values are changed. 

注:假設* X =水平側,Y =垂直側和所述裝置的Z =高程*。

創建一個簡單的xml,如active_main。XML

<RelativeLayout xmlns:androclass="http://schemas.android.com/apk/res/android" 
     xmlns:tools="http://schemas.android.com/tools" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     tools:context=".MainActivity" > 

     <TextView 
      android:id="@+id/textView1" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_alignParentLeft="true" 
      android:layout_alignParentTop="true" 
      android:layout_marginLeft="92dp" 
      android:layout_marginTop="114dp" 
      android:text="TextView" /> 

    </RelativeLayout> 

接下來,創建一個簡單的活動等MainActivity.java測量象向下/向上方向。

import android.app.Activity; 
import android.os.Bundle; 
import android.widget.TextView; 
import android.widget.Toast; 
import android.hardware.SensorManager; 
import android.hardware.SensorEventListener; 
import android.hardware.SensorEvent; 
import android.hardware.Sensor; 
import java.util.List; 
public class MainActivity extends Activity { 
    SensorManager sm = null; 
    TextView textView1 = null; 
    List list; 

    SensorEventListener sel = new SensorEventListener(){ 
     public void onAccuracyChanged(Sensor sensor, int accuracy) {} 
     public void onSensorChanged(SensorEvent event) { 
      float[] values = event.values; 
      textView1.setText("x: "+values[0]+"\ny: "+values[1]+"\nz: "+values[2]); 
     } 
    }; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     /* Get a SensorManager instance */ 
     sm = (SensorManager)getSystemService(SENSOR_SERVICE); 

     textView1 = (TextView)findViewById(R.id.textView1); 

     list = sm.getSensorList(Sensor.TYPE_ACCELEROMETER); 
     if(list.size()>0){ 
      sm.registerListener(sel, (Sensor) list.get(0), SensorManager.SENSOR_DELAY_NORMAL); 
     }else{ 
      Toast.makeText(getBaseContext(), "Error: No Accelerometer.", Toast.LENGTH_LONG).show(); 
     } 
    } 

    @Override 
    protected void onStop() { 
     if(list.size()>0){ 
      sm.unregisterListener(sel); 
     } 
     super.onStop(); 
    } 
} 

輸出好像:

X = 0.0 [否移動在水平]

Y = 9.77622 [繼續前行垂直]

Z = 0.813417 [在海拔上移動]

+0

Z軸的變化實際上是海拔的變化。 –

+0

Y = 9.77622不是加速度,因爲設備正在移動,但重力加速。 – geo

1

案例1:使用GPS內置於幾乎所有的Android設備可以提供的水平約2-3米,4-5米垂直儘可能準確的位置

GPS。如果您的案例的垂直精度正常,您可以在運動開始前獲取高度,並在結束時比較它們並獲得垂直運動。

如果您需要更高的精確度,則GPS無法提供任何安卓客戶級設備。有特殊的專業GPS設備(土地測量師使用,花費1000美元,很少運行Android操作系統)可以提供釐米級別的準確性,但這不是我們在這裏討論的。

Ofcource,你需要在室外以獲得良好的GPS接收。

情況2:使用運動傳感器

如果一個人知道初始速度,加速度和時間可以計算移動的距離。看看這個 http://www.dummies.com/education/science/physics/finding-distance-using-initial-velocity-time-and-acceleration/

我們

距離=的啓動速度+(1/2)* *加速時間^ 2

在我們的例子中,我們知道時間(實際時間從設備內置時鐘開始,我們可以使用設備的傳感器獲得加速度。請注意TYPE_ACCELEROMETER傳感器給我們沿每個軸的加速力,包括重力,所以我們必須減去引力(我們從TYPE_GRAVITY傳感器獲得它)。請記住,當有人拿起設備時,他的手不一定會以穩定的速度或加速度移動。因此,必須考慮速度和加速度的變化。

關於啓動速度,有幾種情況。

如果它爲零(用戶站在建築物中,從桌子上拿起手機並將其移動到他的耳朵),您只需從公式中省略它。

在情況下,它不爲零,使得

速度=器件速度+用戶的「車輛」速度

,我們必須使用GPS來計算它。如果用戶在起重直升機上,我們可以做到這一點。如果他在電梯裏或者在建築物的樓梯上行駛,我們不能這樣做,因爲那裏沒有GPS接收。在直升機或電梯加速的情況下,事情變得更加複雜,因爲沒有辦法自動將「直升機/電梯加速度」與「用戶移動設備」加速度分開。當用戶走路時相同。在那種情況下,隨着他的腳步和身體上下移動,會發生速度,加速度和方向的不斷變化。

我承認,我不知道使用運動傳感器方法可以計算出距離的實際精度。正如你從我寫的內容看到的那樣,我認爲找到一個在任何情況下都適用的解決方案是沒有辦法的。但在用戶仍然只是垂直移動設備的特殊情況下,您可以做一些我相信的事情。

P.S.我沒有深入瞭解如何從設備傳感器獲取GPS數據或運動傳感器數據的細節,因爲您可以輕鬆地谷歌並找到幫助。我相信更重要的是理解涉及設備垂直運動的數學和物理學。