📜 ⬆️ ⬇️

We collect sensor readings from an Android smartphone. Bug work

In my previous post I told how to get the angles of inclination of the apparatus in all three planes. However, as it turned out, the method used in the topic is deprecated since API Level 8 (Android 2.2). I will correct this error and tell you how to correctly receive data under the cut.

First a little bit of theory


In the Android documentation, we are offered to use the method instead of SENSOR_ORIENTATION
getOrientation (float[] R, float[] values) 

This method takes two parameters:

So, to accomplish the goal, we just need to get that very rotation matrix. And you can get it from another method:
 getRotationMatrix (float[] R, float[] I, float[] gravity, float[] geomagnetic) 

This method places the rotation matrix and the apparatus deviation matrix from (the Earth’s magnetic pole?) In the first two arrays. To do this, it also needs to transfer data from the accelerometer sensor and the geomagnetic sensor. Fortunately, TYPE_ACCELEROMETER and TYPE_MAGNETIC_FIELD are not deprecated. Consequently, we will take readings from them.

Go to practice


Layout we can take the same that was in the past example. Here he is:

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <LinearLayout android:id="@+id/linearLayout1" android:layout_width="fill_parent" android:layout_height="wrap_content" > <TextView android:id="@+id/textView1" android:layout_width="60dp" android:layout_height="wrap_content" android:layout_weight="1" android:textSize="25dp" android:text=" XY" /> <TextView android:id="@+id/xyValue" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:textSize="25dp" android:text="0" /> </LinearLayout> <LinearLayout android:id="@+id/linearLayout2" android:layout_width="fill_parent" android:layout_height="wrap_content" > <TextView android:id="@+id/textView3" android:layout_width="60dp" android:layout_height="wrap_content" android:layout_weight="1" android:textSize="25dp" android:text=" XZ" /> /> <TextView android:id="@+id/xzValue" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:textSize="25dp" android:text="0" /> </LinearLayout> <LinearLayout android:id="@+id/linearLayout3" android:layout_width="fill_parent" android:layout_height="wrap_content" > <TextView android:id="@+id/textView5" android:layout_width="60dp" android:layout_height="wrap_content" android:layout_weight="1" android:textSize="25dp" android:text=" ZY" /> <TextView android:id="@+id/zyValue" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:textSize="25dp" android:text="0" /> </LinearLayout> </LinearLayout> 

')
In the main activation, we declare the variables:

  private final SensorManager msensorManager; //   private float[] rotationMatrix; //  private float[] accelData; //   private float[] magnetData; //   private float[] OrientationData; //    private TextView xyView; private TextView xzView; private TextView zyView; 


The onCreate method must implement the methods of the SensorEventListener class, so its declaration will change:

  public class Main extends Activity implements SensorEventListener{ 

And add two mandatory methods onAccuracyChanged and onSensorChanged.
And before setContentView we write:

  msensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE); rotationMatrix = new float[16]; accelData = new float[3]; magnetData = new float[3]; OrientationData = new float[3]; xyView = (TextView) findViewById(R.id.xyValue); // xzView = (TextView) findViewById(R.id.xzValue); //       zyView = (TextView) findViewById(R.id.zyValue); // 


If you read my last post , you haven’t yet seen anything new. If not, then you need to know that in the first line we get the object of the sensor manager.
Now we will create an onResume method in which we will clarify which sensor data we need:

  @Override protected void onResume() { super.onResume(); msensorManager.registerListener(this, msensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_UI ); msensorManager.registerListener(this, msensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), SensorManager.SENSOR_DELAY_UI ); } 

Here we transfer to the registerListener method the type of sensor we need (a complete list of sensor designations ) and the data refresh rate (maybe SENSOR_DELAY_NORMAL, SENSOR_DELAY_UI, SENSOR_DELAY_GAME, or SENSOR_DELAY_FASTEST in the order of increasing frequency).

So that our program does not eat up the resources of a smartphone while being minimized by the onPause event, we "remove" the acquisition of data from the sensors:

  @Override protected void onPause() { super.onPause(); msensorManager.unregisterListener(this); } 


Let's create a new method in which the data from the sensors will be entered into the array corresponding to the sensor. Let's call the loadNewSensorData method:

  private void loadNewSensorData(SensorEvent event) { final int type = event.sensor.getType(); //   if (type == Sensor.TYPE_ACCELEROMETER) { //  accelData = event.values.clone(); } if (type == Sensor.TYPE_MAGNETIC_FIELD) { //   magnetData = event.values.clone(); } } 

Well, almost all! It remains only to write an onSensorChanged event handler:

  public void onSensorChanged(SensorEvent event) { loadNewSensorData(event); //     SensorManager.getRotationMatrix(rotationMatrix, null, accelData, magnetData); //   SensorManager.getOrientation(rotationMatrix, OrientationData); //      if((xyView==null)||(xzView==null)||(zyView==null)){ //   . xyView = (TextView) findViewById(R.id.xyValue); xzView = (TextView) findViewById(R.id.xzValue); zyView = (TextView) findViewById(R.id.zyValue); } //  xyView.setText(String.valueOf(Math.round(Math.toDegrees(OrientationData[0])))); xzView.setText(String.valueOf(Math.round(Math.toDegrees(OrientationData[1])))); zyView.setText(String.valueOf(Math.round(Math.toDegrees(OrientationData[2])))); } 


All is ready! Now I corrected my mistake and taught you to get data from sensors in a non-deprecated way. :)

In conclusion, I will provide links to the sources , to the finished apk and to the source of information .

PS: You probably noticed an extra check of variables for difference from null in the last listing. Without it, the compiler throws a java.lang.NullPointerException. I would be grateful if someone explains or points to an error.

UPD: The problem was solved thanks to firexel .
Rearrange setContentView and lines with findViewById in onCreate

After that, you can remove the extra check.

Source: https://habr.com/ru/post/137820/


All Articles