blob: 1c6bb77359bb8f671e7d86ad418d73b64fcab2bd [file] [log] [blame]
Adam Snaiderc4b3c192015-02-01 01:30:39 +00001#ifndef FRC971_ZEROING_ZEROING_H_
2#define FRC971_ZEROING_ZEROING_H_
3
Austin Schuh66c59ba2019-01-26 20:34:35 -08004#include <algorithm>
5#include <cmath>
Philipp Schrader41d82912015-02-15 03:44:23 +00006#include <cstdint>
Adam Snaiderc4b3c192015-02-01 01:30:39 +00007#include <vector>
Philipp Schrader41d82912015-02-15 03:44:23 +00008
Alex Perrycb7da4b2019-08-28 19:35:56 -07009#include "frc971/control_loops/control_loops_generated.h"
Austin Schuh703b8d42015-02-01 14:56:34 -080010#include "frc971/constants.h"
Adam Snaiderc4b3c192015-02-01 01:30:39 +000011
Alex Perrycb7da4b2019-08-28 19:35:56 -070012#include "flatbuffers/flatbuffers.h"
13
Adam Snaiderb4119252015-02-15 01:30:57 +000014// TODO(pschrader): Flag an error if encoder index pulse is not n revolutions
15// away from the last one (i.e. got extra counts from noise, etc..)
16//
17// TODO(pschrader): Flag error if the pot disagrees too much with the encoder
18// after being zeroed.
19//
20// TODO(pschrader): Watch the offset over long periods of time and flag if it
21// gets too far away from the initial value.
22
Adam Snaiderc4b3c192015-02-01 01:30:39 +000023namespace frc971 {
24namespace zeroing {
25
Lee Mracekcdd19ee2019-01-07 10:19:54 -050026template <typename TPosition, typename TZeroingConstants, typename TState>
Neil Balch1049be92017-02-15 23:20:49 -080027class ZeroingEstimator {
28 public:
Lee Mracekcdd19ee2019-01-07 10:19:54 -050029 using Position = TPosition;
30 using ZeroingConstants = TZeroingConstants;
31 using State = TState;
Neil Balch1049be92017-02-15 23:20:49 -080032 virtual ~ZeroingEstimator(){}
33
34 // Returns true if the logic considers the corresponding mechanism to be
Isaac Wilcove0851ffd2017-02-16 04:13:14 +000035 // zeroed.
Neil Balch1049be92017-02-15 23:20:49 -080036 virtual bool zeroed() const = 0;
37
Isaac Wilcove0851ffd2017-02-16 04:13:14 +000038 // Returns the estimated position of the corresponding mechanism.
Neil Balch1049be92017-02-15 23:20:49 -080039 virtual double offset() const = 0;
40
Isaac Wilcove0851ffd2017-02-16 04:13:14 +000041 // Returns true if there has been an error.
Neil Balch1049be92017-02-15 23:20:49 -080042 virtual bool error() const = 0;
Lee Mracekcdd19ee2019-01-07 10:19:54 -050043
44 // Returns true if an offset is ready.
45 virtual bool offset_ready() const = 0;
46
47 // Triggers an internal error. This is used for testing the error
48 // logic.
49 virtual void TriggerError() = 0;
50
51 // Resets the estimator, clearing error and zeroing states.
52 virtual void Reset() = 0;
53
54 // Updates the internal logic with new sensor values
55 virtual void UpdateEstimate(const Position &) = 0;
56
57 // Returns the state of the estimator
Alex Perrycb7da4b2019-08-28 19:35:56 -070058 virtual flatbuffers::Offset<State> GetEstimatorState(
59 flatbuffers::FlatBufferBuilder *fbb) const = 0;
Neil Balch1049be92017-02-15 23:20:49 -080060};
61
Brian Silvermanab0b6772017-02-05 16:16:21 -080062// Estimates the position with an incremental encoder with an index pulse and a
63// potentiometer.
Lee Mracekcdd19ee2019-01-07 10:19:54 -050064class PotAndIndexPulseZeroingEstimator : public ZeroingEstimator<PotAndIndexPosition,
65 constants::PotAndIndexPulseZeroingConstants,
66 EstimatorState> {
Adam Snaiderc4b3c192015-02-01 01:30:39 +000067 public:
Campbell Crowley36e93e92017-12-23 14:21:43 -080068 explicit PotAndIndexPulseZeroingEstimator(
Tyler Chatowf8f03112017-02-05 14:31:34 -080069 const constants::PotAndIndexPulseZeroingConstants &constants);
Austin Schuh703b8d42015-02-01 14:56:34 -080070
Adam Snaiderb4119252015-02-15 01:30:57 +000071 // Update the internal logic with the next sensor values.
Lee Mracekcdd19ee2019-01-07 10:19:54 -050072 void UpdateEstimate(const PotAndIndexPosition &info) override;
Adam Snaiderb4119252015-02-15 01:30:57 +000073
74 // Reset the internal logic so it needs to be re-zeroed.
Lee Mracekcdd19ee2019-01-07 10:19:54 -050075 void Reset() override;
Adam Snaiderb4119252015-02-15 01:30:57 +000076
Philipp Schrader53f4b6d2015-02-15 22:32:08 +000077 // Manually trigger an internal error. This is used for testing the error
78 // logic.
Lee Mracekcdd19ee2019-01-07 10:19:54 -050079 void TriggerError() override;
Philipp Schrader53f4b6d2015-02-15 22:32:08 +000080
Neil Balch1049be92017-02-15 23:20:49 -080081 bool error() const override { return error_; }
Philipp Schrader53f4b6d2015-02-15 22:32:08 +000082
Neil Balch1049be92017-02-15 23:20:49 -080083 bool zeroed() const override { return zeroed_; }
Adam Snaiderb4119252015-02-15 01:30:57 +000084
Isaac Wilcove0851ffd2017-02-16 04:13:14 +000085 double offset() const override { return offset_; }
Adam Snaiderb4119252015-02-15 01:30:57 +000086
87 // Returns a number between 0 and 1 that represents the percentage of the
88 // samples being used in the moving average filter. A value of 0.0 means that
89 // no samples are being used. A value of 1.0 means that the filter is using
90 // as many samples as it has room for. For example, after a Reset() this
91 // value returns 0.0. As more samples get added with UpdateEstimate(...) the
92 // return value starts increasing to 1.0.
Austin Schuh703b8d42015-02-01 14:56:34 -080093 double offset_ratio_ready() const {
Austin Schuh5f01f152017-02-11 21:34:08 -080094 return start_pos_samples_.size() /
95 static_cast<double>(constants_.average_filter_size);
Austin Schuh703b8d42015-02-01 14:56:34 -080096 }
97
Austin Schuh7485dbb2016-02-08 00:21:58 -080098 // Returns true if the sample buffer is full.
Lee Mracekcdd19ee2019-01-07 10:19:54 -050099 bool offset_ready() const override {
Austin Schuh5f01f152017-02-11 21:34:08 -0800100 return start_pos_samples_.size() == constants_.average_filter_size;
Austin Schuh7485dbb2016-02-08 00:21:58 -0800101 }
102
Brian Silverman4f2e2ce2017-02-19 17:49:47 -0800103 // Returns information about our current state.
Alex Perrycb7da4b2019-08-28 19:35:56 -0700104 virtual flatbuffers::Offset<State> GetEstimatorState(
105 flatbuffers::FlatBufferBuilder *fbb) const override;
Brian Silverman4f2e2ce2017-02-19 17:49:47 -0800106
Adam Snaiderc4b3c192015-02-01 01:30:39 +0000107 private:
Philipp Schradere828be72015-02-15 07:07:37 +0000108 // This function calculates the start position given the internal state and
109 // the provided `latched_encoder' value.
110 double CalculateStartPosition(double start_average,
111 double latched_encoder) const;
112
Austin Schuh5f01f152017-02-11 21:34:08 -0800113 // The zeroing constants used to describe the configuration of the system.
114 const constants::PotAndIndexPulseZeroingConstants constants_;
115
Adam Snaiderb4119252015-02-15 01:30:57 +0000116 // The estimated position.
Austin Schuh5f01f152017-02-11 21:34:08 -0800117 double position_;
Austin Schuhbe133ed2016-03-11 21:23:34 -0800118 // The unzeroed filtered position.
119 double filtered_position_ = 0.0;
Adam Snaiderb4119252015-02-15 01:30:57 +0000120 // The next position in 'start_pos_samples_' to be used to store the next
121 // sample.
Adam Snaiderc4b3c192015-02-01 01:30:39 +0000122 int samples_idx_;
123 // Last 'max_sample_count_' samples for start positions.
124 std::vector<double> start_pos_samples_;
Adam Snaiderb4119252015-02-15 01:30:57 +0000125 // The estimated starting position of the mechanism. We also call this the
126 // 'offset' in some contexts.
Isaac Wilcove0851ffd2017-02-16 04:13:14 +0000127 double offset_;
Philipp Schrader41d82912015-02-15 03:44:23 +0000128 // Flag for triggering logic that takes note of the current index pulse count
Philipp Schradere828be72015-02-15 07:07:37 +0000129 // after a reset. See `last_used_index_pulse_count_'.
Philipp Schrader41d82912015-02-15 03:44:23 +0000130 bool wait_for_index_pulse_;
131 // After a reset we keep track of the index pulse count with this. Only after
132 // the index pulse count changes (i.e. increments at least once or wraps
Philipp Schradere828be72015-02-15 07:07:37 +0000133 // around) will we consider the mechanism zeroed. We also use this to store
134 // the most recent `PotAndIndexPosition::index_pulses' value when the start
135 // position was calculated. It helps us calculate the start position only on
136 // index pulses to reject corrupted intermediate data.
137 uint32_t last_used_index_pulse_count_;
Adam Snaiderb4119252015-02-15 01:30:57 +0000138 // Marker to track whether we're fully zeroed yet or not.
139 bool zeroed_;
Philipp Schrader53f4b6d2015-02-15 22:32:08 +0000140 // Marker to track whether an error has occurred. This gets reset to false
141 // whenever Reset() is called.
142 bool error_;
Adam Snaider3cd11c52015-02-16 02:16:09 +0000143 // Stores the position "start_pos" variable the first time the program
144 // is zeroed.
145 double first_start_pos_;
Austin Schuh5f01f152017-02-11 21:34:08 -0800146};
147
Campbell Crowley36e93e92017-12-23 14:21:43 -0800148// Estimates the position with an incremental encoder and a hall effect sensor.
Lee Mracekcdd19ee2019-01-07 10:19:54 -0500149class HallEffectAndPositionZeroingEstimator
150 : public ZeroingEstimator<HallEffectAndPosition,
151 constants::HallEffectZeroingConstants,
152 HallEffectAndPositionEstimatorState> {
Austin Schuh55934032017-03-11 12:45:27 -0800153 public:
Austin Schuh55934032017-03-11 12:45:27 -0800154 explicit HallEffectAndPositionZeroingEstimator(const ZeroingConstants &constants);
155
156 // Update the internal logic with the next sensor values.
Lee Mracekcdd19ee2019-01-07 10:19:54 -0500157 void UpdateEstimate(const Position &info) override;
Austin Schuh55934032017-03-11 12:45:27 -0800158
159 // Reset the internal logic so it needs to be re-zeroed.
Lee Mracekcdd19ee2019-01-07 10:19:54 -0500160 void Reset() override;
Austin Schuh55934032017-03-11 12:45:27 -0800161
162 // Manually trigger an internal error. This is used for testing the error
163 // logic.
Lee Mracekcdd19ee2019-01-07 10:19:54 -0500164 void TriggerError() override;
Austin Schuh55934032017-03-11 12:45:27 -0800165
166 bool error() const override { return error_; }
167
168 bool zeroed() const override { return zeroed_; }
169
170 double offset() const override { return offset_; }
171
Lee Mracekcdd19ee2019-01-07 10:19:54 -0500172 bool offset_ready() const override { return zeroed_; }
173
Austin Schuh55934032017-03-11 12:45:27 -0800174 // Returns information about our current state.
Alex Perrycb7da4b2019-08-28 19:35:56 -0700175 virtual flatbuffers::Offset<State> GetEstimatorState(
176 flatbuffers::FlatBufferBuilder *fbb) const override;
Austin Schuh55934032017-03-11 12:45:27 -0800177
178 private:
179 // Sets the minimum and maximum posedge position values.
180 void StoreEncoderMaxAndMin(const HallEffectAndPosition &info);
181
182 // The zeroing constants used to describe the configuration of the system.
183 const ZeroingConstants constants_;
184
185 // The estimated state of the hall effect.
186 double current_ = 0.0;
187 // The estimated position.
188 double position_ = 0.0;
189 // The smallest and largest positions of the last set of encoder positions
190 // while the hall effect was low.
191 double min_low_position_;
192 double max_low_position_;
193 // If we've seen the hall effect high for enough times without going low, then
194 // we can be sure it isn't a false positive.
195 bool high_long_enough_;
196 size_t cycles_high_;
197
198 bool last_hall_ = false;
199
200 // The estimated starting position of the mechanism. We also call this the
201 // 'offset' in some contexts.
202 double offset_;
203 // Flag for triggering logic that takes note of the current posedge count
204 // after a reset. See `last_used_posedge_count_'.
205 bool initialized_;
206 // After a reset we keep track of the posedge count with this. Only after the
207 // posedge count changes (i.e. increments at least once or wraps around) will
208 // we consider the mechanism zeroed. We also use this to store the most recent
209 // `HallEffectAndPosition::posedge_count' value when the start position
210 // was calculated. It helps us calculate the start position only on posedges
211 // to reject corrupted intermediate data.
212 int32_t last_used_posedge_count_;
213 // Marker to track whether we're fully zeroed yet or not.
214 bool zeroed_;
215 // Marker to track whether an error has occurred. This gets reset to false
216 // whenever Reset() is called.
217 bool error_ = false;
218 // Stores the position "start_pos" variable the first time the program
219 // is zeroed.
220 double first_start_pos_;
221};
222
Austin Schuh66c59ba2019-01-26 20:34:35 -0800223// Class to encapsulate the logic to decide when we are moving and which samples
224// are safe to use.
Alex Perrycb7da4b2019-08-28 19:35:56 -0700225template <typename Position, typename PositionBuffer>
Austin Schuh66c59ba2019-01-26 20:34:35 -0800226class MoveDetector {
227 public:
228 MoveDetector(size_t filter_size) {
229 buffered_samples_.reserve(filter_size);
230 Reset();
231 }
232
233 // Clears all the state.
234 void Reset() {
235 buffered_samples_.clear();
236 buffered_samples_idx_ = 0;
237 }
238
239 // Updates the detector with a new sample. Returns true if we are moving.
240 // buffer_size is the number of samples in the moving buffer, and
241 // zeroing_threshold is the max amount we can move within the period specified
242 // by buffer_size.
Alex Perrycb7da4b2019-08-28 19:35:56 -0700243 bool Update(const PositionBuffer &position_buffer, size_t buffer_size,
Austin Schuh66c59ba2019-01-26 20:34:35 -0800244 double zeroing_threshold) {
245 bool moving = true;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700246 Position position(position_buffer);
Austin Schuh66c59ba2019-01-26 20:34:35 -0800247 if (buffered_samples_.size() < buffer_size) {
248 // Not enough samples to start determining if the robot is moving or not,
249 // don't use the samples yet.
250 buffered_samples_.push_back(position);
251 } else {
252 // Have enough samples to start determining if the robot is moving or not.
253 buffered_samples_[buffered_samples_idx_] = position;
254 const auto minmax_value = ::std::minmax_element(
255 buffered_samples_.begin(), buffered_samples_.end(),
256 [](const Position &left, const Position &right) {
257 return left.encoder < right.encoder;
258 });
259 const double min_value = minmax_value.first->encoder;
260 const double max_value = minmax_value.second->encoder;
261
262 if (::std::abs(max_value - min_value) < zeroing_threshold) {
263 // Robot isn't moving, use middle sample to determine offsets.
264 moving = false;
265 }
266 }
267 buffered_samples_idx_ = (buffered_samples_idx_ + 1) % buffer_size;
268 return moving;
269 }
270
271 // Returns a safe sample if we aren't moving as reported by Update.
272 const Position &GetSample() const {
273 // The robot is not moving, use the middle sample to determine offsets.
274 // The middle sample makes it so that we don't use the samples from the
275 // beginning or end of periods when the robot is moving.
276 const int middle_index =
277 (buffered_samples_idx_ + (buffered_samples_.size() / 2)) %
278 buffered_samples_.size();
279 return buffered_samples_[middle_index];
280 }
281
282 private:
283 // The last buffer_size samples.
284 ::std::vector<Position> buffered_samples_;
285 // The index to place the next sample in.
286 size_t buffered_samples_idx_;
287};
288
Austin Schuh5f01f152017-02-11 21:34:08 -0800289// Estimates the position with an absolute encoder which also reports
290// incremental counts, and a potentiometer.
Austin Schuh72db9a12019-01-21 18:02:51 -0800291class PotAndAbsoluteEncoderZeroingEstimator
Lee Mracekcdd19ee2019-01-07 10:19:54 -0500292 : public ZeroingEstimator<PotAndAbsolutePosition,
Austin Schuh72db9a12019-01-21 18:02:51 -0800293 constants::PotAndAbsoluteEncoderZeroingConstants,
294 PotAndAbsoluteEncoderEstimatorState> {
Austin Schuh5f01f152017-02-11 21:34:08 -0800295 public:
Austin Schuh72db9a12019-01-21 18:02:51 -0800296 explicit PotAndAbsoluteEncoderZeroingEstimator(
Austin Schuh5f01f152017-02-11 21:34:08 -0800297 const constants::PotAndAbsoluteEncoderZeroingConstants &constants);
298
299 // Resets the internal logic so it needs to be re-zeroed.
Lee Mracekcdd19ee2019-01-07 10:19:54 -0500300 void Reset() override;
Austin Schuh5f01f152017-02-11 21:34:08 -0800301
302 // Updates the sensor values for the zeroing logic.
Lee Mracekcdd19ee2019-01-07 10:19:54 -0500303 void UpdateEstimate(const PotAndAbsolutePosition &info) override;
304
305 void TriggerError() override { error_ = true; }
Austin Schuh5f01f152017-02-11 21:34:08 -0800306
Neil Balch1049be92017-02-15 23:20:49 -0800307 bool zeroed() const override { return zeroed_; }
Austin Schuh5f01f152017-02-11 21:34:08 -0800308
Neil Balch1049be92017-02-15 23:20:49 -0800309 double offset() const override { return offset_; }
Austin Schuh5f01f152017-02-11 21:34:08 -0800310
Neil Balch16275e32017-02-18 16:38:45 -0800311 bool error() const override { return error_; }
Austin Schuh5f01f152017-02-11 21:34:08 -0800312
313 // Returns true if the sample buffer is full.
Lee Mracekcdd19ee2019-01-07 10:19:54 -0500314 bool offset_ready() const override {
Austin Schuh5f01f152017-02-11 21:34:08 -0800315 return relative_to_absolute_offset_samples_.size() ==
316 constants_.average_filter_size &&
317 offset_samples_.size() == constants_.average_filter_size;
318 }
319
Brian Silverman4f2e2ce2017-02-19 17:49:47 -0800320 // Returns information about our current state.
Alex Perrycb7da4b2019-08-28 19:35:56 -0700321 virtual flatbuffers::Offset<State> GetEstimatorState(
322 flatbuffers::FlatBufferBuilder *fbb) const override;
Austin Schuh5f01f152017-02-11 21:34:08 -0800323
324 private:
Alex Perrycb7da4b2019-08-28 19:35:56 -0700325 struct PositionStruct {
326 PositionStruct(const PotAndAbsolutePosition &position_buffer)
327 : absolute_encoder(position_buffer.absolute_encoder()),
328 encoder(position_buffer.encoder()),
329 pot(position_buffer.pot()) {}
330 double absolute_encoder;
331 double encoder;
332 double pot;
333 };
334
Austin Schuh5f01f152017-02-11 21:34:08 -0800335 // The zeroing constants used to describe the configuration of the system.
336 const constants::PotAndAbsoluteEncoderZeroingConstants constants_;
Brian Silvermana10d20a2017-02-19 14:28:53 -0800337
Austin Schuh5f01f152017-02-11 21:34:08 -0800338 // True if the mechanism is zeroed.
339 bool zeroed_;
Brian Silvermana10d20a2017-02-19 14:28:53 -0800340 // Marker to track whether an error has occurred.
341 bool error_;
342 // The first valid offset we recorded. This is only set after zeroed_ first
343 // changes to true.
344 double first_offset_;
345
Austin Schuh0e1c2c62017-02-21 02:03:25 -0800346 // The filtered absolute encoder. This is used in the status for calibration.
347 double filtered_absolute_encoder_ = 0.0;
348
Austin Schuh5f01f152017-02-11 21:34:08 -0800349 // Samples of the offset needed to line the relative encoder up with the
350 // absolute encoder.
351 ::std::vector<double> relative_to_absolute_offset_samples_;
352 // Offset between the Pot and Relative encoder position.
353 ::std::vector<double> offset_samples_;
Austin Schuh66c59ba2019-01-26 20:34:35 -0800354
Alex Perrycb7da4b2019-08-28 19:35:56 -0700355 MoveDetector<PositionStruct, PotAndAbsolutePosition> move_detector_;
Austin Schuh66c59ba2019-01-26 20:34:35 -0800356
Diana Vandenberg8fea6ea2017-02-18 17:24:45 -0800357 // Estimated offset between the pot and relative encoder.
358 double pot_relative_encoder_offset_ = 0;
Austin Schuh5f01f152017-02-11 21:34:08 -0800359 // Estimated start position of the mechanism
Diana Vandenberg8fea6ea2017-02-18 17:24:45 -0800360 double offset_ = 0;
Austin Schuh5f01f152017-02-11 21:34:08 -0800361 // The next position in 'relative_to_absolute_offset_samples_' and
362 // 'encoder_samples_' to be used to store the next sample.
Austin Schuhddd08f82018-03-02 20:05:29 -0800363 int samples_idx_ = 0;
364
365 size_t nan_samples_ = 0;
Brian Silvermana10d20a2017-02-19 14:28:53 -0800366
Austin Schuh5f01f152017-02-11 21:34:08 -0800367 // The unzeroed filtered position.
368 double filtered_position_ = 0.0;
369 // The filtered position.
370 double position_ = 0.0;
Adam Snaiderc4b3c192015-02-01 01:30:39 +0000371};
372
Isaac Wilcove0851ffd2017-02-16 04:13:14 +0000373// Zeros by seeing all the index pulses in the range of motion of the mechanism
374// and using that to figure out which index pulse is which.
Lee Mracekcdd19ee2019-01-07 10:19:54 -0500375class PulseIndexZeroingEstimator : public ZeroingEstimator<IndexPosition,
376 constants::EncoderPlusIndexZeroingConstants,
377 IndexEstimatorState> {
Isaac Wilcove0851ffd2017-02-16 04:13:14 +0000378 public:
Campbell Crowley36e93e92017-12-23 14:21:43 -0800379 explicit PulseIndexZeroingEstimator(const ZeroingConstants &constants)
Isaac Wilcove0851ffd2017-02-16 04:13:14 +0000380 : constants_(constants) {
381 Reset();
382 }
383
384 // Resets the internal logic so it needs to be re-zeroed.
Lee Mracekcdd19ee2019-01-07 10:19:54 -0500385 void Reset() override;
Isaac Wilcove0851ffd2017-02-16 04:13:14 +0000386
387 bool zeroed() const override { return zeroed_; }
388
Austin Schuh6a90cd92017-02-19 20:55:33 -0800389 // It's as ready as it'll ever be...
Lee Mracekcdd19ee2019-01-07 10:19:54 -0500390 bool offset_ready() const override { return true; }
Austin Schuh6a90cd92017-02-19 20:55:33 -0800391
Isaac Wilcove0851ffd2017-02-16 04:13:14 +0000392 double offset() const override { return offset_; }
393
394 bool error() const override { return error_; }
395
396 // Updates the internal logic with the next sensor values.
Lee Mracekcdd19ee2019-01-07 10:19:54 -0500397 void UpdateEstimate(const IndexPosition &info) override;
Isaac Wilcove0851ffd2017-02-16 04:13:14 +0000398
Brian Silvermanf37839c2017-02-19 18:07:15 -0800399 // Returns information about our current state.
Alex Perrycb7da4b2019-08-28 19:35:56 -0700400 virtual flatbuffers::Offset<State> GetEstimatorState(
401 flatbuffers::FlatBufferBuilder *fbb) const override;
Brian Silvermanf37839c2017-02-19 18:07:15 -0800402
Lee Mracekcdd19ee2019-01-07 10:19:54 -0500403 void TriggerError() override { error_ = true; }
Austin Schuhd93160a2017-03-05 01:00:54 -0800404
Isaac Wilcove0851ffd2017-02-16 04:13:14 +0000405 private:
406 // Returns the current real position using the relative encoder offset.
407 double CalculateCurrentPosition(const IndexPosition &info);
408
409 // Sets the minimum and maximum index pulse position values.
410 void StoreIndexPulseMaxAndMin(const IndexPosition &info);
411
412 // Returns the number of index pulses we should have seen so far.
Brian Silvermanf37839c2017-02-19 18:07:15 -0800413 int IndexPulseCount() const;
Isaac Wilcove0851ffd2017-02-16 04:13:14 +0000414
415 // Contains the physical constants describing the system.
Philipp Schrader3f5b6182017-03-25 22:36:37 +0000416 const ZeroingConstants constants_;
Isaac Wilcove0851ffd2017-02-16 04:13:14 +0000417
418 // The smallest position of all the index pulses.
419 double min_index_position_;
420 // The largest position of all the index pulses.
421 double max_index_position_;
422
423 // The estimated starting position of the mechanism.
424 double offset_;
425 // After a reset we keep track of the index pulse count with this. Only after
426 // the index pulse count changes (i.e. increments at least once or wraps
427 // around) will we consider the mechanism zeroed. We also use this to store
428 // the most recent `PotAndIndexPosition::index_pulses' value when the start
429 // position was calculated. It helps us calculate the start position only on
430 // index pulses to reject corrupted intermediate data.
431 uint32_t last_used_index_pulse_count_;
432
433 // True if we are fully zeroed.
434 bool zeroed_;
435 // Marker to track whether an error has occurred.
436 bool error_;
437
438 // The estimated position.
439 double position_;
440};
441
Austin Schuhd82068e2019-01-26 20:05:42 -0800442// Estimates the position with an absolute encoder which also reports
443// incremental counts. The absolute encoder can't spin more than one
444// revolution.
445class AbsoluteEncoderZeroingEstimator
446 : public ZeroingEstimator<AbsolutePosition,
447 constants::AbsoluteEncoderZeroingConstants,
448 AbsoluteEncoderEstimatorState> {
449 public:
450 explicit AbsoluteEncoderZeroingEstimator(
451 const constants::AbsoluteEncoderZeroingConstants &constants);
452
453 // Resets the internal logic so it needs to be re-zeroed.
454 void Reset() override;
455
456 // Updates the sensor values for the zeroing logic.
457 void UpdateEstimate(const AbsolutePosition &info) override;
458
459 void TriggerError() override { error_ = true; }
460
461 bool zeroed() const override { return zeroed_; }
462
463 double offset() const override { return offset_; }
464
465 bool error() const override { return error_; }
466
467 // Returns true if the sample buffer is full.
468 bool offset_ready() const override {
469 return relative_to_absolute_offset_samples_.size() ==
470 constants_.average_filter_size;
471 }
472
473 // Returns information about our current state.
Alex Perrycb7da4b2019-08-28 19:35:56 -0700474 virtual flatbuffers::Offset<State> GetEstimatorState(
475 flatbuffers::FlatBufferBuilder *fbb) const override;
Austin Schuhd82068e2019-01-26 20:05:42 -0800476
477 private:
Alex Perrycb7da4b2019-08-28 19:35:56 -0700478 struct PositionStruct {
479 PositionStruct(const AbsolutePosition &position_buffer)
480 : absolute_encoder(position_buffer.absolute_encoder()),
481 encoder(position_buffer.encoder()) {}
482 double absolute_encoder;
483 double encoder;
484 };
485
Austin Schuhd82068e2019-01-26 20:05:42 -0800486 // The zeroing constants used to describe the configuration of the system.
487 const constants::AbsoluteEncoderZeroingConstants constants_;
488
489 // True if the mechanism is zeroed.
490 bool zeroed_;
491 // Marker to track whether an error has occurred.
492 bool error_;
493 // The first valid offset we recorded. This is only set after zeroed_ first
494 // changes to true.
495 double first_offset_;
496
497 // The filtered absolute encoder. This is used in the status for calibration.
498 double filtered_absolute_encoder_ = 0.0;
499
500 // Samples of the offset needed to line the relative encoder up with the
501 // absolute encoder.
502 ::std::vector<double> relative_to_absolute_offset_samples_;
503
Alex Perrycb7da4b2019-08-28 19:35:56 -0700504 MoveDetector<PositionStruct, AbsolutePosition> move_detector_;
Austin Schuhd82068e2019-01-26 20:05:42 -0800505
506 // Estimated start position of the mechanism
507 double offset_ = 0;
508 // The next position in 'relative_to_absolute_offset_samples_' and
509 // 'encoder_samples_' to be used to store the next sample.
510 int samples_idx_ = 0;
511
512 // Number of NANs we've seen in a row.
513 size_t nan_samples_ = 0;
514
515 // The filtered position.
516 double position_ = 0.0;
517};
518
Adam Snaiderb4119252015-02-15 01:30:57 +0000519} // namespace zeroing
520} // namespace frc971
Adam Snaiderc4b3c192015-02-01 01:30:39 +0000521
522#endif // FRC971_ZEROING_ZEROING_H_