Brian Silverman | a57b701 | 2020-03-11 20:19:23 -0700 | [diff] [blame^] | 1 | #include "frc971/zeroing/pulse_index.h" |
| 2 | |
| 3 | #include <cmath> |
| 4 | #include <limits> |
| 5 | |
| 6 | #include "glog/logging.h" |
| 7 | |
| 8 | namespace frc971 { |
| 9 | namespace zeroing { |
| 10 | |
| 11 | void PulseIndexZeroingEstimator::Reset() { |
| 12 | max_index_position_ = ::std::numeric_limits<double>::lowest(); |
| 13 | min_index_position_ = ::std::numeric_limits<double>::max(); |
| 14 | offset_ = 0; |
| 15 | last_used_index_pulse_count_ = 0; |
| 16 | zeroed_ = false; |
| 17 | error_ = false; |
| 18 | } |
| 19 | |
| 20 | void PulseIndexZeroingEstimator::StoreIndexPulseMaxAndMin( |
| 21 | const IndexPosition &info) { |
| 22 | // If we have a new index pulse. |
| 23 | if (last_used_index_pulse_count_ != info.index_pulses()) { |
| 24 | // If the latest pulses's position is outside the range we've currently |
| 25 | // seen, record it appropriately. |
| 26 | if (info.latched_encoder() > max_index_position_) { |
| 27 | max_index_position_ = info.latched_encoder(); |
| 28 | } |
| 29 | if (info.latched_encoder() < min_index_position_) { |
| 30 | min_index_position_ = info.latched_encoder(); |
| 31 | } |
| 32 | last_used_index_pulse_count_ = info.index_pulses(); |
| 33 | } |
| 34 | } |
| 35 | |
| 36 | int PulseIndexZeroingEstimator::IndexPulseCount() const { |
| 37 | if (min_index_position_ > max_index_position_) { |
| 38 | // This condition means we haven't seen a pulse yet. |
| 39 | return 0; |
| 40 | } |
| 41 | |
| 42 | // Calculate the number of pulses encountered so far. |
| 43 | return 1 + static_cast<int>( |
| 44 | ::std::round((max_index_position_ - min_index_position_) / |
| 45 | constants_.index_difference)); |
| 46 | } |
| 47 | |
| 48 | void PulseIndexZeroingEstimator::UpdateEstimate(const IndexPosition &info) { |
| 49 | StoreIndexPulseMaxAndMin(info); |
| 50 | const int index_pulse_count = IndexPulseCount(); |
| 51 | if (index_pulse_count > constants_.index_pulse_count) { |
| 52 | if (!error_) { |
| 53 | VLOG(1) << "Got more index pulses than expected. Got " |
| 54 | << index_pulse_count << " expected " |
| 55 | << constants_.index_pulse_count; |
| 56 | error_ = true; |
| 57 | } |
| 58 | } |
| 59 | |
| 60 | // TODO(austin): Detect if the encoder or index pulse is unplugged. |
| 61 | // TODO(austin): Detect missing counts. |
| 62 | |
| 63 | if (index_pulse_count == constants_.index_pulse_count && !zeroed_) { |
| 64 | offset_ = constants_.measured_index_position - |
| 65 | constants_.known_index_pulse * constants_.index_difference - |
| 66 | min_index_position_; |
| 67 | zeroed_ = true; |
| 68 | } else if (zeroed_ && !error_) { |
| 69 | // Detect whether the index pulse is somewhere other than where we expect |
| 70 | // it to be. First we compute the position of the most recent index pulse. |
| 71 | double index_pulse_distance = |
| 72 | info.latched_encoder() + offset_ - constants_.measured_index_position; |
| 73 | // Second we compute the position of the index pulse in terms of |
| 74 | // the index difference. I.e. if this index pulse is two pulses away from |
| 75 | // the index pulse that we know about then this number should be positive |
| 76 | // or negative two. |
| 77 | double relative_distance = |
| 78 | index_pulse_distance / constants_.index_difference; |
| 79 | // Now we compute how far away the measured index pulse is from the |
| 80 | // expected index pulse. |
| 81 | double error = relative_distance - ::std::round(relative_distance); |
| 82 | // This lets us check if the index pulse is within an acceptable error |
| 83 | // margin of where we expected it to be. |
| 84 | if (::std::abs(error) > constants_.allowable_encoder_error) { |
| 85 | VLOG(1) |
| 86 | << "Encoder ticks out of range since last index pulse. known index " |
| 87 | "pulse: " |
| 88 | << constants_.measured_index_position << ", expected index pulse: " |
| 89 | << round(relative_distance) * constants_.index_difference + |
| 90 | constants_.measured_index_position |
| 91 | << ", actual index pulse: " << info.latched_encoder() + offset_ |
| 92 | << ", " |
| 93 | "allowable error: " |
| 94 | << constants_.allowable_encoder_error * constants_.index_difference; |
| 95 | error_ = true; |
| 96 | } |
| 97 | } |
| 98 | |
| 99 | position_ = info.encoder() + offset_; |
| 100 | } |
| 101 | |
| 102 | flatbuffers::Offset<PulseIndexZeroingEstimator::State> |
| 103 | PulseIndexZeroingEstimator::GetEstimatorState( |
| 104 | flatbuffers::FlatBufferBuilder *fbb) const { |
| 105 | State::Builder builder(*fbb); |
| 106 | builder.add_error(error_); |
| 107 | builder.add_zeroed(zeroed_); |
| 108 | builder.add_position(position_); |
| 109 | builder.add_min_index_position(min_index_position_); |
| 110 | builder.add_max_index_position(max_index_position_); |
| 111 | builder.add_index_pulses_seen(IndexPulseCount()); |
| 112 | return builder.Finish(); |
| 113 | } |
| 114 | |
| 115 | } // namespace zeroing |
| 116 | } // namespace frc971 |