blob: fb82f228b6f61f781bbe1d0ae4ef30f0067542bb [file] [log] [blame]
Brian Silvermana57b7012020-03-11 20:19:23 -07001#include "frc971/zeroing/pot_and_index.h"
2
3#include <cmath>
4
5#include "glog/logging.h"
6
Stephan Pleinesf63bde82024-01-13 15:59:33 -08007namespace frc971::zeroing {
Brian Silvermana57b7012020-03-11 20:19:23 -07008
9PotAndIndexPulseZeroingEstimator::PotAndIndexPulseZeroingEstimator(
10 const constants::PotAndIndexPulseZeroingConstants &constants)
11 : constants_(constants) {
12 start_pos_samples_.reserve(constants_.average_filter_size);
13 Reset();
14}
15
16void PotAndIndexPulseZeroingEstimator::Reset() {
17 samples_idx_ = 0;
18 offset_ = 0;
19 start_pos_samples_.clear();
20 zeroed_ = false;
21 wait_for_index_pulse_ = true;
22 last_used_index_pulse_count_ = 0;
23 error_ = false;
24}
25
26void PotAndIndexPulseZeroingEstimator::TriggerError() {
27 if (!error_) {
28 VLOG(1) << "Manually triggered zeroing error.";
29 error_ = true;
30 }
31}
32
33double PotAndIndexPulseZeroingEstimator::CalculateStartPosition(
34 double start_average, double latched_encoder) const {
35 // We calculate an aproximation of the value of the last index position.
36 // Also account for index pulses not lining up with integer multiples of the
37 // index_diff.
38 double index_pos =
39 start_average + latched_encoder - constants_.measured_index_position;
40 // We round index_pos to the closest valid value of the index.
41 double accurate_index_pos = (round(index_pos / constants_.index_difference)) *
42 constants_.index_difference;
43 // Now we reverse the first calculation to get the accurate start position.
44 return accurate_index_pos - latched_encoder +
45 constants_.measured_index_position;
46}
47
48void PotAndIndexPulseZeroingEstimator::UpdateEstimate(
49 const PotAndIndexPosition &info) {
50 // We want to make sure that we encounter at least one index pulse while
51 // zeroing. So we take the index pulse count from the first sample after
52 // reset and wait for that count to change before we consider ourselves
53 // zeroed.
54 if (wait_for_index_pulse_) {
55 last_used_index_pulse_count_ = info.index_pulses();
56 wait_for_index_pulse_ = false;
57 }
58
59 if (start_pos_samples_.size() < constants_.average_filter_size) {
60 start_pos_samples_.push_back(info.pot() - info.encoder());
61 } else {
62 start_pos_samples_[samples_idx_] = info.pot() - info.encoder();
63 }
64
65 // Drop the oldest sample when we run this function the next time around.
66 samples_idx_ = (samples_idx_ + 1) % constants_.average_filter_size;
67
68 double sample_sum = 0.0;
69
70 for (size_t i = 0; i < start_pos_samples_.size(); ++i) {
71 sample_sum += start_pos_samples_[i];
72 }
73
74 // Calculates the average of the starting position.
75 double start_average = sample_sum / start_pos_samples_.size();
76
77 // If there are no index pulses to use or we don't have enough samples yet to
78 // have a well-filtered starting position then we use the filtered value as
79 // our best guess.
Philipp Schrader790cb542023-07-05 21:06:52 -070080 if (!zeroed_ && (info.index_pulses() == last_used_index_pulse_count_ ||
81 !offset_ready())) {
Brian Silvermana57b7012020-03-11 20:19:23 -070082 offset_ = start_average;
83 } else if (!zeroed_ || last_used_index_pulse_count_ != info.index_pulses()) {
84 // Note the accurate start position and the current index pulse count so
85 // that we only run this logic once per index pulse. That should be more
86 // resilient to corrupted intermediate data.
87 offset_ = CalculateStartPosition(start_average, info.latched_encoder());
88 last_used_index_pulse_count_ = info.index_pulses();
89
90 // TODO(austin): Reject encoder positions which have x% error rather than
91 // rounding to the closest index pulse.
92
93 // Save the first starting position.
94 if (!zeroed_) {
95 first_start_pos_ = offset_;
96 VLOG(2) << "latching start position" << first_start_pos_;
97 }
98
99 // Now that we have an accurate starting position we can consider ourselves
100 // zeroed.
101 zeroed_ = true;
102 // Throw an error if first_start_pos is bigger/smaller than
103 // constants_.allowable_encoder_error * index_diff + start_pos.
104 if (::std::abs(first_start_pos_ - offset_) >
105 constants_.allowable_encoder_error * constants_.index_difference) {
106 if (!error_) {
107 VLOG(1)
108 << "Encoder ticks out of range since last index pulse. first start "
109 "position: "
110 << first_start_pos_ << " recent starting position: " << offset_
111 << ", allowable error: "
112 << constants_.allowable_encoder_error * constants_.index_difference;
113 error_ = true;
114 }
115 }
116 }
117
118 position_ = offset_ + info.encoder();
119 filtered_position_ = start_average + info.encoder();
120}
121
122flatbuffers::Offset<PotAndIndexPulseZeroingEstimator::State>
123PotAndIndexPulseZeroingEstimator::GetEstimatorState(
124 flatbuffers::FlatBufferBuilder *fbb) const {
125 State::Builder builder(*fbb);
126 builder.add_error(error_);
127 builder.add_zeroed(zeroed_);
128 builder.add_position(position_);
129 builder.add_pot_position(filtered_position_);
130 return builder.Finish();
131}
132
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800133} // namespace frc971::zeroing