Using the accelerometer and other sensors

The Accelerometer records the device acceleration in three dimensions, that is, along the x, y, and z axis. Almost all phones are now shipped with an accelerometer as it's a pretty old technology. Indeed, the very first phone to have one was the Apollo 11 Lunar Module. A phone with wheels. Actually, the first mainstream and terrestrial phone equipped with this technology was the Samsung SCH-S310 in 2005 on which you could dial numbers by writing them in the air. Today's application of the accelerometer are almost all related to games. In this recipe, we will detect if the phone is falling; this can be useful for the elderly in the sense that we can be warned of emergencies automatically.

Getting ready

To follow this recipe, create a new project called Accelerometer. Similar to the previous recipe, you'll have to deploy your code on a physical phone as the emulator doesn't support the accelerometer.

How to do it...

Now, we will see how to use the accelerometer and other sensors:

  1. Add the using Android.Hardware and using System.Text instances at the top of your MainActivity class.
  2. Add a textview element in your Resources/layout/Main.axml file and name it myTextView.
  3. Make your MainActiviy class implement the ISensorEventListener interface:
    public class MainActivity : Activity, ISensorEventListener
  4. Add the following six attributes to your MainActivity class:
    private static readonly object myLock = new object();
    private SensorManager mySensorManager;
    private float x=0, y=0, z=0;
    private TextView myTextView;
  5. Modify your OnCreate() method so that it looks like the following:
    protected override void OnCreate(Bundle bundle) {
      base.OnCreate(bundle);
      SetContentView(Resource.Layout.Main);
      mySensorManager = (SensorManager) GetSystemService(SensorService);
      myTextView = FindViewById<TextView>(Resource.Id.myTextView);
      mySensorManager.RegisterListener(this, mySensorManager.GetDefaultSensor(SensorType.Accelerometer),
      SensorDelay.Ui);
    
    }
  6. Implement the OnSensorChanged function from the ISensorEventListener interface:
    public void OnSensorChanged(SensorEvent e) {
      StringBuilder text = new StringBuilder ();
    
      lock (myLock) {
        float currentX = e.Values [0];
        float currentY = e.Values [1];
        float currentZ = e.Values [2];
    
        // First time
        if (z == 0 && y == 0 && z == 0) {
    
          z = currentZ;
          y = currentY;
          x = currentX;
    
        }
        else if (Math.Abs (currentX / x) > 2 || Math.Abs (currentY / y) > 2 || Math.Abs (currentZ / z) > 2) {
          z = currentZ;
          y = currentY;
          x = currentX;
    
          text.Append ("Is Probably Falling");
        }
    
        text.Append("x = ")
        .Append(currentX)
        .Append(", y=")
        .Append(currentX)
        .Append(", z=")
        .Append(currentZ);
    
        myTextView.Text = text.ToString();
      }
    }
  7. Implement the OnAccuracyChanged() function from ISensorEventListener, which receives [Android.Runtime.GeneratedEnum] SensorType sensor and [Android.Runtime.GeneratedEnum] SensorStatus as parameters and leaves its body blank.
  8. Deploy your application to a physical phone, run the application and move it around for the textview element to be refreshed with new values. If you move the phone fast enough, The Label Is Probably Falling will appear before the x, y, and z accelerations.

How it works...

Each sensor's data can be accessed through background services. In order for our application to be fed by the data of a sensor, we need to create a reference to the SensorManager instance. Finally, we can register our application via a Listener instance, so the OnSensorChanged()method will be triggered every time the sensor changes its value.

To acquire a reference to the SensorManager instance, we simply use the GetSystemService() helper as follows:

mySensorManager = (SensorManager) GetSystemService(SensorService);

Then, we register our application to receive the data from the accelerometer as follows:

mySensorManager.RegisterListener(this, mySensorManager.GetDefaultSensor(SensorType.Accelerometer),
SensorDelay.Ui);

In the OnSensorChanged() method, we implemented a C# thread-safe lock as this method can be retriggered before it finishes its execution:

lock (myLock)

Then, we retrieve the values of the acceleration for the three axes and compare them with the previous values. If the division results is more than two (value of accelerometer) on one of the three axes, it likely means that the phone is falling:

float currentX = e.Values [0];
float currentY = e.Values [1];
float currentZ = e.Values [2];

// First time
if (z == 0 && y == 0 && z == 0) {

  z = currentZ;
  y = currentY;
  x = currentX;

}
else if (Math.Abs (currentX / x) > 2 || Math.Abs (currentY / y) > 2 || Math.Abs (currentZ / z) > 2) {
  z = currentZ;
  y = currentY;
  x = currentX;

  text.Append ("Is Probably Falling");
}

