blob: 5184ad45e77c847702ec80f09166e8f1d730ba37 [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();
14}
15
Austin Schuh703b8d42015-02-01 14:56:34 -080016ZeroingEstimator::ZeroingEstimator(
Brian Silvermanb691f5e2015-08-02 11:37:55 -070017 const constants::ZeroingConstants& constants) {
Adam Snaiderb4119252015-02-15 01:30:57 +000018 index_diff_ = constants.index_difference;
19 max_sample_count_ = constants.average_filter_size;
Philipp Schrader030ad182015-02-15 05:40:58 +000020 known_index_pos_ = constants.measured_index_position;
Adam Snaider3cd11c52015-02-16 02:16:09 +000021 allowable_encoder_error_ = constants.allowable_encoder_error;
Adam Snaiderb4119252015-02-15 01:30:57 +000022 start_pos_samples_.reserve(max_sample_count_);
Adam Snaiderb4119252015-02-15 01:30:57 +000023 Reset();
Austin Schuh703b8d42015-02-01 14:56:34 -080024}
25
Adam Snaiderb4119252015-02-15 01:30:57 +000026void ZeroingEstimator::Reset() {
Adam Snaiderc4b3c192015-02-01 01:30:39 +000027 samples_idx_ = 0;
Adam Snaiderb4119252015-02-15 01:30:57 +000028 start_pos_ = 0;
29 start_pos_samples_.clear();
30 zeroed_ = false;
Philipp Schrader41d82912015-02-15 03:44:23 +000031 wait_for_index_pulse_ = true;
Philipp Schradere828be72015-02-15 07:07:37 +000032 last_used_index_pulse_count_ = 0;
Adam Snaider3cd11c52015-02-16 02:16:09 +000033 first_start_pos_ = 0.0;
Philipp Schrader53f4b6d2015-02-15 22:32:08 +000034 error_ = false;
35}
36
37void ZeroingEstimator::TriggerError() {
38 if (!error_) {
39 LOG(ERROR, "Manually triggered zeroing error.\n");
40 error_ = true;
41 }
Philipp Schradere828be72015-02-15 07:07:37 +000042}
43
44double ZeroingEstimator::CalculateStartPosition(double start_average,
45 double latched_encoder) const {
46 // We calculate an aproximation of the value of the last index position.
47 // Also account for index pulses not lining up with integer multiples of the
48 // index_diff.
49 double index_pos = start_average + latched_encoder - known_index_pos_;
50 // We round index_pos to the closest valid value of the index.
51 double accurate_index_pos = (round(index_pos / index_diff_)) * index_diff_;
52 // Now we reverse the first calculation to get the accurate start position.
53 return accurate_index_pos - latched_encoder + known_index_pos_;
Adam Snaiderc4b3c192015-02-01 01:30:39 +000054}
55
Austin Schuh703b8d42015-02-01 14:56:34 -080056void ZeroingEstimator::UpdateEstimate(const PotAndIndexPosition& info) {
Philipp Schrader41d82912015-02-15 03:44:23 +000057 // We want to make sure that we encounter at least one index pulse while
58 // zeroing. So we take the index pulse count from the first sample after
59 // reset and wait for that count to change before we consider ourselves
60 // zeroed.
61 if (wait_for_index_pulse_) {
Philipp Schradere828be72015-02-15 07:07:37 +000062 last_used_index_pulse_count_ = info.index_pulses;
Philipp Schrader41d82912015-02-15 03:44:23 +000063 wait_for_index_pulse_ = false;
64 }
65
Adam Snaiderc4b3c192015-02-01 01:30:39 +000066 if (start_pos_samples_.size() < max_sample_count_) {
67 start_pos_samples_.push_back(info.pot - info.encoder);
68 } else {
69 start_pos_samples_[samples_idx_] = info.pot - info.encoder;
70 }
Adam Snaiderb4119252015-02-15 01:30:57 +000071
72 // Drop the oldest sample when we run this function the next time around.
Adam Snaiderc4b3c192015-02-01 01:30:39 +000073 samples_idx_ = (samples_idx_ + 1) % max_sample_count_;
74
Adam Snaiderb4119252015-02-15 01:30:57 +000075 double sample_sum = 0.0;
76
Adam Snaiderc4b3c192015-02-01 01:30:39 +000077 for (size_t i = 0; i < start_pos_samples_.size(); ++i) {
Adam Snaiderb4119252015-02-15 01:30:57 +000078 sample_sum += start_pos_samples_[i];
Adam Snaiderc4b3c192015-02-01 01:30:39 +000079 }
80
81 // Calculates the average of the starting position.
Adam Snaiderb4119252015-02-15 01:30:57 +000082 double start_average = sample_sum / start_pos_samples_.size();
83
84 // If there are no index pulses to use or we don't have enough samples yet to
85 // have a well-filtered starting position then we use the filtered value as
86 // our best guess.
Austin Schuh7485dbb2016-02-08 00:21:58 -080087 if (!zeroed_ &&
88 (info.index_pulses == last_used_index_pulse_count_ || !offset_ready())) {
Adam Snaiderb4119252015-02-15 01:30:57 +000089 start_pos_ = start_average;
Philipp Schradere828be72015-02-15 07:07:37 +000090 } else if (!zeroed_ || last_used_index_pulse_count_ != info.index_pulses) {
91 // Note the accurate start position and the current index pulse count so
92 // that we only run this logic once per index pulse. That should be more
93 // resilient to corrupted intermediate data.
94 start_pos_ = CalculateStartPosition(start_average, info.latched_encoder);
95 last_used_index_pulse_count_ = info.index_pulses;
Austin Schuh7485dbb2016-02-08 00:21:58 -080096
97 // TODO(austin): Reject encoder positions which have x% error rather than
98 // rounding to the closest index pulse.
99
Adam Snaider3cd11c52015-02-16 02:16:09 +0000100 // Save the first starting position.
101 if (!zeroed_) {
102 first_start_pos_ = start_pos_;
103 LOG(INFO, "latching start position %f\n", first_start_pos_);
104 }
Adam Snaiderb4119252015-02-15 01:30:57 +0000105
106 // Now that we have an accurate starting position we can consider ourselves
107 // zeroed.
Austin Schuh703b8d42015-02-01 14:56:34 -0800108 zeroed_ = true;
Adam Snaider3cd11c52015-02-16 02:16:09 +0000109 // Throw an error if first_start_pos is bigger/smaller than
110 // allowable_encoder_error_ * index_diff +
111 // start_pos.
112 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 "
117 "position: %f recent starting position: %f\n",
118 first_start_pos_, start_pos_);
119 error_ = true;
120 }
121 }
Adam Snaiderc4b3c192015-02-01 01:30:39 +0000122 }
Adam Snaiderb4119252015-02-15 01:30:57 +0000123
124 pos_ = start_pos_ + info.encoder;
Adam Snaiderc4b3c192015-02-01 01:30:39 +0000125}
126
Adam Snaiderc4b3c192015-02-01 01:30:39 +0000127} // namespace zeroing
128} // namespace frc971