blob: 8512d6b7dcf466e2a88ff0dfcbf41967b5359799 [file] [log] [blame]
Mathias Agopian984826c2011-05-17 22:54:42 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "SensorDevice.h"
18#include "SensorFusion.h"
19#include "SensorService.h"
20
21namespace android {
22// ---------------------------------------------------------------------------
23
24ANDROID_SINGLETON_STATIC_INSTANCE(SensorFusion)
25
26SensorFusion::SensorFusion()
27 : mSensorDevice(SensorDevice::getInstance()),
Mathias Agopian33015422011-05-27 18:18:13 -070028 mEnabled(false), mGyroTime(0)
Mathias Agopian984826c2011-05-17 22:54:42 -070029{
30 sensor_t const* list;
Mathias Agopian03193062013-05-10 19:32:39 -070031 Sensor uncalibratedGyro;
Mathias Agopian7b2b32f2011-07-14 16:39:46 -070032 ssize_t count = mSensorDevice.getSensorList(&list);
33 if (count > 0) {
34 for (size_t i=0 ; i<size_t(count) ; i++) {
35 if (list[i].type == SENSOR_TYPE_ACCELEROMETER) {
36 mAcc = Sensor(list + i);
37 }
38 if (list[i].type == SENSOR_TYPE_MAGNETIC_FIELD) {
39 mMag = Sensor(list + i);
40 }
41 if (list[i].type == SENSOR_TYPE_GYROSCOPE) {
42 mGyro = Sensor(list + i);
Mathias Agopian03193062013-05-10 19:32:39 -070043 }
44 if (list[i].type == SENSOR_TYPE_GYROSCOPE_UNCALIBRATED) {
45 uncalibratedGyro = Sensor(list + i);
Mathias Agopian7b2b32f2011-07-14 16:39:46 -070046 }
Mathias Agopian984826c2011-05-17 22:54:42 -070047 }
Mathias Agopian03193062013-05-10 19:32:39 -070048
49 // Use the uncalibrated gyroscope for sensor fusion when available
50 if (uncalibratedGyro.getType() == SENSOR_TYPE_GYROSCOPE_UNCALIBRATED) {
51 mGyro = uncalibratedGyro;
52 }
53
54 // 200 Hz for gyro events is a good compromise between precision
55 // and power/cpu usage.
Mathias Agopian2e2a5602013-05-30 14:18:23 -070056 mEstimatedGyroRate = 200;
57 mTargetDelayNs = 1000000000LL/mEstimatedGyroRate;
Mathias Agopian7b2b32f2011-07-14 16:39:46 -070058 mFusion.init();
Mathias Agopian984826c2011-05-17 22:54:42 -070059 }
Mathias Agopian984826c2011-05-17 22:54:42 -070060}
61
62void SensorFusion::process(const sensors_event_t& event) {
Mathias Agopian03193062013-05-10 19:32:39 -070063 if (event.type == mGyro.getType()) {
Mathias Agopian984826c2011-05-17 22:54:42 -070064 if (mGyroTime != 0) {
65 const float dT = (event.timestamp - mGyroTime) / 1000000000.0f;
Mathias Agopian2e2a5602013-05-30 14:18:23 -070066 mFusion.handleGyro(vec3_t(event.data), dT);
67 // here we estimate the gyro rate (useful for debugging)
Mathias Agopian984826c2011-05-17 22:54:42 -070068 const float freq = 1 / dT;
Mathias Agopian33015422011-05-27 18:18:13 -070069 if (freq >= 100 && freq<1000) { // filter values obviously wrong
70 const float alpha = 1 / (1 + dT); // 1s time-constant
Mathias Agopian2e2a5602013-05-30 14:18:23 -070071 mEstimatedGyroRate = freq + (mEstimatedGyroRate - freq)*alpha;
Mathias Agopian33015422011-05-27 18:18:13 -070072 }
Mathias Agopian984826c2011-05-17 22:54:42 -070073 }
74 mGyroTime = event.timestamp;
Mathias Agopian984826c2011-05-17 22:54:42 -070075 } else if (event.type == SENSOR_TYPE_MAGNETIC_FIELD) {
76 const vec3_t mag(event.data);
Mathias Agopian33015422011-05-27 18:18:13 -070077 mFusion.handleMag(mag);
Mathias Agopian984826c2011-05-17 22:54:42 -070078 } else if (event.type == SENSOR_TYPE_ACCELEROMETER) {
79 const vec3_t acc(event.data);
Mathias Agopian33015422011-05-27 18:18:13 -070080 mFusion.handleAcc(acc);
81 mAttitude = mFusion.getAttitude();
Mathias Agopian984826c2011-05-17 22:54:42 -070082 }
83}
84
85template <typename T> inline T min(T a, T b) { return a<b ? a : b; }
86template <typename T> inline T max(T a, T b) { return a>b ? a : b; }
87
88status_t SensorFusion::activate(void* ident, bool enabled) {
89
Steve Blocka5512372011-12-20 16:23:08 +000090 ALOGD_IF(DEBUG_CONNECTIONS,
Mathias Agopian984826c2011-05-17 22:54:42 -070091 "SensorFusion::activate(ident=%p, enabled=%d)",
92 ident, enabled);
93
94 const ssize_t idx = mClients.indexOf(ident);
95 if (enabled) {
96 if (idx < 0) {
97 mClients.add(ident);
98 }
99 } else {
100 if (idx >= 0) {
101 mClients.removeItemsAt(idx);
102 }
103 }
104
105 mSensorDevice.activate(ident, mAcc.getHandle(), enabled);
106 mSensorDevice.activate(ident, mMag.getHandle(), enabled);
Mathias Agopian33015422011-05-27 18:18:13 -0700107 mSensorDevice.activate(ident, mGyro.getHandle(), enabled);
Mathias Agopian984826c2011-05-17 22:54:42 -0700108
109 const bool newState = mClients.size() != 0;
110 if (newState != mEnabled) {
111 mEnabled = newState;
112 if (newState) {
113 mFusion.init();
Mathias Agopian33015422011-05-27 18:18:13 -0700114 mGyroTime = 0;
Mathias Agopian984826c2011-05-17 22:54:42 -0700115 }
116 }
117 return NO_ERROR;
118}
119
120status_t SensorFusion::setDelay(void* ident, int64_t ns) {
Aravind Akella88509092013-12-05 16:24:59 -0800121 // Call batch with timeout zero instead of setDelay().
122 mSensorDevice.batch(ident, mAcc.getHandle(), 0, ns, 0);
123 mSensorDevice.batch(ident, mMag.getHandle(), 0, ms2ns(20), 0);
124 mSensorDevice.batch(ident, mGyro.getHandle(), 0, mTargetDelayNs, 0);
Mathias Agopian984826c2011-05-17 22:54:42 -0700125 return NO_ERROR;
126}
127
128
129float SensorFusion::getPowerUsage() const {
Mathias Agopian33015422011-05-27 18:18:13 -0700130 float power = mAcc.getPowerUsage() +
131 mMag.getPowerUsage() +
132 mGyro.getPowerUsage();
Mathias Agopian984826c2011-05-17 22:54:42 -0700133 return power;
134}
135
136int32_t SensorFusion::getMinDelay() const {
137 return mAcc.getMinDelay();
138}
139
Mathias Agopianba02cd22013-07-03 16:20:57 -0700140void SensorFusion::dump(String8& result) {
Mathias Agopian984826c2011-05-17 22:54:42 -0700141 const Fusion& fusion(mFusion);
Mathias Agopianba02cd22013-07-03 16:20:57 -0700142 result.appendFormat("9-axis fusion %s (%d clients), gyro-rate=%7.2fHz, "
Mathias Agopian33015422011-05-27 18:18:13 -0700143 "q=< %g, %g, %g, %g > (%g), "
144 "b=< %g, %g, %g >\n",
Mathias Agopian984826c2011-05-17 22:54:42 -0700145 mEnabled ? "enabled" : "disabled",
146 mClients.size(),
Mathias Agopian2e2a5602013-05-30 14:18:23 -0700147 mEstimatedGyroRate,
Mathias Agopian984826c2011-05-17 22:54:42 -0700148 fusion.getAttitude().x,
149 fusion.getAttitude().y,
150 fusion.getAttitude().z,
Mathias Agopian33015422011-05-27 18:18:13 -0700151 fusion.getAttitude().w,
152 length(fusion.getAttitude()),
Mathias Agopian984826c2011-05-17 22:54:42 -0700153 fusion.getBias().x,
154 fusion.getBias().y,
155 fusion.getBias().z);
Mathias Agopian984826c2011-05-17 22:54:42 -0700156}
157
158// ---------------------------------------------------------------------------
159}; // namespace android