blob: 19e9a18e32dab444cc016666804765c79a76c2c4 [file] [log] [blame]
Austin Schuh3bb9a442014-02-02 16:01:45 -08001#include "frc971/control_loops/claw/claw.h"
2
3#include <stdio.h>
4
5#include <algorithm>
6
7#include "aos/common/control_loop/control_loops.q.h"
8#include "aos/common/logging/logging.h"
9
10#include "frc971/constants.h"
Austin Schuhcda86af2014-02-16 16:16:39 -080011#include "frc971/control_loops/claw/claw_motor_plant.h"
12
Austin Schuh3bb9a442014-02-02 16:01:45 -080013// Zeroing plan.
14// There are 2 types of zeros. Enabled and disabled ones.
15// Disabled ones are only valid during auto mode, and can be used to speed up
16// the enabled zero process. We need to re-zero during teleop in case the auto
17// zero was poor and causes us to miss all our shots.
18//
19// We need to be able to zero manually while disabled by moving the joint over
20// the zeros.
21// Zero on the down edge when disabled (gravity in the direction of motion)
22//
23// When enabled, zero on the up edge (gravity opposing the direction of motion)
24// The enabled sequence needs to work as follows. We can crash the claw if we
25// bring them too close to each other or too far from each other. The only safe
26// thing to do is to move them in unison.
27//
28// Start by moving them both towards the front of the bot to either find either
29// the middle hall effect on either jaw, or the front hall effect on the bottom
30// jaw. Any edge that isn't the desired edge will provide an approximate edge
31// location that can be used for the fine tuning step.
32// Once an edge is found on the front claw, move back the other way with both
33// claws until an edge is found for the other claw.
34// Now that we have an approximate zero, we can robustify the limits to keep
35// both claws safe. Then, we can move both claws to a position that is the
36// correct side of the zero and go zero.
37
38// Valid region plan.
39// Difference between the arms has a range, and the values of each arm has a range.
40// If a claw runs up against a static limit, don't let the goal change outside
41// the limit.
42// If a claw runs up against a movable limit, move both claws outwards to get
43// out of the condition.
44
45namespace frc971 {
46namespace control_loops {
47
Austin Schuhcda86af2014-02-16 16:16:39 -080048void ClawLimitedLoop::CapU() {
Austin Schuh4cb047f2014-02-16 21:10:19 -080049 uncapped_average_voltage_ = U(0, 0) + U(1, 0) / 2.0;
50 if (is_zeroing_) {
51 const frc971::constants::Values &values = constants::GetValues();
52 if (uncapped_average_voltage_ > values.claw.max_zeroing_voltage) {
53 const double difference =
54 uncapped_average_voltage_ - values.claw.max_zeroing_voltage;
55 U(0, 0) -= difference;
Austin Schuh4cb047f2014-02-16 21:10:19 -080056 } else if (uncapped_average_voltage_ < -values.claw.max_zeroing_voltage) {
57 const double difference =
58 -uncapped_average_voltage_ - values.claw.max_zeroing_voltage;
59 U(0, 0) += difference;
Austin Schuh4cb047f2014-02-16 21:10:19 -080060 }
61 }
62
63 double max_value =
64 ::std::max(::std::abs(U(0, 0)), ::std::abs(U(1, 0) + U(0, 0)));
65
Austin Schuhcda86af2014-02-16 16:16:39 -080066 if (max_value > 12.0) {
67 LOG(DEBUG, "Capping U because max is %f\n", max_value);
68 U = U * 12.0 / max_value;
69 LOG(DEBUG, "Capping U is now %f %f\n", U(0, 0), U(1, 0));
Austin Schuh4b7b5d02014-02-10 21:20:34 -080070 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -080071}
72
Austin Schuhcc0bf312014-02-09 00:39:29 -080073ClawMotor::ClawMotor(control_loops::ClawGroup *my_claw)
74 : aos::control_loops::ControlLoop<control_loops::ClawGroup>(my_claw),
Austin Schuh4b7b5d02014-02-10 21:20:34 -080075 has_top_claw_goal_(false),
76 top_claw_goal_(0.0),
Austin Schuhcda86af2014-02-16 16:16:39 -080077 top_claw_(this),
Austin Schuh4b7b5d02014-02-10 21:20:34 -080078 has_bottom_claw_goal_(false),
79 bottom_claw_goal_(0.0),
Austin Schuhcda86af2014-02-16 16:16:39 -080080 bottom_claw_(this),
81 claw_(MakeClawLoop()),
Ben Fredrickson9b388422014-02-13 06:15:31 +000082 was_enabled_(false),
Austin Schuh4cb047f2014-02-16 21:10:19 -080083 doing_calibration_fine_tune_(false),
Austin Schuhe7f90d12014-02-17 00:48:25 -080084 capped_goal_(false),
85 mode_(UNKNOWN_LOCATION) {}
Austin Schuh3bb9a442014-02-02 16:01:45 -080086
Austin Schuh4b7b5d02014-02-10 21:20:34 -080087const int ZeroedStateFeedbackLoop::kZeroingMaxVoltage;
Austin Schuh3bb9a442014-02-02 16:01:45 -080088
Brian Silvermane0a95462014-02-17 00:41:09 -080089bool ZeroedStateFeedbackLoop::DoGetPositionOfEdge(
90 const constants::Values::Claws::AnglePair &angles, double *edge_encoder,
91 double *edge_angle, const HallEffectTracker &sensor,
92 const char *hall_effect_name) {
93 if (sensor.posedge_count_changed()) {
Ben Fredricksonade3eab2014-02-22 07:30:53 +000094 if (min_current_hall_effect_edge_ == max_curent_hall_effect_edge_) {
95 // we oddly got two of the same edge.
96 *edge_angle = last_edge_value_;
97 return true;
98 } else if (posedge_value_ <
99 (min_current_hall_effect_edge_ + max_current_hall_effect_edge_) / 2) {
Brian Silvermane0a95462014-02-17 00:41:09 -0800100 *edge_angle = angles.upper_angle;
Ben Fredricksonade3eab2014-02-22 07:30:53 +0000101 LOG(INFO, "%s Posedge upper of %s -> %f\n", name_, hall_effect_name,
102 *edge_angle);
Brian Silvermane0a95462014-02-17 00:41:09 -0800103 } else {
104 *edge_angle = angles.lower_angle;
Ben Fredricksonade3eab2014-02-22 07:30:53 +0000105 LOG(INFO, "%s Posedge lower of %s -> %f\n", name_, hall_effect_name,
106 *edge_angle);
Brian Silvermane0a95462014-02-17 00:41:09 -0800107 }
108 *edge_encoder = posedge_value_;
Ben Fredricksonade3eab2014-02-22 07:30:53 +0000109 last_edge_value_ = posedge_value_;
Brian Silvermane0a95462014-02-17 00:41:09 -0800110 return true;
111 }
112 if (sensor.negedge_count_changed()) {
Ben Fredricksonade3eab2014-02-22 07:30:53 +0000113 // we oddly got two of the same edge.
114 if (min_current_hall_effect_edge_ == max_curent_hall_effect_edge_) {
115 *edge_angle = last_edge_value_;
116 return true;
117 } else if (negedge_value_ > (min_current_hall_effect_edge_ +
118 max_current_hall_effect_edge_) / 2) {
Brian Silvermane0a95462014-02-17 00:41:09 -0800119 *edge_angle = angles.upper_angle;
Ben Fredricksonade3eab2014-02-22 07:30:53 +0000120 LOG(INFO, "%s Negedge upper of %s -> %f\n", name_, hall_effect_name,
121 *edge_angle);
Brian Silvermane0a95462014-02-17 00:41:09 -0800122 } else {
123 *edge_angle = angles.lower_angle;
Ben Fredricksonade3eab2014-02-22 07:30:53 +0000124 LOG(INFO, "%s Negedge lower of %s -> %f\n", name_, hall_effect_name,
125 *edge_angle);
Brian Silvermane0a95462014-02-17 00:41:09 -0800126 }
127 *edge_encoder = negedge_value_;
Ben Fredricksonade3eab2014-02-22 07:30:53 +0000128 last_edge_value_ = posedge_value_;
Brian Silvermane0a95462014-02-17 00:41:09 -0800129 return true;
130 }
131
132 return false;
133}
134
Austin Schuhf9286cd2014-02-11 00:51:09 -0800135bool ZeroedStateFeedbackLoop::GetPositionOfEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800136 const constants::Values::Claws::Claw &claw_values, double *edge_encoder,
Austin Schuhf9286cd2014-02-11 00:51:09 -0800137 double *edge_angle) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800138 // TODO(austin): Validate that the hall effect edge makes sense.
139 // We must now be on the side of the edge that we expect to be, and the
140 // encoder must have been on either side of the edge before and after.
141
Austin Schuhcda86af2014-02-16 16:16:39 -0800142 // TODO(austin): Compute the last off range min and max and compare the edge
143 // value to the middle of the range. This will be quite a bit more reliable.
144
Brian Silvermane0a95462014-02-17 00:41:09 -0800145 if (DoGetPositionOfEdge(claw_values.front, edge_encoder, edge_angle,
146 front_, "front")) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800147 return true;
148 }
Brian Silvermane0a95462014-02-17 00:41:09 -0800149 if (DoGetPositionOfEdge(claw_values.calibration, edge_encoder, edge_angle,
150 calibration_, "calibration")) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800151 return true;
152 }
Brian Silvermane0a95462014-02-17 00:41:09 -0800153 if (DoGetPositionOfEdge(claw_values.back, edge_encoder, edge_angle,
154 back_, "back")) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800155 return true;
156 }
157 return false;
158}
159
Austin Schuhcda86af2014-02-16 16:16:39 -0800160void TopZeroedStateFeedbackLoop::SetCalibration(double edge_encoder,
161 double edge_angle) {
162 double old_offset = offset_;
163 offset_ = edge_angle - edge_encoder;
164 const double doffset = offset_ - old_offset;
165 motor_->ChangeTopOffset(doffset);
166}
167
168void BottomZeroedStateFeedbackLoop::SetCalibration(double edge_encoder,
169 double edge_angle) {
170 double old_offset = offset_;
171 offset_ = edge_angle - edge_encoder;
172 const double doffset = offset_ - old_offset;
173 motor_->ChangeBottomOffset(doffset);
174}
175
176void ClawMotor::ChangeTopOffset(double doffset) {
177 claw_.ChangeTopOffset(doffset);
178 if (has_top_claw_goal_) {
179 top_claw_goal_ += doffset;
180 }
181}
182
183void ClawMotor::ChangeBottomOffset(double doffset) {
184 claw_.ChangeBottomOffset(doffset);
185 if (has_bottom_claw_goal_) {
186 bottom_claw_goal_ += doffset;
187 }
188}
189
190void ClawLimitedLoop::ChangeTopOffset(double doffset) {
191 Y_(1, 0) += doffset;
192 X_hat(1, 0) += doffset;
193 LOG(INFO, "Changing top offset by %f\n", doffset);
194}
195void ClawLimitedLoop::ChangeBottomOffset(double doffset) {
196 Y_(0, 0) += doffset;
197 X_hat(0, 0) += doffset;
198 X_hat(1, 0) -= doffset;
199 LOG(INFO, "Changing bottom offset by %f\n", doffset);
200}
joe7376ff52014-02-16 18:28:42 -0800201
Austin Schuh069143b2014-02-17 02:46:26 -0800202void LimitClawGoal(double *bottom_goal, double *top_goal,
203 const frc971::constants::Values &values) {
204 // first update position based on angle limit
205
206 const double separation = *top_goal - *bottom_goal;
207 if (separation > values.claw.claw_max_separation) {
208 LOG(DEBUG, "Greater than\n");
209 const double dsep = (separation - values.claw.claw_max_separation) / 2.0;
210 *bottom_goal += dsep;
211 *top_goal -= dsep;
212 LOG(DEBUG, "Goals now bottom: %f, top: %f\n", *bottom_goal, *top_goal);
213 }
214 if (separation < values.claw.claw_min_separation) {
215 LOG(DEBUG, "Less than\n");
216 const double dsep = (separation - values.claw.claw_min_separation) / 2.0;
217 *bottom_goal += dsep;
218 *top_goal -= dsep;
219 LOG(DEBUG, "Goals now bottom: %f, top: %f\n", *bottom_goal, *top_goal);
220 }
221
222 // now move both goals in unison
223 if (*bottom_goal < values.claw.lower_claw.lower_limit) {
224 *top_goal += values.claw.lower_claw.lower_limit - *bottom_goal;
225 *bottom_goal = values.claw.lower_claw.lower_limit;
226 }
227 if (*bottom_goal > values.claw.lower_claw.upper_limit) {
228 *top_goal -= *bottom_goal - values.claw.lower_claw.upper_limit;
229 *bottom_goal = values.claw.lower_claw.upper_limit;
230 }
231
232 if (*top_goal < values.claw.upper_claw.lower_limit) {
233 *bottom_goal += values.claw.upper_claw.lower_limit - *top_goal;
234 *top_goal = values.claw.upper_claw.lower_limit;
235 }
236 if (*top_goal > values.claw.upper_claw.upper_limit) {
237 *bottom_goal -= *top_goal - values.claw.upper_claw.upper_limit;
238 *top_goal = values.claw.upper_claw.upper_limit;
239 }
240}
Austin Schuhcda86af2014-02-16 16:16:39 -0800241
Austin Schuhe7f90d12014-02-17 00:48:25 -0800242bool ClawMotor::is_ready() const {
243 return (
244 (top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED &&
245 bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED) ||
246 (::aos::robot_state->autonomous &&
247 ((top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
248 top_claw_.zeroing_state() ==
249 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION) &&
250 (bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
251 bottom_claw_.zeroing_state() ==
252 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION))));
253}
254
255bool ClawMotor::is_zeroing() const { return !is_ready(); }
256
Austin Schuh3bb9a442014-02-02 16:01:45 -0800257// Positive angle is up, and positive power is up.
Austin Schuhcc0bf312014-02-09 00:39:29 -0800258void ClawMotor::RunIteration(const control_loops::ClawGroup::Goal *goal,
259 const control_loops::ClawGroup::Position *position,
260 control_loops::ClawGroup::Output *output,
Austin Schuh3bb9a442014-02-02 16:01:45 -0800261 ::aos::control_loops::Status *status) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800262 constexpr double dt = 0.01;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800263
264 // Disable the motors now so that all early returns will return with the
265 // motors disabled.
266 if (output) {
267 output->top_claw_voltage = 0;
268 output->bottom_claw_voltage = 0;
269 output->intake_voltage = 0;
270 }
271
Austin Schuh1a499942014-02-17 01:51:58 -0800272 if (reset()) {
273 bottom_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::UNKNOWN_POSITION);
274 top_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::UNKNOWN_POSITION);
Ben Fredrickson4283bb42014-02-22 08:31:50 +0000275 // close up the min and max edge positions as they are no longer valid and
276 // will be expanded in future iterations
277 top_claw_.min_current_hall_effect_edge_ =
278 top_claw_.max_current_hall_effect_edge_ = position->top.position;
279 bottom_claw_.min_current_hall_effect_edge_ =
280 bottom_claw_.max_current_hall_effect_edge_ = position->bottom.position;
Austin Schuh1a499942014-02-17 01:51:58 -0800281 }
282
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800283 if (::aos::robot_state.get() == nullptr) {
284 return;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800285 }
286
Austin Schuhf9286cd2014-02-11 00:51:09 -0800287 const frc971::constants::Values &values = constants::GetValues();
288
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800289 if (position) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800290 Eigen::Matrix<double, 2, 1> Y;
291 Y << position->bottom.position + bottom_claw_.offset(),
292 position->top.position + top_claw_.offset();
293 claw_.Correct(Y);
294
Austin Schuhf9286cd2014-02-11 00:51:09 -0800295 top_claw_.SetPositionValues(position->top);
296 bottom_claw_.SetPositionValues(position->bottom);
297
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800298 if (!has_top_claw_goal_) {
299 has_top_claw_goal_ = true;
Austin Schuhcda86af2014-02-16 16:16:39 -0800300 top_claw_goal_ = top_claw_.absolute_position();
Austin Schuhe7f90d12014-02-17 00:48:25 -0800301 initial_separation_ =
Austin Schuhcda86af2014-02-16 16:16:39 -0800302 top_claw_.absolute_position() - bottom_claw_.absolute_position();
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800303 }
304 if (!has_bottom_claw_goal_) {
305 has_bottom_claw_goal_ = true;
Austin Schuhcda86af2014-02-16 16:16:39 -0800306 bottom_claw_goal_ = bottom_claw_.absolute_position();
Austin Schuhe7f90d12014-02-17 00:48:25 -0800307 initial_separation_ =
Austin Schuhcda86af2014-02-16 16:16:39 -0800308 top_claw_.absolute_position() - bottom_claw_.absolute_position();
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800309 }
Austin Schuhcda86af2014-02-16 16:16:39 -0800310 LOG(DEBUG, "Claw position is (top: %f bottom: %f\n",
311 top_claw_.absolute_position(), bottom_claw_.absolute_position());
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800312 }
313
Austin Schuh069143b2014-02-17 02:46:26 -0800314 const bool autonomous = ::aos::robot_state->autonomous;
315 const bool enabled = ::aos::robot_state->enabled;
316
317 double bottom_claw_velocity_ = 0.0;
318 double top_claw_velocity_ = 0.0;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800319
320 if ((top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED &&
321 bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED) ||
322 (autonomous &&
323 ((top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
324 top_claw_.zeroing_state() ==
325 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION) &&
326 (bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
327 bottom_claw_.zeroing_state() ==
328 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION)))) {
329 // Ready to use the claw.
330 // Limit the goals here.
Austin Schuhf9286cd2014-02-11 00:51:09 -0800331 bottom_claw_goal_ = goal->bottom_angle;
Brian Silverman7c021c42014-02-17 15:15:56 -0800332 top_claw_goal_ = goal->bottom_angle + goal->separation_angle;
Austin Schuhcda86af2014-02-16 16:16:39 -0800333 has_bottom_claw_goal_ = true;
334 has_top_claw_goal_ = true;
335 doing_calibration_fine_tune_ = false;
336
Austin Schuhe7f90d12014-02-17 00:48:25 -0800337 mode_ = READY;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800338 } else if (top_claw_.zeroing_state() !=
339 ZeroedStateFeedbackLoop::UNKNOWN_POSITION &&
340 bottom_claw_.zeroing_state() !=
341 ZeroedStateFeedbackLoop::UNKNOWN_POSITION) {
342 // Time to fine tune the zero.
343 // Limit the goals here.
Austin Schuh0c733422014-02-17 01:17:12 -0800344 if (!enabled) {
345 // If we are disabled, start the fine tune process over again.
346 doing_calibration_fine_tune_ = false;
347 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800348 if (bottom_claw_.zeroing_state() != ZeroedStateFeedbackLoop::CALIBRATED) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800349 // always get the bottom claw to calibrated first
350 LOG(DEBUG, "Calibrating the bottom of the claw\n");
351 if (!doing_calibration_fine_tune_) {
352 if (::std::abs(bottom_absolute_position() -
Austin Schuhd27931c2014-02-16 19:18:20 -0800353 values.claw.start_fine_tune_pos) <
354 values.claw.claw_unimportant_epsilon) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800355 doing_calibration_fine_tune_ = true;
Austin Schuhd27931c2014-02-16 19:18:20 -0800356 bottom_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800357 top_claw_velocity_ = bottom_claw_velocity_ =
358 values.claw.claw_zeroing_speed;
Austin Schuhcda86af2014-02-16 16:16:39 -0800359 LOG(DEBUG, "Ready to fine tune the bottom\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800360 mode_ = FINE_TUNE_BOTTOM;
Austin Schuhcda86af2014-02-16 16:16:39 -0800361 } else {
362 // send bottom to zeroing start
Austin Schuhd27931c2014-02-16 19:18:20 -0800363 bottom_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuhcda86af2014-02-16 16:16:39 -0800364 LOG(DEBUG, "Going to the start position for the bottom\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800365 mode_ = PREP_FINE_TUNE_BOTTOM;
Austin Schuhcda86af2014-02-16 16:16:39 -0800366 }
367 } else {
Austin Schuhe7f90d12014-02-17 00:48:25 -0800368 mode_ = FINE_TUNE_BOTTOM;
Austin Schuhd27931c2014-02-16 19:18:20 -0800369 bottom_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800370 top_claw_velocity_ = bottom_claw_velocity_ =
371 values.claw.claw_zeroing_speed;
Brian Silvermane0a95462014-02-17 00:41:09 -0800372 if (top_claw_.front_or_back_triggered() ||
373 bottom_claw_.front_or_back_triggered()) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800374 // We shouldn't hit a limit, but if we do, go back to the zeroing
375 // point and try again.
376 doing_calibration_fine_tune_ = false;
Austin Schuhd27931c2014-02-16 19:18:20 -0800377 bottom_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuh069143b2014-02-17 02:46:26 -0800378 top_claw_velocity_ = bottom_claw_velocity_ = 0.0;
Austin Schuhcda86af2014-02-16 16:16:39 -0800379 LOG(DEBUG, "Found a limit, starting over.\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800380 mode_ = PREP_FINE_TUNE_BOTTOM;
Austin Schuhcda86af2014-02-16 16:16:39 -0800381 }
Austin Schuh288c8c32014-02-16 17:20:17 -0800382
Brian Silvermane0a95462014-02-17 00:41:09 -0800383 if (bottom_claw_.calibration().value()) {
384 if (bottom_claw_.calibration().posedge_count_changed() &&
Austin Schuh288c8c32014-02-16 17:20:17 -0800385 position) {
386 // do calibration
387 bottom_claw_.SetCalibration(
388 position->bottom.posedge_value,
Austin Schuhd27931c2014-02-16 19:18:20 -0800389 values.claw.lower_claw.calibration.lower_angle);
Austin Schuh288c8c32014-02-16 17:20:17 -0800390 bottom_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::CALIBRATED);
391 // calibrated so we are done fine tuning bottom
392 doing_calibration_fine_tune_ = false;
393 LOG(DEBUG, "Calibrated the bottom correctly!\n");
394 } else {
395 doing_calibration_fine_tune_ = false;
Austin Schuhd27931c2014-02-16 19:18:20 -0800396 bottom_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuh069143b2014-02-17 02:46:26 -0800397 top_claw_velocity_ = bottom_claw_velocity_ = 0.0;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800398 mode_ = PREP_FINE_TUNE_BOTTOM;
Austin Schuh288c8c32014-02-16 17:20:17 -0800399 }
Austin Schuhcda86af2014-02-16 16:16:39 -0800400 } else {
401 LOG(DEBUG, "Fine tuning\n");
402 }
403 }
404 // now set the top claw to track
405
Austin Schuhd27931c2014-02-16 19:18:20 -0800406 top_claw_goal_ = bottom_claw_goal_ + values.claw.claw_zeroing_separation;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800407 } else {
Austin Schuhcda86af2014-02-16 16:16:39 -0800408 // bottom claw must be calibrated, start on the top
409 if (!doing_calibration_fine_tune_) {
Austin Schuhd27931c2014-02-16 19:18:20 -0800410 if (::std::abs(top_absolute_position() -
411 values.claw.start_fine_tune_pos) <
412 values.claw.claw_unimportant_epsilon) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800413 doing_calibration_fine_tune_ = true;
Austin Schuhd27931c2014-02-16 19:18:20 -0800414 top_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800415 top_claw_velocity_ = bottom_claw_velocity_ =
416 values.claw.claw_zeroing_speed;
Austin Schuhcda86af2014-02-16 16:16:39 -0800417 LOG(DEBUG, "Ready to fine tune the top\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800418 mode_ = FINE_TUNE_TOP;
Austin Schuhcda86af2014-02-16 16:16:39 -0800419 } else {
420 // send top to zeroing start
Austin Schuhd27931c2014-02-16 19:18:20 -0800421 top_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuhcda86af2014-02-16 16:16:39 -0800422 LOG(DEBUG, "Going to the start position for the top\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800423 mode_ = PREP_FINE_TUNE_TOP;
Austin Schuhcda86af2014-02-16 16:16:39 -0800424 }
425 } else {
Austin Schuhe7f90d12014-02-17 00:48:25 -0800426 mode_ = FINE_TUNE_TOP;
Austin Schuhd27931c2014-02-16 19:18:20 -0800427 top_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800428 top_claw_velocity_ = bottom_claw_velocity_ =
429 values.claw.claw_zeroing_speed;
Brian Silvermane0a95462014-02-17 00:41:09 -0800430 if (top_claw_.front_or_back_triggered() ||
431 bottom_claw_.front_or_back_triggered()) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800432 // this should not happen, but now we know it won't
433 doing_calibration_fine_tune_ = false;
Austin Schuhd27931c2014-02-16 19:18:20 -0800434 top_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuh069143b2014-02-17 02:46:26 -0800435 top_claw_velocity_ = bottom_claw_velocity_ = 0.0;
Austin Schuhcda86af2014-02-16 16:16:39 -0800436 LOG(DEBUG, "Found a limit, starting over.\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800437 mode_ = PREP_FINE_TUNE_TOP;
Austin Schuhcda86af2014-02-16 16:16:39 -0800438 }
Brian Silvermane0a95462014-02-17 00:41:09 -0800439 if (top_claw_.calibration().value()) {
440 if (top_claw_.calibration().posedge_count_changed() &&
Austin Schuh288c8c32014-02-16 17:20:17 -0800441 position) {
442 // do calibration
Austin Schuhd27931c2014-02-16 19:18:20 -0800443 top_claw_.SetCalibration(
444 position->top.posedge_value,
445 values.claw.upper_claw.calibration.lower_angle);
Austin Schuh288c8c32014-02-16 17:20:17 -0800446 top_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::CALIBRATED);
Austin Schuhe7f90d12014-02-17 00:48:25 -0800447 // calibrated so we are done fine tuning top
Austin Schuh288c8c32014-02-16 17:20:17 -0800448 doing_calibration_fine_tune_ = false;
449 LOG(DEBUG, "Calibrated the top correctly!\n");
450 } else {
451 doing_calibration_fine_tune_ = false;
Austin Schuhd27931c2014-02-16 19:18:20 -0800452 top_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuh069143b2014-02-17 02:46:26 -0800453 top_claw_velocity_ = bottom_claw_velocity_ = 0.0;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800454 mode_ = PREP_FINE_TUNE_TOP;
Austin Schuh288c8c32014-02-16 17:20:17 -0800455 }
Austin Schuhcda86af2014-02-16 16:16:39 -0800456 }
457 }
458 // now set the bottom claw to track
Austin Schuhd27931c2014-02-16 19:18:20 -0800459 bottom_claw_goal_ = top_claw_goal_ - values.claw.claw_zeroing_separation;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800460 }
461 } else {
Austin Schuhcda86af2014-02-16 16:16:39 -0800462 doing_calibration_fine_tune_ = false;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800463 if (!was_enabled_ && enabled) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800464 if (position) {
465 top_claw_goal_ = position->top.position;
466 bottom_claw_goal_ = position->bottom.position;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800467 initial_separation_ =
Austin Schuhcda86af2014-02-16 16:16:39 -0800468 position->top.position - position->bottom.position;
Austin Schuhf9286cd2014-02-11 00:51:09 -0800469 } else {
470 has_top_claw_goal_ = false;
471 has_bottom_claw_goal_ = false;
472 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800473 }
Austin Schuhf9286cd2014-02-11 00:51:09 -0800474
Austin Schuh4cb047f2014-02-16 21:10:19 -0800475 if ((bottom_claw_.zeroing_state() !=
476 ZeroedStateFeedbackLoop::UNKNOWN_POSITION ||
Brian Silvermane0a95462014-02-17 00:41:09 -0800477 bottom_claw_.front().value() || top_claw_.front().value()) &&
478 !top_claw_.back().value() && !bottom_claw_.back().value()) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800479 if (enabled) {
480 // Time to slowly move back up to find any position to narrow down the
481 // zero.
Austin Schuhd27931c2014-02-16 19:18:20 -0800482 top_claw_goal_ += values.claw.claw_zeroing_off_speed * dt;
483 bottom_claw_goal_ += values.claw.claw_zeroing_off_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800484 top_claw_velocity_ = bottom_claw_velocity_ =
485 values.claw.claw_zeroing_off_speed;
Austin Schuhcda86af2014-02-16 16:16:39 -0800486 LOG(DEBUG, "Bottom is known.\n");
Austin Schuhf9286cd2014-02-11 00:51:09 -0800487 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800488 } else {
489 // We don't know where either claw is. Slowly start moving down to find
490 // any hall effect.
Austin Schuhf9286cd2014-02-11 00:51:09 -0800491 if (enabled) {
Austin Schuhd27931c2014-02-16 19:18:20 -0800492 top_claw_goal_ -= values.claw.claw_zeroing_off_speed * dt;
493 bottom_claw_goal_ -= values.claw.claw_zeroing_off_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800494 top_claw_velocity_ = bottom_claw_velocity_ =
495 -values.claw.claw_zeroing_off_speed;
Austin Schuhcda86af2014-02-16 16:16:39 -0800496 LOG(DEBUG, "Both are unknown.\n");
Austin Schuhf9286cd2014-02-11 00:51:09 -0800497 }
498 }
499
500 if (enabled) {
501 top_claw_.SetCalibrationOnEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800502 values.claw.upper_claw, ZeroedStateFeedbackLoop::APPROXIMATE_CALIBRATION);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800503 bottom_claw_.SetCalibrationOnEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800504 values.claw.lower_claw, ZeroedStateFeedbackLoop::APPROXIMATE_CALIBRATION);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800505 } else {
Austin Schuh069143b2014-02-17 02:46:26 -0800506 // TODO(austin): Only calibrate on the predetermined edge.
507 // We might be able to just ignore this since the backlash is soooo low. :)
Austin Schuhf9286cd2014-02-11 00:51:09 -0800508 top_claw_.SetCalibrationOnEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800509 values.claw.upper_claw, ZeroedStateFeedbackLoop::DISABLED_CALIBRATION);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800510 bottom_claw_.SetCalibrationOnEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800511 values.claw.lower_claw, ZeroedStateFeedbackLoop::DISABLED_CALIBRATION);
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800512 }
Austin Schuhe7f90d12014-02-17 00:48:25 -0800513 mode_ = UNKNOWN_LOCATION;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800514 }
515
Austin Schuh069143b2014-02-17 02:46:26 -0800516 // Limit the goals if both claws have been (mostly) found.
517 if (mode_ != UNKNOWN_LOCATION) {
518 LimitClawGoal(&bottom_claw_goal_, &top_claw_goal_, values);
519 }
520
Austin Schuhf9286cd2014-02-11 00:51:09 -0800521 if (has_top_claw_goal_ && has_bottom_claw_goal_) {
Austin Schuh069143b2014-02-17 02:46:26 -0800522 claw_.R << bottom_claw_goal_, top_claw_goal_ - bottom_claw_goal_,
523 bottom_claw_velocity_, top_claw_velocity_ - bottom_claw_velocity_;
Austin Schuhcda86af2014-02-16 16:16:39 -0800524 double separation = -971;
525 if (position != nullptr) {
526 separation = position->top.position - position->bottom.position;
527 }
528 LOG(DEBUG, "Goal is %f (bottom) %f, separation is %f\n", claw_.R(0, 0),
529 claw_.R(1, 0), separation);
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800530
Austin Schuh4cb047f2014-02-16 21:10:19 -0800531 // Only cap power when one of the halves of the claw is unknown.
Austin Schuhe7f90d12014-02-17 00:48:25 -0800532 claw_.set_is_zeroing(mode_ == UNKNOWN_LOCATION || mode_ == FINE_TUNE_TOP ||
533 mode_ == FINE_TUNE_BOTTOM);
Austin Schuhcda86af2014-02-16 16:16:39 -0800534 claw_.Update(output == nullptr);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800535 } else {
Austin Schuhcda86af2014-02-16 16:16:39 -0800536 claw_.Update(true);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800537 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800538
Austin Schuh4cb047f2014-02-16 21:10:19 -0800539 capped_goal_ = false;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800540 switch (mode_) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800541 case READY:
Austin Schuhe7f90d12014-02-17 00:48:25 -0800542 case PREP_FINE_TUNE_TOP:
543 case PREP_FINE_TUNE_BOTTOM:
Austin Schuhcda86af2014-02-16 16:16:39 -0800544 break;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800545 case FINE_TUNE_BOTTOM:
546 case FINE_TUNE_TOP:
Austin Schuh4cb047f2014-02-16 21:10:19 -0800547 case UNKNOWN_LOCATION: {
548 if (claw_.uncapped_average_voltage() > values.claw.max_zeroing_voltage) {
549 double dx = (claw_.uncapped_average_voltage() -
550 values.claw.max_zeroing_voltage) /
551 claw_.K(0, 0);
552 bottom_claw_goal_ -= dx;
553 top_claw_goal_ -= dx;
Austin Schuhcda86af2014-02-16 16:16:39 -0800554 capped_goal_ = true;
Austin Schuh4cb047f2014-02-16 21:10:19 -0800555 LOG(DEBUG, "Moving the goal by %f to prevent windup\n", dx);
Austin Schuhe7f90d12014-02-17 00:48:25 -0800556 LOG(DEBUG, "Uncapped is %f, max is %f, difference is %f\n",
557 claw_.uncapped_average_voltage(), values.claw.max_zeroing_voltage,
558 (claw_.uncapped_average_voltage() -
559 values.claw.max_zeroing_voltage));
Austin Schuh4cb047f2014-02-16 21:10:19 -0800560 } else if (claw_.uncapped_average_voltage() <
561 -values.claw.max_zeroing_voltage) {
562 double dx = (claw_.uncapped_average_voltage() +
563 values.claw.max_zeroing_voltage) /
564 claw_.K(0, 0);
565 bottom_claw_goal_ -= dx;
566 top_claw_goal_ -= dx;
Austin Schuhcda86af2014-02-16 16:16:39 -0800567 capped_goal_ = true;
Austin Schuh4cb047f2014-02-16 21:10:19 -0800568 LOG(DEBUG, "Moving the goal by %f to prevent windup\n", dx);
Austin Schuhcda86af2014-02-16 16:16:39 -0800569 }
Austin Schuh4cb047f2014-02-16 21:10:19 -0800570 } break;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800571 }
572
573 if (output) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800574 output->top_claw_voltage = claw_.U(1, 0) + claw_.U(0, 0);
575 output->bottom_claw_voltage = claw_.U(0, 0);
Austin Schuh3bb9a442014-02-02 16:01:45 -0800576 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800577 status->done = false;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800578
579 was_enabled_ = ::aos::robot_state->enabled;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800580}
581
582} // namespace control_loops
583} // namespace frc971