blob: f5deb67f3e722be07cff6327867979ee70302153 [file] [log] [blame]
James Kuszmaulb5e497c2013-03-02 15:14:13 -08001#ifndef FRC971_CONTROL_LOOPS_HALL_EFFECT_INL_H_
2#define FRC971_CONTROL_LOOPS_HALL_EFFECT_INL_H_
3
4#include "frc971/control_loops/hall_effect_loop.h"
5
6#include "aos/aos_core.h"
7
8#include "aos/common/messages/RobotState.q.h"
9#include "aos/common/logging/logging.h"
10
11namespace frc971 {
12namespace control_loops {
13
14template <int kNumHallEffect>
15HallEffectLoop<kNumHallEffect>::HallEffectLoop(
16 StateFeedbackLoop<2, 1, 1>* state_feedback_loop,
17 bool zero_down, double max_zeroing_voltage)
18 : kMaxZeroingVoltage(max_zeroing_voltage),
19 zero_down_(zero_down),
20 state_(UNINITIALIZED),
21 loop_(state_feedback_loop),
22 current_position_(0.0),
23 last_off_position_(0.0),
24 last_calibration_sensor_(-1),
25 zeroing_position_(0.0),
26 zero_offset_(0.0),
27 old_zero_offset_(0.0) {
28}
29
30template <int kNumHallEffect>
31int HallEffectLoop<kNumHallEffect>::HallEffect() const {
32 for (int i = 0; i < kNumHallEffect; ++i) {
33 if (hall_effect_[i]) {
34 return i;
35 }
36 }
37 return -1;
38}
39
40template <int kNumHallEffect>
41int HallEffectLoop<kNumHallEffect>::WhichHallEffect() const {
42 if (zero_down_) {
43 for (int i = 0; i < kNumHallEffect; ++i) {
44 if (calibration_[i] + hall_effect_angle_[i] < last_off_position_ &&
45 calibration_[i] + hall_effect_angle_[i] >= current_position_) {
46 return i;
47 }
48 }
49 } else {
50 for (int i = 0; i < kNumHallEffect; ++i) {
51 if (calibration_[i] + hall_effect_angle_[i] > last_off_position_ &&
52 calibration_[i] + hall_effect_angle_[i] <= current_position_) {
53 return i;
54 }
55 }
56 }
57 return -1;
58}
59
60template <int kNumHallEffect>
61void HallEffectLoop<kNumHallEffect>::LimitZeroingGoal() {
62 if (loop_->U_uncapped(0, 0) > kMaxZeroingVoltage) {
63 double excess = (loop_->U_uncapped(0, 0) - kMaxZeroingVoltage)
64 / loop_->K(0, 0);
65 zeroing_position_ -= excess;
66 }
67 if (loop_->U_uncapped(0, 0) < -kMaxZeroingVoltage) {
68 double excess = (loop_->U_uncapped(0, 0) + kMaxZeroingVoltage)
69 / loop_->K(0, 0);
70 zeroing_position_ -= excess;
71 }
72}
73
74template <int kNumHallEffect>
75void HallEffectLoop<kNumHallEffect>::UpdateZeros(
76 ::std::array<double, kNumHallEffect> hall_effect_angle,
77 ::std::array<bool, kNumHallEffect> hall_effect,
78 ::std::array<double, kNumHallEffect> calibration,
79 double zeroing_speed,
80 double position, bool good_position) {
81 hall_effect_angle_ = hall_effect_angle;
82 hall_effect_ = hall_effect;
83 calibration_ = calibration;
84 zeroing_speed_ = zeroing_speed;
85 current_position_ = position;
86
87 if (!zero_down_) {
88 zeroing_speed_ *= -1;
89 }
90
91 // Deal with getting all the position variables updated.
92 absolute_position_ = current_position_;
93 if (good_position) {
94 if (state_ == READY) {
95 absolute_position_ -= zero_offset_;
96 }
97 loop_->Y << absolute_position_;
98 if (HallEffect() == -1) {
99 last_off_position_ = current_position_;
100 }
101 } else {
102 absolute_position_ = loop_->X_hat(0, 0);
103 }
104
105 // switch for dealing with various zeroing states.
106 switch (state_) {
107 case UNINITIALIZED:
108 LOG(DEBUG, "status_: UNINITIALIZED\n");
109 last_calibration_sensor_ = -1;
110 if (good_position) {
111 // Reset the zeroing goal.
112 zeroing_position_ = absolute_position_;
113 // Clear the observer state.
114 loop_->X_hat << absolute_position_, 0.0;
115 // Only progress if we are enabled.
116 if (::aos::robot_state->enabled) {
117 if (HallEffect() != -1) {
118 state_ = MOVING_OFF;
119 } else {
120 state_ = ZEROING;
121 }
122 } else {
123 loop_->R << absolute_position_, 0.0;
124 }
125 }
126 break;
127 case MOVING_OFF:
128 LOG(DEBUG, "status_: MOVING_OFF\n");
129 // Move off the hall effect sensor.
130 if (!::aos::robot_state->enabled) {
131 // Start over if disabled.
132 state_ = UNINITIALIZED;
133 } else if (good_position && (HallEffect() == -1)) {
134 // We are now off the sensor. Time to zero now.
135 state_ = ZEROING;
136 } else {
137 // Slowly creep off the sensor.
138 zeroing_position_ += zeroing_speed_ * dt;
139 loop_->R << zeroing_position_, zeroing_speed_;
140 break;
141 }
142 case ZEROING:
143 LOG(DEBUG, "status_: ZEROING\n");
144 if (!::aos::robot_state->enabled) {
145 // Start over if disabled.
146 state_ = UNINITIALIZED;
147 } else if (good_position && (HallEffect() != -1)) {
148 state_ = READY;
149 // Verify that the calibration number is between the last off position
150 // and the current on position. If this is not true, move off and try
151 // again.
152 if (WhichHallEffect() == -1) {
153 LOG(ERROR, "Got a bogus calibration number. Trying again.\n");
154 LOG(ERROR,
155 "Last off position was %f, current is %f,\n",
156 last_off_position_, current_position_);
157 state_ = MOVING_OFF;
158 } else {
159 // Save the zero, and then offset the observer to deal with the
160 // phantom step change.
161 const double old_zero_offset = zero_offset_;
162 zero_offset_ = calibration_[WhichHallEffect()];
163 loop_->X_hat(0, 0) += old_zero_offset - zero_offset_;
164 loop_->Y(0, 0) += old_zero_offset - zero_offset_;
165 last_calibration_sensor_ = WhichHallEffect();
166 }
167 } else {
168 // Slowly creep towards the sensor.
169 zeroing_position_ -= zeroing_speed_ * dt;
170 loop_->R << zeroing_position_, -zeroing_speed_;
171 }
172 break;
173
174 case READY:
175 {
176 LOG(DEBUG, "status_: READY\n");
177 break;
178 }
179
180 case ESTOP:
181 LOG(WARNING, "have already given up\n");
182 return;
183 }
184
185 if (state_ == MOVING_OFF || state_ == ZEROING) {
186 LimitZeroingGoal();
187 }
188
189 if (good_position) {
190 LOG(DEBUG,
191 "calibration sensor: %d zero_offset: %f absolute_position: %f\n",
192 last_calibration_sensor_, zero_offset_, absolute_position_);
193 }
194
195} // UpdateZeros
196
197} // namespace control_loops
198} // namespace frc971
199
200#endif // FRC971_CONTROL_LOOPS_HALL_EFFECT_INL_H_