blob: 0645d43b36246efd26656ee31b300934e37b87f7 [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
11namespace frc971 {
12namespace zeroing {
13
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
38// So, this needs to be a multistep process. We need to first estimate the
39// offset between the absolute encoder and the relative encoder. That process
40// should get us an absolute number which is off by integer multiples of the
41// distance/rev. In parallel, we can estimate the offset between the single
42// turn encoder and encoder. When both estimates have converged, we can then
43// compute the offset in a cycle, and which cycle, which gives us the accurate
44// global offset.
45//
46// It's tricky to compute the offset between the absolute and relative encoder.
47// We need to compute this inside 1 revolution. The easiest way to do this
48// would be to wrap the encoder, subtract the two of them, and then average the
49// result. That will struggle when they are off by PI. Instead, we need to
50// wrap the number to +- PI from the current averaged offset.
51//
52// To guard against the robot moving while updating estimates, buffer a number
53// of samples and check that the buffered samples are not different than the
54// zeroing threshold. At any point that the samples differ too much, do not
55// update estimates based on those samples.
56void AbsoluteAndAbsoluteEncoderZeroingEstimator::UpdateEstimate(
57 const AbsoluteAndAbsolutePosition &info) {
58 // Check for Abs Encoder NaN value that would mess up the rest of the zeroing
59 // code below. NaN values are given when the Absolute Encoder is disconnected.
Ravago Jones937587c2020-12-26 17:21:09 -080060 if (::std::isnan(info.absolute_encoder()) ||
61 ::std::isnan(info.single_turn_absolute_encoder())) {
Ravago Jonesea6464c2020-10-10 15:40:46 -070062 if (zeroed_) {
Ravago Jones937587c2020-12-26 17:21:09 -080063 VLOG(1) << "NAN on one of the absolute encoders.";
Ravago Jonesea6464c2020-10-10 15:40:46 -070064 error_ = true;
65 } else {
66 ++nan_samples_;
Ravago Jones937587c2020-12-26 17:21:09 -080067 VLOG(1) << "NAN on one of the absolute encoders while zeroing"
68 << nan_samples_;
Ravago Jonesea6464c2020-10-10 15:40:46 -070069 if (nan_samples_ >= constants_.average_filter_size) {
70 error_ = true;
71 zeroed_ = true;
72 }
73 }
74 // Throw some dummy values in for now.
75 filtered_absolute_encoder_ = info.absolute_encoder();
Ravago Jones937587c2020-12-26 17:21:09 -080076 filtered_single_turn_absolute_encoder_ =
77 info.single_turn_absolute_encoder();
Ravago Jonesea6464c2020-10-10 15:40:46 -070078 filtered_position_ =
79 single_turn_to_relative_encoder_offset_ + info.encoder();
80 position_ = offset_ + info.encoder();
81 return;
82 }
83
84 const bool moving = move_detector_.Update(info, constants_.moving_buffer_size,
85 constants_.zeroing_threshold);
86
87 if (!moving) {
88 const PositionStruct &sample = move_detector_.GetSample();
89
90 // Compute the average offset between the absolute encoder and relative
91 // encoder. If we have 0 samples, assume it is 0.
92 double average_relative_to_absolute_offset =
93 relative_to_absolute_offset_samples_.size() == 0
94 ? 0.0
95 : ::std::accumulate(relative_to_absolute_offset_samples_.begin(),
96 relative_to_absolute_offset_samples_.end(),
97 0.0) /
98 relative_to_absolute_offset_samples_.size();
99
100 const double adjusted_incremental_encoder =
101 sample.encoder + average_relative_to_absolute_offset;
102
103 // Now, compute the nearest absolute encoder value to the offset relative
104 // encoder position.
105 const double adjusted_absolute_encoder =
106 UnWrap(adjusted_incremental_encoder,
107 sample.absolute_encoder - constants_.measured_absolute_position,
108 constants_.one_revolution_distance);
109
110 // We can now compute the offset now that we have unwrapped the absolute
111 // encoder.
112 const double relative_to_absolute_offset =
113 adjusted_absolute_encoder - sample.encoder;
114
115 // Add the sample and update the average with the new reading.
116 const size_t relative_to_absolute_offset_samples_size =
117 relative_to_absolute_offset_samples_.size();
118 if (relative_to_absolute_offset_samples_size <
119 constants_.average_filter_size) {
120 average_relative_to_absolute_offset =
121 (average_relative_to_absolute_offset *
122 relative_to_absolute_offset_samples_size +
123 relative_to_absolute_offset) /
124 (relative_to_absolute_offset_samples_size + 1);
125
126 relative_to_absolute_offset_samples_.push_back(
127 relative_to_absolute_offset);
128 } else {
129 average_relative_to_absolute_offset -=
130 relative_to_absolute_offset_samples_[samples_idx_] /
131 relative_to_absolute_offset_samples_size;
132 relative_to_absolute_offset_samples_[samples_idx_] =
133 relative_to_absolute_offset;
134 average_relative_to_absolute_offset +=
135 relative_to_absolute_offset /
136 relative_to_absolute_offset_samples_size;
137 }
138
139 const double adjusted_single_turn_absolute_encoder =
140 UnWrap(constants_.single_turn_middle_position,
141 sample.single_turn_absolute_encoder -
142 constants_.single_turn_measured_absolute_position,
143 constants_.single_turn_one_revolution_distance);
144
145 // Now compute the offset between the pot and relative encoder.
146 if (offset_samples_.size() < constants_.average_filter_size) {
Ravago Jones937587c2020-12-26 17:21:09 -0800147 offset_samples_.push_back(sample.encoder -
148 adjusted_single_turn_absolute_encoder);
Ravago Jonesea6464c2020-10-10 15:40:46 -0700149 } else {
150 offset_samples_[samples_idx_] =
Ravago Jones937587c2020-12-26 17:21:09 -0800151 sample.encoder - adjusted_single_turn_absolute_encoder;
Ravago Jonesea6464c2020-10-10 15:40:46 -0700152 }
153
154 // Drop the oldest sample when we run this function the next time around.
155 samples_idx_ = (samples_idx_ + 1) % constants_.average_filter_size;
156
157 single_turn_to_relative_encoder_offset_ =
158 ::std::accumulate(offset_samples_.begin(), offset_samples_.end(), 0.0) /
159 offset_samples_.size();
160
Ravago Jones937587c2020-12-26 17:21:09 -0800161 offset_ = UnWrap(sample.encoder - single_turn_to_relative_encoder_offset_,
Ravago Jonesea6464c2020-10-10 15:40:46 -0700162 average_relative_to_absolute_offset + sample.encoder,
163 constants_.one_revolution_distance) -
164 sample.encoder;
165
166 // Reverse the math for adjusted_absolute_encoder to compute the absolute
167 // encoder. Do this by taking the adjusted encoder, and then subtracting off
168 // the second argument above, and the value that was added by Wrap.
169 filtered_absolute_encoder_ =
170 ((sample.encoder + average_relative_to_absolute_offset) -
171 (-constants_.measured_absolute_position +
172 (adjusted_absolute_encoder -
173 (sample.absolute_encoder - constants_.measured_absolute_position))));
174
Ravago Jones937587c2020-12-26 17:21:09 -0800175 const double what_Unwrap_added =
176 (adjusted_single_turn_absolute_encoder -
177 (sample.single_turn_absolute_encoder -
178 constants_.single_turn_measured_absolute_position));
179
Ravago Jonesea6464c2020-10-10 15:40:46 -0700180 // TODO(Ravago): this is impossible to read.
181 filtered_single_turn_absolute_encoder_ =
Ravago Jones937587c2020-12-26 17:21:09 -0800182 ((sample.encoder - single_turn_to_relative_encoder_offset_) -
Ravago Jonesea6464c2020-10-10 15:40:46 -0700183 (-constants_.single_turn_measured_absolute_position +
Ravago Jones937587c2020-12-26 17:21:09 -0800184 what_Unwrap_added));
185
186 /*
187 filtered_single_turn_absolute_encoder_ =
188 sample.encoder - single_turn_to_relative_encoder_offset_;
189 */
190
191 if (!zeroed_) {
192 first_offset_ = offset_;
193 }
Ravago Jonesea6464c2020-10-10 15:40:46 -0700194
195 if (offset_ready()) {
Ravago Jonesea6464c2020-10-10 15:40:46 -0700196 if (::std::abs(first_offset_ - offset_) >
197 constants_.allowable_encoder_error *
198 constants_.one_revolution_distance) {
Ravago Jones937587c2020-12-26 17:21:09 -0800199 AOS_LOG(INFO,
200 "Offset moved too far. Initial: %f, current %f, allowable "
201 "change: %f ",
202 first_offset_, offset_,
203 constants_.allowable_encoder_error *
204 constants_.one_revolution_distance);
Ravago Jonesea6464c2020-10-10 15:40:46 -0700205 error_ = true;
206 }
207
208 zeroed_ = true;
209 }
210 }
211
212 // Update the position.
Ravago Jones937587c2020-12-26 17:21:09 -0800213 position_ = first_offset_ + info.encoder();
Ravago Jonesea6464c2020-10-10 15:40:46 -0700214}
215
216flatbuffers::Offset<AbsoluteAndAbsoluteEncoderZeroingEstimator::State>
217AbsoluteAndAbsoluteEncoderZeroingEstimator::GetEstimatorState(
218 flatbuffers::FlatBufferBuilder *fbb) const {
219 State::Builder builder(*fbb);
220 builder.add_error(error_);
221 builder.add_zeroed(zeroed_);
222 builder.add_position(position_);
223 builder.add_absolute_position(filtered_absolute_encoder_);
224 builder.add_single_turn_absolute_position(
225 filtered_single_turn_absolute_encoder_);
226 return builder.Finish();
227}
228
229} // namespace zeroing
230} // namespace frc971