blob: 0a6854139a80e64195b6296ab44f45300f40af2f [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
James Kuszmaulb1e29372020-02-11 16:55:36 -08007static constexpr int kMinSamplesToZero =
8 2 * ImuZeroer::kSamplesToAverage * ImuZeroer::kRequiredZeroPoints;
9
James Kuszmauld3f9eb22020-01-12 15:02:07 -080010aos::FlatbufferDetachedBuffer<IMUValues> MakeMeasurement(
James Kuszmaulddc69702021-03-24 21:55:03 -070011 const Eigen::Vector3d &gyro, const Eigen::Vector3d &accel,
12 bool faulted = false) {
James Kuszmauld3f9eb22020-01-12 15:02:07 -080013 flatbuffers::FlatBufferBuilder fbb;
Austin Schuhd7b15da2020-02-17 15:06:11 -080014 fbb.ForceDefaults(true);
James Kuszmaulddc69702021-03-24 21:55:03 -070015
16 ADIS16470DiagStatBuilder diag_stat_builder(fbb);
17 diag_stat_builder.add_clock_error(faulted);
18 diag_stat_builder.add_memory_failure(false);
19 diag_stat_builder.add_sensor_failure(false);
20 diag_stat_builder.add_standby_mode(false);
21 diag_stat_builder.add_spi_communication_error(false);
22 diag_stat_builder.add_flash_memory_update_error(false);
23 diag_stat_builder.add_data_path_overrun(false);
24
25 const auto diag_stat_offset = diag_stat_builder.Finish();
26
James Kuszmauld3f9eb22020-01-12 15:02:07 -080027 IMUValuesBuilder builder(fbb);
28 builder.add_gyro_x(gyro.x());
29 builder.add_gyro_y(gyro.y());
30 builder.add_gyro_z(gyro.z());
31 builder.add_accelerometer_x(accel.x());
32 builder.add_accelerometer_y(accel.y());
33 builder.add_accelerometer_z(accel.z());
James Kuszmaulddc69702021-03-24 21:55:03 -070034 builder.add_previous_reading_diag_stat(diag_stat_offset);
James Kuszmauld3f9eb22020-01-12 15:02:07 -080035 fbb.Finish(builder.Finish());
36 return fbb.Release();
37}
38
39// Tests that when we initialize everything is in a sane state.
40TEST(ImuZeroerTest, InitializeUnzeroed) {
41 ImuZeroer zeroer;
42 ASSERT_FALSE(zeroer.Zeroed());
43 ASSERT_FALSE(zeroer.Faulted());
44 ASSERT_EQ(0.0, zeroer.GyroOffset().norm());
45 ASSERT_EQ(0.0, zeroer.ZeroedGyro().norm());
46 ASSERT_EQ(0.0, zeroer.ZeroedAccel().norm());
47 // A measurement before we are zeroed should just result in the measurement
48 // being passed through without modification.
James Kuszmaulb7f45bb2020-02-26 20:27:48 -080049 zeroer.InsertAndProcessMeasurement(
James Kuszmaulb1e29372020-02-11 16:55:36 -080050 MakeMeasurement({0.01, 0.02, 0.03}, {4, 5, 6}).message());
James Kuszmauld3f9eb22020-01-12 15:02:07 -080051 ASSERT_FALSE(zeroer.Zeroed());
52 ASSERT_FALSE(zeroer.Faulted());
53 ASSERT_EQ(0.0, zeroer.GyroOffset().norm());
James Kuszmaulb1e29372020-02-11 16:55:36 -080054 ASSERT_FLOAT_EQ(0.01, zeroer.ZeroedGyro().x());
55 ASSERT_FLOAT_EQ(0.02, zeroer.ZeroedGyro().y());
56 ASSERT_FLOAT_EQ(0.03, zeroer.ZeroedGyro().z());
James Kuszmauld3f9eb22020-01-12 15:02:07 -080057 ASSERT_EQ(4.0, zeroer.ZeroedAccel().x());
58 ASSERT_EQ(5.0, zeroer.ZeroedAccel().y());
59 ASSERT_EQ(6.0, zeroer.ZeroedAccel().z());
60}
61
62// Tests that we zero if we receive a bunch of identical measurements.
63TEST(ImuZeroerTest, ZeroOnConstantData) {
64 ImuZeroer zeroer;
65 ASSERT_FALSE(zeroer.Zeroed());
James Kuszmaulb1e29372020-02-11 16:55:36 -080066 for (size_t ii = 0; ii < kMinSamplesToZero; ++ii) {
James Kuszmaulb7f45bb2020-02-26 20:27:48 -080067 zeroer.InsertAndProcessMeasurement(
James Kuszmaulb1e29372020-02-11 16:55:36 -080068 MakeMeasurement({0.01, 0.02, 0.03}, {4, 5, 6}).message());
James Kuszmauld3f9eb22020-01-12 15:02:07 -080069 }
70 ASSERT_TRUE(zeroer.Zeroed());
71 ASSERT_FALSE(zeroer.Faulted());
72 // Gyro should be zeroed to {1, 2, 3}.
James Kuszmaulb1e29372020-02-11 16:55:36 -080073 ASSERT_FLOAT_EQ(0.01, zeroer.GyroOffset().x());
74 ASSERT_FLOAT_EQ(0.02, zeroer.GyroOffset().y());
75 ASSERT_FLOAT_EQ(0.03, zeroer.GyroOffset().z());
James Kuszmauld3f9eb22020-01-12 15:02:07 -080076 ASSERT_EQ(0.0, zeroer.ZeroedGyro().x());
77 ASSERT_EQ(0.0, zeroer.ZeroedGyro().y());
78 ASSERT_EQ(0.0, zeroer.ZeroedGyro().z());
79 // Accelerometer readings should not be affected.
80 ASSERT_EQ(4.0, zeroer.ZeroedAccel().x());
81 ASSERT_EQ(5.0, zeroer.ZeroedAccel().y());
82 ASSERT_EQ(6.0, zeroer.ZeroedAccel().z());
83 // If we get another measurement offset by {1, 1, 1} we should read the result
84 // as {1, 1, 1}.
James Kuszmaulb7f45bb2020-02-26 20:27:48 -080085 zeroer.InsertAndProcessMeasurement(
James Kuszmaulb1e29372020-02-11 16:55:36 -080086 MakeMeasurement({0.02, 0.03, 0.04}, {0, 0, 0}).message());
James Kuszmauld3f9eb22020-01-12 15:02:07 -080087 ASSERT_FALSE(zeroer.Faulted());
James Kuszmaulb1e29372020-02-11 16:55:36 -080088 ASSERT_FLOAT_EQ(0.01, zeroer.ZeroedGyro().x());
89 ASSERT_FLOAT_EQ(0.01, zeroer.ZeroedGyro().y());
90 ASSERT_FLOAT_EQ(0.01, zeroer.ZeroedGyro().z());
91}
92
93// Tests that we do not zero if the gyro is producing particularly high
94// magnitude results.
95TEST(ImuZeroerTest, NoZeroOnHighMagnitudeGyro) {
96 ImuZeroer zeroer;
97 ASSERT_FALSE(zeroer.Zeroed());
98 for (size_t ii = 0; ii < kMinSamplesToZero; ++ii) {
James Kuszmaulb7f45bb2020-02-26 20:27:48 -080099 zeroer.InsertAndProcessMeasurement(
James Kuszmaulb1e29372020-02-11 16:55:36 -0800100 MakeMeasurement({0.1, 0.2, 0.3}, {4, 5, 6}).message());
101 ASSERT_FALSE(zeroer.Zeroed());
102 }
103 ASSERT_FALSE(zeroer.Faulted());
James Kuszmauld3f9eb22020-01-12 15:02:07 -0800104}
105
106// Tests that we tolerate small amounts of noise in the incoming data and can
107// still zero.
108TEST(ImuZeroerTest, ZeroOnLowNoiseData) {
109 ImuZeroer zeroer;
110 ASSERT_FALSE(zeroer.Zeroed());
James Kuszmaulb1e29372020-02-11 16:55:36 -0800111 for (size_t ii = 0; ii < kMinSamplesToZero; ++ii) {
James Kuszmauld3f9eb22020-01-12 15:02:07 -0800112 const double offset =
James Kuszmaulb1e29372020-02-11 16:55:36 -0800113 (static_cast<double>(ii) / (kMinSamplesToZero - 1) - 0.5) * 0.001;
James Kuszmaulb7f45bb2020-02-26 20:27:48 -0800114 zeroer.InsertAndProcessMeasurement(
James Kuszmaulb1e29372020-02-11 16:55:36 -0800115 MakeMeasurement({0.01 + offset, 0.02 + offset, 0.03 + offset},
James Kuszmaulb7f45bb2020-02-26 20:27:48 -0800116 {4 + offset, 5 + offset, 6 + offset}).message());
James Kuszmauld3f9eb22020-01-12 15:02:07 -0800117 }
118 ASSERT_TRUE(zeroer.Zeroed());
119 ASSERT_FALSE(zeroer.Faulted());
James Kuszmaulb1e29372020-02-11 16:55:36 -0800120 ASSERT_NEAR(0.01, zeroer.GyroOffset().x(), 1e-3);
121 ASSERT_NEAR(0.02, zeroer.GyroOffset().y(), 1e-3);
122 ASSERT_NEAR(0.03, zeroer.GyroOffset().z(), 1e-3);
123 // If we get another measurement offset by {0.01, 0.01, 0.01} we should read
124 // the result as {0.01, 0.01, 0.01}.
James Kuszmaulb7f45bb2020-02-26 20:27:48 -0800125 zeroer.InsertAndProcessMeasurement(
James Kuszmaulb1e29372020-02-11 16:55:36 -0800126 MakeMeasurement({0.02, 0.03, 0.04}, {0, 0, 0}).message());
James Kuszmauld3f9eb22020-01-12 15:02:07 -0800127 ASSERT_FALSE(zeroer.Faulted());
James Kuszmaulb1e29372020-02-11 16:55:36 -0800128 ASSERT_NEAR(0.01, zeroer.ZeroedGyro().x(), 1e-3);
129 ASSERT_NEAR(0.01, zeroer.ZeroedGyro().y(), 1e-3);
130 ASSERT_NEAR(0.01, zeroer.ZeroedGyro().z(), 1e-3);
James Kuszmauld3f9eb22020-01-12 15:02:07 -0800131 ASSERT_EQ(0.0, zeroer.ZeroedAccel().x());
132 ASSERT_EQ(0.0, zeroer.ZeroedAccel().y());
133 ASSERT_EQ(0.0, zeroer.ZeroedAccel().z());
134}
135
136// Tests that we do not zero if there is too much noise in the input data.
137TEST(ImuZeroerTest, NoZeroOnHighNoiseData) {
138 ImuZeroer zeroer;
139 ASSERT_FALSE(zeroer.Zeroed());
James Kuszmaulb1e29372020-02-11 16:55:36 -0800140 for (size_t ii = 0; ii < kMinSamplesToZero; ++ii) {
James Kuszmauld3f9eb22020-01-12 15:02:07 -0800141 ASSERT_FALSE(zeroer.Zeroed());
142 const double offset =
James Kuszmaulb1e29372020-02-11 16:55:36 -0800143 (static_cast<double>(ii) / (kMinSamplesToZero - 1) - 0.5) * 1.0;
James Kuszmaulb7f45bb2020-02-26 20:27:48 -0800144 zeroer.InsertAndProcessMeasurement(
James Kuszmaulb1e29372020-02-11 16:55:36 -0800145 MakeMeasurement({0.01 + offset, 0.02 + offset, 0.03 + offset},
James Kuszmaulb7f45bb2020-02-26 20:27:48 -0800146 {4 + offset, 5 + offset, 6 + offset}).message());
James Kuszmauld3f9eb22020-01-12 15:02:07 -0800147 }
148 ASSERT_FALSE(zeroer.Zeroed());
149 ASSERT_FALSE(zeroer.Faulted());
150}
151
152// Tests that we fault if we successfully rezero and get a significantly offset
153// zero.
154TEST(ImuZeroerTest, FaultOnNewZero) {
155 ImuZeroer zeroer;
156 ASSERT_FALSE(zeroer.Zeroed());
James Kuszmaulb1e29372020-02-11 16:55:36 -0800157 for (size_t ii = 0; ii < kMinSamplesToZero; ++ii) {
James Kuszmaulb7f45bb2020-02-26 20:27:48 -0800158 zeroer.InsertAndProcessMeasurement(
James Kuszmaulb1e29372020-02-11 16:55:36 -0800159 MakeMeasurement({0.01, 0.02, 0.03}, {4, 5, 6}).message());
James Kuszmauld3f9eb22020-01-12 15:02:07 -0800160 }
161 ASSERT_TRUE(zeroer.Zeroed());
James Kuszmaulb1e29372020-02-11 16:55:36 -0800162 ASSERT_FALSE(zeroer.Faulted())
163 << "We should not fault until we complete a second cycle of zeroing.";
164 for (size_t ii = 0; ii < kMinSamplesToZero; ++ii) {
James Kuszmaulb7f45bb2020-02-26 20:27:48 -0800165 zeroer.InsertAndProcessMeasurement(
James Kuszmaulad2f8db2021-10-24 17:02:57 -0700166 MakeMeasurement({0.01, -0.05, 0.03}, {4, 5, 6}).message());
James Kuszmauld3f9eb22020-01-12 15:02:07 -0800167 }
168 ASSERT_TRUE(zeroer.Faulted());
James Kuszmaulddc69702021-03-24 21:55:03 -0700169 ASSERT_FALSE(zeroer.Zeroed());
James Kuszmauld3f9eb22020-01-12 15:02:07 -0800170}
171
172// Tests that we do not fault if the zero only changes by a small amount.
173TEST(ImuZeroerTest, NoFaultOnSimilarZero) {
174 ImuZeroer zeroer;
175 ASSERT_FALSE(zeroer.Zeroed());
James Kuszmaulb1e29372020-02-11 16:55:36 -0800176 for (size_t ii = 0; ii < kMinSamplesToZero; ++ii) {
James Kuszmaulb7f45bb2020-02-26 20:27:48 -0800177 zeroer.InsertAndProcessMeasurement(
James Kuszmaulb1e29372020-02-11 16:55:36 -0800178 MakeMeasurement({0.01, 0.02, 0.03}, {4, 5, 6}).message());
James Kuszmauld3f9eb22020-01-12 15:02:07 -0800179 }
180 ASSERT_TRUE(zeroer.Zeroed());
James Kuszmaulb1e29372020-02-11 16:55:36 -0800181 for (size_t ii = 0; ii < kMinSamplesToZero; ++ii) {
James Kuszmaulb7f45bb2020-02-26 20:27:48 -0800182 zeroer.InsertAndProcessMeasurement(
James Kuszmaulb1e29372020-02-11 16:55:36 -0800183 MakeMeasurement({0.01, 0.020001, 0.03}, {4, 5, 6}).message());
James Kuszmauld3f9eb22020-01-12 15:02:07 -0800184 }
185 ASSERT_FALSE(zeroer.Faulted());
186}
187
James Kuszmaulddc69702021-03-24 21:55:03 -0700188// Tests that we fault on a bad diagnostic.
189TEST(ImuZeroerTest, FaultOnBadDiagnostic) {
190 ImuZeroer zeroer;
191 ASSERT_FALSE(zeroer.Zeroed());
192 ASSERT_FALSE(zeroer.Faulted());
193 zeroer.InsertAndProcessMeasurement(
194 MakeMeasurement({0.01, 0.02, 0.03}, {4, 5, 6}, true).message());
195 ASSERT_FALSE(zeroer.Zeroed());
196 ASSERT_TRUE(zeroer.Faulted());
197}
198
James Kuszmauld3f9eb22020-01-12 15:02:07 -0800199} // namespace frc971::zeroing