blob: b9ba33df9608bd049744d72e093218ff0460a810 [file] [log] [blame]
Ravago Jonesea6464c2020-10-10 15:40:46 -07001#include "frc971/zeroing/absolute_and_absolute_encoder.h"
2
3#include <cmath>
4#include <numeric>
5
6#include "glog/logging.h"
7
Ravago Jones937587c2020-12-26 17:21:09 -08008#include "aos/logging/logging.h"
Ravago Jonesea6464c2020-10-10 15:40:46 -07009#include "frc971/zeroing/wrap.h"
10
Stephan Pleinesf63bde82024-01-13 15:59:33 -080011namespace frc971::zeroing {
Ravago Jonesea6464c2020-10-10 15:40:46 -070012
13AbsoluteAndAbsoluteEncoderZeroingEstimator::
14 AbsoluteAndAbsoluteEncoderZeroingEstimator(
15 const constants::AbsoluteAndAbsoluteEncoderZeroingConstants &constants)
16 : constants_(constants), move_detector_(constants_.moving_buffer_size) {
17 relative_to_absolute_offset_samples_.reserve(constants_.average_filter_size);
18 offset_samples_.reserve(constants_.average_filter_size);
19 Reset();
20}
21
22void AbsoluteAndAbsoluteEncoderZeroingEstimator::Reset() {
23 first_offset_ = 0.0;
24 single_turn_to_relative_encoder_offset_ = 0.0;
25 offset_ = 0.0;
26 samples_idx_ = 0;
27 filtered_position_ = 0.0;
28 position_ = 0.0;
29 zeroed_ = false;
30 nan_samples_ = 0;
31 relative_to_absolute_offset_samples_.clear();
32 offset_samples_.clear();
33 move_detector_.Reset();
34 error_ = false;
35}
36
milind-ud53408e2021-10-21 19:43:58 -070037double
38AbsoluteAndAbsoluteEncoderZeroingEstimator::AdjustedSingleTurnAbsoluteEncoder(
39 const PositionStruct &sample) const {
40 return UnWrap(constants_.single_turn_middle_position,
41 sample.single_turn_absolute_encoder -
42 constants_.single_turn_measured_absolute_position,
43 constants_.single_turn_one_revolution_distance);
44}
45
Ravago Jonesea6464c2020-10-10 15:40:46 -070046// So, this needs to be a multistep process. We need to first estimate the
47// offset between the absolute encoder and the relative encoder. That process
48// should get us an absolute number which is off by integer multiples of the
49// distance/rev. In parallel, we can estimate the offset between the single
50// turn encoder and encoder. When both estimates have converged, we can then
51// compute the offset in a cycle, and which cycle, which gives us the accurate
52// global offset.
53//
54// It's tricky to compute the offset between the absolute and relative encoder.
55// We need to compute this inside 1 revolution. The easiest way to do this
56// would be to wrap the encoder, subtract the two of them, and then average the
57// result. That will struggle when they are off by PI. Instead, we need to
58// wrap the number to +- PI from the current averaged offset.
59//
60// To guard against the robot moving while updating estimates, buffer a number
61// of samples and check that the buffered samples are not different than the
62// zeroing threshold. At any point that the samples differ too much, do not
63// update estimates based on those samples.
64void AbsoluteAndAbsoluteEncoderZeroingEstimator::UpdateEstimate(
65 const AbsoluteAndAbsolutePosition &info) {
66 // Check for Abs Encoder NaN value that would mess up the rest of the zeroing
67 // code below. NaN values are given when the Absolute Encoder is disconnected.
Ravago Jones937587c2020-12-26 17:21:09 -080068 if (::std::isnan(info.absolute_encoder()) ||
69 ::std::isnan(info.single_turn_absolute_encoder())) {
Ravago Jonesea6464c2020-10-10 15:40:46 -070070 if (zeroed_) {
Ravago Jones937587c2020-12-26 17:21:09 -080071 VLOG(1) << "NAN on one of the absolute encoders.";
Ravago Jonesea6464c2020-10-10 15:40:46 -070072 error_ = true;
Ravago Jones726deb02021-05-29 14:36:43 -070073 errors_.Set(ZeroingError::LOST_ABSOLUTE_ENCODER);
Ravago Jonesea6464c2020-10-10 15:40:46 -070074 } else {
75 ++nan_samples_;
Ravago Jones937587c2020-12-26 17:21:09 -080076 VLOG(1) << "NAN on one of the absolute encoders while zeroing"
77 << nan_samples_;
Ravago Jonesea6464c2020-10-10 15:40:46 -070078 if (nan_samples_ >= constants_.average_filter_size) {
79 error_ = true;
80 zeroed_ = true;
Ravago Jones726deb02021-05-29 14:36:43 -070081 errors_.Set(ZeroingError::LOST_ABSOLUTE_ENCODER);
Ravago Jonesea6464c2020-10-10 15:40:46 -070082 }
83 }
84 // Throw some dummy values in for now.
85 filtered_absolute_encoder_ = info.absolute_encoder();
Ravago Jones937587c2020-12-26 17:21:09 -080086 filtered_single_turn_absolute_encoder_ =
87 info.single_turn_absolute_encoder();
Ravago Jonesea6464c2020-10-10 15:40:46 -070088 filtered_position_ =
89 single_turn_to_relative_encoder_offset_ + info.encoder();
90 position_ = offset_ + info.encoder();
91 return;
92 }
93
94 const bool moving = move_detector_.Update(info, constants_.moving_buffer_size,
95 constants_.zeroing_threshold);
96
97 if (!moving) {
98 const PositionStruct &sample = move_detector_.GetSample();
99
100 // Compute the average offset between the absolute encoder and relative
101 // encoder. If we have 0 samples, assume it is 0.
102 double average_relative_to_absolute_offset =
103 relative_to_absolute_offset_samples_.size() == 0
104 ? 0.0
105 : ::std::accumulate(relative_to_absolute_offset_samples_.begin(),
106 relative_to_absolute_offset_samples_.end(),
107 0.0) /
108 relative_to_absolute_offset_samples_.size();
109
110 const double adjusted_incremental_encoder =
111 sample.encoder + average_relative_to_absolute_offset;
112
113 // Now, compute the nearest absolute encoder value to the offset relative
114 // encoder position.
115 const double adjusted_absolute_encoder =
116 UnWrap(adjusted_incremental_encoder,
117 sample.absolute_encoder - constants_.measured_absolute_position,
118 constants_.one_revolution_distance);
119
120 // We can now compute the offset now that we have unwrapped the absolute
121 // encoder.
122 const double relative_to_absolute_offset =
123 adjusted_absolute_encoder - sample.encoder;
124
125 // Add the sample and update the average with the new reading.
126 const size_t relative_to_absolute_offset_samples_size =
127 relative_to_absolute_offset_samples_.size();
128 if (relative_to_absolute_offset_samples_size <
129 constants_.average_filter_size) {
130 average_relative_to_absolute_offset =
131 (average_relative_to_absolute_offset *
132 relative_to_absolute_offset_samples_size +
133 relative_to_absolute_offset) /
134 (relative_to_absolute_offset_samples_size + 1);
135
136 relative_to_absolute_offset_samples_.push_back(
137 relative_to_absolute_offset);
138 } else {
139 average_relative_to_absolute_offset -=
140 relative_to_absolute_offset_samples_[samples_idx_] /
141 relative_to_absolute_offset_samples_size;
142 relative_to_absolute_offset_samples_[samples_idx_] =
143 relative_to_absolute_offset;
144 average_relative_to_absolute_offset +=
145 relative_to_absolute_offset /
146 relative_to_absolute_offset_samples_size;
147 }
148
149 const double adjusted_single_turn_absolute_encoder =
milind-ud53408e2021-10-21 19:43:58 -0700150 AdjustedSingleTurnAbsoluteEncoder(sample);
Ravago Jonesea6464c2020-10-10 15:40:46 -0700151
152 // Now compute the offset between the pot and relative encoder.
153 if (offset_samples_.size() < constants_.average_filter_size) {
Ravago Jones937587c2020-12-26 17:21:09 -0800154 offset_samples_.push_back(sample.encoder -
155 adjusted_single_turn_absolute_encoder);
Ravago Jonesea6464c2020-10-10 15:40:46 -0700156 } else {
157 offset_samples_[samples_idx_] =
Ravago Jones937587c2020-12-26 17:21:09 -0800158 sample.encoder - adjusted_single_turn_absolute_encoder;
Ravago Jonesea6464c2020-10-10 15:40:46 -0700159 }
160
161 // Drop the oldest sample when we run this function the next time around.
162 samples_idx_ = (samples_idx_ + 1) % constants_.average_filter_size;
163
164 single_turn_to_relative_encoder_offset_ =
165 ::std::accumulate(offset_samples_.begin(), offset_samples_.end(), 0.0) /
166 offset_samples_.size();
167
Ravago Jones937587c2020-12-26 17:21:09 -0800168 offset_ = UnWrap(sample.encoder - single_turn_to_relative_encoder_offset_,
Ravago Jonesea6464c2020-10-10 15:40:46 -0700169 average_relative_to_absolute_offset + sample.encoder,
170 constants_.one_revolution_distance) -
171 sample.encoder;
172
173 // Reverse the math for adjusted_absolute_encoder to compute the absolute
174 // encoder. Do this by taking the adjusted encoder, and then subtracting off
175 // the second argument above, and the value that was added by Wrap.
176 filtered_absolute_encoder_ =
177 ((sample.encoder + average_relative_to_absolute_offset) -
178 (-constants_.measured_absolute_position +
179 (adjusted_absolute_encoder -
180 (sample.absolute_encoder - constants_.measured_absolute_position))));
181
Ravago Jones937587c2020-12-26 17:21:09 -0800182 const double what_Unwrap_added =
183 (adjusted_single_turn_absolute_encoder -
184 (sample.single_turn_absolute_encoder -
185 constants_.single_turn_measured_absolute_position));
186
Ravago Jonesea6464c2020-10-10 15:40:46 -0700187 // TODO(Ravago): this is impossible to read.
188 filtered_single_turn_absolute_encoder_ =
Ravago Jones937587c2020-12-26 17:21:09 -0800189 ((sample.encoder - single_turn_to_relative_encoder_offset_) -
Ravago Jonesea6464c2020-10-10 15:40:46 -0700190 (-constants_.single_turn_measured_absolute_position +
Ravago Jones937587c2020-12-26 17:21:09 -0800191 what_Unwrap_added));
192
Ravago Jones937587c2020-12-26 17:21:09 -0800193 if (!zeroed_) {
194 first_offset_ = offset_;
195 }
Ravago Jonesea6464c2020-10-10 15:40:46 -0700196
197 if (offset_ready()) {
Ravago Jonesea6464c2020-10-10 15:40:46 -0700198 if (::std::abs(first_offset_ - offset_) >
199 constants_.allowable_encoder_error *
200 constants_.one_revolution_distance) {
Ravago Jones937587c2020-12-26 17:21:09 -0800201 AOS_LOG(INFO,
202 "Offset moved too far. Initial: %f, current %f, allowable "
203 "change: %f ",
204 first_offset_, offset_,
205 constants_.allowable_encoder_error *
206 constants_.one_revolution_distance);
Ravago Jonesea6464c2020-10-10 15:40:46 -0700207 error_ = true;
Ravago Jones726deb02021-05-29 14:36:43 -0700208 errors_.Set(ZeroingError::OFFSET_MOVED_TOO_FAR);
Ravago Jonesea6464c2020-10-10 15:40:46 -0700209 }
210
211 zeroed_ = true;
212 }
213 }
214
215 // Update the position.
Ravago Jones937587c2020-12-26 17:21:09 -0800216 position_ = first_offset_ + info.encoder();
Ravago Jonesea6464c2020-10-10 15:40:46 -0700217}
218
219flatbuffers::Offset<AbsoluteAndAbsoluteEncoderZeroingEstimator::State>
220AbsoluteAndAbsoluteEncoderZeroingEstimator::GetEstimatorState(
221 flatbuffers::FlatBufferBuilder *fbb) const {
Ravago Jones726deb02021-05-29 14:36:43 -0700222 flatbuffers::Offset<flatbuffers::Vector<ZeroingError>> errors_offset =
223 errors_.ToFlatbuffer(fbb);
224
Ravago Jonesea6464c2020-10-10 15:40:46 -0700225 State::Builder builder(*fbb);
226 builder.add_error(error_);
Ravago Jones726deb02021-05-29 14:36:43 -0700227 builder.add_errors(errors_offset);
Ravago Jonesea6464c2020-10-10 15:40:46 -0700228 builder.add_zeroed(zeroed_);
229 builder.add_position(position_);
230 builder.add_absolute_position(filtered_absolute_encoder_);
231 builder.add_single_turn_absolute_position(
232 filtered_single_turn_absolute_encoder_);
233 return builder.Finish();
234}
235
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800236} // namespace frc971::zeroing