There's more...

Android phones can be equipped with a very large range of sensors that can be used in the same way as the accelerator. They are categorized in three categories: motion, position, and environment. For each of them, you'll have to register your activity as follows:

mySensorManager.RegisterListener(this, mySensorManager.GetDefaultSensor(SensorType.MY_TYPE),
SensorDelay.MY_FREQ);

Here SensorType.MY_TYPE and SensorType.MY_FREQ have to be adapted to your needs.

While we can easily discover the different sensors using the Intellisense of Xamarin, the data they return is only float. In what follows, I report what those floats represent.

Motion sensors

Here, I present the different values that can be retrieved for motion sensors:

  • Accelerometer:
    • SensorEvent.value[0]: This is the acceleration force on x axis
    • SensorEvent.value[1]: This is the acceleration force on y axis
    • SensorEvent.value[2]: This is the acceleration force on z axis
  • Gravity:
    • SensorEvent.value[0]: This is the gravity force on x axis
    • SensorEvent.value[1]: This is the gravity force on y axis
    • SensorEvent.value[2]: This is the gravity force on z axis
  • Gyroscope:
    • SensorEvent.value[0]: This is the rotation on x axis
    • SensorEvent.value[1]: This is the rotation on y axis
    • SensorEvent.value[2]: This is the rotation on z axis
  • LinerAcceleration:
    • SensorEvent.value[0]: This is the acceleration force on x axis without gravity
    • SensorEvent.value[1]: This is the acceleration force on y axis without gravity
    • SensorEvent.value[2]: This is the acceleration force on z axis without gravity
  • RotationVector:
    • SensorEvent.value[0]: This is the rotation on x axis
    • SensorEvent.value[1]: This is the rotation on y axis
    • SensorEvent.value[2]: This is the rotation on z axis
  • SignificantMotion: This doesn't have any value but triggers the onSensorChanged() method when a significant movement is detected.
  • StepCounter:
    • SensorEvent.value[0]: This is the number of steps since the last activation of the sensor
  • StepDetector: This doesn't have any value but triggers the onSensorChanged() method when a step is detected

Position sensors

In what follows, I present the different values that can be retrieved for position sensors:

  • GameRotationVector:
    • SensorEvent.value[0]: This is the rotation on x axis
    • SensorEvent.value[1]: This is the rotation on y axis
    • SensorEvent.value[2]: This is the rotation on z axis
  • GeoMagneticRotationVector:
    • SensorEvent.value[0]: This is the rotation on x axis
    • SensorEvent.value[1]: This is the rotation on y axis
    • SensorEvent.value[2]: This is the rotation on z axis
  • MagneticField:
    • SensorEvent.value[0]: This is the geomagnetic field on x axis
    • SensorEvent.value[1]: This is the geomagnetic field on y axis
    • SensorEvent.value[2]: This is the geomagnetic field on z axis
  • Proximity:
    • SensorEvent.value[0]: This is the distance with the object

Environment sensors

Here, I present the different values that can be retrieved for environment sensors:

  • AmbientTemperature:
    • SensorEvent.value[0]: This is the air temperature in degree Celsius
  • Light:
    • SensorEvent.value[0]: This is the illuminance in Lx
  • Pressure:
    • SensorEvent.value[0]: This is the air pressure in hPa
  • RelativeHumidity:
    • SensorEvent.value[0]: This is the air humidity in percentage

Refresh rate of sensors

Android provides four different rates at which you can refresh your sensors' data. The faster rate is the most accurate and will consume much more battery. You have to evaluate your needs and choose the right trade-off between accuracy and battery consumption for your applications. The four different rates are as follows:

  • SensorDelay.Fastest: This rate is the fastest possible rate
  • SensorDelay.Game: This is a suitable rate for games
  • SensorDelay.Normal: This is a suitable rate for screen orientation change
  • SensorDelay.UI: This is a suitable rate for graphical interfaces

Listen only when needed

In order to enhance the battery life of the phones your applications are running on, it is a good practice, if possible, to listen to the sensors only when your application is displayed. To accomplish this, we can register ourselves using the OnResume() method and unregister ourselves using the OnPause() method. Consequently, our application will only consume the sensors' data when displayed:

protected override void OnResume() {
  base.OnResume();
  mySensorManager.RegisterListener(this, mySensorManager.GetDefaultSensor(SensorType.Accelerometer),
  SensorDelay.Ui);
}

protected override void OnPause() {
  base.OnPause();
  mySensorManager.UnregisterListener(this);
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.83.185