我只是想知道是否可以/從哪裏開始測量Android設備的向上和向下移動。我需要它儘可能準確。是否有可能測量手機垂直移動的距離
我完全迷失了方向的在哪裏看我已經看到有一些方法here,看着these old questions他們提到這是相當困難的,但我想知道如果從那時開始,曾出現過任何改進的Android的新版本。
下面的圖片是方向的一個額外的例子,我想手機在移動。
我只是想知道是否可以/從哪裏開始測量Android設備的向上和向下移動。我需要它儘可能準確。是否有可能測量手機垂直移動的距離
我完全迷失了方向的在哪裏看我已經看到有一些方法here,看着these old questions他們提到這是相當困難的,但我想知道如果從那時開始,曾出現過任何改進的Android的新版本。
下面的圖片是方向的一個額外的例子,我想手機在移動。
臨睡前的解決方案,我會分裂成小資產的解決方案,並把這一難題的解決方案
顯示時間爲第一步,我將實現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()) + "");
}
});
}
認爲這方案是爲了說明這一目標如何能夠達成,我相信這是可以做到不同的方式。但我想展示解決方案背後的邏輯。
這裏是一個應用程序的屏幕截圖,用於計算每次手機垂直時間和垂直時間的總時間。
的解決方案,包括一些說明:
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的源代碼
之前,我們必須瞭解傳感器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 [在海拔上移動]
Z軸的變化實際上是海拔的變化。 –
Y = 9.77622不是加速度,因爲設備正在移動,但重力加速。 – geo
案例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數據或運動傳感器數據的細節,因爲您可以輕鬆地谷歌並找到幫助。我相信更重要的是理解涉及設備垂直運動的數學和物理學。
更準確地說,我知道這是可以做到的,儘管我真的在尋找一個如何完成的例子。 – jackdh