blob: 5ec16c71537c526610bfaea7f58453ac81bd3f05 [file] [log] [blame]
page.title=Position Sensors
page.tags=sensorevent,orientation,proximity
@jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>In this document</h2>
<ol>
<li><a href="#sensors-pos-gamerot">Using the Game Rotation Vector Sensor</a></li>
<li><a href="#sensors-pos-geomrot">Using the Geomagnetic Rotation Vector Sensor</a></li>
<li><a href="#sensors-pos-orient">Computing the Device's Orientation</a></li>
<li><a href="#sensors-pos-mag">Using the Geomagnetic Field Sensor</a></li>
<li><a href="#sensors-pos-prox">Using the Proximity Sensor</a></li>
</ol>
<h2>Key classes and interfaces</h2>
<ol>
<li>{@link android.hardware.Sensor}</li>
<li>{@link android.hardware.SensorEvent}</li>
<li>{@link android.hardware.SensorManager}</li>
<li>{@link android.hardware.SensorEventListener}</li>
</ol>
<h2>Related samples</h2>
<ol>
<li><a href="{@docRoot}resources/samples/AccelerometerPlay/index.html">Accelerometer
Play</a></li>
<li><a
href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/os/RotationVectorDemo.html">
API Demos (OS - RotationVectorDemo)</a></li>
<li><a
href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/os/Sensors.html">API Demos
(OS - Sensors)</a></li>
</ol>
<h2>See also</h2>
<ol>
<li><a href="{@docRoot}guide/topics/sensors/index.html">Sensors</a></li>
<li><a href="{@docRoot}guide/topics/sensors/sensors_overview.html">Sensors Overview</a></li>
<li><a href="{@docRoot}guide/topics/sensors/sensors_motion.html">Motion
Sensors</a></li>
<li><a href="{@docRoot}guide/topics/sensors/sensors_environment.html">Environment
Sensors</a></li>
</ol>
</div>
</div>
<p>
The Android platform provides two sensors that let you determine the position
of a device: the geomagnetic field sensor and the accelerometer. The Android
platform also provides a sensor that lets you determine how close the face of
a device is to an object (known as the <em>proximity sensor</em>). The
geomagnetic field sensor and the proximity sensor are hardware-based. Most
handset and tablet manufacturers include a geomagnetic field sensor. Likewise,
handset manufacturers usually include a proximity sensor to determine when a
handset is being held close to a user's face (for example, during a phone
call). For determining a device's orientation, you can use the readings from
the device's accelerometer and the geomagnetic field sensor.
</p>
<p class="note">
<strong>Note:</strong> The orientation sensor was deprecated in Android 2.2
(API level 8), and the orientation sensor type was deprecated in Android 4.4W
(API level 20).
</p>
<p>
Position sensors are useful for determining a device's physical position in
the world's frame of reference. For example, you can use the geomagnetic field
sensor in combination with the accelerometer to determine a device's position
relative to the magnetic north pole. You can also use these sensors to
determine a device's orientation in your application's frame of reference.
Position sensors are not typically used to monitor device movement or motion,
such as shake, tilt, or thrust (for more information, see <a
href="{@docRoot}guide/topics/sensors/sensors_motion.html">Motion Sensors</a>).
</p>
<p>
The geomagnetic field sensor and accelerometer return multi-dimensional arrays
of sensor values for each {@link android.hardware.SensorEvent}. For example,
the geomagnetic field sensor provides geomagnetic field strength values for
each of the three coordinate axes during a single sensor event. Likewise, the
accelerometer sensor measures the acceleration applied to the device during a
sensor event. For more information about the coordinate systems that are used
by sensors, see <a
href="{@docRoot}guide/topics/sensors/sensors_overview.html#sensors-coords">
Sensor Coordinate Systems</a>. The proximity sensor provides a single value
for each sensor event. Table 1 summarizes the position sensors that are
supported on the Android platform.
</p>
<p class="table-caption" id="table1">
<strong>Table 1.</strong> Position sensors that are supported on the Android platform.</p>
<table>
<tr>
<th scope="col" style="white-space:nowrap">Sensor</th>
<th scope="col" style="white-space:nowrap">Sensor event data</th>
<th scope="col" style="white-space:nowrap">Description</th>
<th scope="col" style="white-space:nowrap">Units of measure</th>
</tr>
<tr>
<td rowspan="3">{@link android.hardware.Sensor#TYPE_GAME_ROTATION_VECTOR}</td>
<td><code>SensorEvent.values[0]</code></td>
<td>Rotation vector component along the x axis (x * sin(θ/2)).</td>
<td rowspan="3">Unitless</td>
</tr>
<tr>
<td><code>SensorEvent.values[1]</code></td>
<td>Rotation vector component along the y axis (y * sin(θ/2)).</td>
</tr>
<tr>
<td><code>SensorEvent.values[2]</code></td>
<td>Rotation vector component along the z axis (z * sin(θ/2)).</td>
</tr>
<tr>
<td rowspan="3">{@link android.hardware.Sensor#TYPE_GEOMAGNETIC_ROTATION_VECTOR}</td>
<td><code>SensorEvent.values[0]</code></td>
<td>Rotation vector component along the x axis (x * sin(θ/2)).</td>
<td rowspan="3">Unitless</td>
</tr>
<tr>
<td><code>SensorEvent.values[1]</code></td>
<td>Rotation vector component along the y axis (y * sin(θ/2)).</td>
</tr>
<tr>
<td><code>SensorEvent.values[2]</code></td>
<td>Rotation vector component along the z axis (z * sin(θ/2)).</td>
</tr>
<tr>
<td rowspan="3">{@link android.hardware.Sensor#TYPE_MAGNETIC_FIELD}</td>
<td><code>SensorEvent.values[0]</code></td>
<td>Geomagnetic field strength along the x axis.</td>
<td rowspan="3">&mu;T</td>
</tr>
<tr>
<td><code>SensorEvent.values[1]</code></td>
<td>Geomagnetic field strength along the y axis.</td>
</tr>
<tr>
<td><code>SensorEvent.values[2]</code></td>
<td>Geomagnetic field strength along the z axis.</td>
</tr>
<tr>
<td rowspan="6">{@link android.hardware.Sensor#TYPE_MAGNETIC_FIELD_UNCALIBRATED}</td>
<td><code>SensorEvent.values[0]</code></td>
<td>Geomagnetic field strength (without hard iron calibration) along the x axis.</td>
<td rowspan="6">&mu;T</td>
</tr>
<tr>
<td><code>SensorEvent.values[1]</code></td>
<td>Geomagnetic field strength (without hard iron calibration) along the y axis.</td>
</tr>
<tr>
<td><code>SensorEvent.values[2]</code></td>
<td>Geomagnetic field strength (without hard iron calibration) along the z axis.</td>
</tr>
<tr>
<td><code>SensorEvent.values[3]</code></td>
<td>Iron bias estimation along the x axis.</td>
</tr>
<tr>
<td><code>SensorEvent.values[4]</code></td>
<td>Iron bias estimation along the y axis.</td>
</tr>
<tr>
<td><code>SensorEvent.values[5]</code></td>
<td>Iron bias estimation along the z axis.</td>
</tr>
<tr>
<td rowspan="3">{@link android.hardware.Sensor#TYPE_ORIENTATION}<sup>1</sup></td>
<td><code>SensorEvent.values[0]</code></td>
<td>Azimuth (angle around the z-axis).</td>
<td rowspan="3">Degrees</td>
</tr>
<tr>
<td><code>SensorEvent.values[1]</code></td>
<td>Pitch (angle around the x-axis).</td>
</tr>
<tr>
<td><code>SensorEvent.values[2]</code></td>
<td>Roll (angle around the y-axis).</td>
</tr>
<tr>
<td>{@link android.hardware.Sensor#TYPE_PROXIMITY}</td>
<td><code>SensorEvent.values[0]</code></td>
<td>Distance from object.<sup>2</sup></td>
<td>cm</td>
</tr>
</table>
<p class="note">
<sup><strong>1</strong></sup>This sensor was deprecated in Android 2.2 (API
level 8), and this sensor type was deprecated in Android 4.4W (API level 20).
The sensor framework provides alternate methods for acquiring device
orientation, which are discussed in <a href="#sensors-pos-orient">Computing
the Device's Orientation</a>.
</p>
<p class="note"><sup><strong>2</strong></sup> Some proximity sensors provide only binary values
representing near and far.</p>
<h2 id="sensors-pos-gamerot">Using the Game Rotation Vector Sensor</h2>
<p>The game rotation vector sensor is identical to the
<a href="{@docRoot}guide/topics/sensors/sensors_motion.html#sensors-motion-rotate">Rotation
Vector Sensor</a>, except it does not use the geomagnetic field. Therefore the Y axis does not
point north but instead to some other reference. That reference is allowed to drift by the
same order of magnitude as the gyroscope drifts around the Z axis.</p>
<p>Because the game rotation vector sensor does not use the magnetic field, relative rotations
are more accurate, and not impacted by magnetic field changes. Use this sensor in a game if
you do not care about where north is, and the normal rotation vector does not fit your needs
because of its reliance on the magnetic field.</p>
<p>The following code shows you how to get an instance of the default game rotation vector
sensor:</p>
<pre>
private SensorManager mSensorManager;
private Sensor mSensor;
...
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GAME_ROTATION_VECTOR);
</pre>
<h2 id="sensors-pos-geomrot">Using the Geomagnetic Rotation Vector Sensor</h2>
<p>The geomagnetic rotation vector sensor is similar to the
<a href="{@docRoot}guide/topics/sensors/sensors_motion.html#sensors-motion-rotate">Rotation
Vector Sensor</a>, but it uses a magnetometer instead of a gyroscope. The accuracy of this
sensor is lower than the normal rotation vector sensor, but the power consumption is reduced.
Only use this sensor if you want to collect some rotation information in the background without
draining too much battery. This sensor is most useful when used in conjunction with batching.</p>
<p>The following code shows you how to get an instance of the default geomagnetic rotation
vector sensor:</p>
<pre>
private SensorManager mSensorManager;
private Sensor mSensor;
...
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR);
</pre>
<h2 id="sensors-pos-orient">Computing the Device's Orientation</h2>
<p>By computing a device's orientation, you can monitor the position of the
device relative to the earth's frame of reference (specifically, the magnetic
north pole). The following code shows you how to compute a device's
orientation:
</p>
<pre>
private SensorManager mSensorManager;
...
// Rotation matrix based on current readings from accelerometer and magnetometer.
final float[] rotationMatrix = new float[9];
mSensorManager.getRotationMatrix(rotationMatrix, null,
accelerometerReading, magnetometerReading);
// Express the updated rotation matrix as three orientation angles.
final float[] orientationAngles = new float[3];
mSensorManager.getOrientation(rotationMatrix, orientationAngles);
</pre>
<p>The system computes the orientation angles by using a device's geomagnetic
field sensor in combination with the device's accelerometer. Using these two
hardware sensors, the system provides data for the following three
orientation angles:
</p>
<ul>
<li>
<strong>Azimuth (degrees of rotation about the -z axis).</strong> This is
the angle between the device's current compass direction and magnetic north.
If the top edge of the device faces magnetic north, the azimuth is 0
degrees; if the top edge faces south, the azimuth is 180 degrees. Similarly,
if the top edge faces east, the azimuth is 90 degrees, and if the top edge
faces west, the azimuth is 270 degrees.
</li>
<li>
<strong>Pitch (degrees of rotation about the x axis).</strong> This is the
angle between a plane parallel to the device's screen and a plane parallel
to the ground. If you hold the device parallel to the ground with the bottom
edge closest to you and tilt the top edge of the device toward the ground,
the pitch angle becomes positive. Tilting in the opposite direction&mdash;
moving the top edge of the device away from the ground&mdash;causes
the pitch angle to become negative. The range of values is -180 degrees to
180 degrees.
</li>
<li>
<strong>Roll (degrees of rotation about the y axis).</strong> This is the
angle between a plane perpendicular to the device's screen and a plane
perpendicular to the ground. If you hold the device parallel to the ground
with the bottom edge closest to you and tilt the left edge of the device
toward the ground, the roll angle becomes positive. Tilting in the opposite
direction&mdash;moving the right edge of the device toward the ground&mdash;
causes the roll angle to become negative. The range of values is -90 degrees
to 90 degrees.
</li>
</ul>
<p class="note">
<strong>Note:</strong>The sensor's roll definition has changed to reflect the
vast majority of implementations in the geosensor ecosystem.
</p>
<p>
Note that these angles work off of a different coordinate system than the
one used in aviation (for yaw, pitch, and roll). In the aviation system, the
x axis is along the long side of the plane, from tail to nose.
</p>
<p>
The orientation sensor derives its data by processing the raw sensor data
from the accelerometer and the geomagnetic field sensor. Because of the heavy
processing that is involved, the accuracy and precision of the orientation
sensor is diminished. Specifically, this sensor is reliable only when the roll
angle is 0. As a result, the orientation sensor was deprecated in Android
2.2 (API level 8), and the orientation sensor type was deprecated in Android
4.4W (API level 20).
Instead of using raw data from the orientation sensor, we recommend that you
use the {@link android.hardware.SensorManager#getRotationMatrix getRotationMatrix()}
method in conjunction with the
{@link android.hardware.SensorManager#getOrientation getOrientation()} method
to compute orientation values, as shown in the following code sample. As part
of this process, you can use the
{@link android.hardware.SensorManager#remapCoordinateSystem remapCoordinateSystem()}
method to translate the orientation values to your application's frame of
reference.
</p>
<pre>
public class SensorActivity extends Activity implements SensorEventListener {
private SensorManager mSensorManager;
private final float[] mAccelerometerReading = new float[3];
private final float[] mMagnetometerReading = new float[3];
private final float[] mRotationMatrix = new float[9];
private final float[] mOrientationAngles = new float[3];
&#64;Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
}
&#64;Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// Do something here if sensor accuracy changes.
// You must implement this callback in your code.
}
&#64;Override
protected void onResume() {
super.onResume();
// Get updates from the accelerometer and magnetometer at a constant rate.
// To make batch operations more efficient and reduce power consumption,
// provide support for delaying updates to the application.
//
// In this example, the sensor reporting delay is small enough such that
// the application receives an update before the system checks the sensor
// readings again.
mSensorManager.registerListener(this, Sensor.TYPE_ACCELEROMETER,
SensorManager.SENSOR_DELAY_NORMAL, SensorManager.SENSOR_DELAY_UI);
mSensorManager.registerListener(this, Sensor.TYPE_MAGNETIC_FIELD,
SensorManager.SENSOR_DELAY_NORMAL, SensorManager.SENSOR_DELAY_UI);
}
&#64;Override
protected void onPause() {
super.onPause();
// Don't receive any more updates from either sensor.
mSensorManager.unregisterListener(this);
}
// Get readings from accelerometer and magnetometer. To simplify calculations,
// consider storing these readings as unit vectors.
&#64;Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor == Sensor.TYPE_ACCELEROMETER) {
System.arraycopy(event.values, 0, mAccelerometerReading,
0, mAccelerometerReading.length);
}
else if (event.sensor == Sensor.TYPE_MAGNETIC_FIELD) {
System.arraycopy(event.values, 0, mMagnetometerReading,
0, mMagnetometerReading.length);
}
}
// Compute the three orientation angles based on the most recent readings from
// the device's accelerometer and magnetometer.
public void updateOrientationAngles() {
// Update rotation matrix, which is needed to update orientation angles.
mSensorManager.getRotationMatrix(mRotationMatrix, null,
mAccelerometerReading, mMagnetometerReading);
// "mRotationMatrix" now has up-to-date information.
mSensorManager.getOrientation(mRotationMatrix, mOrientationAngles);
// "mOrientationAngles" now has up-to-date information.
}
}
</pre>
<p>
You don't usually need to perform any data processing or filtering of the
device's raw orientation angles other than translating the sensor's
coordinate system to your application's frame of reference.
</p>
<h2 id="sensors-pos-mag">Using the Geomagnetic Field Sensor</h2>
<p>The geomagnetic field sensor lets you monitor changes in the earth's magnetic field. The
following code shows you how to get an instance of the default geomagnetic field sensor:</p>
<pre>
private SensorManager mSensorManager;
private Sensor mSensor;
...
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
</pre>
<p>This sensor provides raw field strength data (in &mu;T) for each of the three coordinate axes.
Usually, you do not need to use this sensor directly. Instead, you can use the rotation vector
sensor to determine raw rotational movement or you can use the accelerometer and geomagnetic field
sensor in conjunction with the {@link android.hardware.SensorManager#getRotationMatrix
getRotationMatrix()} method to obtain the rotation matrix and the inclination matrix. You can then
use these matrices with the {@link android.hardware.SensorManager#getOrientation getOrientation()}
and {@link android.hardware.SensorManager#getInclination getInclination()} methods to obtain azimuth
and geomagnetic inclination data.</p>
<h2 id="sensors-pos-magunc">Using the Uncalibrated Magnetometer</h2>
<p>The uncalibrated magnetometer is similar to the <a href="#sensors-pos-mag">geomagnetic field
sensor</a>, except that no hard iron calibration is applied to the magnetic field. Factory calibration
and temperature compensation are still applied to the magnetic field. The uncalibrated magnetometer
is useful to handle bad hard iron estimations. In general, <code>geomagneticsensor_event.values[0]</code>
will be close to <code>uncalibrated_magnetometer_event.values[0] -
uncalibrated_magnetometer_event.values[3]</code>. That is,</p>
<p><code>calibrated_x ~= uncalibrated_x - bias_estimate_x</code></p></p>
<p class="note"><strong>Note:</strong> Uncalibrated sensors provide more raw results and may
include some bias, but their measurements contain fewer jumps from corrections applied through
calibration. Some applications may prefer these uncalibrated results as smoother and more
reliable. For instance, if an application is attempting to conduct its own sensor fusion,
introducing calibrations can actually distort results.</p>
<p>In addition to the magnetic field, the uncalibrated magnetometer also provides the
estimated hard iron bias in each axis. The following code shows you how to get an instance of the
default uncalibrated magnetometer:</p>
<pre>
private SensorManager mSensorManager;
private Sensor mSensor;
...
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED);
</pre>
<h2 id="sensors-pos-prox">Using the Proximity Sensor</h2>
<p>The proximity sensor lets you determine how far away an object is from a device. The following
code shows you how to get an instance of the default proximity sensor:</p>
<pre>
private SensorManager mSensorManager;
private Sensor mSensor;
...
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
</pre>
<p>The proximity sensor is usually used to determine how far away a person's head is from the face
of a handset device (for example, when a user is making or receiving a phone call). Most
proximity sensors return the absolute distance, in cm, but some return only near and
far values. The following code shows you how to use the proximity sensor:</p>
<pre>
public class SensorActivity extends Activity implements SensorEventListener {
private SensorManager mSensorManager;
private Sensor mProximity;
&#64;Override
public final void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Get an instance of the sensor service, and use that to get an instance of
// a particular sensor.
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mProximity = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
}
&#64;Override
public final void onAccuracyChanged(Sensor sensor, int accuracy) {
// Do something here if sensor accuracy changes.
}
&#64;Override
public final void onSensorChanged(SensorEvent event) {
float distance = event.values[0];
// Do something with this sensor data.
}
&#64;Override
protected void onResume() {
// Register a listener for the sensor.
super.onResume();
mSensorManager.registerListener(this, mProximity, SensorManager.SENSOR_DELAY_NORMAL);
}
&#64;Override
protected void onPause() {
// Be sure to unregister the sensor when the activity pauses.
super.onPause();
mSensorManager.unregisterListener(this);
}
}
</pre>
<p class="note"><strong>Note:</strong> Some proximity sensors return binary values that represent
"near" or "far." In this case, the sensor usually reports its maximum range value in the far state
and a lesser value in the near state. Typically, the far value is a value > 5 cm, but this can vary
from sensor to sensor. You can determine a sensor's maximum range by using the {@link
android.hardware.Sensor#getMaximumRange} method.</p>