¿Es posible medir hasta qué punto el teléfono viaja verticalmente

Sólo me pregunto si es posible / dónde empezaría a medir el movimiento ascendente y descendente de un dispositivo Android. Lo necesitaría para ser lo más preciso posible.

Estoy muy perdido de donde buscar He visto que hay ciertos métodos aquí , y mirando a estas viejas preguntas que mencionan es bastante difícil, pero yo quería saber si había habido alguna mejora desde entonces en las nuevas versiones de android.

La imagen de abajo es un ejemplo extra de la dirección en la que me gustaría que el teléfono se mueva.

Introduzca aquí la descripción de la imagen

Antes de ir a la solución, dividiría la solución en pequeños activos y pondría el rompecabezas para la solución

  1. Necesitamos escuchar sensores telefónicos
  2. Tenemos que comprobar que el teléfono está en posición vertical o no
  3. Tenemos que hacer un contador de tiempo que registrar el teléfono verticalmente y contar hasta
  4. Necesitamos mostrar la hora en la pantalla

Para el paso uno, implementaría SensorEventListener en nuestra clase, esto nos permitirá usar el método 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; } } } 

Para el paso dos, he construido un método llamado isPhoneVertical para comprobar si nuestro teléfono está en forma vertical o no, es principalmente comprobar el eje y. Puede cambiar el grado pronunciado cambiando maxVertical . Menos valor ella menos empinada, 0 significa que el teléfono debe ser casi 100% vertical. Para mi prueba se establece en 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; } 

Para el paso 3 he hecho pocos métodos para comprobar el tiempo de inicio y el tiempo de parada y actualizar una variable global que realiza un seguimiento del tiempo en segundos.

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

Para el paso 4 he hecho un runOnUiThread regular para actualizar el tiempo en la pantalla.

 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()) + ""); } }); } 

Dicho esto, esta solución es para ilustrar cómo se puede alcanzar este objetivo, estoy seguro de que se puede hacer de diferentes maneras. Pero quería mostrar la lógica detrás de la solución.

Y aquí está una captura de pantalla de la aplicación que cuenta el tiempo para cada vez que el teléfono es vertical y el tiempo total que ha sido vertical.

Introduzca aquí la descripción de la imagen

La solución incluye algunas explicaciones:

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> 

Dejaré un cierto acoplamiento para la lectura también.

Si crees que podría agregar más información que pueda ayudarte con tu pregunta, por favor avísame. También no está claro si usted estaba buscando detección de caminar / contador, si eso es algo en lo que es interesante, mira las siguientes respuestas / enlaces.

  • Actividad Reconocimiento Api
  • Cómo detectar caminar con Android acelerómetro
  • Cómo calcular el pie exacto paso de contar con acelerómetro en android?
  • Detectar movimiento con precisión usando acelerómetro en Android

Y códigos fuente GitHub

Antes, tenemos que saber sobre sensor API que es que estamos utilizando.

Android Sensor API

La API del sensor de Android ofrece muchas clases e interfaz. Las clases e interfaces importantes del sensor API son las siguientes:

1) Clase SensorManager

La clase android.hardware.SensorManager proporciona métodos:

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

Puede obtener la instancia de SensorManager llamando al método getSystemService() y pasando la constante SENSOR_SERVICE en ella.

 SensorManager sm = (SensorManager)getSystemService(SENSOR_SERVICE); 

2) Clase del sensor

La clase android.hardware.Sensor proporciona métodos para obtener información del sensor, como el nombre del sensor, el tipo de sensor, la resolución del sensor, el tipo de sensor, etc.

3) Clase SensorEvent

Su instancia es creada por el sistema. Proporciona información sobre el sensor .

4) Interfaz SensorEventListener

Proporciona dos métodos de devolución de llamada para obtener información cuando cambian los valores de los sensores (x, yyz) o la precisión del sensor. Métodos públicos y abstractos Descripción

  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. 

