| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "services/device/generic_sensor/relative_orientation_euler_angles_fusion_algorithm_using_accelerometer_and_gyroscope.h" |
| |
| #include <cmath> |
| |
| #include "base/logging.h" |
| #include "base/numerics/math_constants.h" |
| #include "services/device/generic_sensor/generic_sensor_consts.h" |
| #include "services/device/generic_sensor/platform_sensor_fusion.h" |
| #include "ui/gfx/geometry/angle_conversions.h" |
| |
| namespace device { |
| |
| RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerAndGyroscope:: |
| RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerAndGyroscope() |
| : PlatformSensorFusionAlgorithm( |
| mojom::SensorType::RELATIVE_ORIENTATION_EULER_ANGLES, |
| {mojom::SensorType::ACCELEROMETER, mojom::SensorType::GYROSCOPE}) { |
| Reset(); |
| } |
| |
| RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerAndGyroscope:: |
| ~RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerAndGyroscope() = |
| default; |
| |
| void RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerAndGyroscope:: |
| Reset() { |
| timestamp_ = 0.0; |
| alpha_ = 0.0; |
| beta_ = 0.0; |
| gamma_ = 0.0; |
| } |
| |
| bool RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerAndGyroscope:: |
| GetFusedDataInternal(mojom::SensorType which_sensor_changed, |
| SensorReading* fused_reading) { |
| DCHECK(fusion_sensor_); |
| |
| // Only generate a new sensor value when the gyroscope reading changes. |
| if (which_sensor_changed != mojom::SensorType::GYROSCOPE) |
| return false; |
| |
| SensorReading accelerometer_reading; |
| SensorReading gyroscope_reading; |
| if (!fusion_sensor_->GetSourceReading(mojom::SensorType::ACCELEROMETER, |
| &accelerometer_reading) || |
| !fusion_sensor_->GetSourceReading(mojom::SensorType::GYROSCOPE, |
| &gyroscope_reading)) { |
| return false; |
| } |
| |
| double dt = |
| (timestamp_ != 0.0) ? (gyroscope_reading.timestamp() - timestamp_) : 0.0; |
| timestamp_ = gyroscope_reading.timestamp(); |
| |
| double accel_x = accelerometer_reading.accel.x; |
| double accel_y = accelerometer_reading.accel.y; |
| double accel_z = accelerometer_reading.accel.z; |
| double gyro_x = gyroscope_reading.gyro.x; |
| double gyro_y = gyroscope_reading.gyro.y; |
| double gyro_z = gyroscope_reading.gyro.z; |
| |
| // Treat the acceleration vector as an orientation vector by normalizing it. |
| // Keep in mind that the if the device is flipped, the vector will just be |
| // pointing in the other direction, so we have no way to know from the |
| // accelerometer data which way the device is oriented. |
| double norm = |
| std::sqrt(accel_x * accel_x + accel_y * accel_y + accel_z * accel_z); |
| double norm_reciprocal = 0.0; |
| // Avoid dividing by zero. |
| if (norm > kEpsilon) |
| norm_reciprocal = 1 / norm; |
| |
| // As we only can cover half (PI rad) of the full spectrum (2*PI rad) we |
| // multiply the unit vector with values from [-1, 1] with PI/2, covering |
| // [-PI/2, PI/2]. |
| double scale = base::kPiDouble / 2; |
| |
| alpha_ += gyro_z * dt; |
| // Make sure |alpha_| is in [0, 2*PI). |
| alpha_ = std::fmod(alpha_, 2 * base::kPiDouble); |
| if (alpha_ < 0) |
| alpha_ += 2 * base::kPiDouble; |
| |
| beta_ = kBias * (beta_ + gyro_x * dt) + |
| (1.0 - kBias) * (accel_x * scale * norm_reciprocal); |
| // Make sure |beta_| is in [-PI, PI). |
| beta_ = std::fmod(beta_, 2 * base::kPiDouble); |
| if (beta_ >= base::kPiDouble) |
| beta_ -= 2 * base::kPiDouble; |
| else if (beta_ < -base::kPiDouble) |
| beta_ += 2 * base::kPiDouble; |
| |
| gamma_ = kBias * (gamma_ + gyro_y * dt) + |
| (1.0 - kBias) * (accel_y * -scale * norm_reciprocal); |
| // Make sure |gamma_| is in [-PI/2, PI/2). |
| gamma_ = std::fmod(gamma_, base::kPiDouble); |
| if (gamma_ >= base::kPiDouble / 2) |
| gamma_ -= base::kPiDouble; |
| else if (gamma_ < -base::kPiDouble / 2) |
| gamma_ += base::kPiDouble; |
| |
| fused_reading->orientation_euler.z = gfx::RadToDeg(alpha_); |
| fused_reading->orientation_euler.x = gfx::RadToDeg(beta_); |
| fused_reading->orientation_euler.y = gfx::RadToDeg(gamma_); |
| |
| return true; |
| } |
| |
| } // namespace device |