RotationVectorSensor.cpp revision 2cf098846c83bab82272f107ba110f7c47df1763
1/* 2 * Copyright (C) 2010 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 <stdint.h> 18#include <math.h> 19#include <sys/types.h> 20 21#include <utils/Errors.h> 22 23#include <hardware/sensors.h> 24 25#include "RotationVectorSensor.h" 26 27namespace android { 28// --------------------------------------------------------------------------- 29 30template <typename T> 31static inline T clamp(T v) { 32 return v < 0 ? 0 : v; 33} 34 35RotationVectorSensor::RotationVectorSensor(sensor_t const* list, size_t count) 36 : mSensorDevice(SensorDevice::getInstance()), 37 mALowPass(M_SQRT1_2, 1.5f), 38 mAX(mALowPass), mAY(mALowPass), mAZ(mALowPass), 39 mMLowPass(M_SQRT1_2, 1.5f), 40 mMX(mMLowPass), mMY(mMLowPass), mMZ(mMLowPass) 41{ 42 for (size_t i=0 ; i<count ; i++) { 43 if (list[i].type == SENSOR_TYPE_ACCELEROMETER) { 44 mAcc = Sensor(list + i); 45 } 46 if (list[i].type == SENSOR_TYPE_MAGNETIC_FIELD) { 47 mMag = Sensor(list + i); 48 } 49 } 50 memset(mMagData, 0, sizeof(mMagData)); 51} 52 53bool RotationVectorSensor::process(sensors_event_t* outEvent, 54 const sensors_event_t& event) 55{ 56 const static double NS2S = 1.0 / 1000000000.0; 57 if (event.type == SENSOR_TYPE_MAGNETIC_FIELD) { 58 const double now = event.timestamp * NS2S; 59 if (mMagTime == 0) { 60 mMagData[0] = mMX.init(event.magnetic.x); 61 mMagData[1] = mMY.init(event.magnetic.y); 62 mMagData[2] = mMZ.init(event.magnetic.z); 63 } else { 64 double dT = now - mMagTime; 65 mMLowPass.setSamplingPeriod(dT); 66 mMagData[0] = mMX(event.magnetic.x); 67 mMagData[1] = mMY(event.magnetic.y); 68 mMagData[2] = mMZ(event.magnetic.z); 69 } 70 mMagTime = now; 71 } 72 if (event.type == SENSOR_TYPE_ACCELEROMETER) { 73 const double now = event.timestamp * NS2S; 74 float Ax, Ay, Az; 75 if (mAccTime == 0) { 76 Ax = mAX.init(event.acceleration.x); 77 Ay = mAY.init(event.acceleration.y); 78 Az = mAZ.init(event.acceleration.z); 79 } else { 80 double dT = now - mAccTime; 81 mALowPass.setSamplingPeriod(dT); 82 Ax = mAX(event.acceleration.x); 83 Ay = mAY(event.acceleration.y); 84 Az = mAZ(event.acceleration.z); 85 } 86 mAccTime = now; 87 const float Ex = mMagData[0]; 88 const float Ey = mMagData[1]; 89 const float Ez = mMagData[2]; 90 float Hx = Ey*Az - Ez*Ay; 91 float Hy = Ez*Ax - Ex*Az; 92 float Hz = Ex*Ay - Ey*Ax; 93 const float normH = sqrtf(Hx*Hx + Hy*Hy + Hz*Hz); 94 if (normH < 0.1f) { 95 // device is close to free fall (or in space?), or close to 96 // magnetic north pole. Typical values are > 100. 97 return false; 98 } 99 const float invH = 1.0f / normH; 100 const float invA = 1.0f / sqrtf(Ax*Ax + Ay*Ay + Az*Az); 101 Hx *= invH; 102 Hy *= invH; 103 Hz *= invH; 104 Ax *= invA; 105 Ay *= invA; 106 Az *= invA; 107 const float Mx = Ay*Hz - Az*Hy; 108 const float My = Az*Hx - Ax*Hz; 109 const float Mz = Ax*Hy - Ay*Hx; 110 111 // matrix to rotation vector (normalized quaternion) 112 float qw = sqrtf( clamp( Hx + My + Az + 1) * 0.25f ); 113 float qx = sqrtf( clamp( Hx - My - Az + 1) * 0.25f ); 114 float qy = sqrtf( clamp(-Hx + My - Az + 1) * 0.25f ); 115 float qz = sqrtf( clamp(-Hx - My + Az + 1) * 0.25f ); 116 qx = copysignf(qx, Ay - Mz); 117 qy = copysignf(qy, Hz - Ax); 118 qz = copysignf(qz, Mx - Hy); 119 120 // this quaternion is guaranteed to be normalized, by construction 121 // of the rotation matrix. 122 123 *outEvent = event; 124 outEvent->data[0] = qx; 125 outEvent->data[1] = qy; 126 outEvent->data[2] = qz; 127 outEvent->data[3] = qw; 128 outEvent->sensor = '_rov'; 129 outEvent->type = SENSOR_TYPE_ROTATION_VECTOR; 130 return true; 131 } 132 return false; 133} 134 135status_t RotationVectorSensor::activate(void* ident, bool enabled) { 136 mSensorDevice.activate(this, mAcc.getHandle(), enabled); 137 mSensorDevice.activate(this, mMag.getHandle(), enabled); 138 if (enabled) { 139 mMagTime = 0; 140 mAccTime = 0; 141 } 142 return NO_ERROR; 143} 144 145status_t RotationVectorSensor::setDelay(void* ident, int handle, int64_t ns) 146{ 147 mSensorDevice.setDelay(this, mAcc.getHandle(), ns); 148 mSensorDevice.setDelay(this, mMag.getHandle(), ns); 149 return NO_ERROR; 150} 151 152Sensor RotationVectorSensor::getSensor() const { 153 sensor_t hwSensor; 154 hwSensor.name = "Rotation Vector Sensor"; 155 hwSensor.vendor = "Google Inc."; 156 hwSensor.version = 1; 157 hwSensor.handle = '_rov'; 158 hwSensor.type = SENSOR_TYPE_ROTATION_VECTOR; 159 hwSensor.maxRange = 1; 160 hwSensor.resolution = 1.0f / (1<<24); 161 hwSensor.power = mAcc.getPowerUsage() + mMag.getPowerUsage(); 162 hwSensor.minDelay = mAcc.getMinDelay(); 163 Sensor sensor(&hwSensor); 164 return sensor; 165} 166 167// --------------------------------------------------------------------------- 168}; // namespace android 169 170