9-axis sensor fusion with Kalman filter
Add support for 9-axis gravity and linear-acceleration sensors
virtual orientation sensor using 9-axis fusion
Change-Id: I6717539373fce781c10e97b6fa59f68a831a592f
diff --git a/services/sensorservice/GravitySensor.cpp b/services/sensorservice/GravitySensor.cpp
index 5c6aa99..541fad2 100644
--- a/services/sensorservice/GravitySensor.cpp
+++ b/services/sensorservice/GravitySensor.cpp
@@ -23,16 +23,18 @@
#include <hardware/sensors.h>
#include "GravitySensor.h"
+#include "SensorDevice.h"
+#include "SensorFusion.h"
namespace android {
// ---------------------------------------------------------------------------
GravitySensor::GravitySensor(sensor_t const* list, size_t count)
: mSensorDevice(SensorDevice::getInstance()),
+ mSensorFusion(SensorFusion::getInstance()),
mAccTime(0),
mLowPass(M_SQRT1_2, 1.5f),
mX(mLowPass), mY(mLowPass), mZ(mLowPass)
-
{
for (size_t i=0 ; i<count ; i++) {
if (list[i].type == SENSOR_TYPE_ACCELEROMETER) {
@@ -47,35 +49,52 @@
{
const static double NS2S = 1.0 / 1000000000.0;
if (event.type == SENSOR_TYPE_ACCELEROMETER) {
- float x, y, z;
- const double now = event.timestamp * NS2S;
- if (mAccTime == 0) {
- x = mX.init(event.acceleration.x);
- y = mY.init(event.acceleration.y);
- z = mZ.init(event.acceleration.z);
+ vec3_t g;
+ if (mSensorFusion.hasGyro()) {
+ if (!mSensorFusion.hasEstimate())
+ return false;
+ const mat33_t R(mSensorFusion.getRotationMatrix());
+ // FIXME: we need to estimate the length of gravity because
+ // the accelerometer may have a small scaling error. This
+ // translates to an offset in the linear-acceleration sensor.
+ g = R[2] * GRAVITY_EARTH;
} else {
- double dT = now - mAccTime;
- mLowPass.setSamplingPeriod(dT);
- x = mX(event.acceleration.x);
- y = mY(event.acceleration.y);
- z = mZ(event.acceleration.z);
+ const double now = event.timestamp * NS2S;
+ if (mAccTime == 0) {
+ g.x = mX.init(event.acceleration.x);
+ g.y = mY.init(event.acceleration.y);
+ g.z = mZ.init(event.acceleration.z);
+ } else {
+ double dT = now - mAccTime;
+ mLowPass.setSamplingPeriod(dT);
+ g.x = mX(event.acceleration.x);
+ g.y = mY(event.acceleration.y);
+ g.z = mZ(event.acceleration.z);
+ }
+ g *= (GRAVITY_EARTH / length(g));
+ mAccTime = now;
}
- mAccTime = now;
*outEvent = event;
- outEvent->data[0] = x;
- outEvent->data[1] = y;
- outEvent->data[2] = z;
+ outEvent->data[0] = g.x;
+ outEvent->data[1] = g.y;
+ outEvent->data[2] = g.z;
outEvent->sensor = '_grv';
outEvent->type = SENSOR_TYPE_GRAVITY;
return true;
}
return false;
}
+
status_t GravitySensor::activate(void* ident, bool enabled) {
- status_t err = mSensorDevice.activate(this, mAccelerometer.getHandle(), enabled);
- if (err == NO_ERROR) {
- if (enabled) {
- mAccTime = 0;
+ status_t err;
+ if (mSensorFusion.hasGyro()) {
+ err = mSensorFusion.activate(this, enabled);
+ } else {
+ err = mSensorDevice.activate(this, mAccelerometer.getHandle(), enabled);
+ if (err == NO_ERROR) {
+ if (enabled) {
+ mAccTime = 0;
+ }
}
}
return err;
@@ -83,20 +102,26 @@
status_t GravitySensor::setDelay(void* ident, int handle, int64_t ns)
{
- return mSensorDevice.setDelay(this, mAccelerometer.getHandle(), ns);
+ if (mSensorFusion.hasGyro()) {
+ return mSensorFusion.setDelay(this, ns);
+ } else {
+ return mSensorDevice.setDelay(this, mAccelerometer.getHandle(), ns);
+ }
}
Sensor GravitySensor::getSensor() const {
sensor_t hwSensor;
hwSensor.name = "Gravity Sensor";
hwSensor.vendor = "Google Inc.";
- hwSensor.version = 1;
+ hwSensor.version = mSensorFusion.hasGyro() ? 3 : 2;
hwSensor.handle = '_grv';
hwSensor.type = SENSOR_TYPE_GRAVITY;
- hwSensor.maxRange = mAccelerometer.getMaxValue();
+ hwSensor.maxRange = GRAVITY_EARTH * 2;
hwSensor.resolution = mAccelerometer.getResolution();
- hwSensor.power = mAccelerometer.getPowerUsage();
- hwSensor.minDelay = mAccelerometer.getMinDelay();
+ hwSensor.power = mSensorFusion.hasGyro() ?
+ mSensorFusion.getPowerUsage() : mAccelerometer.getPowerUsage();
+ hwSensor.minDelay = mSensorFusion.hasGyro() ?
+ mSensorFusion.getMinDelay() : mAccelerometer.getMinDelay();
Sensor sensor(&hwSensor);
return sensor;
}