blob: 10ea25f7fa11f5227e08c4c9b770d3bcb7d3fff8 [file] [log] [blame]
Austin Schuh3bb9a442014-02-02 16:01:45 -08001#include "frc971/control_loops/claw/claw.h"
2
Austin Schuh3bb9a442014-02-02 16:01:45 -08003#include <algorithm>
4
Briana6553ed2014-04-02 21:26:46 -07005#include "aos/common/controls/control_loops.q.h"
Austin Schuh3bb9a442014-02-02 16:01:45 -08006#include "aos/common/logging/logging.h"
Brian Silvermanf48fab32014-03-09 14:32:24 -07007#include "aos/common/logging/queue_logging.h"
Brian Silverman6dd2c532014-03-29 23:34:39 -07008#include "aos/common/logging/matrix_logging.h"
Brian Silvermanad9e0002014-04-13 14:55:57 -07009#include "aos/common/commonmath.h"
Austin Schuh3bb9a442014-02-02 16:01:45 -080010
11#include "frc971/constants.h"
Austin Schuhcda86af2014-02-16 16:16:39 -080012#include "frc971/control_loops/claw/claw_motor_plant.h"
13
Austin Schuh3bb9a442014-02-02 16:01:45 -080014// Zeroing plan.
15// There are 2 types of zeros. Enabled and disabled ones.
16// Disabled ones are only valid during auto mode, and can be used to speed up
17// the enabled zero process. We need to re-zero during teleop in case the auto
18// zero was poor and causes us to miss all our shots.
19//
20// We need to be able to zero manually while disabled by moving the joint over
21// the zeros.
22// Zero on the down edge when disabled (gravity in the direction of motion)
23//
24// When enabled, zero on the up edge (gravity opposing the direction of motion)
25// The enabled sequence needs to work as follows. We can crash the claw if we
26// bring them too close to each other or too far from each other. The only safe
27// thing to do is to move them in unison.
28//
29// Start by moving them both towards the front of the bot to either find either
30// the middle hall effect on either jaw, or the front hall effect on the bottom
31// jaw. Any edge that isn't the desired edge will provide an approximate edge
32// location that can be used for the fine tuning step.
33// Once an edge is found on the front claw, move back the other way with both
34// claws until an edge is found for the other claw.
35// Now that we have an approximate zero, we can robustify the limits to keep
36// both claws safe. Then, we can move both claws to a position that is the
37// correct side of the zero and go zero.
38
39// Valid region plan.
Ben Fredrickson81ba2d52014-03-02 08:21:46 +000040// Difference between the arms has a range, and the values of each arm has a
41// range.
Austin Schuh3bb9a442014-02-02 16:01:45 -080042// If a claw runs up against a static limit, don't let the goal change outside
43// the limit.
44// If a claw runs up against a movable limit, move both claws outwards to get
45// out of the condition.
46
47namespace frc971 {
48namespace control_loops {
49
Austin Schuh01c652b2014-02-21 23:13:42 -080050static const double kZeroingVoltage = 4.0;
51static const double kMaxVoltage = 12.0;
Austin Schuh3ba10f022014-12-14 14:19:51 -080052const double kRezeroThreshold = 0.07;
Austin Schuhf84a1302014-02-19 00:23:30 -080053
Brian Silverman0a151c92014-05-02 15:28:44 -070054ClawLimitedLoop::ClawLimitedLoop(StateFeedbackLoop<4, 2, 2> &&loop)
55 : StateFeedbackLoop<4, 2, 2>(::std::move(loop)),
Austin Schuh27b8fb12014-02-22 15:10:05 -080056 uncapped_average_voltage_(0.0),
James Kuszmaulf63b0ae2014-03-25 16:52:11 -070057 is_zeroing_(true),
58 U_Poly_((Eigen::Matrix<double, 4, 2>() << 1, 0,
59 -1, 0,
60 0, 1,
61 0, -1).finished(),
62 (Eigen::Matrix<double, 4, 1>() << kMaxVoltage, kMaxVoltage,
Brian Silverman6dd2c532014-03-29 23:34:39 -070063 kMaxVoltage, kMaxVoltage).finished()),
64 U_Poly_zeroing_((Eigen::Matrix<double, 4, 2>() << 1, 0,
65 -1, 0,
66 0, 1,
67 0, -1).finished(),
68 (Eigen::Matrix<double, 4, 1>() <<
69 kZeroingVoltage, kZeroingVoltage,
70 kZeroingVoltage, kZeroingVoltage).finished()) {
James Kuszmaulf63b0ae2014-03-25 16:52:11 -070071 ::aos::controls::HPolytope<0>::Init();
72}
Austin Schuh27b8fb12014-02-22 15:10:05 -080073
James Kuszmaulf63b0ae2014-03-25 16:52:11 -070074// Caps the voltage prioritizing reducing velocity error over reducing
75// positional error.
76// Uses the polytope libararies which we used to just use for the drivetrain.
77// Uses a region representing the maximum voltage and then transforms it such
78// that the points represent different amounts of positional error and
79// constrains the region such that, if at all possible, it will maintain its
80// current efforts to reduce velocity error.
Austin Schuhcda86af2014-02-16 16:16:39 -080081void ClawLimitedLoop::CapU() {
Brian Silverman273d8a32014-05-10 22:19:09 -070082 const Eigen::Matrix<double, 4, 1> error = R() - X_hat();
Austin Schuh4cb047f2014-02-16 21:10:19 -080083
Brian Silvermana21c3a22014-06-12 21:49:15 -070084 double u_top = U(1, 0);
85 double u_bottom = U(0, 0);
Austin Schuhcda86af2014-02-16 16:16:39 -080086
James Kuszmaulf63b0ae2014-03-25 16:52:11 -070087 uncapped_average_voltage_ = (u_top + u_bottom) / 2;
88
89 double max_voltage = is_zeroing_ ? kZeroingVoltage : kMaxVoltage;
90
Brian Silvermanad9e0002014-04-13 14:55:57 -070091 if (::std::abs(u_bottom) > max_voltage || ::std::abs(u_top) > max_voltage) {
Brian Silverman273d8a32014-05-10 22:19:09 -070092 LOG_MATRIX(DEBUG, "U at start", U());
James Kuszmaulf63b0ae2014-03-25 16:52:11 -070093 // H * U <= k
94 // U = UPos + UVel
95 // H * (UPos + UVel) <= k
96 // H * UPos <= k - H * UVel
97
98 // Now, we can do a coordinate transformation and say the following.
99
100 // UPos = position_K * position_error
101 // (H * position_K) * position_error <= k - H * UVel
102
103 Eigen::Matrix<double, 2, 2> position_K;
104 position_K << K(0, 0), K(0, 1),
105 K(1, 0), K(1, 1);
106 Eigen::Matrix<double, 2, 2> velocity_K;
107 velocity_K << K(0, 2), K(0, 3),
108 K(1, 2), K(1, 3);
109
110 Eigen::Matrix<double, 2, 1> position_error;
111 position_error << error(0, 0), error(1, 0);
112 Eigen::Matrix<double, 2, 1> velocity_error;
113 velocity_error << error(2, 0), error(3, 0);
Brian Silverman6dd2c532014-03-29 23:34:39 -0700114 LOG_MATRIX(DEBUG, "error", error);
James Kuszmaulf63b0ae2014-03-25 16:52:11 -0700115
Brian Silverman6dd2c532014-03-29 23:34:39 -0700116 const auto &poly = is_zeroing_ ? U_Poly_zeroing_ : U_Poly_;
117 const Eigen::Matrix<double, 4, 2> pos_poly_H = poly.H() * position_K;
118 const Eigen::Matrix<double, 4, 1> pos_poly_k =
119 poly.k() - poly.H() * velocity_K * velocity_error;
120 const ::aos::controls::HPolytope<2> pos_poly(pos_poly_H, pos_poly_k);
James Kuszmaulf63b0ae2014-03-25 16:52:11 -0700121
Brian Silverman6dd2c532014-03-29 23:34:39 -0700122 Eigen::Matrix<double, 2, 1> adjusted_pos_error;
123 {
124 const auto &P = position_error;
Brian Silvermanb087c0a2014-03-30 12:59:52 -0700125
126 // This line was at 45 degrees but is now at some angle steeper than the
127 // straight one between the points.
128 Eigen::Matrix<double, 1, 2> angle_45;
129 // If the top claw is above its soft upper limit, make the line actually
130 // 45 degrees to avoid smashing it into the limit in an attempt to fix the
131 // separation error faster than the bottom position one.
Brian Silvermana21c3a22014-06-12 21:49:15 -0700132 if (X_hat(0, 0) + X_hat(1, 0) >
Brian Silvermanb087c0a2014-03-30 12:59:52 -0700133 constants::GetValues().claw.upper_claw.upper_limit) {
134 angle_45 << 1, 1;
135 } else {
136 // Fixing separation error half as fast as positional error works well
137 // because it means they both close evenly.
138 angle_45 << ::std::sqrt(3), 1;
139 }
140 Eigen::Matrix<double, 1, 2> L45_quadrant;
Brian Silvermanad9e0002014-04-13 14:55:57 -0700141 L45_quadrant << ::aos::sign(P(1, 0)), -::aos::sign(P(0, 0));
Brian Silvermanb087c0a2014-03-30 12:59:52 -0700142 const auto L45 = L45_quadrant.cwiseProduct(angle_45);
Brian Silverman6dd2c532014-03-29 23:34:39 -0700143 const double w45 = 0;
James Kuszmaulf63b0ae2014-03-25 16:52:11 -0700144
Brian Silverman6dd2c532014-03-29 23:34:39 -0700145 Eigen::Matrix<double, 1, 2> LH;
146 if (::std::abs(P(0, 0)) > ::std::abs(P(1, 0))) {
147 LH << 0, 1;
148 } else {
149 LH << 1, 0;
150 }
151 const double wh = LH.dot(P);
James Kuszmaulf63b0ae2014-03-25 16:52:11 -0700152
Brian Silverman6dd2c532014-03-29 23:34:39 -0700153 Eigen::Matrix<double, 2, 2> standard;
154 standard << L45, LH;
155 Eigen::Matrix<double, 2, 1> W;
156 W << w45, wh;
157 const Eigen::Matrix<double, 2, 1> intersection = standard.inverse() * W;
158
159 bool is_inside_h;
160 const auto adjusted_pos_error_h =
161 DoCoerceGoal(pos_poly, LH, wh, position_error, &is_inside_h);
162 const auto adjusted_pos_error_45 =
163 DoCoerceGoal(pos_poly, L45, w45, intersection, nullptr);
164 if (pos_poly.IsInside(intersection)) {
165 adjusted_pos_error = adjusted_pos_error_h;
166 } else {
167 if (is_inside_h) {
168 if (adjusted_pos_error_h.norm() > adjusted_pos_error_45.norm()) {
169 adjusted_pos_error = adjusted_pos_error_h;
170 } else {
171 adjusted_pos_error = adjusted_pos_error_45;
172 }
173 } else {
174 adjusted_pos_error = adjusted_pos_error_45;
175 }
176 }
177 }
178
179 LOG_MATRIX(DEBUG, "adjusted_pos_error", adjusted_pos_error);
Brian Silverman0ca790b2014-06-12 21:33:08 -0700180 mutable_U() = velocity_K * velocity_error + position_K * adjusted_pos_error;
Brian Silverman273d8a32014-05-10 22:19:09 -0700181 LOG_MATRIX(DEBUG, "U is now", U());
Brian Silverman7b7c9072014-03-30 13:33:30 -0700182
183 {
184 const auto values = constants::GetValues().claw;
Brian Silvermaned9df2f2014-04-05 07:07:15 -0700185 if (top_known_) {
Brian Silvermana21c3a22014-06-12 21:49:15 -0700186 if (X_hat(0, 0) + X_hat(1, 0) > values.upper_claw.upper_limit && U(1, 0) > 0) {
Brian Silvermaned9df2f2014-04-05 07:07:15 -0700187 LOG(WARNING, "upper claw too high and moving up\n");
Brian Silvermana21c3a22014-06-12 21:49:15 -0700188 mutable_U(1, 0) = 0;
189 } else if (X_hat(0, 0) + X_hat(1, 0) < values.upper_claw.lower_limit &&
190 U(1, 0) < 0) {
Brian Silvermaned9df2f2014-04-05 07:07:15 -0700191 LOG(WARNING, "upper claw too low and moving down\n");
Brian Silvermana21c3a22014-06-12 21:49:15 -0700192 mutable_U(1, 0) = 0;
Brian Silvermaned9df2f2014-04-05 07:07:15 -0700193 }
Brian Silverman7b7c9072014-03-30 13:33:30 -0700194 }
Brian Silvermaned9df2f2014-04-05 07:07:15 -0700195 if (bottom_known_) {
Brian Silvermana21c3a22014-06-12 21:49:15 -0700196 if (X_hat(0, 0) > values.lower_claw.upper_limit && U(0, 0) > 0) {
Brian Silvermaned9df2f2014-04-05 07:07:15 -0700197 LOG(WARNING, "lower claw too high and moving up\n");
Brian Silvermana21c3a22014-06-12 21:49:15 -0700198 mutable_U(0, 0) = 0;
199 } else if (X_hat(0, 0) < values.lower_claw.lower_limit && U(0, 0) < 0) {
Brian Silvermaned9df2f2014-04-05 07:07:15 -0700200 LOG(WARNING, "lower claw too low and moving down\n");
Brian Silvermana21c3a22014-06-12 21:49:15 -0700201 mutable_U(0, 0) = 0;
Brian Silvermaned9df2f2014-04-05 07:07:15 -0700202 }
Brian Silverman7b7c9072014-03-30 13:33:30 -0700203 }
204 }
James Kuszmauld536a402014-02-18 22:32:12 -0800205 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800206}
207
Austin Schuh27b8fb12014-02-22 15:10:05 -0800208ZeroedStateFeedbackLoop::ZeroedStateFeedbackLoop(const char *name,
209 ClawMotor *motor)
210 : offset_(0.0),
211 name_(name),
212 motor_(motor),
213 zeroing_state_(UNKNOWN_POSITION),
214 posedge_value_(0.0),
215 negedge_value_(0.0),
216 encoder_(0.0),
217 last_encoder_(0.0) {}
218
219void ZeroedStateFeedbackLoop::SetPositionValues(const HalfClawPosition &claw) {
220 front_.Update(claw.front);
221 calibration_.Update(claw.calibration);
222 back_.Update(claw.back);
223
224 bool any_sensor_triggered = any_triggered();
225 if (any_sensor_triggered && any_triggered_last_) {
226 // We are still on the hall effect and nothing has changed.
227 min_hall_effect_on_angle_ =
228 ::std::min(min_hall_effect_on_angle_, claw.position);
229 max_hall_effect_on_angle_ =
230 ::std::max(max_hall_effect_on_angle_, claw.position);
231 } else if (!any_sensor_triggered && !any_triggered_last_) {
232 // We are still off the hall effect and nothing has changed.
233 min_hall_effect_off_angle_ =
234 ::std::min(min_hall_effect_off_angle_, claw.position);
235 max_hall_effect_off_angle_ =
236 ::std::max(max_hall_effect_off_angle_, claw.position);
237 } else if (any_sensor_triggered && !any_triggered_last_) {
238 // Saw a posedge on the hall effect. Reset the limits.
239 min_hall_effect_on_angle_ = ::std::min(claw.posedge_value, claw.position);
240 max_hall_effect_on_angle_ = ::std::max(claw.posedge_value, claw.position);
241 } else if (!any_sensor_triggered && any_triggered_last_) {
242 // Saw a negedge on the hall effect. Reset the limits.
243 min_hall_effect_off_angle_ = ::std::min(claw.negedge_value, claw.position);
244 max_hall_effect_off_angle_ = ::std::max(claw.negedge_value, claw.position);
245 }
246
247 posedge_value_ = claw.posedge_value;
248 negedge_value_ = claw.negedge_value;
249 last_encoder_ = encoder_;
250 if (front().value() || calibration().value() || back().value()) {
251 last_on_encoder_ = encoder_;
252 } else {
253 last_off_encoder_ = encoder_;
254 }
255 encoder_ = claw.position;
256 any_triggered_last_ = any_sensor_triggered;
257}
258
259void ZeroedStateFeedbackLoop::Reset(const HalfClawPosition &claw) {
260 set_zeroing_state(ZeroedStateFeedbackLoop::UNKNOWN_POSITION);
261
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000262 front_.Reset(claw.front);
263 calibration_.Reset(claw.calibration);
264 back_.Reset(claw.back);
Austin Schuh27b8fb12014-02-22 15:10:05 -0800265 // close up the min and max edge positions as they are no longer valid and
266 // will be expanded in future iterations
267 min_hall_effect_on_angle_ = claw.position;
268 max_hall_effect_on_angle_ = claw.position;
269 min_hall_effect_off_angle_ = claw.position;
270 max_hall_effect_off_angle_ = claw.position;
271 any_triggered_last_ = any_triggered();
272}
273
274bool TopZeroedStateFeedbackLoop::SetCalibrationOnEdge(
275 const constants::Values::Claws::Claw &claw_values,
276 JointZeroingState zeroing_state) {
277 double edge_encoder;
278 double edge_angle;
279 if (GetPositionOfEdge(claw_values, &edge_encoder, &edge_angle)) {
280 LOG(INFO, "Calibration edge edge should be %f.\n", edge_angle);
281 SetCalibration(edge_encoder, edge_angle);
282 set_zeroing_state(zeroing_state);
283 return true;
284 }
285 return false;
286}
287
Brian Silverman084372e2014-04-10 10:55:53 -0700288void TopZeroedStateFeedbackLoop::HandleCalibrationError(
289 const constants::Values::Claws::Claw &claw_values) {
290 double edge_encoder;
291 double edge_angle;
292 if (GetPositionOfEdge(claw_values, &edge_encoder, &edge_angle)) {
293 const double calibration_error =
294 ComputeCalibrationChange(edge_encoder, edge_angle);
295 LOG(INFO, "Top calibration error is %f\n", calibration_error);
296 if (::std::abs(calibration_error) > kRezeroThreshold) {
Brian Silvermane4c701d2014-04-10 19:29:25 -0700297 LOG(WARNING, "rezeroing top\n");
Brian Silverman084372e2014-04-10 10:55:53 -0700298 SetCalibration(edge_encoder, edge_angle);
Brian Silverman640f97a2014-04-19 16:07:55 -0700299 set_zeroing_state(ZeroedStateFeedbackLoop::UNKNOWN_POSITION);
Brian Silverman084372e2014-04-10 10:55:53 -0700300 }
301 }
302}
303
304
305void BottomZeroedStateFeedbackLoop::HandleCalibrationError(
306 const constants::Values::Claws::Claw &claw_values) {
307 double edge_encoder;
308 double edge_angle;
309 if (GetPositionOfEdge(claw_values, &edge_encoder, &edge_angle)) {
310 const double calibration_error =
311 ComputeCalibrationChange(edge_encoder, edge_angle);
312 LOG(INFO, "Bottom calibration error is %f\n", calibration_error);
313 if (::std::abs(calibration_error) > kRezeroThreshold) {
Brian Silvermane4c701d2014-04-10 19:29:25 -0700314 LOG(WARNING, "rezeroing bottom\n");
Brian Silverman084372e2014-04-10 10:55:53 -0700315 SetCalibration(edge_encoder, edge_angle);
Brian Silverman640f97a2014-04-19 16:07:55 -0700316 set_zeroing_state(ZeroedStateFeedbackLoop::UNKNOWN_POSITION);
Brian Silverman084372e2014-04-10 10:55:53 -0700317 }
318 }
319}
320
Austin Schuh27b8fb12014-02-22 15:10:05 -0800321bool BottomZeroedStateFeedbackLoop::SetCalibrationOnEdge(
322 const constants::Values::Claws::Claw &claw_values,
323 JointZeroingState zeroing_state) {
324 double edge_encoder;
325 double edge_angle;
326 if (GetPositionOfEdge(claw_values, &edge_encoder, &edge_angle)) {
327 LOG(INFO, "Calibration edge.\n");
328 SetCalibration(edge_encoder, edge_angle);
329 set_zeroing_state(zeroing_state);
330 return true;
331 }
332 return false;
333}
334
Austin Schuhcc0bf312014-02-09 00:39:29 -0800335ClawMotor::ClawMotor(control_loops::ClawGroup *my_claw)
Brian Silvermand8f403a2014-12-13 19:12:04 -0500336 : aos::controls::ControlLoop<control_loops::ClawGroup, false>(my_claw),
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800337 has_top_claw_goal_(false),
338 top_claw_goal_(0.0),
Austin Schuhcda86af2014-02-16 16:16:39 -0800339 top_claw_(this),
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800340 has_bottom_claw_goal_(false),
341 bottom_claw_goal_(0.0),
Austin Schuhcda86af2014-02-16 16:16:39 -0800342 bottom_claw_(this),
343 claw_(MakeClawLoop()),
Ben Fredrickson9b388422014-02-13 06:15:31 +0000344 was_enabled_(false),
Austin Schuh4cb047f2014-02-16 21:10:19 -0800345 doing_calibration_fine_tune_(false),
Austin Schuhe7f90d12014-02-17 00:48:25 -0800346 capped_goal_(false),
347 mode_(UNKNOWN_LOCATION) {}
Austin Schuh3bb9a442014-02-02 16:01:45 -0800348
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800349const int ZeroedStateFeedbackLoop::kZeroingMaxVoltage;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800350
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000351bool ZeroedStateFeedbackLoop::SawFilteredPosedge(
352 const HallEffectTracker &this_sensor, const HallEffectTracker &sensorA,
353 const HallEffectTracker &sensorB) {
354 if (posedge_filter_ == nullptr && this_sensor.posedge_count_changed() &&
355 !sensorA.posedge_count_changed() && !sensorB.posedge_count_changed() &&
356 this_sensor.value() && !this_sensor.last_value()) {
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000357 posedge_filter_ = &this_sensor;
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000358 } else if (posedge_filter_ == &this_sensor &&
359 !this_sensor.posedge_count_changed() &&
360 !sensorA.posedge_count_changed() &&
361 !sensorB.posedge_count_changed() && this_sensor.value()) {
362 posedge_filter_ = nullptr;
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000363 return true;
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000364 } else if (posedge_filter_ == &this_sensor) {
365 posedge_filter_ = nullptr;
366 }
367 return false;
368}
369
370bool ZeroedStateFeedbackLoop::SawFilteredNegedge(
371 const HallEffectTracker &this_sensor, const HallEffectTracker &sensorA,
372 const HallEffectTracker &sensorB) {
373 if (negedge_filter_ == nullptr && this_sensor.negedge_count_changed() &&
374 !sensorA.negedge_count_changed() && !sensorB.negedge_count_changed() &&
375 !this_sensor.value() && this_sensor.last_value()) {
376 negedge_filter_ = &this_sensor;
377 } else if (negedge_filter_ == &this_sensor &&
378 !this_sensor.negedge_count_changed() &&
379 !sensorA.negedge_count_changed() &&
380 !sensorB.negedge_count_changed() && !this_sensor.value()) {
381 negedge_filter_ = nullptr;
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000382 return true;
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000383 } else if (negedge_filter_ == &this_sensor) {
384 negedge_filter_ = nullptr;
385 }
386 return false;
387}
388
Brian Silvermane0a95462014-02-17 00:41:09 -0800389bool ZeroedStateFeedbackLoop::DoGetPositionOfEdge(
390 const constants::Values::Claws::AnglePair &angles, double *edge_encoder,
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000391 double *edge_angle, const HallEffectTracker &this_sensor,
392 const HallEffectTracker &sensorA, const HallEffectTracker &sensorB,
Brian Silvermane0a95462014-02-17 00:41:09 -0800393 const char *hall_effect_name) {
Austin Schuhf84a1302014-02-19 00:23:30 -0800394 bool found_edge = false;
Austin Schuh27b8fb12014-02-22 15:10:05 -0800395
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000396 if (SawFilteredPosedge(this_sensor, sensorA, sensorB)) {
Austin Schuh27b8fb12014-02-22 15:10:05 -0800397 if (min_hall_effect_off_angle_ == max_hall_effect_off_angle_) {
Brian Silvermanf48fab32014-03-09 14:32:24 -0700398 LOG(WARNING, "%s: Uncertain which side, rejecting posedge\n", name_);
Brian Silvermane0a95462014-02-17 00:41:09 -0800399 } else {
Austin Schuh27b8fb12014-02-22 15:10:05 -0800400 const double average_last_encoder =
401 (min_hall_effect_off_angle_ + max_hall_effect_off_angle_) / 2.0;
402 if (posedge_value_ < average_last_encoder) {
403 *edge_angle = angles.upper_decreasing_angle;
404 LOG(INFO, "%s Posedge upper of %s -> %f posedge: %f avg_encoder: %f\n",
405 name_, hall_effect_name, *edge_angle, posedge_value_,
406 average_last_encoder);
407 } else {
408 *edge_angle = angles.lower_angle;
409 LOG(INFO, "%s Posedge lower of %s -> %f posedge: %f avg_encoder: %f\n",
410 name_, hall_effect_name, *edge_angle, posedge_value_,
411 average_last_encoder);
412 }
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000413 *edge_encoder = posedge_value_;
Austin Schuh27b8fb12014-02-22 15:10:05 -0800414 found_edge = true;
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000415 }
416 }
417
418 if (SawFilteredNegedge(this_sensor, sensorA, sensorB)) {
419 if (min_hall_effect_on_angle_ == max_hall_effect_on_angle_) {
Brian Silvermanf48fab32014-03-09 14:32:24 -0700420 LOG(WARNING, "%s: Uncertain which side, rejecting negedge\n", name_);
Brian Silvermane0a95462014-02-17 00:41:09 -0800421 } else {
Austin Schuh27b8fb12014-02-22 15:10:05 -0800422 const double average_last_encoder =
423 (min_hall_effect_on_angle_ + max_hall_effect_on_angle_) / 2.0;
424 if (negedge_value_ > average_last_encoder) {
425 *edge_angle = angles.upper_angle;
426 LOG(INFO, "%s Negedge upper of %s -> %f negedge: %f avg_encoder: %f\n",
427 name_, hall_effect_name, *edge_angle, negedge_value_,
428 average_last_encoder);
429 } else {
430 *edge_angle = angles.lower_decreasing_angle;
431 LOG(INFO, "%s Negedge lower of %s -> %f negedge: %f avg_encoder: %f\n",
432 name_, hall_effect_name, *edge_angle, negedge_value_,
433 average_last_encoder);
434 }
435 *edge_encoder = negedge_value_;
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000436 found_edge = true;
Brian Silvermane0a95462014-02-17 00:41:09 -0800437 }
Austin Schuh27b8fb12014-02-22 15:10:05 -0800438 }
439
Austin Schuhf84a1302014-02-19 00:23:30 -0800440 return found_edge;
Brian Silvermane0a95462014-02-17 00:41:09 -0800441}
442
Austin Schuhf9286cd2014-02-11 00:51:09 -0800443bool ZeroedStateFeedbackLoop::GetPositionOfEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800444 const constants::Values::Claws::Claw &claw_values, double *edge_encoder,
Austin Schuhf9286cd2014-02-11 00:51:09 -0800445 double *edge_angle) {
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000446 if (DoGetPositionOfEdge(claw_values.front, edge_encoder, edge_angle, front_,
447 calibration_, back_, "front")) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800448 return true;
449 }
Brian Silvermane0a95462014-02-17 00:41:09 -0800450 if (DoGetPositionOfEdge(claw_values.calibration, edge_encoder, edge_angle,
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000451 calibration_, front_, back_, "calibration")) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800452 return true;
453 }
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000454 if (DoGetPositionOfEdge(claw_values.back, edge_encoder, edge_angle, back_,
455 calibration_, front_, "back")) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800456 return true;
457 }
458 return false;
459}
460
Austin Schuhcda86af2014-02-16 16:16:39 -0800461void TopZeroedStateFeedbackLoop::SetCalibration(double edge_encoder,
462 double edge_angle) {
463 double old_offset = offset_;
464 offset_ = edge_angle - edge_encoder;
465 const double doffset = offset_ - old_offset;
466 motor_->ChangeTopOffset(doffset);
467}
468
Brian Silverman084372e2014-04-10 10:55:53 -0700469double TopZeroedStateFeedbackLoop::ComputeCalibrationChange(double edge_encoder,
470 double edge_angle) {
471 const double offset = edge_angle - edge_encoder;
472 const double doffset = offset - offset_;
473 return doffset;
474}
475
Austin Schuhcda86af2014-02-16 16:16:39 -0800476void BottomZeroedStateFeedbackLoop::SetCalibration(double edge_encoder,
477 double edge_angle) {
478 double old_offset = offset_;
479 offset_ = edge_angle - edge_encoder;
480 const double doffset = offset_ - old_offset;
481 motor_->ChangeBottomOffset(doffset);
482}
483
Brian Silverman084372e2014-04-10 10:55:53 -0700484double BottomZeroedStateFeedbackLoop::ComputeCalibrationChange(
485 double edge_encoder, double edge_angle) {
486 const double offset = edge_angle - edge_encoder;
487 const double doffset = offset - offset_;
488 return doffset;
489}
490
Austin Schuhcda86af2014-02-16 16:16:39 -0800491void ClawMotor::ChangeTopOffset(double doffset) {
492 claw_.ChangeTopOffset(doffset);
493 if (has_top_claw_goal_) {
494 top_claw_goal_ += doffset;
495 }
496}
497
498void ClawMotor::ChangeBottomOffset(double doffset) {
499 claw_.ChangeBottomOffset(doffset);
500 if (has_bottom_claw_goal_) {
501 bottom_claw_goal_ += doffset;
502 }
503}
504
505void ClawLimitedLoop::ChangeTopOffset(double doffset) {
Brian Silverman73df9342014-06-12 23:33:16 -0700506 mutable_Y()(1, 0) += doffset;
507 mutable_X_hat()(1, 0) += doffset;
Austin Schuhcda86af2014-02-16 16:16:39 -0800508 LOG(INFO, "Changing top offset by %f\n", doffset);
509}
510void ClawLimitedLoop::ChangeBottomOffset(double doffset) {
Brian Silverman73df9342014-06-12 23:33:16 -0700511 mutable_Y()(0, 0) += doffset;
512 mutable_X_hat()(0, 0) += doffset;
513 mutable_X_hat()(1, 0) -= doffset;
Austin Schuhcda86af2014-02-16 16:16:39 -0800514 LOG(INFO, "Changing bottom offset by %f\n", doffset);
515}
joe7376ff52014-02-16 18:28:42 -0800516
Austin Schuh069143b2014-02-17 02:46:26 -0800517void LimitClawGoal(double *bottom_goal, double *top_goal,
518 const frc971::constants::Values &values) {
519 // first update position based on angle limit
Austin Schuh069143b2014-02-17 02:46:26 -0800520 const double separation = *top_goal - *bottom_goal;
Brian Silverman06374312014-04-12 16:09:28 -0700521 if (separation > values.claw.soft_max_separation) {
Brian Silverman11c6f7f2014-04-30 17:38:21 -0700522 LOG_STRUCT(DEBUG, "before", ClawPositionToLog(*top_goal, *bottom_goal));
Brian Silverman06374312014-04-12 16:09:28 -0700523 const double dsep = (separation - values.claw.soft_max_separation) / 2.0;
Austin Schuh069143b2014-02-17 02:46:26 -0800524 *bottom_goal += dsep;
525 *top_goal -= dsep;
Brian Silverman11c6f7f2014-04-30 17:38:21 -0700526 LOG_STRUCT(DEBUG, "after", ClawPositionToLog(*top_goal, *bottom_goal));
Austin Schuh069143b2014-02-17 02:46:26 -0800527 }
Brian Silverman06374312014-04-12 16:09:28 -0700528 if (separation < values.claw.soft_min_separation) {
Brian Silverman11c6f7f2014-04-30 17:38:21 -0700529 LOG_STRUCT(DEBUG, "before", ClawPositionToLog(*top_goal, *bottom_goal));
Brian Silverman06374312014-04-12 16:09:28 -0700530 const double dsep = (separation - values.claw.soft_min_separation) / 2.0;
Austin Schuh069143b2014-02-17 02:46:26 -0800531 *bottom_goal += dsep;
532 *top_goal -= dsep;
Brian Silverman11c6f7f2014-04-30 17:38:21 -0700533 LOG_STRUCT(DEBUG, "after", ClawPositionToLog(*top_goal, *bottom_goal));
Austin Schuh069143b2014-02-17 02:46:26 -0800534 }
535
536 // now move both goals in unison
537 if (*bottom_goal < values.claw.lower_claw.lower_limit) {
Brian Silverman11c6f7f2014-04-30 17:38:21 -0700538 LOG_STRUCT(DEBUG, "before", ClawPositionToLog(*top_goal, *bottom_goal));
Austin Schuh069143b2014-02-17 02:46:26 -0800539 *top_goal += values.claw.lower_claw.lower_limit - *bottom_goal;
540 *bottom_goal = values.claw.lower_claw.lower_limit;
Brian Silverman11c6f7f2014-04-30 17:38:21 -0700541 LOG_STRUCT(DEBUG, "after", ClawPositionToLog(*top_goal, *bottom_goal));
Austin Schuh069143b2014-02-17 02:46:26 -0800542 }
543 if (*bottom_goal > values.claw.lower_claw.upper_limit) {
Brian Silverman11c6f7f2014-04-30 17:38:21 -0700544 LOG_STRUCT(DEBUG, "before", ClawPositionToLog(*top_goal, *bottom_goal));
Austin Schuh069143b2014-02-17 02:46:26 -0800545 *top_goal -= *bottom_goal - values.claw.lower_claw.upper_limit;
546 *bottom_goal = values.claw.lower_claw.upper_limit;
Brian Silverman11c6f7f2014-04-30 17:38:21 -0700547 LOG_STRUCT(DEBUG, "after", ClawPositionToLog(*top_goal, *bottom_goal));
Austin Schuh069143b2014-02-17 02:46:26 -0800548 }
549
550 if (*top_goal < values.claw.upper_claw.lower_limit) {
Brian Silverman11c6f7f2014-04-30 17:38:21 -0700551 LOG_STRUCT(DEBUG, "before", ClawPositionToLog(*top_goal, *bottom_goal));
Austin Schuh069143b2014-02-17 02:46:26 -0800552 *bottom_goal += values.claw.upper_claw.lower_limit - *top_goal;
553 *top_goal = values.claw.upper_claw.lower_limit;
Brian Silverman11c6f7f2014-04-30 17:38:21 -0700554 LOG_STRUCT(DEBUG, "after", ClawPositionToLog(*top_goal, *bottom_goal));
Austin Schuh069143b2014-02-17 02:46:26 -0800555 }
556 if (*top_goal > values.claw.upper_claw.upper_limit) {
Brian Silverman11c6f7f2014-04-30 17:38:21 -0700557 LOG_STRUCT(DEBUG, "before", ClawPositionToLog(*top_goal, *bottom_goal));
Austin Schuh069143b2014-02-17 02:46:26 -0800558 *bottom_goal -= *top_goal - values.claw.upper_claw.upper_limit;
559 *top_goal = values.claw.upper_claw.upper_limit;
Brian Silverman11c6f7f2014-04-30 17:38:21 -0700560 LOG_STRUCT(DEBUG, "after", ClawPositionToLog(*top_goal, *bottom_goal));
Austin Schuh069143b2014-02-17 02:46:26 -0800561 }
562}
Austin Schuhcda86af2014-02-16 16:16:39 -0800563
Austin Schuhe7f90d12014-02-17 00:48:25 -0800564bool ClawMotor::is_ready() const {
565 return (
566 (top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED &&
567 bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED) ||
Brian Silverman71fbee02014-03-13 17:24:54 -0700568 (((::aos::robot_state.get() == NULL) ? true
569 : ::aos::robot_state->autonomous) &&
Austin Schuhe7f90d12014-02-17 00:48:25 -0800570 ((top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
571 top_claw_.zeroing_state() ==
572 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION) &&
573 (bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
574 bottom_claw_.zeroing_state() ==
575 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION))));
576}
577
578bool ClawMotor::is_zeroing() const { return !is_ready(); }
579
Austin Schuh3bb9a442014-02-02 16:01:45 -0800580// Positive angle is up, and positive power is up.
Austin Schuhcc0bf312014-02-09 00:39:29 -0800581void ClawMotor::RunIteration(const control_loops::ClawGroup::Goal *goal,
582 const control_loops::ClawGroup::Position *position,
583 control_loops::ClawGroup::Output *output,
James Kuszmaul9ead1de2014-02-28 21:24:39 -0800584 control_loops::ClawGroup::Status *status) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800585 constexpr double dt = 0.01;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800586
587 // Disable the motors now so that all early returns will return with the
588 // motors disabled.
589 if (output) {
590 output->top_claw_voltage = 0;
591 output->bottom_claw_voltage = 0;
592 output->intake_voltage = 0;
Ben Fredrickson61893d52014-03-02 09:43:23 +0000593 output->tusk_voltage = 0;
594 }
595
Brian Silverman71fbee02014-03-13 17:24:54 -0700596 if (goal) {
597 if (::std::isnan(goal->bottom_angle) ||
598 ::std::isnan(goal->separation_angle) || ::std::isnan(goal->intake) ||
599 ::std::isnan(goal->centering)) {
600 return;
601 }
Austin Schuh3bb9a442014-02-02 16:01:45 -0800602 }
603
Austin Schuh1a499942014-02-17 01:51:58 -0800604 if (reset()) {
Austin Schuh27b8fb12014-02-22 15:10:05 -0800605 top_claw_.Reset(position->top);
606 bottom_claw_.Reset(position->bottom);
Austin Schuh1a499942014-02-17 01:51:58 -0800607 }
608
Austin Schuhf9286cd2014-02-11 00:51:09 -0800609 const frc971::constants::Values &values = constants::GetValues();
610
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800611 if (position) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800612 Eigen::Matrix<double, 2, 1> Y;
613 Y << position->bottom.position + bottom_claw_.offset(),
614 position->top.position + top_claw_.offset();
615 claw_.Correct(Y);
616
Austin Schuhf9286cd2014-02-11 00:51:09 -0800617 top_claw_.SetPositionValues(position->top);
618 bottom_claw_.SetPositionValues(position->bottom);
619
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800620 if (!has_top_claw_goal_) {
621 has_top_claw_goal_ = true;
Austin Schuhcda86af2014-02-16 16:16:39 -0800622 top_claw_goal_ = top_claw_.absolute_position();
Austin Schuhe7f90d12014-02-17 00:48:25 -0800623 initial_separation_ =
Austin Schuhcda86af2014-02-16 16:16:39 -0800624 top_claw_.absolute_position() - bottom_claw_.absolute_position();
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800625 }
626 if (!has_bottom_claw_goal_) {
627 has_bottom_claw_goal_ = true;
Austin Schuhcda86af2014-02-16 16:16:39 -0800628 bottom_claw_goal_ = bottom_claw_.absolute_position();
Austin Schuhe7f90d12014-02-17 00:48:25 -0800629 initial_separation_ =
Austin Schuhcda86af2014-02-16 16:16:39 -0800630 top_claw_.absolute_position() - bottom_claw_.absolute_position();
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800631 }
Brian Silvermanf48fab32014-03-09 14:32:24 -0700632 LOG_STRUCT(DEBUG, "absolute position",
633 ClawPositionToLog(top_claw_.absolute_position(),
634 bottom_claw_.absolute_position()));
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800635 }
636
Brian Silverman71fbee02014-03-13 17:24:54 -0700637 bool autonomous, enabled;
638 if (::aos::robot_state.get() == nullptr) {
639 autonomous = true;
640 enabled = false;
641 } else {
642 autonomous = ::aos::robot_state->autonomous;
643 enabled = ::aos::robot_state->enabled;
644 }
Austin Schuh069143b2014-02-17 02:46:26 -0800645
646 double bottom_claw_velocity_ = 0.0;
647 double top_claw_velocity_ = 0.0;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800648
Brian Silverman71fbee02014-03-13 17:24:54 -0700649 if (goal != NULL &&
650 ((top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED &&
651 bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED) ||
652 (autonomous &&
653 ((top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
654 top_claw_.zeroing_state() ==
655 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION) &&
656 (bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
657 bottom_claw_.zeroing_state() ==
658 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION))))) {
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800659 // Ready to use the claw.
660 // Limit the goals here.
Austin Schuhf9286cd2014-02-11 00:51:09 -0800661 bottom_claw_goal_ = goal->bottom_angle;
Brian Silverman7c021c42014-02-17 15:15:56 -0800662 top_claw_goal_ = goal->bottom_angle + goal->separation_angle;
Austin Schuhcda86af2014-02-16 16:16:39 -0800663 has_bottom_claw_goal_ = true;
664 has_top_claw_goal_ = true;
665 doing_calibration_fine_tune_ = false;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800666 mode_ = READY;
Brian Silverman084372e2014-04-10 10:55:53 -0700667
668 bottom_claw_.HandleCalibrationError(values.claw.lower_claw);
669 top_claw_.HandleCalibrationError(values.claw.upper_claw);
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800670 } else if (top_claw_.zeroing_state() !=
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000671 ZeroedStateFeedbackLoop::UNKNOWN_POSITION &&
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800672 bottom_claw_.zeroing_state() !=
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000673 ZeroedStateFeedbackLoop::UNKNOWN_POSITION) {
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800674 // Time to fine tune the zero.
675 // Limit the goals here.
Austin Schuh0c733422014-02-17 01:17:12 -0800676 if (!enabled) {
677 // If we are disabled, start the fine tune process over again.
678 doing_calibration_fine_tune_ = false;
679 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800680 if (bottom_claw_.zeroing_state() != ZeroedStateFeedbackLoop::CALIBRATED) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800681 // always get the bottom claw to calibrated first
682 LOG(DEBUG, "Calibrating the bottom of the claw\n");
683 if (!doing_calibration_fine_tune_) {
684 if (::std::abs(bottom_absolute_position() -
Austin Schuhd27931c2014-02-16 19:18:20 -0800685 values.claw.start_fine_tune_pos) <
686 values.claw.claw_unimportant_epsilon) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800687 doing_calibration_fine_tune_ = true;
Austin Schuhd27931c2014-02-16 19:18:20 -0800688 bottom_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800689 top_claw_velocity_ = bottom_claw_velocity_ =
690 values.claw.claw_zeroing_speed;
Austin Schuhcda86af2014-02-16 16:16:39 -0800691 LOG(DEBUG, "Ready to fine tune the bottom\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800692 mode_ = FINE_TUNE_BOTTOM;
Austin Schuhcda86af2014-02-16 16:16:39 -0800693 } else {
694 // send bottom to zeroing start
Austin Schuhd27931c2014-02-16 19:18:20 -0800695 bottom_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuhcda86af2014-02-16 16:16:39 -0800696 LOG(DEBUG, "Going to the start position for the bottom\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800697 mode_ = PREP_FINE_TUNE_BOTTOM;
Austin Schuhcda86af2014-02-16 16:16:39 -0800698 }
699 } else {
Austin Schuhe7f90d12014-02-17 00:48:25 -0800700 mode_ = FINE_TUNE_BOTTOM;
Austin Schuhd27931c2014-02-16 19:18:20 -0800701 bottom_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800702 top_claw_velocity_ = bottom_claw_velocity_ =
703 values.claw.claw_zeroing_speed;
Brian Silvermane0a95462014-02-17 00:41:09 -0800704 if (top_claw_.front_or_back_triggered() ||
705 bottom_claw_.front_or_back_triggered()) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800706 // We shouldn't hit a limit, but if we do, go back to the zeroing
707 // point and try again.
708 doing_calibration_fine_tune_ = false;
Austin Schuhd27931c2014-02-16 19:18:20 -0800709 bottom_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuh069143b2014-02-17 02:46:26 -0800710 top_claw_velocity_ = bottom_claw_velocity_ = 0.0;
Austin Schuhcda86af2014-02-16 16:16:39 -0800711 LOG(DEBUG, "Found a limit, starting over.\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800712 mode_ = PREP_FINE_TUNE_BOTTOM;
Austin Schuhcda86af2014-02-16 16:16:39 -0800713 }
Austin Schuh288c8c32014-02-16 17:20:17 -0800714
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000715 if (position && bottom_claw_.SawFilteredPosedge(
716 bottom_claw_.calibration(), bottom_claw_.front(),
717 bottom_claw_.back())) {
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000718 // do calibration
719 bottom_claw_.SetCalibration(
720 position->bottom.posedge_value,
721 values.claw.lower_claw.calibration.lower_angle);
722 bottom_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::CALIBRATED);
723 // calibrated so we are done fine tuning bottom
724 doing_calibration_fine_tune_ = false;
725 LOG(DEBUG, "Calibrated the bottom correctly!\n");
726 } else if (bottom_claw_.calibration().last_value()) {
Brian Silvermane4c701d2014-04-10 19:29:25 -0700727 LOG(DEBUG, "Aborting bottom fine tune because sensor triggered\n");
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000728 doing_calibration_fine_tune_ = false;
Brian Silvermancc3844a2014-04-10 21:15:07 -0700729 bottom_claw_.set_zeroing_state(
730 ZeroedStateFeedbackLoop::UNKNOWN_POSITION);
Austin Schuhcda86af2014-02-16 16:16:39 -0800731 } else {
732 LOG(DEBUG, "Fine tuning\n");
733 }
734 }
735 // now set the top claw to track
736
Austin Schuhd27931c2014-02-16 19:18:20 -0800737 top_claw_goal_ = bottom_claw_goal_ + values.claw.claw_zeroing_separation;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800738 } else {
Austin Schuhcda86af2014-02-16 16:16:39 -0800739 // bottom claw must be calibrated, start on the top
740 if (!doing_calibration_fine_tune_) {
Austin Schuhd27931c2014-02-16 19:18:20 -0800741 if (::std::abs(top_absolute_position() -
742 values.claw.start_fine_tune_pos) <
743 values.claw.claw_unimportant_epsilon) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800744 doing_calibration_fine_tune_ = true;
Austin Schuhd27931c2014-02-16 19:18:20 -0800745 top_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800746 top_claw_velocity_ = bottom_claw_velocity_ =
747 values.claw.claw_zeroing_speed;
Austin Schuhcda86af2014-02-16 16:16:39 -0800748 LOG(DEBUG, "Ready to fine tune the top\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800749 mode_ = FINE_TUNE_TOP;
Austin Schuhcda86af2014-02-16 16:16:39 -0800750 } else {
751 // send top to zeroing start
Austin Schuhd27931c2014-02-16 19:18:20 -0800752 top_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuhcda86af2014-02-16 16:16:39 -0800753 LOG(DEBUG, "Going to the start position for the top\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800754 mode_ = PREP_FINE_TUNE_TOP;
Austin Schuhcda86af2014-02-16 16:16:39 -0800755 }
756 } else {
Austin Schuhe7f90d12014-02-17 00:48:25 -0800757 mode_ = FINE_TUNE_TOP;
Austin Schuhd27931c2014-02-16 19:18:20 -0800758 top_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800759 top_claw_velocity_ = bottom_claw_velocity_ =
760 values.claw.claw_zeroing_speed;
Brian Silvermane0a95462014-02-17 00:41:09 -0800761 if (top_claw_.front_or_back_triggered() ||
762 bottom_claw_.front_or_back_triggered()) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800763 // this should not happen, but now we know it won't
764 doing_calibration_fine_tune_ = false;
Austin Schuhd27931c2014-02-16 19:18:20 -0800765 top_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuh069143b2014-02-17 02:46:26 -0800766 top_claw_velocity_ = bottom_claw_velocity_ = 0.0;
Austin Schuhcda86af2014-02-16 16:16:39 -0800767 LOG(DEBUG, "Found a limit, starting over.\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800768 mode_ = PREP_FINE_TUNE_TOP;
Austin Schuhcda86af2014-02-16 16:16:39 -0800769 }
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000770
771 if (position &&
772 top_claw_.SawFilteredPosedge(top_claw_.calibration(),
773 top_claw_.front(), top_claw_.back())) {
774 // do calibration
775 top_claw_.SetCalibration(
776 position->top.posedge_value,
777 values.claw.upper_claw.calibration.lower_angle);
778 top_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::CALIBRATED);
779 // calibrated so we are done fine tuning top
780 doing_calibration_fine_tune_ = false;
781 LOG(DEBUG, "Calibrated the top correctly!\n");
782 } else if (top_claw_.calibration().last_value()) {
Brian Silvermane4c701d2014-04-10 19:29:25 -0700783 LOG(DEBUG, "Aborting top fine tune because sensor triggered\n");
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000784 doing_calibration_fine_tune_ = false;
Brian Silvermancc3844a2014-04-10 21:15:07 -0700785 top_claw_.set_zeroing_state(
786 ZeroedStateFeedbackLoop::UNKNOWN_POSITION);
Austin Schuhcda86af2014-02-16 16:16:39 -0800787 }
788 }
789 // now set the bottom claw to track
Austin Schuhd27931c2014-02-16 19:18:20 -0800790 bottom_claw_goal_ = top_claw_goal_ - values.claw.claw_zeroing_separation;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800791 }
792 } else {
Austin Schuhcda86af2014-02-16 16:16:39 -0800793 doing_calibration_fine_tune_ = false;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800794 if (!was_enabled_ && enabled) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800795 if (position) {
Brian Silverman72035692014-03-14 10:18:27 -0700796 top_claw_goal_ = position->top.position + top_claw_.offset();
797 bottom_claw_goal_ = position->bottom.position + bottom_claw_.offset();
Austin Schuhe7f90d12014-02-17 00:48:25 -0800798 initial_separation_ =
Austin Schuhcda86af2014-02-16 16:16:39 -0800799 position->top.position - position->bottom.position;
Austin Schuhf9286cd2014-02-11 00:51:09 -0800800 } else {
801 has_top_claw_goal_ = false;
802 has_bottom_claw_goal_ = false;
803 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800804 }
Austin Schuhf9286cd2014-02-11 00:51:09 -0800805
Austin Schuh4cb047f2014-02-16 21:10:19 -0800806 if ((bottom_claw_.zeroing_state() !=
807 ZeroedStateFeedbackLoop::UNKNOWN_POSITION ||
Brian Silvermane0a95462014-02-17 00:41:09 -0800808 bottom_claw_.front().value() || top_claw_.front().value()) &&
809 !top_claw_.back().value() && !bottom_claw_.back().value()) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800810 if (enabled) {
811 // Time to slowly move back up to find any position to narrow down the
812 // zero.
Austin Schuhd27931c2014-02-16 19:18:20 -0800813 top_claw_goal_ += values.claw.claw_zeroing_off_speed * dt;
814 bottom_claw_goal_ += values.claw.claw_zeroing_off_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800815 top_claw_velocity_ = bottom_claw_velocity_ =
816 values.claw.claw_zeroing_off_speed;
Austin Schuhcda86af2014-02-16 16:16:39 -0800817 LOG(DEBUG, "Bottom is known.\n");
Austin Schuhf9286cd2014-02-11 00:51:09 -0800818 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800819 } else {
820 // We don't know where either claw is. Slowly start moving down to find
821 // any hall effect.
Austin Schuhf9286cd2014-02-11 00:51:09 -0800822 if (enabled) {
Austin Schuhd27931c2014-02-16 19:18:20 -0800823 top_claw_goal_ -= values.claw.claw_zeroing_off_speed * dt;
824 bottom_claw_goal_ -= values.claw.claw_zeroing_off_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800825 top_claw_velocity_ = bottom_claw_velocity_ =
826 -values.claw.claw_zeroing_off_speed;
Austin Schuhcda86af2014-02-16 16:16:39 -0800827 LOG(DEBUG, "Both are unknown.\n");
Austin Schuhf9286cd2014-02-11 00:51:09 -0800828 }
829 }
830
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000831 if (position) {
832 if (enabled) {
833 top_claw_.SetCalibrationOnEdge(
834 values.claw.upper_claw,
835 ZeroedStateFeedbackLoop::APPROXIMATE_CALIBRATION);
836 bottom_claw_.SetCalibrationOnEdge(
837 values.claw.lower_claw,
838 ZeroedStateFeedbackLoop::APPROXIMATE_CALIBRATION);
839 } else {
840 // TODO(austin): Only calibrate on the predetermined edge.
841 // We might be able to just ignore this since the backlash is soooo
842 // low.
843 // :)
844 top_claw_.SetCalibrationOnEdge(
845 values.claw.upper_claw,
846 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION);
847 bottom_claw_.SetCalibrationOnEdge(
848 values.claw.lower_claw,
849 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION);
850 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800851 }
Austin Schuhe7f90d12014-02-17 00:48:25 -0800852 mode_ = UNKNOWN_LOCATION;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800853 }
854
Austin Schuh069143b2014-02-17 02:46:26 -0800855 // Limit the goals if both claws have been (mostly) found.
856 if (mode_ != UNKNOWN_LOCATION) {
857 LimitClawGoal(&bottom_claw_goal_, &top_claw_goal_, values);
858 }
859
Brian Silverman273d8a32014-05-10 22:19:09 -0700860 claw_.set_positions_known(
861 top_claw_.zeroing_state() != ZeroedStateFeedbackLoop::UNKNOWN_POSITION,
862 bottom_claw_.zeroing_state() !=
863 ZeroedStateFeedbackLoop::UNKNOWN_POSITION);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800864 if (has_top_claw_goal_ && has_bottom_claw_goal_) {
Brian Silverman0ca790b2014-06-12 21:33:08 -0700865 claw_.mutable_R() << bottom_claw_goal_, top_claw_goal_ - bottom_claw_goal_,
Austin Schuh069143b2014-02-17 02:46:26 -0800866 bottom_claw_velocity_, top_claw_velocity_ - bottom_claw_velocity_;
Brian Silverman273d8a32014-05-10 22:19:09 -0700867 LOG_MATRIX(DEBUG, "actual goal", claw_.R());
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800868
Austin Schuh01c652b2014-02-21 23:13:42 -0800869 // Only cap power when one of the halves of the claw is moving slowly and
870 // could wind up.
Austin Schuhe7f90d12014-02-17 00:48:25 -0800871 claw_.set_is_zeroing(mode_ == UNKNOWN_LOCATION || mode_ == FINE_TUNE_TOP ||
872 mode_ == FINE_TUNE_BOTTOM);
Austin Schuhcda86af2014-02-16 16:16:39 -0800873 claw_.Update(output == nullptr);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800874 } else {
Austin Schuhcda86af2014-02-16 16:16:39 -0800875 claw_.Update(true);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800876 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800877
Austin Schuh4cb047f2014-02-16 21:10:19 -0800878 capped_goal_ = false;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800879 switch (mode_) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800880 case READY:
Austin Schuhe7f90d12014-02-17 00:48:25 -0800881 case PREP_FINE_TUNE_TOP:
882 case PREP_FINE_TUNE_BOTTOM:
Austin Schuhcda86af2014-02-16 16:16:39 -0800883 break;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800884 case FINE_TUNE_BOTTOM:
885 case FINE_TUNE_TOP:
Austin Schuh4cb047f2014-02-16 21:10:19 -0800886 case UNKNOWN_LOCATION: {
887 if (claw_.uncapped_average_voltage() > values.claw.max_zeroing_voltage) {
Brian Silvermana21c3a22014-06-12 21:49:15 -0700888 double dx_bot = (claw_.U_uncapped(0, 0) -
Austin Schuh4cb047f2014-02-16 21:10:19 -0800889 values.claw.max_zeroing_voltage) /
890 claw_.K(0, 0);
Brian Silvermana21c3a22014-06-12 21:49:15 -0700891 double dx_top = (claw_.U_uncapped(1, 0) -
James Kuszmaul0e866512014-02-21 13:12:52 -0800892 values.claw.max_zeroing_voltage) /
893 claw_.K(0, 0);
894 double dx = ::std::max(dx_top, dx_bot);
Austin Schuh4cb047f2014-02-16 21:10:19 -0800895 bottom_claw_goal_ -= dx;
896 top_claw_goal_ -= dx;
James Kuszmaul0e866512014-02-21 13:12:52 -0800897 Eigen::Matrix<double, 4, 1> R;
Brian Silvermana21c3a22014-06-12 21:49:15 -0700898 R << bottom_claw_goal_, top_claw_goal_ - bottom_claw_goal_, claw_.R(2, 0),
899 claw_.R(3, 0);
Brian Silverman0ca790b2014-06-12 21:33:08 -0700900 claw_.mutable_U() = claw_.K() * (R - claw_.X_hat());
Austin Schuhcda86af2014-02-16 16:16:39 -0800901 capped_goal_ = true;
Brian Silvermanf48fab32014-03-09 14:32:24 -0700902 LOG(DEBUG, "Moving the goal by %f to prevent windup."
903 " Uncapped is %f, max is %f, difference is %f\n",
904 dx,
Austin Schuhe7f90d12014-02-17 00:48:25 -0800905 claw_.uncapped_average_voltage(), values.claw.max_zeroing_voltage,
906 (claw_.uncapped_average_voltage() -
907 values.claw.max_zeroing_voltage));
Austin Schuh4cb047f2014-02-16 21:10:19 -0800908 } else if (claw_.uncapped_average_voltage() <
909 -values.claw.max_zeroing_voltage) {
Brian Silvermana21c3a22014-06-12 21:49:15 -0700910 double dx_bot = (claw_.U_uncapped(0, 0) +
Austin Schuh4cb047f2014-02-16 21:10:19 -0800911 values.claw.max_zeroing_voltage) /
912 claw_.K(0, 0);
Brian Silvermana21c3a22014-06-12 21:49:15 -0700913 double dx_top = (claw_.U_uncapped(1, 0) +
James Kuszmaul0e866512014-02-21 13:12:52 -0800914 values.claw.max_zeroing_voltage) /
915 claw_.K(0, 0);
916 double dx = ::std::min(dx_top, dx_bot);
Austin Schuh4cb047f2014-02-16 21:10:19 -0800917 bottom_claw_goal_ -= dx;
918 top_claw_goal_ -= dx;
James Kuszmaul0e866512014-02-21 13:12:52 -0800919 Eigen::Matrix<double, 4, 1> R;
Brian Silvermana21c3a22014-06-12 21:49:15 -0700920 R << bottom_claw_goal_, top_claw_goal_ - bottom_claw_goal_, claw_.R(2, 0),
921 claw_.R(3, 0);
Brian Silverman0ca790b2014-06-12 21:33:08 -0700922 claw_.mutable_U() = claw_.K() * (R - claw_.X_hat());
Austin Schuhcda86af2014-02-16 16:16:39 -0800923 capped_goal_ = true;
Austin Schuh4cb047f2014-02-16 21:10:19 -0800924 LOG(DEBUG, "Moving the goal by %f to prevent windup\n", dx);
Austin Schuhcda86af2014-02-16 16:16:39 -0800925 }
Austin Schuh4cb047f2014-02-16 21:10:19 -0800926 } break;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800927 }
928
929 if (output) {
Ben Fredrickson2f76ddf2014-02-23 05:58:23 +0000930 if (goal) {
931 //setup the intake
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000932 output->intake_voltage =
933 (goal->intake > 12.0) ? 12 : (goal->intake < -12.0) ? -12.0
934 : goal->intake;
Ben Fredrickson2f76ddf2014-02-23 05:58:23 +0000935 output->tusk_voltage = goal->centering;
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000936 output->tusk_voltage =
937 (goal->centering > 12.0) ? 12 : (goal->centering < -12.0)
938 ? -12.0
939 : goal->centering;
Ben Fredrickson2f76ddf2014-02-23 05:58:23 +0000940 }
Brian Silvermana21c3a22014-06-12 21:49:15 -0700941 output->top_claw_voltage = claw_.U(1, 0);
942 output->bottom_claw_voltage = claw_.U(0, 0);
Austin Schuhf84a1302014-02-19 00:23:30 -0800943
944 if (output->top_claw_voltage > kMaxVoltage) {
945 output->top_claw_voltage = kMaxVoltage;
946 } else if (output->top_claw_voltage < -kMaxVoltage) {
947 output->top_claw_voltage = -kMaxVoltage;
948 }
949
950 if (output->bottom_claw_voltage > kMaxVoltage) {
951 output->bottom_claw_voltage = kMaxVoltage;
952 } else if (output->bottom_claw_voltage < -kMaxVoltage) {
953 output->bottom_claw_voltage = -kMaxVoltage;
954 }
Austin Schuh3bb9a442014-02-02 16:01:45 -0800955 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800956
James Kuszmaul4abaf482014-02-26 21:16:35 -0800957 status->bottom = bottom_absolute_position();
958 status->separation = top_absolute_position() - bottom_absolute_position();
Brian Silvermana21c3a22014-06-12 21:49:15 -0700959 status->bottom_velocity = claw_.X_hat(2, 0);
960 status->separation_velocity = claw_.X_hat(3, 0);
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800961
Brian Silverman71fbee02014-03-13 17:24:54 -0700962 if (goal) {
963 bool bottom_done =
964 ::std::abs(bottom_absolute_position() - goal->bottom_angle) < 0.020;
965 bool bottom_velocity_done = ::std::abs(status->bottom_velocity) < 0.2;
966 bool separation_done =
967 ::std::abs((top_absolute_position() - bottom_absolute_position()) -
968 goal->separation_angle) < 0.020;
969 bool separation_done_with_ball =
970 ::std::abs((top_absolute_position() - bottom_absolute_position()) -
971 goal->separation_angle) < 0.06;
972 status->done = is_ready() && separation_done && bottom_done && bottom_velocity_done;
973 status->done_with_ball =
974 is_ready() && separation_done_with_ball && bottom_done && bottom_velocity_done;
975 } else {
976 status->done = status->done_with_ball = false;
977 }
Austin Schuha556b012014-03-02 11:55:52 -0800978
Austin Schuh4f8633f2014-03-02 13:59:46 -0800979 status->zeroed = is_ready();
Brian Silverman80fc94c2014-03-09 16:56:01 -0700980 status->zeroed_for_auto =
981 (top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
982 top_claw_.zeroing_state() ==
983 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION) &&
984 (bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
985 bottom_claw_.zeroing_state() ==
986 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION);
Austin Schuh4f8633f2014-03-02 13:59:46 -0800987
Brian Silverman71fbee02014-03-13 17:24:54 -0700988 was_enabled_ = enabled;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800989}
990
991} // namespace control_loops
992} // namespace frc971
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000993