blob: b2b00ce843a243fe6ea3da9ce51aa363c6fd97b3 [file] [log] [blame]
Brian Silvermana57b7012020-03-11 20:19:23 -07001#include "frc971/zeroing/pot_and_index.h"
2
3#include "gtest/gtest.h"
4
5#include "frc971/zeroing/zeroing_test.h"
6
7namespace frc971 {
8namespace zeroing {
9namespace testing {
10
11using constants::PotAndIndexPulseZeroingConstants;
12
13class PotAndIndexZeroingTest : public ZeroingTest {
14 protected:
15 void MoveTo(PositionSensorSimulator *simulator,
16 PotAndIndexPulseZeroingEstimator *estimator,
17 double new_position) {
18 simulator->MoveTo(new_position);
19 FBB fbb;
20 estimator->UpdateEstimate(
21 *simulator->FillSensorValues<PotAndIndexPosition>(&fbb));
22 }
23};
24
25TEST_F(PotAndIndexZeroingTest, TestMovingAverageFilter) {
26 const double index_diff = 1.0;
27 PositionSensorSimulator sim(index_diff);
28 sim.Initialize(3.6 * index_diff, index_diff / 3.0);
29 PotAndIndexPulseZeroingEstimator estimator(PotAndIndexPulseZeroingConstants{
30 kSampleSize, index_diff, 0.0, kIndexErrorFraction});
31
32 // The zeroing code is supposed to perform some filtering on the difference
33 // between the potentiometer value and the encoder value. We assume that 300
34 // samples are sufficient to have updated the filter.
35 for (int i = 0; i < 300; i++) {
36 MoveTo(&sim, &estimator, 3.3 * index_diff);
37 }
38 ASSERT_NEAR(3.3 * index_diff, GetEstimatorPosition(&estimator),
39 kAcceptableUnzeroedError * index_diff);
40
41 for (int i = 0; i < 300; i++) {
42 MoveTo(&sim, &estimator, 3.9 * index_diff);
43 }
44 ASSERT_NEAR(3.9 * index_diff, GetEstimatorPosition(&estimator),
45 kAcceptableUnzeroedError * index_diff);
46}
47
48TEST_F(PotAndIndexZeroingTest, NotZeroedBeforeEnoughSamplesCollected) {
49 double index_diff = 0.5;
50 double position = 3.6 * index_diff;
51 PositionSensorSimulator sim(index_diff);
52 sim.Initialize(position, index_diff / 3.0);
53 PotAndIndexPulseZeroingEstimator estimator(PotAndIndexPulseZeroingConstants{
54 kSampleSize, index_diff, 0.0, kIndexErrorFraction});
55
56 // Make sure that the zeroing code does not consider itself zeroed until we
57 // collect a good amount of samples. In this case we're waiting until the
58 // moving average filter is full.
59 for (unsigned int i = 0; i < kSampleSize - 1; i++) {
60 MoveTo(&sim, &estimator, position += index_diff);
61 ASSERT_FALSE(estimator.zeroed());
62 }
63
64 MoveTo(&sim, &estimator, position);
65 ASSERT_TRUE(estimator.zeroed());
66}
67
68TEST_F(PotAndIndexZeroingTest, TestLotsOfMovement) {
69 double index_diff = 1.0;
70 PositionSensorSimulator sim(index_diff);
71 sim.Initialize(3.6, index_diff / 3.0);
72 PotAndIndexPulseZeroingEstimator estimator(PotAndIndexPulseZeroingConstants{
73 kSampleSize, index_diff, 0.0, kIndexErrorFraction});
74
75 // The zeroing code is supposed to perform some filtering on the difference
76 // between the potentiometer value and the encoder value. We assume that 300
77 // samples are sufficient to have updated the filter.
78 for (int i = 0; i < 300; i++) {
79 MoveTo(&sim, &estimator, 3.6);
80 }
81 ASSERT_NEAR(3.6, GetEstimatorPosition(&estimator),
82 kAcceptableUnzeroedError * index_diff);
83
84 // With a single index pulse the zeroing estimator should be able to lock
85 // onto the true value of the position.
86 MoveTo(&sim, &estimator, 4.01);
87 ASSERT_NEAR(4.01, GetEstimatorPosition(&estimator), 0.001);
88
89 MoveTo(&sim, &estimator, 4.99);
90 ASSERT_NEAR(4.99, GetEstimatorPosition(&estimator), 0.001);
91
92 MoveTo(&sim, &estimator, 3.99);
93 ASSERT_NEAR(3.99, GetEstimatorPosition(&estimator), 0.001);
94
95 MoveTo(&sim, &estimator, 3.01);
96 ASSERT_NEAR(3.01, GetEstimatorPosition(&estimator), 0.001);
97
98 MoveTo(&sim, &estimator, 13.55);
99 ASSERT_NEAR(13.55, GetEstimatorPosition(&estimator), 0.001);
100}
101
102TEST_F(PotAndIndexZeroingTest, TestDifferentIndexDiffs) {
103 double index_diff = 0.89;
104 PositionSensorSimulator sim(index_diff);
105 sim.Initialize(3.5 * index_diff, index_diff / 3.0);
106 PotAndIndexPulseZeroingEstimator estimator(PotAndIndexPulseZeroingConstants{
107 kSampleSize, index_diff, 0.0, kIndexErrorFraction});
108
109 // The zeroing code is supposed to perform some filtering on the difference
110 // between the potentiometer value and the encoder value. We assume that 300
111 // samples are sufficient to have updated the filter.
112 for (int i = 0; i < 300; i++) {
113 MoveTo(&sim, &estimator, 3.5 * index_diff);
114 }
115 ASSERT_NEAR(3.5 * index_diff, GetEstimatorPosition(&estimator),
116 kAcceptableUnzeroedError * index_diff);
117
118 // With a single index pulse the zeroing estimator should be able to lock
119 // onto the true value of the position.
120 MoveTo(&sim, &estimator, 4.01);
121 ASSERT_NEAR(4.01, GetEstimatorPosition(&estimator), 0.001);
122
123 MoveTo(&sim, &estimator, 4.99);
124 ASSERT_NEAR(4.99, GetEstimatorPosition(&estimator), 0.001);
125
126 MoveTo(&sim, &estimator, 3.99);
127 ASSERT_NEAR(3.99, GetEstimatorPosition(&estimator), 0.001);
128
129 MoveTo(&sim, &estimator, 3.01);
130 ASSERT_NEAR(3.01, GetEstimatorPosition(&estimator), 0.001);
131
132 MoveTo(&sim, &estimator, 13.55);
133 ASSERT_NEAR(13.55, GetEstimatorPosition(&estimator), 0.001);
134}
135
136TEST_F(PotAndIndexZeroingTest, TestPercentage) {
137 double index_diff = 0.89;
138 PositionSensorSimulator sim(index_diff);
139 sim.Initialize(3.5 * index_diff, index_diff / 3.0);
140 PotAndIndexPulseZeroingEstimator estimator(PotAndIndexPulseZeroingConstants{
141 kSampleSize, index_diff, 0.0, kIndexErrorFraction});
142
143 for (unsigned int i = 0; i < kSampleSize / 2; i++) {
144 MoveTo(&sim, &estimator, 3.5 * index_diff);
145 }
146 ASSERT_NEAR(0.5, estimator.offset_ratio_ready(), 0.001);
147 ASSERT_FALSE(estimator.offset_ready());
148
149 for (unsigned int i = 0; i < kSampleSize / 2; i++) {
150 MoveTo(&sim, &estimator, 3.5 * index_diff);
151 }
152 ASSERT_NEAR(1.0, estimator.offset_ratio_ready(), 0.001);
153 ASSERT_TRUE(estimator.offset_ready());
154}
155
156TEST_F(PotAndIndexZeroingTest, TestOffset) {
157 double index_diff = 0.89;
158 PositionSensorSimulator sim(index_diff);
159 sim.Initialize(3.1 * index_diff, index_diff / 3.0);
160 PotAndIndexPulseZeroingEstimator estimator(PotAndIndexPulseZeroingConstants{
161 kSampleSize, index_diff, 0.0, kIndexErrorFraction});
162
163 MoveTo(&sim, &estimator, 3.1 * index_diff);
164
165 for (unsigned int i = 0; i < kSampleSize; i++) {
166 MoveTo(&sim, &estimator, 5.0 * index_diff);
167 }
168
169 ASSERT_NEAR(3.1 * index_diff, estimator.offset(), 0.001);
170}
171
172TEST_F(PotAndIndexZeroingTest, WaitForIndexPulseAfterReset) {
173 double index_diff = 0.6;
174 PositionSensorSimulator sim(index_diff);
175 sim.Initialize(3.1 * index_diff, index_diff / 3.0);
176 PotAndIndexPulseZeroingEstimator estimator(PotAndIndexPulseZeroingConstants{
177 kSampleSize, index_diff, 0.0, kIndexErrorFraction});
178
179 // Make sure to fill up the averaging filter with samples.
180 for (unsigned int i = 0; i < kSampleSize; i++) {
181 MoveTo(&sim, &estimator, 3.1 * index_diff);
182 }
183
184 // Make sure we're not zeroed until we hit an index pulse.
185 ASSERT_FALSE(estimator.zeroed());
186
187 // Trigger an index pulse; we should now be zeroed.
188 MoveTo(&sim, &estimator, 4.5 * index_diff);
189 ASSERT_TRUE(estimator.zeroed());
190
191 // Reset the zeroing logic and supply a bunch of samples within the current
192 // index segment.
193 estimator.Reset();
194 for (unsigned int i = 0; i < kSampleSize; i++) {
195 MoveTo(&sim, &estimator, 4.2 * index_diff);
196 }
197
198 // Make sure we're not zeroed until we hit an index pulse.
199 ASSERT_FALSE(estimator.zeroed());
200
201 // Trigger another index pulse; we should be zeroed again.
202 MoveTo(&sim, &estimator, 3.1 * index_diff);
203 ASSERT_TRUE(estimator.zeroed());
204}
205
206TEST_F(PotAndIndexZeroingTest, TestNonZeroIndexPulseOffsets) {
207 const double index_diff = 0.9;
208 const double known_index_pos = 3.5 * index_diff;
209 PositionSensorSimulator sim(index_diff);
210 sim.Initialize(3.3 * index_diff, index_diff / 3.0, known_index_pos);
211 PotAndIndexPulseZeroingEstimator estimator(PotAndIndexPulseZeroingConstants{
212 kSampleSize, index_diff, known_index_pos, kIndexErrorFraction});
213
214 // Make sure to fill up the averaging filter with samples.
215 for (unsigned int i = 0; i < kSampleSize; i++) {
216 MoveTo(&sim, &estimator, 3.3 * index_diff);
217 }
218
219 // Make sure we're not zeroed until we hit an index pulse.
220 ASSERT_FALSE(estimator.zeroed());
221
222 // Trigger an index pulse; we should now be zeroed.
223 MoveTo(&sim, &estimator, 3.7 * index_diff);
224 ASSERT_TRUE(estimator.zeroed());
225 ASSERT_DOUBLE_EQ(3.3 * index_diff, estimator.offset());
226 ASSERT_DOUBLE_EQ(3.7 * index_diff, GetEstimatorPosition(&estimator));
227
228 // Trigger one more index pulse and check the offset.
229 MoveTo(&sim, &estimator, 4.7 * index_diff);
230 ASSERT_DOUBLE_EQ(3.3 * index_diff, estimator.offset());
231 ASSERT_DOUBLE_EQ(4.7 * index_diff, GetEstimatorPosition(&estimator));
232}
233
234TEST_F(PotAndIndexZeroingTest, BasicErrorAPITest) {
235 const double index_diff = 1.0;
236 PotAndIndexPulseZeroingEstimator estimator(PotAndIndexPulseZeroingConstants{
237 kSampleSize, index_diff, 0.0, kIndexErrorFraction});
238 PositionSensorSimulator sim(index_diff);
239 sim.Initialize(1.5 * index_diff, index_diff / 3.0, 0.0);
240
241 // Perform a simple move and make sure that no error occured.
242 MoveTo(&sim, &estimator, 3.5 * index_diff);
243 ASSERT_FALSE(estimator.error());
244
245 // Trigger an error and make sure it's reported.
246 estimator.TriggerError();
247 ASSERT_TRUE(estimator.error());
248
249 // Make sure that it can recover after a reset.
250 estimator.Reset();
251 ASSERT_FALSE(estimator.error());
252 MoveTo(&sim, &estimator, 4.5 * index_diff);
253 MoveTo(&sim, &estimator, 5.5 * index_diff);
254 ASSERT_FALSE(estimator.error());
255}
256
257// Tests that an error is detected when the starting position changes too much.
258TEST_F(PotAndIndexZeroingTest, TestIndexOffsetError) {
259 const double index_diff = 0.8;
260 const double known_index_pos = 2 * index_diff;
261 const size_t sample_size = 30;
262 PositionSensorSimulator sim(index_diff);
263 sim.Initialize(10 * index_diff, index_diff / 3.0, known_index_pos);
264 PotAndIndexPulseZeroingEstimator estimator(PotAndIndexPulseZeroingConstants{
265 sample_size, index_diff, known_index_pos, kIndexErrorFraction});
266
267 for (size_t i = 0; i < sample_size; i++) {
268 MoveTo(&sim, &estimator, 13 * index_diff);
269 }
270 MoveTo(&sim, &estimator, 8 * index_diff);
271
272 ASSERT_TRUE(estimator.zeroed());
273 ASSERT_FALSE(estimator.error());
274 sim.Initialize(9.0 * index_diff + 0.31 * index_diff, index_diff / 3.0,
275 known_index_pos);
276 MoveTo(&sim, &estimator, 9 * index_diff);
277 ASSERT_TRUE(estimator.zeroed());
278 ASSERT_TRUE(estimator.error());
279}
280
281} // namespace testing
282} // namespace zeroing
283} // namespace frc971