Nota: suponga * X = lado horizontal, Y = lado vertical y Z = elevación * del dispositivo.

Crear un xml simple como 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> 

A continuación, cree una actividad simple como MainActivity.java para medir direcciones como hacia abajo / hacia arriba.

 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(); } } 

El resultado parece ser:

X = 0.0 [No mover en horizontal]

Y = 9.77622 [Movido verticalmente]

Z = 0.813417 [Mover en Elevación]

Caso 1: Uso del GPS

El GPS incorporado en casi todos los dispositivos de android puede proporcionar la posición con la mejor exactitud posible de cerca de 2-3 metros horizontalmente y 4-5 metros verticalmente. Si esa exactitud vertical es aceptable para su caso, usted puede conseguir la altitud antes de que el movimiento comience, y cuando termina, compárelas y consiga el movimiento vertical.

Si necesita una mejor precisión, ningún dispositivo GPS de nivel de cliente android puede proporcionarlo. Hay dispositivos GPS profesionales especiales (utilizados por los agrimensores, que cuestan miles de dólares, y muy rara vez se ejecuta android os) que pueden proporcionar precisión a nivel de cm, pero esto no es lo que estamos hablando aquí.

Ofcource, usted necesita estar al aire libre para tener buena recepción del GPS.

Caso 2: Uso de sensores de movimiento

Si se conoce la velocidad inicial, la aceleración y el tiempo pueden calcular la distancia movida. Echa un vistazo a esta http://www.dummies.com/education/science/physics/finding-distance-using-initial-velocity-time-and-acceleration/

Tenemos

Distancia = velocidad de arranque + (1/2) * aceleración * tiempo ^ 2

En nuestro caso conocemos el tiempo (en realidad el tiempo) de los dispositivos incorporados reloj, y podemos obtener la aceleración con los sensores del dispositivo. Tenga en cuenta que TYPE_ACCELEROMETER sensor nos da la fuerza de aceleración a lo largo de cada eje, incluyendo la gravedad , por lo que tenemos que restar la fuerza gravitacional (lo obtenemos de TYPE_GRAVITY sensor). Tenga en cuenta que cuando alguien recoge un dispositivo, su mano no se mueve necesariamente en velocidad constante o aceleración. Por lo tanto, los cambios en velocidad y aceleración deben tenerse en cuenta.

En cuanto a la velocidad de arranque hay varios casos.

En caso de que sea cero (el usuario está de pie en un edificio, escoge el teléfono de una mesa y lo mueve a su oído) simplemente lo omite de las fórmulas.

En caso de que no sea cero para que

Velocidad = velocidad del dispositivo + velocidad del "vehículo" del usuario

, Tenemos que usar GPS para calcularlo. Si el usuario está en un helicóptero de elevación podemos hacerlo. En caso de que esté en un ascensor o subir las escaleras de un edificio no podemos porque no hay recepción GPS. Las cosas se complican más en caso de que el helicóptero o el ascensor acelere demasiado porque no hay forma de separar automáticamente la aceleración del helicóptero / ascensor de la aceleración del "usuario que mueve el dispositivo". Lo mismo cuando el usuario está caminando. En ese caso los cambios continuos de velocidad, aceleración y dirección tienen lugar mientras él hace sus pasos y el cuerpo se mueve hacia arriba y hacia abajo.

Confieso que no tengo idea de la exactitud real se puede obtener en la distancia calculada mediante el método de sensores de movimiento. Y como usted ve de lo que estoy escribiendo no hay forma de pensar para encontrar una solución que funcione en todas las circunstancias. Pero en el caso especial que el usuario está todavía y sólo mueve el dispositivo verticalmente puede hacer algo que creo.

PS No estoy entrando en detalles sobre cómo obtener datos de GPS o datos de sensores de movimiento de los sensores del dispositivo porque usted puede fácilmente google y encontrar ayuda en eso. Creo que lo que es más importante es entender las matemáticas y la física que se involucran en el movimiento vertical de los dispositivos.

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.