blob: 1910989d56e668cdec7f87bf13984a4dce9b4fb9 [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() {
James Kuszmauld536a402014-02-18 22:32:12 -080049 uncapped_average_voltage_ = (U(0, 0) + U(1, 0)) / 2.0;
Austin Schuh4cb047f2014-02-16 21:10:19 -080050 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;
James Kuszmauld536a402014-02-18 22:32:12 -080056 U(1, 0) -= difference;
Austin Schuh4cb047f2014-02-16 21:10:19 -080057 } else if (uncapped_average_voltage_ < -values.claw.max_zeroing_voltage) {
58 const double difference =
59 -uncapped_average_voltage_ - values.claw.max_zeroing_voltage;
60 U(0, 0) += difference;
James Kuszmauld536a402014-02-18 22:32:12 -080061 U(1, 0) += difference;
Austin Schuh4cb047f2014-02-16 21:10:19 -080062 }
63 }
64
65 double max_value =
James Kuszmauld536a402014-02-18 22:32:12 -080066 ::std::max(::std::abs(U(0, 0)), ::std::abs(U(1, 0)));
67 double scalar = 12.0 / max_value;
68 bool bottom_big = (::std::abs(U(0, 0)) > 12.0) &&
69 (::std::abs(U(0, 0)) > ::std::abs(U(1, 0)));
70 bool top_big = (::std::abs(U(1, 0)) > 12.0) && (!bottom_big);
71 double separation_voltage = U(1, 0) - U(0, 0) / 3.0000;
72 double u_top = U(1, 0);
73 double u_bottom = U(0, 0);
Austin Schuh4cb047f2014-02-16 21:10:19 -080074
James Kuszmauld536a402014-02-18 22:32:12 -080075 if (bottom_big) {
76 LOG(DEBUG, "Capping U because bottom is %f\n", max_value);
77 u_bottom *= scalar;
78 u_top = separation_voltage + u_bottom / 3.0000;
79 // If we can't maintain the separation, just clip it.
80 if (u_top > 12.0) u_top = 12.0;
81 else if (u_top < -12.0) u_top = -12.0;
Austin Schuh4b7b5d02014-02-10 21:20:34 -080082 }
James Kuszmauld536a402014-02-18 22:32:12 -080083 else if (top_big) {
84 LOG(DEBUG, "Capping U because top is %f\n", max_value);
85 u_top *= scalar;
86 u_bottom = (u_top - separation_voltage) * 3.0000;
87 if (u_bottom > 12.0) u_bottom = 12.0;
88 else if (u_bottom < -12.0) u_bottom = -12.0;
89 }
90
91 U(0, 0) = u_bottom;
92 U(1, 0) = u_top;
93
94 LOG(DEBUG, "Capping U is now %f %f\n", U(0, 0), U(1, 0));
95 LOG(DEBUG, "Separation Voltage was %f, is now %f\n", separation_voltage,
96 U(1, 0) - U(0, 0) / 3.0000);
Austin Schuh4b7b5d02014-02-10 21:20:34 -080097}
98
Austin Schuhcc0bf312014-02-09 00:39:29 -080099ClawMotor::ClawMotor(control_loops::ClawGroup *my_claw)
100 : aos::control_loops::ControlLoop<control_loops::ClawGroup>(my_claw),
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800101 has_top_claw_goal_(false),
102 top_claw_goal_(0.0),
Austin Schuhcda86af2014-02-16 16:16:39 -0800103 top_claw_(this),
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800104 has_bottom_claw_goal_(false),
105 bottom_claw_goal_(0.0),
Austin Schuhcda86af2014-02-16 16:16:39 -0800106 bottom_claw_(this),
107 claw_(MakeClawLoop()),
Ben Fredrickson9b388422014-02-13 06:15:31 +0000108 was_enabled_(false),
Austin Schuh4cb047f2014-02-16 21:10:19 -0800109 doing_calibration_fine_tune_(false),
Austin Schuhe7f90d12014-02-17 00:48:25 -0800110 capped_goal_(false),
111 mode_(UNKNOWN_LOCATION) {}
Austin Schuh3bb9a442014-02-02 16:01:45 -0800112
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800113const int ZeroedStateFeedbackLoop::kZeroingMaxVoltage;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800114
Brian Silvermane0a95462014-02-17 00:41:09 -0800115bool ZeroedStateFeedbackLoop::DoGetPositionOfEdge(
116 const constants::Values::Claws::AnglePair &angles, double *edge_encoder,
117 double *edge_angle, const HallEffectTracker &sensor,
118 const char *hall_effect_name) {
119 if (sensor.posedge_count_changed()) {
120 if (posedge_value_ < last_encoder()) {
121 *edge_angle = angles.upper_angle;
122 LOG(INFO, "%s Posedge upper of %s -> %f\n", name_,
123 hall_effect_name, *edge_angle);
124 } else {
125 *edge_angle = angles.lower_angle;
126 LOG(INFO, "%s Posedge lower of %s -> %f\n", name_,
127 hall_effect_name, *edge_angle);
128 }
129 *edge_encoder = posedge_value_;
130 return true;
131 }
132 if (sensor.negedge_count_changed()) {
133 if (negedge_value_ > last_encoder()) {
134 *edge_angle = angles.upper_angle;
135 LOG(INFO, "%s Negedge upper of %s -> %f\n", name_,
136 hall_effect_name, *edge_angle);
137 } else {
138 *edge_angle = angles.lower_angle;
139 LOG(INFO, "%s Negedge lower of %s -> %f\n", name_,
140 hall_effect_name, *edge_angle);
141 }
142 *edge_encoder = negedge_value_;
143 return true;
144 }
145
146 return false;
147}
148
Austin Schuhf9286cd2014-02-11 00:51:09 -0800149bool ZeroedStateFeedbackLoop::GetPositionOfEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800150 const constants::Values::Claws::Claw &claw_values, double *edge_encoder,
Austin Schuhf9286cd2014-02-11 00:51:09 -0800151 double *edge_angle) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800152 // TODO(austin): Validate that the hall effect edge makes sense.
153 // We must now be on the side of the edge that we expect to be, and the
154 // encoder must have been on either side of the edge before and after.
155
Austin Schuhcda86af2014-02-16 16:16:39 -0800156 // TODO(austin): Compute the last off range min and max and compare the edge
157 // value to the middle of the range. This will be quite a bit more reliable.
158
Brian Silvermane0a95462014-02-17 00:41:09 -0800159 if (DoGetPositionOfEdge(claw_values.front, edge_encoder, edge_angle,
160 front_, "front")) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800161 return true;
162 }
Brian Silvermane0a95462014-02-17 00:41:09 -0800163 if (DoGetPositionOfEdge(claw_values.calibration, edge_encoder, edge_angle,
164 calibration_, "calibration")) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800165 return true;
166 }
Brian Silvermane0a95462014-02-17 00:41:09 -0800167 if (DoGetPositionOfEdge(claw_values.back, edge_encoder, edge_angle,
168 back_, "back")) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800169 return true;
170 }
171 return false;
172}
173
Austin Schuhcda86af2014-02-16 16:16:39 -0800174void TopZeroedStateFeedbackLoop::SetCalibration(double edge_encoder,
175 double edge_angle) {
176 double old_offset = offset_;
177 offset_ = edge_angle - edge_encoder;
178 const double doffset = offset_ - old_offset;
179 motor_->ChangeTopOffset(doffset);
180}
181
182void BottomZeroedStateFeedbackLoop::SetCalibration(double edge_encoder,
183 double edge_angle) {
184 double old_offset = offset_;
185 offset_ = edge_angle - edge_encoder;
186 const double doffset = offset_ - old_offset;
187 motor_->ChangeBottomOffset(doffset);
188}
189
190void ClawMotor::ChangeTopOffset(double doffset) {
191 claw_.ChangeTopOffset(doffset);
192 if (has_top_claw_goal_) {
193 top_claw_goal_ += doffset;
194 }
195}
196
197void ClawMotor::ChangeBottomOffset(double doffset) {
198 claw_.ChangeBottomOffset(doffset);
199 if (has_bottom_claw_goal_) {
200 bottom_claw_goal_ += doffset;
201 }
202}
203
204void ClawLimitedLoop::ChangeTopOffset(double doffset) {
205 Y_(1, 0) += doffset;
206 X_hat(1, 0) += doffset;
207 LOG(INFO, "Changing top offset by %f\n", doffset);
208}
209void ClawLimitedLoop::ChangeBottomOffset(double doffset) {
210 Y_(0, 0) += doffset;
211 X_hat(0, 0) += doffset;
212 X_hat(1, 0) -= doffset;
213 LOG(INFO, "Changing bottom offset by %f\n", doffset);
214}
joe7376ff52014-02-16 18:28:42 -0800215
Austin Schuh069143b2014-02-17 02:46:26 -0800216void LimitClawGoal(double *bottom_goal, double *top_goal,
217 const frc971::constants::Values &values) {
218 // first update position based on angle limit
219
220 const double separation = *top_goal - *bottom_goal;
221 if (separation > values.claw.claw_max_separation) {
222 LOG(DEBUG, "Greater than\n");
223 const double dsep = (separation - values.claw.claw_max_separation) / 2.0;
224 *bottom_goal += dsep;
225 *top_goal -= dsep;
226 LOG(DEBUG, "Goals now bottom: %f, top: %f\n", *bottom_goal, *top_goal);
227 }
228 if (separation < values.claw.claw_min_separation) {
229 LOG(DEBUG, "Less than\n");
230 const double dsep = (separation - values.claw.claw_min_separation) / 2.0;
231 *bottom_goal += dsep;
232 *top_goal -= dsep;
233 LOG(DEBUG, "Goals now bottom: %f, top: %f\n", *bottom_goal, *top_goal);
234 }
235
236 // now move both goals in unison
237 if (*bottom_goal < values.claw.lower_claw.lower_limit) {
238 *top_goal += values.claw.lower_claw.lower_limit - *bottom_goal;
239 *bottom_goal = values.claw.lower_claw.lower_limit;
240 }
241 if (*bottom_goal > values.claw.lower_claw.upper_limit) {
242 *top_goal -= *bottom_goal - values.claw.lower_claw.upper_limit;
243 *bottom_goal = values.claw.lower_claw.upper_limit;
244 }
245
246 if (*top_goal < values.claw.upper_claw.lower_limit) {
247 *bottom_goal += values.claw.upper_claw.lower_limit - *top_goal;
248 *top_goal = values.claw.upper_claw.lower_limit;
249 }
250 if (*top_goal > values.claw.upper_claw.upper_limit) {
251 *bottom_goal -= *top_goal - values.claw.upper_claw.upper_limit;
252 *top_goal = values.claw.upper_claw.upper_limit;
253 }
254}
Austin Schuhcda86af2014-02-16 16:16:39 -0800255
Austin Schuhe7f90d12014-02-17 00:48:25 -0800256bool ClawMotor::is_ready() const {
257 return (
258 (top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED &&
259 bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED) ||
260 (::aos::robot_state->autonomous &&
261 ((top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
262 top_claw_.zeroing_state() ==
263 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION) &&
264 (bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
265 bottom_claw_.zeroing_state() ==
266 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION))));
267}
268
269bool ClawMotor::is_zeroing() const { return !is_ready(); }
270
Austin Schuh3bb9a442014-02-02 16:01:45 -0800271// Positive angle is up, and positive power is up.
Austin Schuhcc0bf312014-02-09 00:39:29 -0800272void ClawMotor::RunIteration(const control_loops::ClawGroup::Goal *goal,
273 const control_loops::ClawGroup::Position *position,
274 control_loops::ClawGroup::Output *output,
Austin Schuh3bb9a442014-02-02 16:01:45 -0800275 ::aos::control_loops::Status *status) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800276 constexpr double dt = 0.01;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800277
278 // Disable the motors now so that all early returns will return with the
279 // motors disabled.
280 if (output) {
281 output->top_claw_voltage = 0;
282 output->bottom_claw_voltage = 0;
283 output->intake_voltage = 0;
284 }
285
Austin Schuh1a499942014-02-17 01:51:58 -0800286 if (reset()) {
287 bottom_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::UNKNOWN_POSITION);
288 top_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::UNKNOWN_POSITION);
289 }
290
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800291 if (::aos::robot_state.get() == nullptr) {
292 return;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800293 }
294
Austin Schuhf9286cd2014-02-11 00:51:09 -0800295 const frc971::constants::Values &values = constants::GetValues();
296
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800297 if (position) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800298 Eigen::Matrix<double, 2, 1> Y;
299 Y << position->bottom.position + bottom_claw_.offset(),
300 position->top.position + top_claw_.offset();
301 claw_.Correct(Y);
302
Austin Schuhf9286cd2014-02-11 00:51:09 -0800303 top_claw_.SetPositionValues(position->top);
304 bottom_claw_.SetPositionValues(position->bottom);
305
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800306 if (!has_top_claw_goal_) {
307 has_top_claw_goal_ = true;
Austin Schuhcda86af2014-02-16 16:16:39 -0800308 top_claw_goal_ = top_claw_.absolute_position();
Austin Schuhe7f90d12014-02-17 00:48:25 -0800309 initial_separation_ =
Austin Schuhcda86af2014-02-16 16:16:39 -0800310 top_claw_.absolute_position() - bottom_claw_.absolute_position();
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800311 }
312 if (!has_bottom_claw_goal_) {
313 has_bottom_claw_goal_ = true;
Austin Schuhcda86af2014-02-16 16:16:39 -0800314 bottom_claw_goal_ = bottom_claw_.absolute_position();
Austin Schuhe7f90d12014-02-17 00:48:25 -0800315 initial_separation_ =
Austin Schuhcda86af2014-02-16 16:16:39 -0800316 top_claw_.absolute_position() - bottom_claw_.absolute_position();
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800317 }
Austin Schuhcda86af2014-02-16 16:16:39 -0800318 LOG(DEBUG, "Claw position is (top: %f bottom: %f\n",
319 top_claw_.absolute_position(), bottom_claw_.absolute_position());
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800320 }
321
Austin Schuh069143b2014-02-17 02:46:26 -0800322 const bool autonomous = ::aos::robot_state->autonomous;
323 const bool enabled = ::aos::robot_state->enabled;
324
325 double bottom_claw_velocity_ = 0.0;
326 double top_claw_velocity_ = 0.0;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800327
328 if ((top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED &&
329 bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED) ||
330 (autonomous &&
331 ((top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
332 top_claw_.zeroing_state() ==
333 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION) &&
334 (bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
335 bottom_claw_.zeroing_state() ==
336 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION)))) {
337 // Ready to use the claw.
338 // Limit the goals here.
Austin Schuhf9286cd2014-02-11 00:51:09 -0800339 bottom_claw_goal_ = goal->bottom_angle;
Brian Silverman7c021c42014-02-17 15:15:56 -0800340 top_claw_goal_ = goal->bottom_angle + goal->separation_angle;
Austin Schuhcda86af2014-02-16 16:16:39 -0800341 has_bottom_claw_goal_ = true;
342 has_top_claw_goal_ = true;
343 doing_calibration_fine_tune_ = false;
344
Austin Schuhe7f90d12014-02-17 00:48:25 -0800345 mode_ = READY;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800346 } else if (top_claw_.zeroing_state() !=
347 ZeroedStateFeedbackLoop::UNKNOWN_POSITION &&
348 bottom_claw_.zeroing_state() !=
349 ZeroedStateFeedbackLoop::UNKNOWN_POSITION) {
350 // Time to fine tune the zero.
351 // Limit the goals here.
Austin Schuh0c733422014-02-17 01:17:12 -0800352 if (!enabled) {
353 // If we are disabled, start the fine tune process over again.
354 doing_calibration_fine_tune_ = false;
355 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800356 if (bottom_claw_.zeroing_state() != ZeroedStateFeedbackLoop::CALIBRATED) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800357 // always get the bottom claw to calibrated first
358 LOG(DEBUG, "Calibrating the bottom of the claw\n");
359 if (!doing_calibration_fine_tune_) {
360 if (::std::abs(bottom_absolute_position() -
Austin Schuhd27931c2014-02-16 19:18:20 -0800361 values.claw.start_fine_tune_pos) <
362 values.claw.claw_unimportant_epsilon) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800363 doing_calibration_fine_tune_ = true;
Austin Schuhd27931c2014-02-16 19:18:20 -0800364 bottom_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800365 top_claw_velocity_ = bottom_claw_velocity_ =
366 values.claw.claw_zeroing_speed;
Austin Schuhcda86af2014-02-16 16:16:39 -0800367 LOG(DEBUG, "Ready to fine tune the bottom\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800368 mode_ = FINE_TUNE_BOTTOM;
Austin Schuhcda86af2014-02-16 16:16:39 -0800369 } else {
370 // send bottom to zeroing start
Austin Schuhd27931c2014-02-16 19:18:20 -0800371 bottom_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuhcda86af2014-02-16 16:16:39 -0800372 LOG(DEBUG, "Going to the start position for the bottom\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800373 mode_ = PREP_FINE_TUNE_BOTTOM;
Austin Schuhcda86af2014-02-16 16:16:39 -0800374 }
375 } else {
Austin Schuhe7f90d12014-02-17 00:48:25 -0800376 mode_ = FINE_TUNE_BOTTOM;
Austin Schuhd27931c2014-02-16 19:18:20 -0800377 bottom_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800378 top_claw_velocity_ = bottom_claw_velocity_ =
379 values.claw.claw_zeroing_speed;
Brian Silvermane0a95462014-02-17 00:41:09 -0800380 if (top_claw_.front_or_back_triggered() ||
381 bottom_claw_.front_or_back_triggered()) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800382 // We shouldn't hit a limit, but if we do, go back to the zeroing
383 // point and try again.
384 doing_calibration_fine_tune_ = false;
Austin Schuhd27931c2014-02-16 19:18:20 -0800385 bottom_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuh069143b2014-02-17 02:46:26 -0800386 top_claw_velocity_ = bottom_claw_velocity_ = 0.0;
Austin Schuhcda86af2014-02-16 16:16:39 -0800387 LOG(DEBUG, "Found a limit, starting over.\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800388 mode_ = PREP_FINE_TUNE_BOTTOM;
Austin Schuhcda86af2014-02-16 16:16:39 -0800389 }
Austin Schuh288c8c32014-02-16 17:20:17 -0800390
Brian Silvermane0a95462014-02-17 00:41:09 -0800391 if (bottom_claw_.calibration().value()) {
392 if (bottom_claw_.calibration().posedge_count_changed() &&
Austin Schuh288c8c32014-02-16 17:20:17 -0800393 position) {
394 // do calibration
395 bottom_claw_.SetCalibration(
396 position->bottom.posedge_value,
Austin Schuhd27931c2014-02-16 19:18:20 -0800397 values.claw.lower_claw.calibration.lower_angle);
Austin Schuh288c8c32014-02-16 17:20:17 -0800398 bottom_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::CALIBRATED);
399 // calibrated so we are done fine tuning bottom
400 doing_calibration_fine_tune_ = false;
401 LOG(DEBUG, "Calibrated the bottom correctly!\n");
402 } else {
403 doing_calibration_fine_tune_ = false;
Austin Schuhd27931c2014-02-16 19:18:20 -0800404 bottom_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuh069143b2014-02-17 02:46:26 -0800405 top_claw_velocity_ = bottom_claw_velocity_ = 0.0;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800406 mode_ = PREP_FINE_TUNE_BOTTOM;
Austin Schuh288c8c32014-02-16 17:20:17 -0800407 }
Austin Schuhcda86af2014-02-16 16:16:39 -0800408 } else {
409 LOG(DEBUG, "Fine tuning\n");
410 }
411 }
412 // now set the top claw to track
413
Austin Schuhd27931c2014-02-16 19:18:20 -0800414 top_claw_goal_ = bottom_claw_goal_ + values.claw.claw_zeroing_separation;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800415 } else {
Austin Schuhcda86af2014-02-16 16:16:39 -0800416 // bottom claw must be calibrated, start on the top
417 if (!doing_calibration_fine_tune_) {
Austin Schuhd27931c2014-02-16 19:18:20 -0800418 if (::std::abs(top_absolute_position() -
419 values.claw.start_fine_tune_pos) <
James Kuszmauld536a402014-02-18 22:32:12 -0800420 values.claw.claw_unimportant_epsilon) {//HERE
Austin Schuhcda86af2014-02-16 16:16:39 -0800421 doing_calibration_fine_tune_ = true;
Austin Schuhd27931c2014-02-16 19:18:20 -0800422 top_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800423 top_claw_velocity_ = bottom_claw_velocity_ =
424 values.claw.claw_zeroing_speed;
Austin Schuhcda86af2014-02-16 16:16:39 -0800425 LOG(DEBUG, "Ready to fine tune the top\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800426 mode_ = FINE_TUNE_TOP;
Austin Schuhcda86af2014-02-16 16:16:39 -0800427 } else {
428 // send top to zeroing start
Austin Schuhd27931c2014-02-16 19:18:20 -0800429 top_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuhcda86af2014-02-16 16:16:39 -0800430 LOG(DEBUG, "Going to the start position for the top\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800431 mode_ = PREP_FINE_TUNE_TOP;
Austin Schuhcda86af2014-02-16 16:16:39 -0800432 }
433 } else {
Austin Schuhe7f90d12014-02-17 00:48:25 -0800434 mode_ = FINE_TUNE_TOP;
Austin Schuhd27931c2014-02-16 19:18:20 -0800435 top_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800436 top_claw_velocity_ = bottom_claw_velocity_ =
437 values.claw.claw_zeroing_speed;
Brian Silvermane0a95462014-02-17 00:41:09 -0800438 if (top_claw_.front_or_back_triggered() ||
439 bottom_claw_.front_or_back_triggered()) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800440 // this should not happen, but now we know it won't
441 doing_calibration_fine_tune_ = false;
Austin Schuhd27931c2014-02-16 19:18:20 -0800442 top_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuh069143b2014-02-17 02:46:26 -0800443 top_claw_velocity_ = bottom_claw_velocity_ = 0.0;
Austin Schuhcda86af2014-02-16 16:16:39 -0800444 LOG(DEBUG, "Found a limit, starting over.\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800445 mode_ = PREP_FINE_TUNE_TOP;
Austin Schuhcda86af2014-02-16 16:16:39 -0800446 }
Brian Silvermane0a95462014-02-17 00:41:09 -0800447 if (top_claw_.calibration().value()) {
448 if (top_claw_.calibration().posedge_count_changed() &&
Austin Schuh288c8c32014-02-16 17:20:17 -0800449 position) {
450 // do calibration
Austin Schuhd27931c2014-02-16 19:18:20 -0800451 top_claw_.SetCalibration(
452 position->top.posedge_value,
453 values.claw.upper_claw.calibration.lower_angle);
Austin Schuh288c8c32014-02-16 17:20:17 -0800454 top_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::CALIBRATED);
Austin Schuhe7f90d12014-02-17 00:48:25 -0800455 // calibrated so we are done fine tuning top
Austin Schuh288c8c32014-02-16 17:20:17 -0800456 doing_calibration_fine_tune_ = false;
457 LOG(DEBUG, "Calibrated the top correctly!\n");
James Kuszmauld536a402014-02-18 22:32:12 -0800458 } else { //HERE
Austin Schuh288c8c32014-02-16 17:20:17 -0800459 doing_calibration_fine_tune_ = false;
Austin Schuhd27931c2014-02-16 19:18:20 -0800460 top_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuh069143b2014-02-17 02:46:26 -0800461 top_claw_velocity_ = bottom_claw_velocity_ = 0.0;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800462 mode_ = PREP_FINE_TUNE_TOP;
Austin Schuh288c8c32014-02-16 17:20:17 -0800463 }
Austin Schuhcda86af2014-02-16 16:16:39 -0800464 }
465 }
466 // now set the bottom claw to track
Austin Schuhd27931c2014-02-16 19:18:20 -0800467 bottom_claw_goal_ = top_claw_goal_ - values.claw.claw_zeroing_separation;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800468 }
469 } else {
Austin Schuhcda86af2014-02-16 16:16:39 -0800470 doing_calibration_fine_tune_ = false;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800471 if (!was_enabled_ && enabled) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800472 if (position) {
473 top_claw_goal_ = position->top.position;
474 bottom_claw_goal_ = position->bottom.position;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800475 initial_separation_ =
Austin Schuhcda86af2014-02-16 16:16:39 -0800476 position->top.position - position->bottom.position;
Austin Schuhf9286cd2014-02-11 00:51:09 -0800477 } else {
478 has_top_claw_goal_ = false;
479 has_bottom_claw_goal_ = false;
480 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800481 }
Austin Schuhf9286cd2014-02-11 00:51:09 -0800482
Austin Schuh4cb047f2014-02-16 21:10:19 -0800483 if ((bottom_claw_.zeroing_state() !=
484 ZeroedStateFeedbackLoop::UNKNOWN_POSITION ||
Brian Silvermane0a95462014-02-17 00:41:09 -0800485 bottom_claw_.front().value() || top_claw_.front().value()) &&
486 !top_claw_.back().value() && !bottom_claw_.back().value()) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800487 if (enabled) {
488 // Time to slowly move back up to find any position to narrow down the
489 // zero.
Austin Schuhd27931c2014-02-16 19:18:20 -0800490 top_claw_goal_ += values.claw.claw_zeroing_off_speed * dt;
491 bottom_claw_goal_ += values.claw.claw_zeroing_off_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800492 top_claw_velocity_ = bottom_claw_velocity_ =
493 values.claw.claw_zeroing_off_speed;
Austin Schuhcda86af2014-02-16 16:16:39 -0800494 LOG(DEBUG, "Bottom is known.\n");
Austin Schuhf9286cd2014-02-11 00:51:09 -0800495 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800496 } else {
497 // We don't know where either claw is. Slowly start moving down to find
498 // any hall effect.
Austin Schuhf9286cd2014-02-11 00:51:09 -0800499 if (enabled) {
Austin Schuhd27931c2014-02-16 19:18:20 -0800500 top_claw_goal_ -= values.claw.claw_zeroing_off_speed * dt;
501 bottom_claw_goal_ -= values.claw.claw_zeroing_off_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800502 top_claw_velocity_ = bottom_claw_velocity_ =
503 -values.claw.claw_zeroing_off_speed;
Austin Schuhcda86af2014-02-16 16:16:39 -0800504 LOG(DEBUG, "Both are unknown.\n");
Austin Schuhf9286cd2014-02-11 00:51:09 -0800505 }
506 }
507
508 if (enabled) {
509 top_claw_.SetCalibrationOnEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800510 values.claw.upper_claw, ZeroedStateFeedbackLoop::APPROXIMATE_CALIBRATION);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800511 bottom_claw_.SetCalibrationOnEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800512 values.claw.lower_claw, ZeroedStateFeedbackLoop::APPROXIMATE_CALIBRATION);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800513 } else {
Austin Schuh069143b2014-02-17 02:46:26 -0800514 // TODO(austin): Only calibrate on the predetermined edge.
515 // We might be able to just ignore this since the backlash is soooo low. :)
Austin Schuhf9286cd2014-02-11 00:51:09 -0800516 top_claw_.SetCalibrationOnEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800517 values.claw.upper_claw, ZeroedStateFeedbackLoop::DISABLED_CALIBRATION);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800518 bottom_claw_.SetCalibrationOnEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800519 values.claw.lower_claw, ZeroedStateFeedbackLoop::DISABLED_CALIBRATION);
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800520 }
Austin Schuhe7f90d12014-02-17 00:48:25 -0800521 mode_ = UNKNOWN_LOCATION;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800522 }
523
Austin Schuh069143b2014-02-17 02:46:26 -0800524 // Limit the goals if both claws have been (mostly) found.
525 if (mode_ != UNKNOWN_LOCATION) {
526 LimitClawGoal(&bottom_claw_goal_, &top_claw_goal_, values);
527 }
528
Austin Schuhf9286cd2014-02-11 00:51:09 -0800529 if (has_top_claw_goal_ && has_bottom_claw_goal_) {
Austin Schuh069143b2014-02-17 02:46:26 -0800530 claw_.R << bottom_claw_goal_, top_claw_goal_ - bottom_claw_goal_,
531 bottom_claw_velocity_, top_claw_velocity_ - bottom_claw_velocity_;
Austin Schuhcda86af2014-02-16 16:16:39 -0800532 double separation = -971;
533 if (position != nullptr) {
534 separation = position->top.position - position->bottom.position;
535 }
536 LOG(DEBUG, "Goal is %f (bottom) %f, separation is %f\n", claw_.R(0, 0),
537 claw_.R(1, 0), separation);
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800538
Austin Schuh4cb047f2014-02-16 21:10:19 -0800539 // Only cap power when one of the halves of the claw is unknown.
Austin Schuhe7f90d12014-02-17 00:48:25 -0800540 claw_.set_is_zeroing(mode_ == UNKNOWN_LOCATION || mode_ == FINE_TUNE_TOP ||
541 mode_ == FINE_TUNE_BOTTOM);
Austin Schuhcda86af2014-02-16 16:16:39 -0800542 claw_.Update(output == nullptr);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800543 } else {
Austin Schuhcda86af2014-02-16 16:16:39 -0800544 claw_.Update(true);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800545 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800546
Austin Schuh4cb047f2014-02-16 21:10:19 -0800547 capped_goal_ = false;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800548 switch (mode_) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800549 case READY:
Austin Schuhe7f90d12014-02-17 00:48:25 -0800550 case PREP_FINE_TUNE_TOP:
551 case PREP_FINE_TUNE_BOTTOM:
Austin Schuhcda86af2014-02-16 16:16:39 -0800552 break;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800553 case FINE_TUNE_BOTTOM:
554 case FINE_TUNE_TOP:
Austin Schuh4cb047f2014-02-16 21:10:19 -0800555 case UNKNOWN_LOCATION: {
556 if (claw_.uncapped_average_voltage() > values.claw.max_zeroing_voltage) {
557 double dx = (claw_.uncapped_average_voltage() -
558 values.claw.max_zeroing_voltage) /
559 claw_.K(0, 0);
560 bottom_claw_goal_ -= dx;
561 top_claw_goal_ -= dx;
Austin Schuhcda86af2014-02-16 16:16:39 -0800562 capped_goal_ = true;
Austin Schuh4cb047f2014-02-16 21:10:19 -0800563 LOG(DEBUG, "Moving the goal by %f to prevent windup\n", dx);
Austin Schuhe7f90d12014-02-17 00:48:25 -0800564 LOG(DEBUG, "Uncapped is %f, max is %f, difference is %f\n",
565 claw_.uncapped_average_voltage(), values.claw.max_zeroing_voltage,
566 (claw_.uncapped_average_voltage() -
567 values.claw.max_zeroing_voltage));
Austin Schuh4cb047f2014-02-16 21:10:19 -0800568 } else if (claw_.uncapped_average_voltage() <
569 -values.claw.max_zeroing_voltage) {
570 double dx = (claw_.uncapped_average_voltage() +
571 values.claw.max_zeroing_voltage) /
572 claw_.K(0, 0);
573 bottom_claw_goal_ -= dx;
574 top_claw_goal_ -= dx;
Austin Schuhcda86af2014-02-16 16:16:39 -0800575 capped_goal_ = true;
Austin Schuh4cb047f2014-02-16 21:10:19 -0800576 LOG(DEBUG, "Moving the goal by %f to prevent windup\n", dx);
Austin Schuhcda86af2014-02-16 16:16:39 -0800577 }
Austin Schuh4cb047f2014-02-16 21:10:19 -0800578 } break;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800579 }
580
581 if (output) {
James Kuszmauld536a402014-02-18 22:32:12 -0800582 output->top_claw_voltage = claw_.U(1, 0);
Austin Schuhcda86af2014-02-16 16:16:39 -0800583 output->bottom_claw_voltage = claw_.U(0, 0);
Austin Schuh3bb9a442014-02-02 16:01:45 -0800584 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800585 status->done = false;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800586
587 was_enabled_ = ::aos::robot_state->enabled;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800588}
589
590} // namespace control_loops
591} // namespace frc971