blob: 69c4de6dab782667f85b2c68f3e4d9b5d0a3d6e6 [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
Tyler Chatowf8f03112017-02-05 14:31:34 -08009void PopulateEstimatorState(
10 const zeroing::PotAndIndexPulseZeroingEstimator &estimator,
11 EstimatorState *state) {
Daniel Pettiab274232015-02-16 19:15:34 -080012 state->error = estimator.error();
13 state->zeroed = estimator.zeroed();
14 state->position = estimator.position();
Austin Schuhbe133ed2016-03-11 21:23:34 -080015 state->pot_position = estimator.filtered_position();
Daniel Pettiab274232015-02-16 19:15:34 -080016}
17
Tyler Chatowf8f03112017-02-05 14:31:34 -080018PotAndIndexPulseZeroingEstimator::PotAndIndexPulseZeroingEstimator(
19 const constants::PotAndIndexPulseZeroingConstants &constants) {
Adam Snaiderb4119252015-02-15 01:30:57 +000020 index_diff_ = constants.index_difference;
21 max_sample_count_ = constants.average_filter_size;
Philipp Schrader030ad182015-02-15 05:40:58 +000022 known_index_pos_ = constants.measured_index_position;
Adam Snaider3cd11c52015-02-16 02:16:09 +000023 allowable_encoder_error_ = constants.allowable_encoder_error;
Adam Snaiderb4119252015-02-15 01:30:57 +000024 start_pos_samples_.reserve(max_sample_count_);
Adam Snaiderb4119252015-02-15 01:30:57 +000025 Reset();
Austin Schuh703b8d42015-02-01 14:56:34 -080026}
27
Tyler Chatowf8f03112017-02-05 14:31:34 -080028void PotAndIndexPulseZeroingEstimator::Reset() {
Adam Snaiderc4b3c192015-02-01 01:30:39 +000029 samples_idx_ = 0;
Adam Snaiderb4119252015-02-15 01:30:57 +000030 start_pos_ = 0;
31 start_pos_samples_.clear();
32 zeroed_ = false;
Philipp Schrader41d82912015-02-15 03:44:23 +000033 wait_for_index_pulse_ = true;
Philipp Schradere828be72015-02-15 07:07:37 +000034 last_used_index_pulse_count_ = 0;
Adam Snaider3cd11c52015-02-16 02:16:09 +000035 first_start_pos_ = 0.0;
Philipp Schrader53f4b6d2015-02-15 22:32:08 +000036 error_ = false;
37}
38
Tyler Chatowf8f03112017-02-05 14:31:34 -080039void PotAndIndexPulseZeroingEstimator::TriggerError() {
Philipp Schrader53f4b6d2015-02-15 22:32:08 +000040 if (!error_) {
41 LOG(ERROR, "Manually triggered zeroing error.\n");
42 error_ = true;
43 }
Philipp Schradere828be72015-02-15 07:07:37 +000044}
45
Tyler Chatowf8f03112017-02-05 14:31:34 -080046double PotAndIndexPulseZeroingEstimator::CalculateStartPosition(
47 double start_average, double latched_encoder) const {
Philipp Schradere828be72015-02-15 07:07:37 +000048 // We calculate an aproximation of the value of the last index position.
49 // Also account for index pulses not lining up with integer multiples of the
50 // index_diff.
51 double index_pos = start_average + latched_encoder - known_index_pos_;
52 // We round index_pos to the closest valid value of the index.
53 double accurate_index_pos = (round(index_pos / index_diff_)) * index_diff_;
54 // Now we reverse the first calculation to get the accurate start position.
55 return accurate_index_pos - latched_encoder + known_index_pos_;
Adam Snaiderc4b3c192015-02-01 01:30:39 +000056}
57
Tyler Chatowf8f03112017-02-05 14:31:34 -080058void PotAndIndexPulseZeroingEstimator::UpdateEstimate(
59 const PotAndIndexPosition &info) {
Philipp Schrader41d82912015-02-15 03:44:23 +000060 // We want to make sure that we encounter at least one index pulse while
61 // zeroing. So we take the index pulse count from the first sample after
62 // reset and wait for that count to change before we consider ourselves
63 // zeroed.
64 if (wait_for_index_pulse_) {
Philipp Schradere828be72015-02-15 07:07:37 +000065 last_used_index_pulse_count_ = info.index_pulses;
Philipp Schrader41d82912015-02-15 03:44:23 +000066 wait_for_index_pulse_ = false;
67 }
68
Adam Snaiderc4b3c192015-02-01 01:30:39 +000069 if (start_pos_samples_.size() < max_sample_count_) {
70 start_pos_samples_.push_back(info.pot - info.encoder);
71 } else {
72 start_pos_samples_[samples_idx_] = info.pot - info.encoder;
73 }
Adam Snaiderb4119252015-02-15 01:30:57 +000074
75 // Drop the oldest sample when we run this function the next time around.
Adam Snaiderc4b3c192015-02-01 01:30:39 +000076 samples_idx_ = (samples_idx_ + 1) % max_sample_count_;
77
Adam Snaiderb4119252015-02-15 01:30:57 +000078 double sample_sum = 0.0;
79
Adam Snaiderc4b3c192015-02-01 01:30:39 +000080 for (size_t i = 0; i < start_pos_samples_.size(); ++i) {
Adam Snaiderb4119252015-02-15 01:30:57 +000081 sample_sum += start_pos_samples_[i];
Adam Snaiderc4b3c192015-02-01 01:30:39 +000082 }
83
84 // Calculates the average of the starting position.
Adam Snaiderb4119252015-02-15 01:30:57 +000085 double start_average = sample_sum / start_pos_samples_.size();
86
87 // If there are no index pulses to use or we don't have enough samples yet to
88 // have a well-filtered starting position then we use the filtered value as
89 // our best guess.
Austin Schuh7485dbb2016-02-08 00:21:58 -080090 if (!zeroed_ &&
91 (info.index_pulses == last_used_index_pulse_count_ || !offset_ready())) {
Adam Snaiderb4119252015-02-15 01:30:57 +000092 start_pos_ = start_average;
Philipp Schradere828be72015-02-15 07:07:37 +000093 } else if (!zeroed_ || last_used_index_pulse_count_ != info.index_pulses) {
94 // Note the accurate start position and the current index pulse count so
95 // that we only run this logic once per index pulse. That should be more
96 // resilient to corrupted intermediate data.
97 start_pos_ = CalculateStartPosition(start_average, info.latched_encoder);
98 last_used_index_pulse_count_ = info.index_pulses;
Austin Schuh7485dbb2016-02-08 00:21:58 -080099
100 // TODO(austin): Reject encoder positions which have x% error rather than
101 // rounding to the closest index pulse.
102
Adam Snaider3cd11c52015-02-16 02:16:09 +0000103 // Save the first starting position.
104 if (!zeroed_) {
105 first_start_pos_ = start_pos_;
106 LOG(INFO, "latching start position %f\n", first_start_pos_);
107 }
Adam Snaiderb4119252015-02-15 01:30:57 +0000108
109 // Now that we have an accurate starting position we can consider ourselves
110 // zeroed.
Austin Schuh703b8d42015-02-01 14:56:34 -0800111 zeroed_ = true;
Adam Snaider3cd11c52015-02-16 02:16:09 +0000112 // Throw an error if first_start_pos is bigger/smaller than
Brian Silverman852824a2016-05-15 23:03:01 -0700113 // allowable_encoder_error_ * index_diff + start_pos.
Adam Snaider3cd11c52015-02-16 02:16:09 +0000114 if (::std::abs(first_start_pos_ - start_pos_) >
115 allowable_encoder_error_ * index_diff_) {
116 if (!error_) {
117 LOG(ERROR,
118 "Encoder ticks out of range since last index pulse. first start "
Austin Schuh1c85bc82016-04-03 21:36:31 -0700119 "position: %f recent starting position: %f, allowable error: %f\n",
120 first_start_pos_, start_pos_,
121 allowable_encoder_error_ * index_diff_);
Adam Snaider3cd11c52015-02-16 02:16:09 +0000122 error_ = true;
123 }
124 }
Adam Snaiderc4b3c192015-02-01 01:30:39 +0000125 }
Adam Snaiderb4119252015-02-15 01:30:57 +0000126
127 pos_ = start_pos_ + info.encoder;
Austin Schuhbe133ed2016-03-11 21:23:34 -0800128 filtered_position_ = start_average + info.encoder;
Adam Snaiderc4b3c192015-02-01 01:30:39 +0000129}
130
Adam Snaiderc4b3c192015-02-01 01:30:39 +0000131} // namespace zeroing
132} // namespace frc971