blob: c40d7d2dfff12bf6a5cb00915af706bd60cb3cb0 [file] [log] [blame]
// 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