blob: b445546fbdcffc501ee0049f46b18610aefef53c [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()) {
94 if (posedge_value_ < last_encoder()) {
95 *edge_angle = angles.upper_angle;
96 LOG(INFO, "%s Posedge upper of %s -> %f\n", name_,
97 hall_effect_name, *edge_angle);
98 } else {
99 *edge_angle = angles.lower_angle;
100 LOG(INFO, "%s Posedge lower of %s -> %f\n", name_,
101 hall_effect_name, *edge_angle);
102 }
103 *edge_encoder = posedge_value_;
104 return true;
105 }
106 if (sensor.negedge_count_changed()) {
107 if (negedge_value_ > last_encoder()) {
108 *edge_angle = angles.upper_angle;
109 LOG(INFO, "%s Negedge upper of %s -> %f\n", name_,
110 hall_effect_name, *edge_angle);
111 } else {
112 *edge_angle = angles.lower_angle;
113 LOG(INFO, "%s Negedge lower of %s -> %f\n", name_,
114 hall_effect_name, *edge_angle);
115 }
116 *edge_encoder = negedge_value_;
117 return true;
118 }
119
120 return false;
121}
122
Austin Schuhf9286cd2014-02-11 00:51:09 -0800123bool ZeroedStateFeedbackLoop::GetPositionOfEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800124 const constants::Values::Claws::Claw &claw_values, double *edge_encoder,
Austin Schuhf9286cd2014-02-11 00:51:09 -0800125 double *edge_angle) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800126 // TODO(austin): Validate that the hall effect edge makes sense.
127 // We must now be on the side of the edge that we expect to be, and the
128 // encoder must have been on either side of the edge before and after.
129
Austin Schuhcda86af2014-02-16 16:16:39 -0800130 // TODO(austin): Compute the last off range min and max and compare the edge
131 // value to the middle of the range. This will be quite a bit more reliable.
132
Brian Silvermane0a95462014-02-17 00:41:09 -0800133 if (DoGetPositionOfEdge(claw_values.front, edge_encoder, edge_angle,
134 front_, "front")) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800135 return true;
136 }
Brian Silvermane0a95462014-02-17 00:41:09 -0800137 if (DoGetPositionOfEdge(claw_values.calibration, edge_encoder, edge_angle,
138 calibration_, "calibration")) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800139 return true;
140 }
Brian Silvermane0a95462014-02-17 00:41:09 -0800141 if (DoGetPositionOfEdge(claw_values.back, edge_encoder, edge_angle,
142 back_, "back")) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800143 return true;
144 }
145 return false;
146}
147
Austin Schuhcda86af2014-02-16 16:16:39 -0800148void TopZeroedStateFeedbackLoop::SetCalibration(double edge_encoder,
149 double edge_angle) {
150 double old_offset = offset_;
151 offset_ = edge_angle - edge_encoder;
152 const double doffset = offset_ - old_offset;
153 motor_->ChangeTopOffset(doffset);
154}
155
156void BottomZeroedStateFeedbackLoop::SetCalibration(double edge_encoder,
157 double edge_angle) {
158 double old_offset = offset_;
159 offset_ = edge_angle - edge_encoder;
160 const double doffset = offset_ - old_offset;
161 motor_->ChangeBottomOffset(doffset);
162}
163
164void ClawMotor::ChangeTopOffset(double doffset) {
165 claw_.ChangeTopOffset(doffset);
166 if (has_top_claw_goal_) {
167 top_claw_goal_ += doffset;
168 }
169}
170
171void ClawMotor::ChangeBottomOffset(double doffset) {
172 claw_.ChangeBottomOffset(doffset);
173 if (has_bottom_claw_goal_) {
174 bottom_claw_goal_ += doffset;
175 }
176}
177
178void ClawLimitedLoop::ChangeTopOffset(double doffset) {
179 Y_(1, 0) += doffset;
180 X_hat(1, 0) += doffset;
181 LOG(INFO, "Changing top offset by %f\n", doffset);
182}
183void ClawLimitedLoop::ChangeBottomOffset(double doffset) {
184 Y_(0, 0) += doffset;
185 X_hat(0, 0) += doffset;
186 X_hat(1, 0) -= doffset;
187 LOG(INFO, "Changing bottom offset by %f\n", doffset);
188}
joe7376ff52014-02-16 18:28:42 -0800189//void FixClawPos(double * bottom_goal, double * top_goal, frc971::constants::Values &values) {
190// //first update position based on angle limit
191//
192// double goal_angle = *top_goal - *bottom_goal;
193// if (goal_angle > values.lower_claw.front.upper_angle) {
194// *bottom_goal += goal_angle - values.lower_claw.front.upper_angle;
195// }
196// if (goal_angle < values.lower_claw.front.lower_angle) {
197// *bottom_goal += goal_angle - values.lower_claw.front.lower_angle;
198// }
199//
200// //now move both goals in unison
201// if (*bottom_goal < values.bottom.lower_limit) {
202// *bottom_goal += *bottom_goal - values.lower_claw.lower_limit;
203// *top_goal += *bottom_goal - values.bottom.lower_limit;
204// }
205// if (*bottom_goal > values.bottom.upper_limit) {
206// *bottom_goal -= *bottom_goal - values.bottom.upper_limit;
207// *top_goal -= *bottom_goal - values.bottom.upper_limit;
208// }
209//
210// if (*top_goal < values.bottom.lower_limit) {
211// *top_goal += *top_goal - values.bottom.lower_limit;
212// *bottom_goal += *top_goal - values.bottom.lower_limit;
213// }
214// if (*top_goal > values.top.upper_limit) {
215// *top_goal -= *top_goal - values.top.upper_limit;
216// *bottom_goal -= *top_goal - values.top.upper_limit;
217// }
218//}
219
Austin Schuhcda86af2014-02-16 16:16:39 -0800220
Austin Schuhe7f90d12014-02-17 00:48:25 -0800221bool ClawMotor::is_ready() const {
222 return (
223 (top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED &&
224 bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED) ||
225 (::aos::robot_state->autonomous &&
226 ((top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
227 top_claw_.zeroing_state() ==
228 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION) &&
229 (bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
230 bottom_claw_.zeroing_state() ==
231 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION))));
232}
233
234bool ClawMotor::is_zeroing() const { return !is_ready(); }
235
Austin Schuh3bb9a442014-02-02 16:01:45 -0800236// Positive angle is up, and positive power is up.
Austin Schuhcc0bf312014-02-09 00:39:29 -0800237void ClawMotor::RunIteration(const control_loops::ClawGroup::Goal *goal,
238 const control_loops::ClawGroup::Position *position,
239 control_loops::ClawGroup::Output *output,
Austin Schuh3bb9a442014-02-02 16:01:45 -0800240 ::aos::control_loops::Status *status) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800241 constexpr double dt = 0.01;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800242
243 // Disable the motors now so that all early returns will return with the
244 // motors disabled.
245 if (output) {
246 output->top_claw_voltage = 0;
247 output->bottom_claw_voltage = 0;
248 output->intake_voltage = 0;
249 }
250
Austin Schuhcda86af2014-02-16 16:16:39 -0800251 // TODO(austin): Handle zeroing while disabled correctly (only use a single
252 // edge and direction when zeroing.)
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800253
Austin Schuh1a499942014-02-17 01:51:58 -0800254 if (reset()) {
255 bottom_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::UNKNOWN_POSITION);
256 top_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::UNKNOWN_POSITION);
257 }
258
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800259 if (::aos::robot_state.get() == nullptr) {
260 return;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800261 }
262
Austin Schuhf9286cd2014-02-11 00:51:09 -0800263 const frc971::constants::Values &values = constants::GetValues();
264
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800265 if (position) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800266 Eigen::Matrix<double, 2, 1> Y;
267 Y << position->bottom.position + bottom_claw_.offset(),
268 position->top.position + top_claw_.offset();
269 claw_.Correct(Y);
270
Austin Schuhf9286cd2014-02-11 00:51:09 -0800271 top_claw_.SetPositionValues(position->top);
272 bottom_claw_.SetPositionValues(position->bottom);
273
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800274 if (!has_top_claw_goal_) {
275 has_top_claw_goal_ = true;
Austin Schuhcda86af2014-02-16 16:16:39 -0800276 top_claw_goal_ = top_claw_.absolute_position();
Austin Schuhe7f90d12014-02-17 00:48:25 -0800277 initial_separation_ =
Austin Schuhcda86af2014-02-16 16:16:39 -0800278 top_claw_.absolute_position() - bottom_claw_.absolute_position();
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800279 }
280 if (!has_bottom_claw_goal_) {
281 has_bottom_claw_goal_ = true;
Austin Schuhcda86af2014-02-16 16:16:39 -0800282 bottom_claw_goal_ = bottom_claw_.absolute_position();
Austin Schuhe7f90d12014-02-17 00:48:25 -0800283 initial_separation_ =
Austin Schuhcda86af2014-02-16 16:16:39 -0800284 top_claw_.absolute_position() - bottom_claw_.absolute_position();
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800285 }
Austin Schuhcda86af2014-02-16 16:16:39 -0800286 LOG(DEBUG, "Claw position is (top: %f bottom: %f\n",
287 top_claw_.absolute_position(), bottom_claw_.absolute_position());
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800288 }
289
290 bool autonomous = ::aos::robot_state->autonomous;
Austin Schuhf9286cd2014-02-11 00:51:09 -0800291 bool enabled = ::aos::robot_state->enabled;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800292
293 if ((top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED &&
294 bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED) ||
295 (autonomous &&
296 ((top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
297 top_claw_.zeroing_state() ==
298 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION) &&
299 (bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
300 bottom_claw_.zeroing_state() ==
301 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION)))) {
302 // Ready to use the claw.
303 // Limit the goals here.
Austin Schuhf9286cd2014-02-11 00:51:09 -0800304 bottom_claw_goal_ = goal->bottom_angle;
305 top_claw_goal_ = goal->bottom_angle + goal->seperation_angle;
Austin Schuhcda86af2014-02-16 16:16:39 -0800306 has_bottom_claw_goal_ = true;
307 has_top_claw_goal_ = true;
308 doing_calibration_fine_tune_ = false;
309
Austin Schuhe7f90d12014-02-17 00:48:25 -0800310 mode_ = READY;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800311 } else if (top_claw_.zeroing_state() !=
312 ZeroedStateFeedbackLoop::UNKNOWN_POSITION &&
313 bottom_claw_.zeroing_state() !=
314 ZeroedStateFeedbackLoop::UNKNOWN_POSITION) {
315 // Time to fine tune the zero.
316 // Limit the goals here.
Austin Schuh0c733422014-02-17 01:17:12 -0800317 if (!enabled) {
318 // If we are disabled, start the fine tune process over again.
319 doing_calibration_fine_tune_ = false;
320 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800321 if (bottom_claw_.zeroing_state() != ZeroedStateFeedbackLoop::CALIBRATED) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800322 // always get the bottom claw to calibrated first
323 LOG(DEBUG, "Calibrating the bottom of the claw\n");
324 if (!doing_calibration_fine_tune_) {
325 if (::std::abs(bottom_absolute_position() -
Austin Schuhd27931c2014-02-16 19:18:20 -0800326 values.claw.start_fine_tune_pos) <
327 values.claw.claw_unimportant_epsilon) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800328 doing_calibration_fine_tune_ = true;
Austin Schuhd27931c2014-02-16 19:18:20 -0800329 bottom_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuhcda86af2014-02-16 16:16:39 -0800330 LOG(DEBUG, "Ready to fine tune the bottom\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800331 mode_ = FINE_TUNE_BOTTOM;
Austin Schuhcda86af2014-02-16 16:16:39 -0800332 } else {
333 // send bottom to zeroing start
Austin Schuhd27931c2014-02-16 19:18:20 -0800334 bottom_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuhcda86af2014-02-16 16:16:39 -0800335 LOG(DEBUG, "Going to the start position for the bottom\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800336 mode_ = PREP_FINE_TUNE_BOTTOM;
Austin Schuhcda86af2014-02-16 16:16:39 -0800337 }
338 } else {
Austin Schuhe7f90d12014-02-17 00:48:25 -0800339 mode_ = FINE_TUNE_BOTTOM;
Austin Schuhd27931c2014-02-16 19:18:20 -0800340 bottom_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Brian Silvermane0a95462014-02-17 00:41:09 -0800341 if (top_claw_.front_or_back_triggered() ||
342 bottom_claw_.front_or_back_triggered()) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800343 // We shouldn't hit a limit, but if we do, go back to the zeroing
344 // point and try again.
345 doing_calibration_fine_tune_ = false;
Austin Schuhd27931c2014-02-16 19:18:20 -0800346 bottom_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuhcda86af2014-02-16 16:16:39 -0800347 LOG(DEBUG, "Found a limit, starting over.\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800348 mode_ = PREP_FINE_TUNE_BOTTOM;
Austin Schuhcda86af2014-02-16 16:16:39 -0800349 }
Austin Schuh288c8c32014-02-16 17:20:17 -0800350
Brian Silvermane0a95462014-02-17 00:41:09 -0800351 if (bottom_claw_.calibration().value()) {
352 if (bottom_claw_.calibration().posedge_count_changed() &&
Austin Schuh288c8c32014-02-16 17:20:17 -0800353 position) {
354 // do calibration
355 bottom_claw_.SetCalibration(
356 position->bottom.posedge_value,
Austin Schuhd27931c2014-02-16 19:18:20 -0800357 values.claw.lower_claw.calibration.lower_angle);
Austin Schuh288c8c32014-02-16 17:20:17 -0800358 bottom_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::CALIBRATED);
359 // calibrated so we are done fine tuning bottom
360 doing_calibration_fine_tune_ = false;
361 LOG(DEBUG, "Calibrated the bottom correctly!\n");
362 } else {
363 doing_calibration_fine_tune_ = false;
Austin Schuhd27931c2014-02-16 19:18:20 -0800364 bottom_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800365 mode_ = PREP_FINE_TUNE_BOTTOM;
Austin Schuh288c8c32014-02-16 17:20:17 -0800366 }
Austin Schuhcda86af2014-02-16 16:16:39 -0800367 } else {
368 LOG(DEBUG, "Fine tuning\n");
369 }
370 }
371 // now set the top claw to track
372
Austin Schuhd27931c2014-02-16 19:18:20 -0800373 top_claw_goal_ = bottom_claw_goal_ + values.claw.claw_zeroing_separation;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800374 } else {
Austin Schuhcda86af2014-02-16 16:16:39 -0800375 // bottom claw must be calibrated, start on the top
376 if (!doing_calibration_fine_tune_) {
Austin Schuhd27931c2014-02-16 19:18:20 -0800377 if (::std::abs(top_absolute_position() -
378 values.claw.start_fine_tune_pos) <
379 values.claw.claw_unimportant_epsilon) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800380 doing_calibration_fine_tune_ = true;
Austin Schuhd27931c2014-02-16 19:18:20 -0800381 top_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuhcda86af2014-02-16 16:16:39 -0800382 LOG(DEBUG, "Ready to fine tune the top\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800383 mode_ = FINE_TUNE_TOP;
Austin Schuhcda86af2014-02-16 16:16:39 -0800384 } else {
385 // send top to zeroing start
Austin Schuhd27931c2014-02-16 19:18:20 -0800386 top_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuhcda86af2014-02-16 16:16:39 -0800387 LOG(DEBUG, "Going to the start position for the top\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800388 mode_ = PREP_FINE_TUNE_TOP;
Austin Schuhcda86af2014-02-16 16:16:39 -0800389 }
390 } else {
Austin Schuhe7f90d12014-02-17 00:48:25 -0800391 mode_ = FINE_TUNE_TOP;
Austin Schuhd27931c2014-02-16 19:18:20 -0800392 top_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Brian Silvermane0a95462014-02-17 00:41:09 -0800393 if (top_claw_.front_or_back_triggered() ||
394 bottom_claw_.front_or_back_triggered()) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800395 // this should not happen, but now we know it won't
396 doing_calibration_fine_tune_ = false;
Austin Schuhd27931c2014-02-16 19:18:20 -0800397 top_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuhcda86af2014-02-16 16:16:39 -0800398 LOG(DEBUG, "Found a limit, starting over.\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800399 mode_ = PREP_FINE_TUNE_TOP;
Austin Schuhcda86af2014-02-16 16:16:39 -0800400 }
Brian Silvermane0a95462014-02-17 00:41:09 -0800401 if (top_claw_.calibration().value()) {
402 if (top_claw_.calibration().posedge_count_changed() &&
Austin Schuh288c8c32014-02-16 17:20:17 -0800403 position) {
404 // do calibration
Austin Schuhd27931c2014-02-16 19:18:20 -0800405 top_claw_.SetCalibration(
406 position->top.posedge_value,
407 values.claw.upper_claw.calibration.lower_angle);
Austin Schuh288c8c32014-02-16 17:20:17 -0800408 top_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::CALIBRATED);
Austin Schuhe7f90d12014-02-17 00:48:25 -0800409 // calibrated so we are done fine tuning top
Austin Schuh288c8c32014-02-16 17:20:17 -0800410 doing_calibration_fine_tune_ = false;
411 LOG(DEBUG, "Calibrated the top correctly!\n");
412 } else {
413 doing_calibration_fine_tune_ = false;
Austin Schuhd27931c2014-02-16 19:18:20 -0800414 top_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800415 mode_ = PREP_FINE_TUNE_TOP;
Austin Schuh288c8c32014-02-16 17:20:17 -0800416 }
Austin Schuhcda86af2014-02-16 16:16:39 -0800417 }
418 }
419 // now set the bottom claw to track
Austin Schuhd27931c2014-02-16 19:18:20 -0800420 bottom_claw_goal_ = top_claw_goal_ - values.claw.claw_zeroing_separation;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800421 }
422 } else {
Austin Schuhcda86af2014-02-16 16:16:39 -0800423 doing_calibration_fine_tune_ = false;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800424 if (!was_enabled_ && enabled) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800425 if (position) {
426 top_claw_goal_ = position->top.position;
427 bottom_claw_goal_ = position->bottom.position;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800428 initial_separation_ =
Austin Schuhcda86af2014-02-16 16:16:39 -0800429 position->top.position - position->bottom.position;
Austin Schuhf9286cd2014-02-11 00:51:09 -0800430 } else {
431 has_top_claw_goal_ = false;
432 has_bottom_claw_goal_ = false;
433 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800434 }
Austin Schuhf9286cd2014-02-11 00:51:09 -0800435
436 // TODO(austin): Limit the goals here.
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800437
Austin Schuh4cb047f2014-02-16 21:10:19 -0800438 if ((bottom_claw_.zeroing_state() !=
439 ZeroedStateFeedbackLoop::UNKNOWN_POSITION ||
Brian Silvermane0a95462014-02-17 00:41:09 -0800440 bottom_claw_.front().value() || top_claw_.front().value()) &&
441 !top_claw_.back().value() && !bottom_claw_.back().value()) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800442 if (enabled) {
443 // Time to slowly move back up to find any position to narrow down the
444 // zero.
Austin Schuhd27931c2014-02-16 19:18:20 -0800445 top_claw_goal_ += values.claw.claw_zeroing_off_speed * dt;
446 bottom_claw_goal_ += values.claw.claw_zeroing_off_speed * dt;
Austin Schuhf9286cd2014-02-11 00:51:09 -0800447 // TODO(austin): Goal velocity too!
Austin Schuhcda86af2014-02-16 16:16:39 -0800448 LOG(DEBUG, "Bottom is known.\n");
Austin Schuhf9286cd2014-02-11 00:51:09 -0800449 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800450 } else {
451 // We don't know where either claw is. Slowly start moving down to find
452 // any hall effect.
Austin Schuhf9286cd2014-02-11 00:51:09 -0800453 if (enabled) {
Austin Schuhd27931c2014-02-16 19:18:20 -0800454 top_claw_goal_ -= values.claw.claw_zeroing_off_speed * dt;
455 bottom_claw_goal_ -= values.claw.claw_zeroing_off_speed * dt;
Austin Schuhf9286cd2014-02-11 00:51:09 -0800456 // TODO(austin): Goal velocity too!
Austin Schuhcda86af2014-02-16 16:16:39 -0800457 LOG(DEBUG, "Both are unknown.\n");
Austin Schuhf9286cd2014-02-11 00:51:09 -0800458 }
459 }
460
461 if (enabled) {
462 top_claw_.SetCalibrationOnEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800463 values.claw.upper_claw, ZeroedStateFeedbackLoop::APPROXIMATE_CALIBRATION);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800464 bottom_claw_.SetCalibrationOnEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800465 values.claw.lower_claw, ZeroedStateFeedbackLoop::APPROXIMATE_CALIBRATION);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800466 } else {
467 top_claw_.SetCalibrationOnEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800468 values.claw.upper_claw, ZeroedStateFeedbackLoop::DISABLED_CALIBRATION);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800469 bottom_claw_.SetCalibrationOnEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800470 values.claw.lower_claw, ZeroedStateFeedbackLoop::DISABLED_CALIBRATION);
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800471 }
Austin Schuhe7f90d12014-02-17 00:48:25 -0800472 mode_ = UNKNOWN_LOCATION;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800473 }
474
Austin Schuh288c8c32014-02-16 17:20:17 -0800475 // TODO(Joe): Write this.
joe7376ff52014-02-16 18:28:42 -0800476 // make sure this is possible phsically
477 // fix goals to make it possible
478 // break into function at some point?
479 //
480 //FixClawPos(&bottom_claw_goal_, &top_claw_goal_, values);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800481 if (has_top_claw_goal_ && has_bottom_claw_goal_) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800482 claw_.R << bottom_claw_goal_, top_claw_goal_ - bottom_claw_goal_, 0, 0;
483 double separation = -971;
484 if (position != nullptr) {
485 separation = position->top.position - position->bottom.position;
486 }
487 LOG(DEBUG, "Goal is %f (bottom) %f, separation is %f\n", claw_.R(0, 0),
488 claw_.R(1, 0), separation);
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800489
Austin Schuh4cb047f2014-02-16 21:10:19 -0800490 // Only cap power when one of the halves of the claw is unknown.
Austin Schuhe7f90d12014-02-17 00:48:25 -0800491 claw_.set_is_zeroing(mode_ == UNKNOWN_LOCATION || mode_ == FINE_TUNE_TOP ||
492 mode_ == FINE_TUNE_BOTTOM);
Austin Schuhcda86af2014-02-16 16:16:39 -0800493 claw_.Update(output == nullptr);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800494 } else {
Austin Schuhcda86af2014-02-16 16:16:39 -0800495 claw_.Update(true);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800496 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800497
Austin Schuh4cb047f2014-02-16 21:10:19 -0800498 capped_goal_ = false;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800499 switch (mode_) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800500 case READY:
Austin Schuhe7f90d12014-02-17 00:48:25 -0800501 case PREP_FINE_TUNE_TOP:
502 case PREP_FINE_TUNE_BOTTOM:
Austin Schuhcda86af2014-02-16 16:16:39 -0800503 break;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800504 case FINE_TUNE_BOTTOM:
505 case FINE_TUNE_TOP:
Austin Schuh4cb047f2014-02-16 21:10:19 -0800506 case UNKNOWN_LOCATION: {
507 if (claw_.uncapped_average_voltage() > values.claw.max_zeroing_voltage) {
508 double dx = (claw_.uncapped_average_voltage() -
509 values.claw.max_zeroing_voltage) /
510 claw_.K(0, 0);
511 bottom_claw_goal_ -= dx;
512 top_claw_goal_ -= dx;
Austin Schuhcda86af2014-02-16 16:16:39 -0800513 capped_goal_ = true;
Austin Schuh4cb047f2014-02-16 21:10:19 -0800514 LOG(DEBUG, "Moving the goal by %f to prevent windup\n", dx);
Austin Schuhe7f90d12014-02-17 00:48:25 -0800515 LOG(DEBUG, "Uncapped is %f, max is %f, difference is %f\n",
516 claw_.uncapped_average_voltage(), values.claw.max_zeroing_voltage,
517 (claw_.uncapped_average_voltage() -
518 values.claw.max_zeroing_voltage));
Austin Schuh4cb047f2014-02-16 21:10:19 -0800519 } else if (claw_.uncapped_average_voltage() <
520 -values.claw.max_zeroing_voltage) {
521 double dx = (claw_.uncapped_average_voltage() +
522 values.claw.max_zeroing_voltage) /
523 claw_.K(0, 0);
524 bottom_claw_goal_ -= dx;
525 top_claw_goal_ -= dx;
Austin Schuhcda86af2014-02-16 16:16:39 -0800526 capped_goal_ = true;
Austin Schuh4cb047f2014-02-16 21:10:19 -0800527 LOG(DEBUG, "Moving the goal by %f to prevent windup\n", dx);
Austin Schuhcda86af2014-02-16 16:16:39 -0800528 }
Austin Schuh4cb047f2014-02-16 21:10:19 -0800529 } break;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800530 }
531
532 if (output) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800533 output->top_claw_voltage = claw_.U(1, 0) + claw_.U(0, 0);
534 output->bottom_claw_voltage = claw_.U(0, 0);
Austin Schuh3bb9a442014-02-02 16:01:45 -0800535 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800536 status->done = false;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800537
538 was_enabled_ = ::aos::robot_state->enabled;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800539}
540
541} // namespace control_loops
542} // namespace frc971