blob: e0746682196ebf686e129d828535dce87709bfec [file] [log] [blame]
Brian Silvermana57b7012020-03-11 20:19:23 -07001#include "frc971/zeroing/hall_effect_and_position.h"
2
3#include <algorithm>
4#include <cmath>
5#include <limits>
6
7#include "glog/logging.h"
8
9namespace frc971 {
10namespace zeroing {
11
12HallEffectAndPositionZeroingEstimator::HallEffectAndPositionZeroingEstimator(
13 const ZeroingConstants &constants)
14 : constants_(constants) {
15 Reset();
16}
17
18void HallEffectAndPositionZeroingEstimator::Reset() {
19 offset_ = 0.0;
20 min_low_position_ = ::std::numeric_limits<double>::max();
21 max_low_position_ = ::std::numeric_limits<double>::lowest();
22 zeroed_ = false;
23 initialized_ = false;
24 last_used_posedge_count_ = 0;
25 cycles_high_ = 0;
26 high_long_enough_ = false;
27 first_start_pos_ = 0.0;
28 error_ = false;
29 current_ = 0.0;
30 first_start_pos_ = 0.0;
31}
32
33void HallEffectAndPositionZeroingEstimator::TriggerError() {
34 if (!error_) {
35 VLOG(1) << "Manually triggered zeroing error.\n";
36 error_ = true;
37 }
38}
39
40void HallEffectAndPositionZeroingEstimator::StoreEncoderMaxAndMin(
41 const HallEffectAndPosition &info) {
42 // If we have a new posedge.
43 if (!info.current()) {
44 if (last_hall_) {
45 min_low_position_ = max_low_position_ = info.encoder();
46 } else {
47 min_low_position_ = ::std::min(min_low_position_, info.encoder());
48 max_low_position_ = ::std::max(max_low_position_, info.encoder());
49 }
50 }
51 last_hall_ = info.current();
52}
53
54void HallEffectAndPositionZeroingEstimator::UpdateEstimate(
55 const HallEffectAndPosition &info) {
56 // We want to make sure that we encounter at least one posedge while zeroing.
57 // So we take the posedge count from the first sample after reset and wait for
58 // that count to change and for the hall effect to stay high before we
59 // consider ourselves zeroed.
60 if (!initialized_) {
61 last_used_posedge_count_ = info.posedge_count();
62 initialized_ = true;
63 last_hall_ = info.current();
64 }
65
66 StoreEncoderMaxAndMin(info);
67
68 if (info.current()) {
69 cycles_high_++;
70 } else {
71 cycles_high_ = 0;
72 last_used_posedge_count_ = info.posedge_count();
73 }
74
75 high_long_enough_ = cycles_high_ >= constants_.hall_trigger_zeroing_length;
76
77 bool moving_backward = false;
78 if (constants_.zeroing_move_direction) {
79 moving_backward = info.encoder() > min_low_position_;
80 } else {
81 moving_backward = info.encoder() < max_low_position_;
82 }
83
84 // If there are no posedges to use or we don't have enough samples yet to
85 // have a well-filtered starting position then we use the filtered value as
86 // our best guess.
87 if (last_used_posedge_count_ != info.posedge_count() && high_long_enough_ &&
88 moving_backward) {
89 // Note the offset and the current posedge count so that we only run this
90 // logic once per posedge. That should be more resilient to corrupted
91 // intermediate data.
92 offset_ = -info.posedge_value();
93 if (constants_.zeroing_move_direction) {
94 offset_ += constants_.lower_hall_position;
95 } else {
96 offset_ += constants_.upper_hall_position;
97 }
98 last_used_posedge_count_ = info.posedge_count();
99
100 // Save the first starting position.
101 if (!zeroed_) {
102 first_start_pos_ = offset_;
103 VLOG(2) << "latching start position" << first_start_pos_;
104 }
105
106 // Now that we have an accurate starting position we can consider ourselves
107 // zeroed.
108 zeroed_ = true;
109 }
110
111 position_ = info.encoder() - offset_;
112}
113
114flatbuffers::Offset<HallEffectAndPositionZeroingEstimator::State>
115HallEffectAndPositionZeroingEstimator::GetEstimatorState(
116 flatbuffers::FlatBufferBuilder *fbb) const {
117 State::Builder builder(*fbb);
118 builder.add_error(error_);
119 builder.add_zeroed(zeroed_);
120 builder.add_encoder(position_);
121 builder.add_high_long_enough(high_long_enough_);
122 builder.add_offset(offset_);
123 return builder.Finish();
124}
125
126} // namespace zeroing
127} // namespace frc971