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