Posted by Geoffrey Boullanger – Senior Software Engineer, Shandor Dektor – Sensors Algorithms Engineer, Martin Frassl and Benjamin Joseph – Technical Leaders and Managers
Device orientation, or pose, is used as an input signal for many use cases: virtual or augmented reality, gesture detection or compass and navigation – whenever the app needs to know the orientation of a device relative to its environment. We've heard from developers that it's difficult to get the orientation right, with frequent complaints from users when the orientation is incorrect. A maps app should indicate the correct walking direction when a user navigates to an exciting restaurant in a strange city!
The Fused Orientation Provider (FOP) is a new API in Google Play Services that provides quality and consistent device orientation by combining accelerometer, gyroscope, and magnetometer signals.
While Android Rotation Vector already provides device orientation (and will continue to do so), the new FOP offers more consistent behavior and high performance across devices. We designed the FOP API to be similar to the Rotation Vector to make the transition as easy as possible for developers.
In particular the Fused Orientation Provider
- Provides uniform implementation across devices: An API in Google Play Services means there are no implementation differences between different manufacturers. Algorithm updates can be rolled out quickly and independently of Android platform updates;
- Includes local magnetic declination directly, if available;
- Compensates for lower quality sensors and OEM implementations (e.g. gyro bias, sensor timing).
In certain cases, the FOP returns values piped from the AOSP rotation vector, adjusted to include magnetic declination.
How to use the FOP API
Device orientation updates can be requested by creating and sending a DeviceOrientationRequest object, which defines some details of the request, such as the update period.
The FOP then outputs a stream of the device's orientation estimates as quaternions. The orientation is referenced geographically north. In cases where the local magnetic declination is not known (e.g. the location is not available), the orientation will be relative magnetic north.
In addition, the FOP displays the device's heading and accuracy, which are derived from the orientation estimate. This is the same heading that appears in Google Maps, which also uses the FOP. We recently added changes to better handle magnetic disturbances, to improve cone reliability for Google Maps and FOP clients.
The update rate can be set by requesting a specific update period. The FOP does not guarantee a minimum or maximum update rate. For example, the update rate may be faster than requested if another app has a faster parallel request, or slower than requested if the device does not support the high speed.
For the full specification of the API, please refer to the API documentation:
Example usage (Kotlin)
package ...
import android.content.Context
import com.google.android.gms.location.DeviceOrientation
import com.google.android.gms.location.DeviceOrientationListener
import com.google.android.gms.location.DeviceOrientationRequest
import com.google.android.gms.location.FusedOrientationProviderClient
import com.google.android.gms.location.LocationServices
import com.google.common.flogger.FluentLogger
import java.util.concurrent.Executors
class Example(context: Context) {
private val logger: FluentLogger = FluentLogger.forEnclosingClass()
// Get the FOP API client
private val fusedOrientationProviderClient: FusedOrientationProviderClient =
LocationServices.getFusedOrientationProviderClient(context)
// Create an FOP listener
private val listener: DeviceOrientationListener =
DeviceOrientationListener { orientation: DeviceOrientation ->
// Use the orientation object returned by the FOP, e.g.
logger.atFinest().log("Device Orientation: %s deg", orientation.headingDegrees)
}
fun start() {
// Create an FOP request
val request =
DeviceOrientationRequest.Builder(DeviceOrientationRequest.OUTPUT_PERIOD_DEFAULT).build()
// Create (or re-use) an Executor or Looper, e.g.
val executor = Executors.newSingleThreadExecutor()
// Register the request and listener
fusedOrientationProviderClient
.requestOrientationUpdates(request, executor, listener)
.addOnSuccessListener { logger.atInfo().log("FOP: Registration Success") }
.addOnFailureListener { e: Exception? ->
logger.atSevere().withCause(e).log("FOP: Registration Failure")
}
}
fun stop() {
// Unregister the listener
fusedOrientationProviderClient.removeOrientationUpdates(listener)
}
}
Technical background
The Android ecosystem has a wide variety of system implementations for sensors. Devices must meet the criteria in the Android Compatibility Definition Document (CDD) and an accelerometer, gyroscope, and magnetometer must be available to use the fused orientation provider. It is preferable that the device vendor implements the high-fidelity sensor portion of the CDD.
Although Android devices are compliant with the Android CDD, the recommended sensor specifications are not tight enough to completely prevent orientation inaccuracies. Examples include magnetometer interference from internal sources and delayed, inaccurate, or non-uniform sensor sampling. In addition, the environment around the device usually contains materials that disrupt the geomagnetic field, and user behavior can vary greatly. To deal with this, the FOP performs a number of tasks to provide robust and accurate orientation:
- Synchronize sensors that operate on different clocks and delays;
- Compensate for hard iron offset (magnetometer deviation);
- Combine accelerometer, gyroscope, and magnetometer measurements to determine the device's orientation in the world;
- Compensate for gyro drift (gyro bias) while moving;
- Make a realistic estimate of compass heading accuracy.
We have validated our algorithms against extensive test data to deliver a high-quality result on a wide range of devices.
Availability and limitations
The Fused Orientation Provider is available on all devices with Google Play Services on Android 5 (Lollipop) and later. Developers must add the dependency play-services-location:21.2.0 (or higher) to access the new API.
Rights
No permissions are required to use the FOP API. The output speed is limited to 200 Hz on devices with API level 31 (Android S) or higher unless the android.permissions.HIGH_SAMPLING_RATE_SENSORS permission has been added to your Manifest.xml.
Consideration of power
Always request the longest update period (lowest frequency) that is sufficient for your use case. Although more frequent FOP updates may be necessary for high-precision tasks (e.g. Augmented Reality), this comes at a cost of energy. If you don't know which update window to use, we recommend you start there DeviceOrientationRequest::OUTPUT_PERIOD_DEFAULT because it meets most customer needs.
Foreground behavior
FOP updates are only available for apps running in the foreground.
Copyright 2023 Google LLC. SPDX-License-Identifier: Apache-2.0