blob: a325f1fdc8b0106aef5945725a3d459b404e7461 [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 "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/numerics/math_constants.h"
#include "services/device/device_service_test_base.h"
#include "services/device/generic_sensor/fake_platform_sensor_fusion.h"
#include "services/device/generic_sensor/generic_sensor_consts.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace device {
namespace {
class
RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerAndGyroscopeTest
: public DeviceServiceTestBase {
public:
RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerAndGyroscopeTest() {
auto fusion_algorithm = std::make_unique<
RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerAndGyroscope>();
fusion_algorithm_ = fusion_algorithm.get();
fake_fusion_sensor_ = base::MakeRefCounted<FakePlatformSensorFusion>(
std::move(fusion_algorithm));
fusion_algorithm_->set_fusion_sensor(fake_fusion_sensor_.get());
EXPECT_EQ(2UL, fusion_algorithm_->source_types().size());
}
void VerifyRelativeOrientation(double accel_x,
double accel_y,
double accel_z,
double gyro_x,
double gyro_y,
double gyro_z,
double gyro_timestamp,
double expected_relative_orientation_alpha,
double expected_relative_orientation_beta,
double expected_relative_orientation_gamma) {
SensorReading accel_reading;
accel_reading.accel.x = accel_x;
accel_reading.accel.y = accel_y;
accel_reading.accel.z = accel_z;
fake_fusion_sensor_->SetSensorReading(mojom::SensorType::ACCELEROMETER,
accel_reading,
true /* sensor_reading_success */);
SensorReading gyro_reading;
gyro_reading.gyro.x = gyro_x;
gyro_reading.gyro.y = gyro_y;
gyro_reading.gyro.z = gyro_z;
gyro_reading.gyro.timestamp.value() = gyro_timestamp;
fake_fusion_sensor_->SetSensorReading(mojom::SensorType::GYROSCOPE,
gyro_reading,
true /* sensor_reading_success */);
SensorReading fused_reading;
EXPECT_TRUE(fusion_algorithm_->GetFusedData(mojom::SensorType::GYROSCOPE,
&fused_reading));
EXPECT_NEAR(expected_relative_orientation_alpha,
fused_reading.orientation_euler.z, kEpsilon);
EXPECT_NEAR(expected_relative_orientation_beta,
fused_reading.orientation_euler.x, kEpsilon);
EXPECT_NEAR(expected_relative_orientation_gamma,
fused_reading.orientation_euler.y, kEpsilon);
}
protected:
scoped_refptr<FakePlatformSensorFusion> fake_fusion_sensor_;
RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerAndGyroscope*
fusion_algorithm_;
};
} // namespace
TEST_F(
RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerAndGyroscopeTest,
GyroscopeReadingNotChanged) {
SensorReading reading;
fake_fusion_sensor_->SetSensorReading(mojom::SensorType::ACCELEROMETER,
reading,
true /* sensor_reading_success */);
fake_fusion_sensor_->SetSensorReading(mojom::SensorType::GYROSCOPE, reading,
true /* sensor_reading_success */);
SensorReading fused_reading;
EXPECT_FALSE(fusion_algorithm_->GetFusedData(mojom::SensorType::ACCELEROMETER,
&fused_reading));
}
TEST_F(
RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerAndGyroscopeTest,
NoAccelerometerReading) {
SensorReading reading;
fake_fusion_sensor_->SetSensorReading(mojom::SensorType::ACCELEROMETER,
reading,
false /* sensor_reading_success */);
fake_fusion_sensor_->SetSensorReading(mojom::SensorType::GYROSCOPE, reading,
true /* sensor_reading_success */);
SensorReading fused_reading;
EXPECT_FALSE(fusion_algorithm_->GetFusedData(mojom::SensorType::GYROSCOPE,
&fused_reading));
}
TEST_F(
RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerAndGyroscopeTest,
NoGyroscopeReading) {
SensorReading reading;
fake_fusion_sensor_->SetSensorReading(mojom::SensorType::ACCELEROMETER,
reading,
true /* sensor_reading_success */);
fake_fusion_sensor_->SetSensorReading(mojom::SensorType::GYROSCOPE, reading,
false /* sensor_reading_success */);
SensorReading fused_reading;
EXPECT_FALSE(fusion_algorithm_->GetFusedData(mojom::SensorType::GYROSCOPE,
&fused_reading));
}
TEST_F(
RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerAndGyroscopeTest,
AccelerometerAndGyroscopeReadingAllZero) {
double accel_x = 0.0;
double accel_y = 0.0;
double accel_z = 0.0;
double gyro_x = 0.0;
double gyro_y = 0.0;
double gyro_z = 0.0;
double gyro_timestamp = 1.0;
double expected_relative_orientation_alpha = 0.0;
double expected_relative_orientation_beta = 0.0;
double expected_relative_orientation_gamma = 0.0;
VerifyRelativeOrientation(accel_x, accel_y, accel_z, gyro_x, gyro_y, gyro_z,
gyro_timestamp, expected_relative_orientation_alpha,
expected_relative_orientation_beta,
expected_relative_orientation_gamma);
}
TEST_F(
RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerAndGyroscopeTest,
GryoscopeZReadingPositiveValues) {
double accel_x = 0.0;
double accel_y = 0.0;
double accel_z = device::kMeanGravity;
double gyro_x = 0.0;
double gyro_y = 0.0;
double gyro_z = base::kPiDouble;
const std::vector<double> gyro_timestamp = {0.5, 1.0, 1.5, 2.0, 2.5};
const std::vector<double> expected_relative_orientation_alpha = {
0.0, 90.0, 180.0, 270.0, 0.0};
double expected_relative_orientation_beta = 0.0;
double expected_relative_orientation_gamma = 0.0;
for (size_t i = 0; i < gyro_timestamp.size(); ++i) {
VerifyRelativeOrientation(accel_x, accel_y, accel_z, gyro_x, gyro_y, gyro_z,
gyro_timestamp[i],
expected_relative_orientation_alpha[i],
expected_relative_orientation_beta,
expected_relative_orientation_gamma);
}
}
TEST_F(
RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerAndGyroscopeTest,
GryoscopeZReadingNegativeValues) {
double accel_x = 0.0;
double accel_y = 0.0;
double accel_z = device::kMeanGravity;
double gyro_x = 0.0;
double gyro_y = 0.0;
double gyro_z = -base::kPiDouble;
const std::vector<double> gyro_timestamp = {0.5, 1.0, 1.5, 2.0, 2.5};
const std::vector<double> expected_relative_orientation_alpha = {
0.0, 270.0, 180.0, 90.0, 0.0};
double expected_relative_orientation_beta = 0.0;
double expected_relative_orientation_gamma = 0.0;
for (size_t i = 0; i < gyro_timestamp.size(); ++i) {
VerifyRelativeOrientation(accel_x, accel_y, accel_z, gyro_x, gyro_y, gyro_z,
gyro_timestamp[i],
expected_relative_orientation_alpha[i],
expected_relative_orientation_beta,
expected_relative_orientation_gamma);
}
}
TEST_F(
RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerAndGyroscopeTest,
GryoscopeXReadingNonZeroValues) {
// Test the device rotates around x-axis in 360 degrees with positive |gyro_x|
// reading, and in each step it rotates base::kPiDouble/6 radians.
double accel_x = 0.0;
double accel_y = 0.0;
double accel_z = 0.0;
double gyro_x = base::kPiDouble;
double gyro_y = 0.0;
double gyro_z = 0.0;
double gyro_timestamp = 1.0 / 6.0;
const double kTimestampIncrement = 1.0 / 6.0;
const double kAngleIncrement = kTimestampIncrement * gyro_x;
double angle = 0.0;
double expected_relative_orientation_alpha = 0.0;
const std::vector<double> expected_relative_orientation_beta = {
0.0,
29.3999999999,
58.212,
86.4477599999,
114.1188047999,
141.2364287039,
167.8117001299,
-166.1445338726,
-133.4216431952,
-101.3532103313,
-69.9261461246,
-39.1276232022,
-8.9450707381};
const std::vector<double> expected_relative_orientation_gamma = {
0.0, -0.9, -2.4408457268, -4.1920288122, -5.6670339628,
-6.4536932835, -6.3246194179, -5.2981270295, -3.6333187621, -1.7606523869,
-0.1665936123, 0.7367382598, 0.7220034946};
for (size_t i = 0; i < expected_relative_orientation_beta.size(); ++i) {
VerifyRelativeOrientation(accel_x, accel_y, accel_z, gyro_x, gyro_y, gyro_z,
gyro_timestamp,
expected_relative_orientation_alpha,
expected_relative_orientation_beta[i],
expected_relative_orientation_gamma[i]);
gyro_timestamp += kTimestampIncrement;
angle += kAngleIncrement;
accel_y = device::kMeanGravity * std::sin(angle);
accel_z = device::kMeanGravity * std::cos(angle);
}
// Test the device rotates around x-axis in 360 degrees with negative |gyro_x|
// reading, and in each step it rotates base::kPiDouble/6 radians.
fusion_algorithm_->Reset();
accel_y = 0.0;
accel_z = 0.0;
gyro_x = -base::kPiDouble;
gyro_timestamp = 1.0 / 6.0;
angle = 0.0;
for (size_t i = 0; i < expected_relative_orientation_beta.size(); ++i) {
VerifyRelativeOrientation(accel_x, accel_y, accel_z, gyro_x, gyro_y, gyro_z,
gyro_timestamp,
expected_relative_orientation_alpha,
-expected_relative_orientation_beta[i],
-expected_relative_orientation_gamma[i]);
gyro_timestamp += kTimestampIncrement;
angle += kAngleIncrement;
// Here the |accel_y| is different from the above because the device
// rotates around x-axis in the opposite direction.
accel_y = -device::kMeanGravity * std::sin(angle);
accel_z = device::kMeanGravity * std::cos(angle);
}
}
TEST_F(
RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerAndGyroscopeTest,
GryoscopeYReadingNonZeroValues) {
// Test the device rotates around y-axis in 360 degrees with positive |gyro_y|
// reading, and in each step it rotates base::kPiDouble/6 radians.
double accel_x = 0.0;
double accel_y = 0.0;
double accel_z = 0.0;
double gyro_x = 0.0;
double gyro_y = base::kPiDouble;
double gyro_z = 0.0;
double gyro_timestamp = 1.0 / 6.0;
const double kTimestampIncrement = 1.0 / 6.0;
const double kAngleIncrement = kTimestampIncrement * gyro_y;
double angle = 0.0;
double expected_relative_orientation_alpha = 0.0;
const std::vector<double> expected_relative_orientation_beta = {
0.0, -0.9, -2.4408457268, -4.1920288122, -5.6670339628,
-6.4536932835, -6.3246194179, -5.2981270295, -3.6333187621, -1.7606523869,
-0.1665936123, 0.7367382598, 0.7220034946};
const std::vector<double> expected_relative_orientation_gamma = {
0.0, 29.3999999999, 58.212, 86.4477599999,
-65.8811952, -35.163571296, -5.06029987, 24.4409061273,
53.3520880047, 81.6850462446, -70.5486546802, -39.7376815866,
-9.5429279548};
for (size_t i = 0; i < expected_relative_orientation_beta.size(); ++i) {
VerifyRelativeOrientation(accel_x, accel_y, accel_z, gyro_x, gyro_y, gyro_z,
gyro_timestamp,
expected_relative_orientation_alpha,
expected_relative_orientation_beta[i],
expected_relative_orientation_gamma[i]);
gyro_timestamp += kTimestampIncrement;
angle += kAngleIncrement;
accel_x = -device::kMeanGravity * std::sin(angle);
accel_z = device::kMeanGravity * std::cos(angle);
}
// Test the device rotates around y-axis in 360 degrees with negative |gyro_y|
// reading, and in each step it rotates base::kPiDouble/6 radians.
fusion_algorithm_->Reset();
accel_x = 0.0;
accel_z = 0.0;
gyro_y = -base::kPiDouble;
gyro_timestamp = 1.0 / 6.0;
angle = 0.0;
for (size_t i = 0; i < expected_relative_orientation_beta.size(); ++i) {
VerifyRelativeOrientation(accel_x, accel_y, accel_z, gyro_x, gyro_y, gyro_z,
gyro_timestamp,
expected_relative_orientation_alpha,
-expected_relative_orientation_beta[i],
-expected_relative_orientation_gamma[i]);
gyro_timestamp += kTimestampIncrement;
angle += kAngleIncrement;
// Here the |accel_x| is different from the above because the device
// rotates around y-axis in the opposite direction.
accel_x = device::kMeanGravity * std::sin(angle);
accel_z = device::kMeanGravity * std::cos(angle);
}
}
TEST_F(
RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerAndGyroscopeTest,
AccelerometerZReadingChangeNotAffectingAlpha) {
double accel_x = 0.0;
double accel_y = 0.0;
const std::vector<double> accel_z = {0.0, 1.0, 2.0, 3.0, 4.0};
double gyro_x = 0.0;
double gyro_y = 0.0;
double gyro_z = base::kPiDouble;
const std::vector<double> gyro_timestamp = {0.5, 1.0, 1.5, 2.0, 2.5};
const std::vector<double> expected_relative_orientation_alpha = {
0.0, 90.0, 180.0, 270.0, 0.0};
double expected_relative_orientation_beta = 0.0;
double expected_relative_orientation_gamma = 0.0;
for (size_t i = 0; i < gyro_timestamp.size(); ++i) {
VerifyRelativeOrientation(accel_x, accel_y, accel_z[i], gyro_x, gyro_y,
gyro_z, gyro_timestamp[i],
expected_relative_orientation_alpha[i],
expected_relative_orientation_beta,
expected_relative_orientation_gamma);
}
}
TEST_F(
RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerAndGyroscopeTest,
StopSensorShouldClearAllInternalStatisticalData) {
double accel_x_1 = 1.0;
double accel_y_1 = 2.0;
double accel_z_1 = 3.0;
double gyro_x_1 = 4.0;
double gyro_y_1 = 5.0;
double gyro_z_1 = 6.0;
double gyro_timestamp_1 = 1.0;
double expected_relative_orientation_alpha_1 = 0.0;
double expected_relative_orientation_beta_1 = 0.48107023544;
double expected_relative_orientation_gamma_1 = -0.9621404708;
VerifyRelativeOrientation(accel_x_1, accel_y_1, accel_z_1, gyro_x_1, gyro_y_1,
gyro_z_1, gyro_timestamp_1,
expected_relative_orientation_alpha_1,
expected_relative_orientation_beta_1,
expected_relative_orientation_gamma_1);
double accel_x_2 = 7.0;
double accel_y_2 = 8.0;
double accel_z_2 = 9.0;
double gyro_x_2 = 10.0;
double gyro_y_2 = 11.0;
double gyro_z_2 = 12.0;
double gyro_timestamp_2 = 2.0;
double expected_relative_orientation_alpha_2 = 327.5493541569;
double expected_relative_orientation_beta_2 = -157.1252846612;
double expected_relative_orientation_gamma_2 = 75.6717457411;
VerifyRelativeOrientation(accel_x_2, accel_y_2, accel_z_2, gyro_x_2, gyro_y_2,
gyro_z_2, gyro_timestamp_2,
expected_relative_orientation_alpha_2,
expected_relative_orientation_beta_2,
expected_relative_orientation_gamma_2);
fusion_algorithm_->Reset();
// After sensor stops, all internal statistical data are reset. When using
// the same accelerometer and gyroscope data but different timestamps (as
// long as the timestamp delta is the same), the relative orientation fused
// data should be the same as before.
double gyro_timestamp_3 = 3.0;
VerifyRelativeOrientation(accel_x_1, accel_y_1, accel_z_1, gyro_x_1, gyro_y_1,
gyro_z_1, gyro_timestamp_3,
expected_relative_orientation_alpha_1,
expected_relative_orientation_beta_1,
expected_relative_orientation_gamma_1);
double gyro_timestamp_4 = 4.0;
VerifyRelativeOrientation(accel_x_2, accel_y_2, accel_z_2, gyro_x_2, gyro_y_2,
gyro_z_2, gyro_timestamp_4,
expected_relative_orientation_alpha_2,
expected_relative_orientation_beta_2,
expected_relative_orientation_gamma_2);
}
} // namespace device