blob: 8eef149fac0e6d7dd84866136c44357e0cacce8d [file] [log] [blame]
James Kuszmauld3f9eb22020-01-12 15:02:07 -08001#include "aos/flatbuffers.h"
2#include "gtest/gtest.h"
3#include "frc971/zeroing/imu_zeroer.h"
4
5namespace frc971::zeroing {
6
7aos::FlatbufferDetachedBuffer<IMUValues> MakeMeasurement(
8 const Eigen::Vector3d &gyro, const Eigen::Vector3d &accel) {
9 flatbuffers::FlatBufferBuilder fbb;
Austin Schuhd7b15da2020-02-17 15:06:11 -080010 fbb.ForceDefaults(true);
James Kuszmauld3f9eb22020-01-12 15:02:07 -080011 IMUValuesBuilder builder(fbb);
12 builder.add_gyro_x(gyro.x());
13 builder.add_gyro_y(gyro.y());
14 builder.add_gyro_z(gyro.z());
15 builder.add_accelerometer_x(accel.x());
16 builder.add_accelerometer_y(accel.y());
17 builder.add_accelerometer_z(accel.z());
18 fbb.Finish(builder.Finish());
19 return fbb.Release();
20}
21
22// Tests that when we initialize everything is in a sane state.
23TEST(ImuZeroerTest, InitializeUnzeroed) {
24 ImuZeroer zeroer;
25 ASSERT_FALSE(zeroer.Zeroed());
26 ASSERT_FALSE(zeroer.Faulted());
27 ASSERT_EQ(0.0, zeroer.GyroOffset().norm());
28 ASSERT_EQ(0.0, zeroer.ZeroedGyro().norm());
29 ASSERT_EQ(0.0, zeroer.ZeroedAccel().norm());
30 // A measurement before we are zeroed should just result in the measurement
31 // being passed through without modification.
32 zeroer.ProcessMeasurement(MakeMeasurement({1, 2, 3}, {4, 5, 6}).message());
33 ASSERT_FALSE(zeroer.Zeroed());
34 ASSERT_FALSE(zeroer.Faulted());
35 ASSERT_EQ(0.0, zeroer.GyroOffset().norm());
36 ASSERT_EQ(1.0, zeroer.ZeroedGyro().x());
37 ASSERT_EQ(2.0, zeroer.ZeroedGyro().y());
38 ASSERT_EQ(3.0, zeroer.ZeroedGyro().z());
39 ASSERT_EQ(4.0, zeroer.ZeroedAccel().x());
40 ASSERT_EQ(5.0, zeroer.ZeroedAccel().y());
41 ASSERT_EQ(6.0, zeroer.ZeroedAccel().z());
42}
43
44// Tests that we zero if we receive a bunch of identical measurements.
45TEST(ImuZeroerTest, ZeroOnConstantData) {
46 ImuZeroer zeroer;
47 ASSERT_FALSE(zeroer.Zeroed());
48 for (size_t ii = 0; ii < ImuZeroer::kSamplesToAverage; ++ii) {
49 ASSERT_FALSE(zeroer.Zeroed());
50 zeroer.ProcessMeasurement(MakeMeasurement({1, 2, 3}, {4, 5, 6}).message());
51 }
52 ASSERT_TRUE(zeroer.Zeroed());
53 ASSERT_FALSE(zeroer.Faulted());
54 // Gyro should be zeroed to {1, 2, 3}.
55 ASSERT_EQ(1.0, zeroer.GyroOffset().x());
56 ASSERT_EQ(2.0, zeroer.GyroOffset().y());
57 ASSERT_EQ(3.0, zeroer.GyroOffset().z());
58 ASSERT_EQ(0.0, zeroer.ZeroedGyro().x());
59 ASSERT_EQ(0.0, zeroer.ZeroedGyro().y());
60 ASSERT_EQ(0.0, zeroer.ZeroedGyro().z());
61 // Accelerometer readings should not be affected.
62 ASSERT_EQ(4.0, zeroer.ZeroedAccel().x());
63 ASSERT_EQ(5.0, zeroer.ZeroedAccel().y());
64 ASSERT_EQ(6.0, zeroer.ZeroedAccel().z());
65 // If we get another measurement offset by {1, 1, 1} we should read the result
66 // as {1, 1, 1}.
67 zeroer.ProcessMeasurement(MakeMeasurement({2, 3, 4}, {0, 0, 0}).message());
68 ASSERT_FALSE(zeroer.Faulted());
69 ASSERT_EQ(1.0, zeroer.ZeroedGyro().x());
70 ASSERT_EQ(1.0, zeroer.ZeroedGyro().y());
71 ASSERT_EQ(1.0, zeroer.ZeroedGyro().z());
72}
73
74// Tests that we tolerate small amounts of noise in the incoming data and can
75// still zero.
76TEST(ImuZeroerTest, ZeroOnLowNoiseData) {
77 ImuZeroer zeroer;
78 ASSERT_FALSE(zeroer.Zeroed());
79 for (size_t ii = 0; ii < ImuZeroer::kSamplesToAverage; ++ii) {
80 ASSERT_FALSE(zeroer.Zeroed());
81 const double offset =
82 (static_cast<double>(ii) / (ImuZeroer::kSamplesToAverage - 1) - 0.5) *
83 0.01;
84 zeroer.ProcessMeasurement(
85 MakeMeasurement({1 + offset, 2 + offset, 3 + offset},
86 {4 + offset, 5 + offset, 6 + offset})
87 .message());
88 }
89 ASSERT_TRUE(zeroer.Zeroed());
90 ASSERT_FALSE(zeroer.Faulted());
91 // Gyro should be zeroed to {1, 2, 3}.
James Kuszmaul30aca502020-01-19 15:05:33 -080092 ASSERT_NEAR(1.0, zeroer.GyroOffset().x(), 1e-8);
93 ASSERT_NEAR(2.0, zeroer.GyroOffset().y(), 1e-8);
94 ASSERT_NEAR(3.0, zeroer.GyroOffset().z(), 1e-8);
James Kuszmauld3f9eb22020-01-12 15:02:07 -080095 // If we get another measurement offset by {1, 1, 1} we should read the result
96 // as {1, 1, 1}.
97 zeroer.ProcessMeasurement(MakeMeasurement({2, 3, 4}, {0, 0, 0}).message());
98 ASSERT_FALSE(zeroer.Faulted());
James Kuszmaul30aca502020-01-19 15:05:33 -080099 ASSERT_NEAR(1.0, zeroer.ZeroedGyro().x(), 1e-8);
100 ASSERT_NEAR(1.0, zeroer.ZeroedGyro().y(), 1e-8);
101 ASSERT_NEAR(1.0, zeroer.ZeroedGyro().z(), 1e-8);
James Kuszmauld3f9eb22020-01-12 15:02:07 -0800102 ASSERT_EQ(0.0, zeroer.ZeroedAccel().x());
103 ASSERT_EQ(0.0, zeroer.ZeroedAccel().y());
104 ASSERT_EQ(0.0, zeroer.ZeroedAccel().z());
105}
106
107// Tests that we do not zero if there is too much noise in the input data.
108TEST(ImuZeroerTest, NoZeroOnHighNoiseData) {
109 ImuZeroer zeroer;
110 ASSERT_FALSE(zeroer.Zeroed());
111 for (size_t ii = 0; ii < ImuZeroer::kSamplesToAverage; ++ii) {
112 ASSERT_FALSE(zeroer.Zeroed());
113 const double offset =
114 (static_cast<double>(ii) / (ImuZeroer::kSamplesToAverage - 1) - 0.5) *
115 1.0;
116 zeroer.ProcessMeasurement(
117 MakeMeasurement({1 + offset, 2 + offset, 3 + offset},
118 {4 + offset, 5 + offset, 6 + offset})
119 .message());
120 }
121 ASSERT_FALSE(zeroer.Zeroed());
122 ASSERT_FALSE(zeroer.Faulted());
123}
124
125// Tests that we fault if we successfully rezero and get a significantly offset
126// zero.
127TEST(ImuZeroerTest, FaultOnNewZero) {
128 ImuZeroer zeroer;
129 ASSERT_FALSE(zeroer.Zeroed());
130 for (size_t ii = 0; ii < ImuZeroer::kSamplesToAverage; ++ii) {
131 ASSERT_FALSE(zeroer.Zeroed());
132 zeroer.ProcessMeasurement(MakeMeasurement({1, 2, 3}, {4, 5, 6}).message());
133 }
134 ASSERT_TRUE(zeroer.Zeroed());
135 for (size_t ii = 0; ii < ImuZeroer::kSamplesToAverage; ++ii) {
136 ASSERT_FALSE(zeroer.Faulted())
137 << "We should not fault until we complete a second cycle of zeroing.";
138 zeroer.ProcessMeasurement(MakeMeasurement({1, 5, 3}, {4, 5, 6}).message());
139 }
140 ASSERT_TRUE(zeroer.Faulted());
141}
142
143// Tests that we do not fault if the zero only changes by a small amount.
144TEST(ImuZeroerTest, NoFaultOnSimilarZero) {
145 ImuZeroer zeroer;
146 ASSERT_FALSE(zeroer.Zeroed());
147 for (size_t ii = 0; ii < ImuZeroer::kSamplesToAverage; ++ii) {
148 ASSERT_FALSE(zeroer.Zeroed());
149 zeroer.ProcessMeasurement(MakeMeasurement({1, 2, 3}, {4, 5, 6}).message());
150 }
151 ASSERT_TRUE(zeroer.Zeroed());
152 for (size_t ii = 0; ii < ImuZeroer::kSamplesToAverage; ++ii) {
153 zeroer.ProcessMeasurement(
154 MakeMeasurement({1, 2.0001, 3}, {4, 5, 6}).message());
155 }
156 ASSERT_FALSE(zeroer.Faulted());
157}
158
159} // namespace frc971::zeroing