blob: dab814b053e0d027553c8796403984416813607b [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
Austin Schuh99f7c6a2024-06-25 22:07:44 -07006#include "absl/log/check.h"
7#include "absl/log/log.h"
Ravago Jonesea6464c2020-10-10 15:40:46 -07008
Ravago Jones937587c2020-12-26 17:21:09 -08009#include "aos/logging/logging.h"
Ravago Jonesea6464c2020-10-10 15:40:46 -070010#include "frc971/zeroing/wrap.h"
11
Stephan Pleinesf63bde82024-01-13 15:59:33 -080012namespace frc971::zeroing {
Ravago Jonesea6464c2020-10-10 15:40:46 -070013
14AbsoluteAndAbsoluteEncoderZeroingEstimator::
15 AbsoluteAndAbsoluteEncoderZeroingEstimator(
16 const constants::AbsoluteAndAbsoluteEncoderZeroingConstants &constants)
17 : constants_(constants), move_detector_(constants_.moving_buffer_size) {
18 relative_to_absolute_offset_samples_.reserve(constants_.average_filter_size);
19 offset_samples_.reserve(constants_.average_filter_size);
20 Reset();
21}
22
23void AbsoluteAndAbsoluteEncoderZeroingEstimator::Reset() {
24 first_offset_ = 0.0;
25 single_turn_to_relative_encoder_offset_ = 0.0;
26 offset_ = 0.0;
27 samples_idx_ = 0;
28 filtered_position_ = 0.0;
29 position_ = 0.0;
30 zeroed_ = false;
31 nan_samples_ = 0;
32 relative_to_absolute_offset_samples_.clear();
33 offset_samples_.clear();
34 move_detector_.Reset();
35 error_ = false;
36}
37
milind-ud53408e2021-10-21 19:43:58 -070038double
39AbsoluteAndAbsoluteEncoderZeroingEstimator::AdjustedSingleTurnAbsoluteEncoder(
40 const PositionStruct &sample) const {
41 return UnWrap(constants_.single_turn_middle_position,
42 sample.single_turn_absolute_encoder -
43 constants_.single_turn_measured_absolute_position,
44 constants_.single_turn_one_revolution_distance);
45}
46
Ravago Jonesea6464c2020-10-10 15:40:46 -070047// So, this needs to be a multistep process. We need to first estimate the
48// offset between the absolute encoder and the relative encoder. That process
49// should get us an absolute number which is off by integer multiples of the
50// distance/rev. In parallel, we can estimate the offset between the single
51// turn encoder and encoder. When both estimates have converged, we can then
52// compute the offset in a cycle, and which cycle, which gives us the accurate
53// global offset.
54//
55// It's tricky to compute the offset between the absolute and relative encoder.
56// We need to compute this inside 1 revolution. The easiest way to do this
57// would be to wrap the encoder, subtract the two of them, and then average the
58// result. That will struggle when they are off by PI. Instead, we need to
59// wrap the number to +- PI from the current averaged offset.
60//
61// To guard against the robot moving while updating estimates, buffer a number
62// of samples and check that the buffered samples are not different than the
63// zeroing threshold. At any point that the samples differ too much, do not
64// update estimates based on those samples.
65void AbsoluteAndAbsoluteEncoderZeroingEstimator::UpdateEstimate(
66 const AbsoluteAndAbsolutePosition &info) {
67 // Check for Abs Encoder NaN value that would mess up the rest of the zeroing
68 // code below. NaN values are given when the Absolute Encoder is disconnected.
Ravago Jones937587c2020-12-26 17:21:09 -080069 if (::std::isnan(info.absolute_encoder()) ||
70 ::std::isnan(info.single_turn_absolute_encoder())) {
Ravago Jonesea6464c2020-10-10 15:40:46 -070071 if (zeroed_) {
Ravago Jones937587c2020-12-26 17:21:09 -080072 VLOG(1) << "NAN on one of the absolute encoders.";
Ravago Jonesea6464c2020-10-10 15:40:46 -070073 error_ = true;
Ravago Jones726deb02021-05-29 14:36:43 -070074 errors_.Set(ZeroingError::LOST_ABSOLUTE_ENCODER);
Ravago Jonesea6464c2020-10-10 15:40:46 -070075 } else {
76 ++nan_samples_;
Ravago Jones937587c2020-12-26 17:21:09 -080077 VLOG(1) << "NAN on one of the absolute encoders while zeroing"
78 << nan_samples_;
Ravago Jonesea6464c2020-10-10 15:40:46 -070079 if (nan_samples_ >= constants_.average_filter_size) {
80 error_ = true;
81 zeroed_ = true;
Ravago Jones726deb02021-05-29 14:36:43 -070082 errors_.Set(ZeroingError::LOST_ABSOLUTE_ENCODER);
Ravago Jonesea6464c2020-10-10 15:40:46 -070083 }
84 }
85 // Throw some dummy values in for now.
86 filtered_absolute_encoder_ = info.absolute_encoder();
Ravago Jones937587c2020-12-26 17:21:09 -080087 filtered_single_turn_absolute_encoder_ =
88 info.single_turn_absolute_encoder();
Ravago Jonesea6464c2020-10-10 15:40:46 -070089 filtered_position_ =
90 single_turn_to_relative_encoder_offset_ + info.encoder();
91 position_ = offset_ + info.encoder();
92 return;
93 }
94
95 const bool moving = move_detector_.Update(info, constants_.moving_buffer_size,
96 constants_.zeroing_threshold);
97
98 if (!moving) {
99 const PositionStruct &sample = move_detector_.GetSample();
100
101 // Compute the average offset between the absolute encoder and relative
102 // encoder. If we have 0 samples, assume it is 0.
103 double average_relative_to_absolute_offset =
104 relative_to_absolute_offset_samples_.size() == 0
105 ? 0.0
106 : ::std::accumulate(relative_to_absolute_offset_samples_.begin(),
107 relative_to_absolute_offset_samples_.end(),
108 0.0) /
109 relative_to_absolute_offset_samples_.size();
110
111 const double adjusted_incremental_encoder =
112 sample.encoder + average_relative_to_absolute_offset;
113
114 // Now, compute the nearest absolute encoder value to the offset relative
115 // encoder position.
116 const double adjusted_absolute_encoder =
117 UnWrap(adjusted_incremental_encoder,
118 sample.absolute_encoder - constants_.measured_absolute_position,
119 constants_.one_revolution_distance);
120
121 // We can now compute the offset now that we have unwrapped the absolute
122 // encoder.
123 const double relative_to_absolute_offset =
124 adjusted_absolute_encoder - sample.encoder;
125
126 // Add the sample and update the average with the new reading.
127 const size_t relative_to_absolute_offset_samples_size =
128 relative_to_absolute_offset_samples_.size();
129 if (relative_to_absolute_offset_samples_size <
130 constants_.average_filter_size) {
131 average_relative_to_absolute_offset =
132 (average_relative_to_absolute_offset *
133 relative_to_absolute_offset_samples_size +
134 relative_to_absolute_offset) /
135 (relative_to_absolute_offset_samples_size + 1);
136
137 relative_to_absolute_offset_samples_.push_back(
138 relative_to_absolute_offset);
139 } else {
140 average_relative_to_absolute_offset -=
141 relative_to_absolute_offset_samples_[samples_idx_] /
142 relative_to_absolute_offset_samples_size;
143 relative_to_absolute_offset_samples_[samples_idx_] =
144 relative_to_absolute_offset;
145 average_relative_to_absolute_offset +=
146 relative_to_absolute_offset /
147 relative_to_absolute_offset_samples_size;
148 }
149
150 const double adjusted_single_turn_absolute_encoder =
milind-ud53408e2021-10-21 19:43:58 -0700151 AdjustedSingleTurnAbsoluteEncoder(sample);
Ravago Jonesea6464c2020-10-10 15:40:46 -0700152
153 // Now compute the offset between the pot and relative encoder.
154 if (offset_samples_.size() < constants_.average_filter_size) {
Ravago Jones937587c2020-12-26 17:21:09 -0800155 offset_samples_.push_back(sample.encoder -
156 adjusted_single_turn_absolute_encoder);
Ravago Jonesea6464c2020-10-10 15:40:46 -0700157 } else {
158 offset_samples_[samples_idx_] =
Ravago Jones937587c2020-12-26 17:21:09 -0800159 sample.encoder - adjusted_single_turn_absolute_encoder;
Ravago Jonesea6464c2020-10-10 15:40:46 -0700160 }
161
162 // Drop the oldest sample when we run this function the next time around.
163 samples_idx_ = (samples_idx_ + 1) % constants_.average_filter_size;
164
165 single_turn_to_relative_encoder_offset_ =
166 ::std::accumulate(offset_samples_.begin(), offset_samples_.end(), 0.0) /
167 offset_samples_.size();
168
Ravago Jones937587c2020-12-26 17:21:09 -0800169 offset_ = UnWrap(sample.encoder - single_turn_to_relative_encoder_offset_,
Ravago Jonesea6464c2020-10-10 15:40:46 -0700170 average_relative_to_absolute_offset + sample.encoder,
171 constants_.one_revolution_distance) -
172 sample.encoder;
173
174 // Reverse the math for adjusted_absolute_encoder to compute the absolute
175 // encoder. Do this by taking the adjusted encoder, and then subtracting off
176 // the second argument above, and the value that was added by Wrap.
177 filtered_absolute_encoder_ =
178 ((sample.encoder + average_relative_to_absolute_offset) -
179 (-constants_.measured_absolute_position +
180 (adjusted_absolute_encoder -
181 (sample.absolute_encoder - constants_.measured_absolute_position))));
182
Ravago Jones937587c2020-12-26 17:21:09 -0800183 const double what_Unwrap_added =
184 (adjusted_single_turn_absolute_encoder -
185 (sample.single_turn_absolute_encoder -
186 constants_.single_turn_measured_absolute_position));
187
Ravago Jonesea6464c2020-10-10 15:40:46 -0700188 // TODO(Ravago): this is impossible to read.
189 filtered_single_turn_absolute_encoder_ =
Ravago Jones937587c2020-12-26 17:21:09 -0800190 ((sample.encoder - single_turn_to_relative_encoder_offset_) -
Ravago Jonesea6464c2020-10-10 15:40:46 -0700191 (-constants_.single_turn_measured_absolute_position +
Ravago Jones937587c2020-12-26 17:21:09 -0800192 what_Unwrap_added));
193
Ravago Jones937587c2020-12-26 17:21:09 -0800194 if (!zeroed_) {
195 first_offset_ = offset_;
196 }
Ravago Jonesea6464c2020-10-10 15:40:46 -0700197
198 if (offset_ready()) {
Ravago Jonesea6464c2020-10-10 15:40:46 -0700199 if (::std::abs(first_offset_ - offset_) >
200 constants_.allowable_encoder_error *
201 constants_.one_revolution_distance) {
Ravago Jones937587c2020-12-26 17:21:09 -0800202 AOS_LOG(INFO,
203 "Offset moved too far. Initial: %f, current %f, allowable "
204 "change: %f ",
205 first_offset_, offset_,
206 constants_.allowable_encoder_error *
207 constants_.one_revolution_distance);
Ravago Jonesea6464c2020-10-10 15:40:46 -0700208 error_ = true;
Ravago Jones726deb02021-05-29 14:36:43 -0700209 errors_.Set(ZeroingError::OFFSET_MOVED_TOO_FAR);
Ravago Jonesea6464c2020-10-10 15:40:46 -0700210 }
211
212 zeroed_ = true;
213 }
214 }
215
216 // Update the position.
Ravago Jones937587c2020-12-26 17:21:09 -0800217 position_ = first_offset_ + info.encoder();
Ravago Jonesea6464c2020-10-10 15:40:46 -0700218}
219
220flatbuffers::Offset<AbsoluteAndAbsoluteEncoderZeroingEstimator::State>
221AbsoluteAndAbsoluteEncoderZeroingEstimator::GetEstimatorState(
222 flatbuffers::FlatBufferBuilder *fbb) const {
Ravago Jones726deb02021-05-29 14:36:43 -0700223 flatbuffers::Offset<flatbuffers::Vector<ZeroingError>> errors_offset =
224 errors_.ToFlatbuffer(fbb);
225
Ravago Jonesea6464c2020-10-10 15:40:46 -0700226 State::Builder builder(*fbb);
227 builder.add_error(error_);
Ravago Jones726deb02021-05-29 14:36:43 -0700228 builder.add_errors(errors_offset);
Ravago Jonesea6464c2020-10-10 15:40:46 -0700229 builder.add_zeroed(zeroed_);
230 builder.add_position(position_);
231 builder.add_absolute_position(filtered_absolute_encoder_);
232 builder.add_single_turn_absolute_position(
233 filtered_single_turn_absolute_encoder_);
234 return builder.Finish();
235}
236
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800237} // namespace frc971::zeroing