blob: 4ff6391d4886c88e4cc38b72bab300619c03de43 [file] [log] [blame]
Adam Snaiderc4b3c192015-02-01 01:30:39 +00001#include "frc971/zeroing/zeroing.h"
Adam Snaiderb4119252015-02-15 01:30:57 +00002
Brian Silvermanb691f5e2015-08-02 11:37:55 -07003#include <cmath>
Adam Snaiderc4b3c192015-02-01 01:30:39 +00004#include <vector>
5
6namespace frc971 {
7namespace zeroing {
8
Adam Snaider3cd11c52015-02-16 02:16:09 +00009void PopulateEstimatorState(const zeroing::ZeroingEstimator& estimator,
10 EstimatorState* state) {
Daniel Pettiab274232015-02-16 19:15:34 -080011 state->error = estimator.error();
12 state->zeroed = estimator.zeroed();
13 state->position = estimator.position();
Austin Schuhbe133ed2016-03-11 21:23:34 -080014 state->pot_position = estimator.filtered_position();
Daniel Pettiab274232015-02-16 19:15:34 -080015}
16
Austin Schuh703b8d42015-02-01 14:56:34 -080017ZeroingEstimator::ZeroingEstimator(
Brian Silvermanb691f5e2015-08-02 11:37:55 -070018 const constants::ZeroingConstants& constants) {
Adam Snaiderb4119252015-02-15 01:30:57 +000019 index_diff_ = constants.index_difference;
20 max_sample_count_ = constants.average_filter_size;
Philipp Schrader030ad182015-02-15 05:40:58 +000021 known_index_pos_ = constants.measured_index_position;
Adam Snaider3cd11c52015-02-16 02:16:09 +000022 allowable_encoder_error_ = constants.allowable_encoder_error;
Adam Snaiderb4119252015-02-15 01:30:57 +000023 start_pos_samples_.reserve(max_sample_count_);
Adam Snaiderb4119252015-02-15 01:30:57 +000024 Reset();
Austin Schuh703b8d42015-02-01 14:56:34 -080025}
26
Adam Snaiderb4119252015-02-15 01:30:57 +000027void ZeroingEstimator::Reset() {
Adam Snaiderc4b3c192015-02-01 01:30:39 +000028 samples_idx_ = 0;
Adam Snaiderb4119252015-02-15 01:30:57 +000029 start_pos_ = 0;
30 start_pos_samples_.clear();
31 zeroed_ = false;
Philipp Schrader41d82912015-02-15 03:44:23 +000032 wait_for_index_pulse_ = true;
Philipp Schradere828be72015-02-15 07:07:37 +000033 last_used_index_pulse_count_ = 0;
Adam Snaider3cd11c52015-02-16 02:16:09 +000034 first_start_pos_ = 0.0;
Philipp Schrader53f4b6d2015-02-15 22:32:08 +000035 error_ = false;
36}
37
38void ZeroingEstimator::TriggerError() {
39 if (!error_) {
40 LOG(ERROR, "Manually triggered zeroing error.\n");
41 error_ = true;
42 }
Philipp Schradere828be72015-02-15 07:07:37 +000043}
44
45double ZeroingEstimator::CalculateStartPosition(double start_average,
46 double latched_encoder) const {
47 // We calculate an aproximation of the value of the last index position.
48 // Also account for index pulses not lining up with integer multiples of the
49 // index_diff.
50 double index_pos = start_average + latched_encoder - known_index_pos_;
51 // We round index_pos to the closest valid value of the index.
52 double accurate_index_pos = (round(index_pos / index_diff_)) * index_diff_;
53 // Now we reverse the first calculation to get the accurate start position.
54 return accurate_index_pos - latched_encoder + known_index_pos_;
Adam Snaiderc4b3c192015-02-01 01:30:39 +000055}
56
Austin Schuh703b8d42015-02-01 14:56:34 -080057void ZeroingEstimator::UpdateEstimate(const PotAndIndexPosition& info) {
Philipp Schrader41d82912015-02-15 03:44:23 +000058 // We want to make sure that we encounter at least one index pulse while
59 // zeroing. So we take the index pulse count from the first sample after
60 // reset and wait for that count to change before we consider ourselves
61 // zeroed.
62 if (wait_for_index_pulse_) {
Philipp Schradere828be72015-02-15 07:07:37 +000063 last_used_index_pulse_count_ = info.index_pulses;
Philipp Schrader41d82912015-02-15 03:44:23 +000064 wait_for_index_pulse_ = false;
65 }
66
Adam Snaiderc4b3c192015-02-01 01:30:39 +000067 if (start_pos_samples_.size() < max_sample_count_) {
68 start_pos_samples_.push_back(info.pot - info.encoder);
69 } else {
70 start_pos_samples_[samples_idx_] = info.pot - info.encoder;
71 }
Adam Snaiderb4119252015-02-15 01:30:57 +000072
73 // Drop the oldest sample when we run this function the next time around.
Adam Snaiderc4b3c192015-02-01 01:30:39 +000074 samples_idx_ = (samples_idx_ + 1) % max_sample_count_;
75
Adam Snaiderb4119252015-02-15 01:30:57 +000076 double sample_sum = 0.0;
77
Adam Snaiderc4b3c192015-02-01 01:30:39 +000078 for (size_t i = 0; i < start_pos_samples_.size(); ++i) {
Adam Snaiderb4119252015-02-15 01:30:57 +000079 sample_sum += start_pos_samples_[i];
Adam Snaiderc4b3c192015-02-01 01:30:39 +000080 }
81
82 // Calculates the average of the starting position.
Adam Snaiderb4119252015-02-15 01:30:57 +000083 double start_average = sample_sum / start_pos_samples_.size();
84
85 // If there are no index pulses to use or we don't have enough samples yet to
86 // have a well-filtered starting position then we use the filtered value as
87 // our best guess.
Austin Schuh7485dbb2016-02-08 00:21:58 -080088 if (!zeroed_ &&
89 (info.index_pulses == last_used_index_pulse_count_ || !offset_ready())) {
Adam Snaiderb4119252015-02-15 01:30:57 +000090 start_pos_ = start_average;
Philipp Schradere828be72015-02-15 07:07:37 +000091 } else if (!zeroed_ || last_used_index_pulse_count_ != info.index_pulses) {
92 // Note the accurate start position and the current index pulse count so
93 // that we only run this logic once per index pulse. That should be more
94 // resilient to corrupted intermediate data.
95 start_pos_ = CalculateStartPosition(start_average, info.latched_encoder);
96 last_used_index_pulse_count_ = info.index_pulses;
Austin Schuh7485dbb2016-02-08 00:21:58 -080097
98 // TODO(austin): Reject encoder positions which have x% error rather than
99 // rounding to the closest index pulse.
100
Adam Snaider3cd11c52015-02-16 02:16:09 +0000101 // Save the first starting position.
102 if (!zeroed_) {
103 first_start_pos_ = start_pos_;
104 LOG(INFO, "latching start position %f\n", first_start_pos_);
105 }
Adam Snaiderb4119252015-02-15 01:30:57 +0000106
107 // Now that we have an accurate starting position we can consider ourselves
108 // zeroed.
Austin Schuh703b8d42015-02-01 14:56:34 -0800109 zeroed_ = true;
Adam Snaider3cd11c52015-02-16 02:16:09 +0000110 // Throw an error if first_start_pos is bigger/smaller than
Brian Silverman852824a2016-05-15 23:03:01 -0700111 // allowable_encoder_error_ * index_diff + start_pos.
Adam Snaider3cd11c52015-02-16 02:16:09 +0000112 if (::std::abs(first_start_pos_ - start_pos_) >
113 allowable_encoder_error_ * index_diff_) {
114 if (!error_) {
115 LOG(ERROR,
116 "Encoder ticks out of range since last index pulse. first start "
Austin Schuh1c85bc82016-04-03 21:36:31 -0700117 "position: %f recent starting position: %f, allowable error: %f\n",
118 first_start_pos_, start_pos_,
119 allowable_encoder_error_ * index_diff_);
Adam Snaider3cd11c52015-02-16 02:16:09 +0000120 error_ = true;
121 }
122 }
Adam Snaiderc4b3c192015-02-01 01:30:39 +0000123 }
Adam Snaiderb4119252015-02-15 01:30:57 +0000124
125 pos_ = start_pos_ + info.encoder;
Austin Schuhbe133ed2016-03-11 21:23:34 -0800126 filtered_position_ = start_average + info.encoder;
Adam Snaiderc4b3c192015-02-01 01:30:39 +0000127}
128
Adam Snaiderc4b3c192015-02-01 01:30:39 +0000129} // namespace zeroing
130} // namespace frc971