blob: cfe61a078334926707178a8788f024694f61bc08 [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;
56 U(1, 0) -= difference;
57 } 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;
61 U(1, 0) += difference;
62 }
63 }
64
65 double max_value =
66 ::std::max(::std::abs(U(0, 0)), ::std::abs(U(1, 0) + U(0, 0)));
67
Austin Schuhcda86af2014-02-16 16:16:39 -080068 if (max_value > 12.0) {
69 LOG(DEBUG, "Capping U because max is %f\n", max_value);
70 U = U * 12.0 / max_value;
71 LOG(DEBUG, "Capping U is now %f %f\n", U(0, 0), U(1, 0));
Austin Schuh4b7b5d02014-02-10 21:20:34 -080072 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -080073}
74
Austin Schuhcc0bf312014-02-09 00:39:29 -080075ClawMotor::ClawMotor(control_loops::ClawGroup *my_claw)
76 : aos::control_loops::ControlLoop<control_loops::ClawGroup>(my_claw),
Austin Schuh4b7b5d02014-02-10 21:20:34 -080077 has_top_claw_goal_(false),
78 top_claw_goal_(0.0),
Austin Schuhcda86af2014-02-16 16:16:39 -080079 top_claw_(this),
Austin Schuh4b7b5d02014-02-10 21:20:34 -080080 has_bottom_claw_goal_(false),
81 bottom_claw_goal_(0.0),
Austin Schuhcda86af2014-02-16 16:16:39 -080082 bottom_claw_(this),
83 claw_(MakeClawLoop()),
Ben Fredrickson9b388422014-02-13 06:15:31 +000084 was_enabled_(false),
Austin Schuh4cb047f2014-02-16 21:10:19 -080085 doing_calibration_fine_tune_(false),
86 capped_goal_(false) {}
Austin Schuh3bb9a442014-02-02 16:01:45 -080087
Austin Schuh4b7b5d02014-02-10 21:20:34 -080088const int ZeroedStateFeedbackLoop::kZeroingMaxVoltage;
Austin Schuh3bb9a442014-02-02 16:01:45 -080089
Austin Schuhf9286cd2014-02-11 00:51:09 -080090bool ZeroedStateFeedbackLoop::GetPositionOfEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -080091 const constants::Values::Claws::Claw &claw_values, double *edge_encoder,
Austin Schuhf9286cd2014-02-11 00:51:09 -080092 double *edge_angle) {
93
94 // TODO(austin): Validate that the hall effect edge makes sense.
95 // We must now be on the side of the edge that we expect to be, and the
96 // encoder must have been on either side of the edge before and after.
97
Austin Schuhcda86af2014-02-16 16:16:39 -080098 // TODO(austin): Compute the last off range min and max and compare the edge
99 // value to the middle of the range. This will be quite a bit more reliable.
100
Austin Schuhf9286cd2014-02-11 00:51:09 -0800101 if (front_hall_effect_posedge_count_changed()) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800102 if (posedge_value_ - last_encoder() < 0) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800103 *edge_angle = claw_values.front.upper_angle;
Austin Schuhcda86af2014-02-16 16:16:39 -0800104 LOG(INFO, "%s Posedge front upper edge -> %f\n", name_, *edge_angle);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800105 } else {
106 *edge_angle = claw_values.front.lower_angle;
Austin Schuhcda86af2014-02-16 16:16:39 -0800107 LOG(INFO, "%s Posedge front lower edge -> %f\n", name_, *edge_angle);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800108 }
109 *edge_encoder = posedge_value_;
110 return true;
111 }
112 if (front_hall_effect_negedge_count_changed()) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800113 if (negedge_value_ - last_encoder() > 0) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800114 *edge_angle = claw_values.front.upper_angle;
Austin Schuhcda86af2014-02-16 16:16:39 -0800115 LOG(INFO, "%s Negedge front upper edge -> %f\n", name_, *edge_angle);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800116 } else {
117 *edge_angle = claw_values.front.lower_angle;
Austin Schuhcda86af2014-02-16 16:16:39 -0800118 LOG(INFO, "%s Negedge front lower edge -> %f\n", name_, *edge_angle);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800119 }
120 *edge_encoder = negedge_value_;
121 return true;
122 }
123 if (calibration_hall_effect_posedge_count_changed()) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800124 if (posedge_value_ - last_encoder() < 0) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800125 *edge_angle = claw_values.calibration.upper_angle;
Austin Schuhcda86af2014-02-16 16:16:39 -0800126 LOG(INFO, "%s Posedge calibration upper edge -> %f\n", name_,
127 *edge_angle);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800128 } else {
129 *edge_angle = claw_values.calibration.lower_angle;
Austin Schuhcda86af2014-02-16 16:16:39 -0800130 LOG(INFO, "%s Posedge calibration lower edge -> %f\n", name_,
131 *edge_angle);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800132 }
133 *edge_encoder = posedge_value_;
134 return true;
135 }
136 if (calibration_hall_effect_negedge_count_changed()) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800137 if (negedge_value_ - last_encoder() > 0) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800138 *edge_angle = claw_values.calibration.upper_angle;
Austin Schuhcda86af2014-02-16 16:16:39 -0800139 LOG(INFO, "%s Negedge calibration upper edge -> %f\n", name_, *edge_angle);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800140 } else {
141 *edge_angle = claw_values.calibration.lower_angle;
Austin Schuhcda86af2014-02-16 16:16:39 -0800142 LOG(INFO, "%s Negedge calibration lower edge -> %f\n", name_, *edge_angle);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800143 }
144 *edge_encoder = negedge_value_;
145 return true;
146 }
147 if (back_hall_effect_posedge_count_changed()) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800148 if (posedge_value_ - last_encoder() < 0) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800149 *edge_angle = claw_values.back.upper_angle;
Austin Schuhcda86af2014-02-16 16:16:39 -0800150 LOG(INFO, "%s Posedge back upper edge -> %f\n", name_, *edge_angle);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800151 } else {
152 *edge_angle = claw_values.back.lower_angle;
Austin Schuhcda86af2014-02-16 16:16:39 -0800153 LOG(INFO, "%s Posedge back lower edge -> %f\n", name_, *edge_angle);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800154 }
155 *edge_encoder = posedge_value_;
156 return true;
157 }
158 if (back_hall_effect_negedge_count_changed()) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800159 if (negedge_value_ - last_encoder() > 0) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800160 *edge_angle = claw_values.back.upper_angle;
Austin Schuhcda86af2014-02-16 16:16:39 -0800161 LOG(INFO, "%s Negedge back upper edge -> %f\n", name_, *edge_angle);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800162 } else {
163 *edge_angle = claw_values.back.lower_angle;
Austin Schuhcda86af2014-02-16 16:16:39 -0800164 LOG(INFO, "%s Negedge back lower edge -> %f\n", name_, *edge_angle);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800165 }
166 *edge_encoder = negedge_value_;
167 return true;
168 }
169 return false;
170}
171
Austin Schuhcda86af2014-02-16 16:16:39 -0800172void TopZeroedStateFeedbackLoop::SetCalibration(double edge_encoder,
173 double edge_angle) {
174 double old_offset = offset_;
175 offset_ = edge_angle - edge_encoder;
176 const double doffset = offset_ - old_offset;
177 motor_->ChangeTopOffset(doffset);
178}
179
180void BottomZeroedStateFeedbackLoop::SetCalibration(double edge_encoder,
181 double edge_angle) {
182 double old_offset = offset_;
183 offset_ = edge_angle - edge_encoder;
184 const double doffset = offset_ - old_offset;
185 motor_->ChangeBottomOffset(doffset);
186}
187
188void ClawMotor::ChangeTopOffset(double doffset) {
189 claw_.ChangeTopOffset(doffset);
190 if (has_top_claw_goal_) {
191 top_claw_goal_ += doffset;
192 }
193}
194
195void ClawMotor::ChangeBottomOffset(double doffset) {
196 claw_.ChangeBottomOffset(doffset);
197 if (has_bottom_claw_goal_) {
198 bottom_claw_goal_ += doffset;
199 }
200}
201
202void ClawLimitedLoop::ChangeTopOffset(double doffset) {
203 Y_(1, 0) += doffset;
204 X_hat(1, 0) += doffset;
205 LOG(INFO, "Changing top offset by %f\n", doffset);
206}
207void ClawLimitedLoop::ChangeBottomOffset(double doffset) {
208 Y_(0, 0) += doffset;
209 X_hat(0, 0) += doffset;
210 X_hat(1, 0) -= doffset;
211 LOG(INFO, "Changing bottom offset by %f\n", doffset);
212}
213
Austin Schuh3bb9a442014-02-02 16:01:45 -0800214// Positive angle is up, and positive power is up.
Austin Schuhcc0bf312014-02-09 00:39:29 -0800215void ClawMotor::RunIteration(const control_loops::ClawGroup::Goal *goal,
216 const control_loops::ClawGroup::Position *position,
217 control_loops::ClawGroup::Output *output,
Austin Schuh3bb9a442014-02-02 16:01:45 -0800218 ::aos::control_loops::Status *status) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800219 constexpr double dt = 0.01;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800220
221 // Disable the motors now so that all early returns will return with the
222 // motors disabled.
223 if (output) {
224 output->top_claw_voltage = 0;
225 output->bottom_claw_voltage = 0;
226 output->intake_voltage = 0;
227 }
228
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800229 // TODO(austin): Handle the disabled state and the disabled -> enabled
Austin Schuhcda86af2014-02-16 16:16:39 -0800230 // transition in all of these states.
231 // TODO(austin): Handle zeroing while disabled correctly (only use a single
232 // edge and direction when zeroing.)
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800233
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800234 if (::aos::robot_state.get() == nullptr) {
235 return;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800236 }
237
Austin Schuhf9286cd2014-02-11 00:51:09 -0800238 const frc971::constants::Values &values = constants::GetValues();
239
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800240 if (position) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800241 Eigen::Matrix<double, 2, 1> Y;
242 Y << position->bottom.position + bottom_claw_.offset(),
243 position->top.position + top_claw_.offset();
244 claw_.Correct(Y);
245
Austin Schuhf9286cd2014-02-11 00:51:09 -0800246 top_claw_.SetPositionValues(position->top);
247 bottom_claw_.SetPositionValues(position->bottom);
248
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800249 if (!has_top_claw_goal_) {
250 has_top_claw_goal_ = true;
Austin Schuhcda86af2014-02-16 16:16:39 -0800251 top_claw_goal_ = top_claw_.absolute_position();
252 initial_seperation_ =
253 top_claw_.absolute_position() - bottom_claw_.absolute_position();
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800254 }
255 if (!has_bottom_claw_goal_) {
256 has_bottom_claw_goal_ = true;
Austin Schuhcda86af2014-02-16 16:16:39 -0800257 bottom_claw_goal_ = bottom_claw_.absolute_position();
258 initial_seperation_ =
259 top_claw_.absolute_position() - bottom_claw_.absolute_position();
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800260 }
Austin Schuhcda86af2014-02-16 16:16:39 -0800261 LOG(DEBUG, "Claw position is (top: %f bottom: %f\n",
262 top_claw_.absolute_position(), bottom_claw_.absolute_position());
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800263 }
264
265 bool autonomous = ::aos::robot_state->autonomous;
Austin Schuhf9286cd2014-02-11 00:51:09 -0800266 bool enabled = ::aos::robot_state->enabled;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800267
Austin Schuhcda86af2014-02-16 16:16:39 -0800268 enum CalibrationMode {
269 READY,
270 FINE_TUNE,
271 UNKNOWN_LOCATION
272 };
273
274 CalibrationMode mode;
275
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800276 if ((top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED &&
277 bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED) ||
278 (autonomous &&
279 ((top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
280 top_claw_.zeroing_state() ==
281 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION) &&
282 (bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
283 bottom_claw_.zeroing_state() ==
284 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION)))) {
285 // Ready to use the claw.
286 // Limit the goals here.
Austin Schuhf9286cd2014-02-11 00:51:09 -0800287 bottom_claw_goal_ = goal->bottom_angle;
288 top_claw_goal_ = goal->bottom_angle + goal->seperation_angle;
Austin Schuhcda86af2014-02-16 16:16:39 -0800289 has_bottom_claw_goal_ = true;
290 has_top_claw_goal_ = true;
291 doing_calibration_fine_tune_ = false;
292
293 mode = READY;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800294 } else if (top_claw_.zeroing_state() !=
295 ZeroedStateFeedbackLoop::UNKNOWN_POSITION &&
296 bottom_claw_.zeroing_state() !=
297 ZeroedStateFeedbackLoop::UNKNOWN_POSITION) {
298 // Time to fine tune the zero.
299 // Limit the goals here.
300 if (bottom_claw_.zeroing_state() != ZeroedStateFeedbackLoop::CALIBRATED) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800301 // always get the bottom claw to calibrated first
302 LOG(DEBUG, "Calibrating the bottom of the claw\n");
303 if (!doing_calibration_fine_tune_) {
304 if (::std::abs(bottom_absolute_position() -
Austin Schuhd27931c2014-02-16 19:18:20 -0800305 values.claw.start_fine_tune_pos) <
306 values.claw.claw_unimportant_epsilon) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800307 doing_calibration_fine_tune_ = true;
Austin Schuhd27931c2014-02-16 19:18:20 -0800308 bottom_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuhcda86af2014-02-16 16:16:39 -0800309 LOG(DEBUG, "Ready to fine tune the bottom\n");
310 } else {
311 // send bottom to zeroing start
Austin Schuhd27931c2014-02-16 19:18:20 -0800312 bottom_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuhcda86af2014-02-16 16:16:39 -0800313 LOG(DEBUG, "Going to the start position for the bottom\n");
314 }
315 } else {
Austin Schuhd27931c2014-02-16 19:18:20 -0800316 bottom_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuhcda86af2014-02-16 16:16:39 -0800317 if (top_claw_.front_hall_effect() || top_claw_.back_hall_effect() ||
318 bottom_claw_.front_hall_effect() ||
319 bottom_claw_.back_hall_effect()) {
320 // We shouldn't hit a limit, but if we do, go back to the zeroing
321 // point and try again.
322 doing_calibration_fine_tune_ = false;
Austin Schuhd27931c2014-02-16 19:18:20 -0800323 bottom_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuhcda86af2014-02-16 16:16:39 -0800324 LOG(DEBUG, "Found a limit, starting over.\n");
325 }
Austin Schuh288c8c32014-02-16 17:20:17 -0800326
Austin Schuhcda86af2014-02-16 16:16:39 -0800327 if (bottom_claw_.calibration_hall_effect()) {
Austin Schuh288c8c32014-02-16 17:20:17 -0800328 if (bottom_claw_.calibration_hall_effect_posedge_count_changed() &&
329 position) {
330 // do calibration
331 bottom_claw_.SetCalibration(
332 position->bottom.posedge_value,
Austin Schuhd27931c2014-02-16 19:18:20 -0800333 values.claw.lower_claw.calibration.lower_angle);
Austin Schuh288c8c32014-02-16 17:20:17 -0800334 bottom_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::CALIBRATED);
335 // calibrated so we are done fine tuning bottom
336 doing_calibration_fine_tune_ = false;
337 LOG(DEBUG, "Calibrated the bottom correctly!\n");
338 } else {
339 doing_calibration_fine_tune_ = false;
Austin Schuhd27931c2014-02-16 19:18:20 -0800340 bottom_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuh288c8c32014-02-16 17:20:17 -0800341 }
Austin Schuhcda86af2014-02-16 16:16:39 -0800342 } else {
343 LOG(DEBUG, "Fine tuning\n");
344 }
345 }
346 // now set the top claw to track
347
Austin Schuhd27931c2014-02-16 19:18:20 -0800348 top_claw_goal_ = bottom_claw_goal_ + values.claw.claw_zeroing_separation;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800349 } else {
Austin Schuhcda86af2014-02-16 16:16:39 -0800350 // bottom claw must be calibrated, start on the top
351 if (!doing_calibration_fine_tune_) {
Austin Schuhd27931c2014-02-16 19:18:20 -0800352 if (::std::abs(top_absolute_position() -
353 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 top_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuhcda86af2014-02-16 16:16:39 -0800357 LOG(DEBUG, "Ready to fine tune the top\n");
358 } else {
359 // send top to zeroing start
Austin Schuhd27931c2014-02-16 19:18:20 -0800360 top_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuhcda86af2014-02-16 16:16:39 -0800361 LOG(DEBUG, "Going to the start position for the top\n");
362 }
363 } else {
Austin Schuhd27931c2014-02-16 19:18:20 -0800364 top_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuhcda86af2014-02-16 16:16:39 -0800365 if (top_claw_.front_hall_effect() || top_claw_.back_hall_effect() ||
366 bottom_claw_.front_hall_effect() ||
367 bottom_claw_.back_hall_effect()) {
368 // this should not happen, but now we know it won't
369 doing_calibration_fine_tune_ = false;
Austin Schuhd27931c2014-02-16 19:18:20 -0800370 top_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuhcda86af2014-02-16 16:16:39 -0800371 LOG(DEBUG, "Found a limit, starting over.\n");
372 }
373 if (top_claw_.calibration_hall_effect()) {
Austin Schuh288c8c32014-02-16 17:20:17 -0800374 if (top_claw_.calibration_hall_effect_posedge_count_changed() &&
375 position) {
376 // do calibration
Austin Schuhd27931c2014-02-16 19:18:20 -0800377 top_claw_.SetCalibration(
378 position->top.posedge_value,
379 values.claw.upper_claw.calibration.lower_angle);
Austin Schuh288c8c32014-02-16 17:20:17 -0800380 top_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::CALIBRATED);
381 // calinrated so we are done fine tuning top
382 doing_calibration_fine_tune_ = false;
383 LOG(DEBUG, "Calibrated the top correctly!\n");
384 } else {
385 doing_calibration_fine_tune_ = false;
Austin Schuhd27931c2014-02-16 19:18:20 -0800386 top_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuh288c8c32014-02-16 17:20:17 -0800387 }
Austin Schuhcda86af2014-02-16 16:16:39 -0800388 }
389 }
390 // now set the bottom claw to track
Austin Schuhd27931c2014-02-16 19:18:20 -0800391 bottom_claw_goal_ = top_claw_goal_ - values.claw.claw_zeroing_separation;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800392 }
Austin Schuhcda86af2014-02-16 16:16:39 -0800393 mode = FINE_TUNE;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800394 } else {
Austin Schuhcda86af2014-02-16 16:16:39 -0800395 doing_calibration_fine_tune_ = false;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800396 if (!was_enabled_ && enabled) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800397 if (position) {
398 top_claw_goal_ = position->top.position;
399 bottom_claw_goal_ = position->bottom.position;
Austin Schuhcda86af2014-02-16 16:16:39 -0800400 initial_seperation_ =
401 position->top.position - position->bottom.position;
Austin Schuhf9286cd2014-02-11 00:51:09 -0800402 } else {
403 has_top_claw_goal_ = false;
404 has_bottom_claw_goal_ = false;
405 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800406 }
Austin Schuhf9286cd2014-02-11 00:51:09 -0800407
408 // TODO(austin): Limit the goals here.
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800409
Austin Schuh4cb047f2014-02-16 21:10:19 -0800410 if ((bottom_claw_.zeroing_state() !=
411 ZeroedStateFeedbackLoop::UNKNOWN_POSITION ||
412 bottom_claw_.front_hall_effect() || top_claw_.front_hall_effect()) &&
413 !top_claw_.back_hall_effect() && !bottom_claw_.back_hall_effect()) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800414 if (enabled) {
415 // Time to slowly move back up to find any position to narrow down the
416 // zero.
Austin Schuhd27931c2014-02-16 19:18:20 -0800417 top_claw_goal_ += values.claw.claw_zeroing_off_speed * dt;
418 bottom_claw_goal_ += values.claw.claw_zeroing_off_speed * dt;
Austin Schuhf9286cd2014-02-11 00:51:09 -0800419 // TODO(austin): Goal velocity too!
Austin Schuhcda86af2014-02-16 16:16:39 -0800420 LOG(DEBUG, "Bottom is known.\n");
Austin Schuhf9286cd2014-02-11 00:51:09 -0800421 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800422 } else {
423 // We don't know where either claw is. Slowly start moving down to find
424 // any hall effect.
Austin Schuhf9286cd2014-02-11 00:51:09 -0800425 if (enabled) {
Austin Schuhd27931c2014-02-16 19:18:20 -0800426 top_claw_goal_ -= values.claw.claw_zeroing_off_speed * dt;
427 bottom_claw_goal_ -= values.claw.claw_zeroing_off_speed * dt;
Austin Schuhf9286cd2014-02-11 00:51:09 -0800428 // TODO(austin): Goal velocity too!
Austin Schuhcda86af2014-02-16 16:16:39 -0800429 LOG(DEBUG, "Both are unknown.\n");
Austin Schuhf9286cd2014-02-11 00:51:09 -0800430 }
431 }
432
433 if (enabled) {
434 top_claw_.SetCalibrationOnEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800435 values.claw.upper_claw, ZeroedStateFeedbackLoop::APPROXIMATE_CALIBRATION);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800436 bottom_claw_.SetCalibrationOnEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800437 values.claw.lower_claw, ZeroedStateFeedbackLoop::APPROXIMATE_CALIBRATION);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800438 } else {
439 top_claw_.SetCalibrationOnEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800440 values.claw.upper_claw, ZeroedStateFeedbackLoop::DISABLED_CALIBRATION);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800441 bottom_claw_.SetCalibrationOnEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800442 values.claw.lower_claw, ZeroedStateFeedbackLoop::DISABLED_CALIBRATION);
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800443 }
Austin Schuhcda86af2014-02-16 16:16:39 -0800444 mode = UNKNOWN_LOCATION;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800445 }
446
Austin Schuh288c8c32014-02-16 17:20:17 -0800447 // TODO(austin): Handle disabled properly everwhere... Restart and all that
448 // jazz.
449
Austin Schuhf9286cd2014-02-11 00:51:09 -0800450 if (has_top_claw_goal_ && has_bottom_claw_goal_) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800451 claw_.R << bottom_claw_goal_, top_claw_goal_ - bottom_claw_goal_, 0, 0;
452 double separation = -971;
453 if (position != nullptr) {
454 separation = position->top.position - position->bottom.position;
455 }
456 LOG(DEBUG, "Goal is %f (bottom) %f, separation is %f\n", claw_.R(0, 0),
457 claw_.R(1, 0), separation);
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800458
Austin Schuh4cb047f2014-02-16 21:10:19 -0800459 // Only cap power when one of the halves of the claw is unknown.
460 claw_.set_is_zeroing(mode == UNKNOWN_LOCATION);
Austin Schuhcda86af2014-02-16 16:16:39 -0800461 claw_.Update(output == nullptr);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800462 } else {
Austin Schuhcda86af2014-02-16 16:16:39 -0800463 claw_.Update(true);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800464 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800465
Austin Schuh4cb047f2014-02-16 21:10:19 -0800466 capped_goal_ = false;
Austin Schuhcda86af2014-02-16 16:16:39 -0800467 switch (mode) {
468 case READY:
469 break;
470 case FINE_TUNE:
471 break;
Austin Schuh4cb047f2014-02-16 21:10:19 -0800472 case UNKNOWN_LOCATION: {
473 if (claw_.uncapped_average_voltage() > values.claw.max_zeroing_voltage) {
474 double dx = (claw_.uncapped_average_voltage() -
475 values.claw.max_zeroing_voltage) /
476 claw_.K(0, 0);
477 bottom_claw_goal_ -= dx;
478 top_claw_goal_ -= dx;
Austin Schuhcda86af2014-02-16 16:16:39 -0800479 capped_goal_ = true;
Austin Schuh4cb047f2014-02-16 21:10:19 -0800480 LOG(DEBUG, "Moving the goal by %f to prevent windup\n", dx);
481 } else if (claw_.uncapped_average_voltage() <
482 -values.claw.max_zeroing_voltage) {
483 double dx = (claw_.uncapped_average_voltage() +
484 values.claw.max_zeroing_voltage) /
485 claw_.K(0, 0);
486 bottom_claw_goal_ -= dx;
487 top_claw_goal_ -= dx;
Austin Schuhcda86af2014-02-16 16:16:39 -0800488 capped_goal_ = true;
Austin Schuh4cb047f2014-02-16 21:10:19 -0800489 LOG(DEBUG, "Moving the goal by %f to prevent windup\n", dx);
Austin Schuhcda86af2014-02-16 16:16:39 -0800490 }
Austin Schuh4cb047f2014-02-16 21:10:19 -0800491 } break;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800492 }
493
494 if (output) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800495 output->top_claw_voltage = claw_.U(1, 0) + claw_.U(0, 0);
496 output->bottom_claw_voltage = claw_.U(0, 0);
Austin Schuh3bb9a442014-02-02 16:01:45 -0800497 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800498 status->done = false;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800499
500 was_enabled_ = ::aos::robot_state->enabled;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800501}
502
503} // namespace control_loops
504} // namespace frc971