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