blob: dd81ecbe16769f1f80a55a05e3471afd7ac3f87a [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 Schuh01c652b2014-02-21 23:13:42 -080048static const double kZeroingVoltage = 4.0;
49static const double kMaxVoltage = 12.0;
Austin Schuhf84a1302014-02-19 00:23:30 -080050
Austin Schuhcda86af2014-02-16 16:16:39 -080051void ClawLimitedLoop::CapU() {
Austin Schuh4cb047f2014-02-16 21:10:19 -080052 uncapped_average_voltage_ = U(0, 0) + U(1, 0) / 2.0;
53 if (is_zeroing_) {
Austin Schuhf84a1302014-02-19 00:23:30 -080054 LOG(DEBUG, "zeroing\n");
Austin Schuh4cb047f2014-02-16 21:10:19 -080055 const frc971::constants::Values &values = constants::GetValues();
56 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 } else if (uncapped_average_voltage_ < -values.claw.max_zeroing_voltage) {
61 const double difference =
62 -uncapped_average_voltage_ - values.claw.max_zeroing_voltage;
63 U(0, 0) += difference;
Austin Schuh4cb047f2014-02-16 21:10:19 -080064 }
65 }
66
67 double max_value =
68 ::std::max(::std::abs(U(0, 0)), ::std::abs(U(1, 0) + U(0, 0)));
69
Austin Schuh01c652b2014-02-21 23:13:42 -080070 const double k_max_voltage = is_zeroing_ ? kZeroingVoltage : kMaxVoltage;
71 if (max_value > k_max_voltage) {
Austin Schuhcda86af2014-02-16 16:16:39 -080072 LOG(DEBUG, "Capping U because max is %f\n", max_value);
Austin Schuh01c652b2014-02-21 23:13:42 -080073 U = U * k_max_voltage / max_value;
Austin Schuhcda86af2014-02-16 16:16:39 -080074 LOG(DEBUG, "Capping U is now %f %f\n", U(0, 0), U(1, 0));
Austin Schuh4b7b5d02014-02-10 21:20:34 -080075 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -080076}
77
Austin Schuhcc0bf312014-02-09 00:39:29 -080078ClawMotor::ClawMotor(control_loops::ClawGroup *my_claw)
79 : aos::control_loops::ControlLoop<control_loops::ClawGroup>(my_claw),
Austin Schuh4b7b5d02014-02-10 21:20:34 -080080 has_top_claw_goal_(false),
81 top_claw_goal_(0.0),
Austin Schuhcda86af2014-02-16 16:16:39 -080082 top_claw_(this),
Austin Schuh4b7b5d02014-02-10 21:20:34 -080083 has_bottom_claw_goal_(false),
84 bottom_claw_goal_(0.0),
Austin Schuhcda86af2014-02-16 16:16:39 -080085 bottom_claw_(this),
86 claw_(MakeClawLoop()),
Ben Fredrickson9b388422014-02-13 06:15:31 +000087 was_enabled_(false),
Austin Schuh4cb047f2014-02-16 21:10:19 -080088 doing_calibration_fine_tune_(false),
Austin Schuhe7f90d12014-02-17 00:48:25 -080089 capped_goal_(false),
90 mode_(UNKNOWN_LOCATION) {}
Austin Schuh3bb9a442014-02-02 16:01:45 -080091
Austin Schuh4b7b5d02014-02-10 21:20:34 -080092const int ZeroedStateFeedbackLoop::kZeroingMaxVoltage;
Austin Schuh3bb9a442014-02-02 16:01:45 -080093
Brian Silvermane0a95462014-02-17 00:41:09 -080094bool ZeroedStateFeedbackLoop::DoGetPositionOfEdge(
95 const constants::Values::Claws::AnglePair &angles, double *edge_encoder,
96 double *edge_angle, const HallEffectTracker &sensor,
97 const char *hall_effect_name) {
Austin Schuhf84a1302014-02-19 00:23:30 -080098 bool found_edge = false;
Brian Silvermane0a95462014-02-17 00:41:09 -080099 if (sensor.posedge_count_changed()) {
Austin Schuhf84a1302014-02-19 00:23:30 -0800100 if (posedge_value_ < last_off_encoder_) {
Brian Silvermane0a95462014-02-17 00:41:09 -0800101 *edge_angle = angles.upper_angle;
Austin Schuhf84a1302014-02-19 00:23:30 -0800102 LOG(INFO, "%s Posedge upper of %s -> %f posedge: %f last_encoder: %f\n", name_,
103 hall_effect_name, *edge_angle, posedge_value_, last_off_encoder_);
Brian Silvermane0a95462014-02-17 00:41:09 -0800104 } else {
105 *edge_angle = angles.lower_angle;
Austin Schuhf84a1302014-02-19 00:23:30 -0800106 LOG(INFO, "%s Posedge lower of %s -> %f posedge: %f last_encoder: %f\n", name_,
107 hall_effect_name, *edge_angle, posedge_value_, last_off_encoder_);
Brian Silvermane0a95462014-02-17 00:41:09 -0800108 }
109 *edge_encoder = posedge_value_;
Austin Schuhf84a1302014-02-19 00:23:30 -0800110 found_edge = true;
Brian Silvermane0a95462014-02-17 00:41:09 -0800111 }
112 if (sensor.negedge_count_changed()) {
Austin Schuhf84a1302014-02-19 00:23:30 -0800113 if (negedge_value_ > last_on_encoder_) {
Brian Silvermane0a95462014-02-17 00:41:09 -0800114 *edge_angle = angles.upper_angle;
Austin Schuhf84a1302014-02-19 00:23:30 -0800115 LOG(INFO, "%s Negedge upper of %s -> %f negedge: %f last_encoder: %f\n", name_,
116 hall_effect_name, *edge_angle, negedge_value_, last_on_encoder_);
Brian Silvermane0a95462014-02-17 00:41:09 -0800117 } else {
118 *edge_angle = angles.lower_angle;
Austin Schuhf84a1302014-02-19 00:23:30 -0800119 LOG(INFO, "%s Negedge lower of %s -> %f negedge: %f last_encoder: %f\n", name_,
120 hall_effect_name, *edge_angle, negedge_value_, last_on_encoder_);
Brian Silvermane0a95462014-02-17 00:41:09 -0800121 }
122 *edge_encoder = negedge_value_;
Austin Schuhf84a1302014-02-19 00:23:30 -0800123 found_edge = true;
Brian Silvermane0a95462014-02-17 00:41:09 -0800124 }
125
Austin Schuhf84a1302014-02-19 00:23:30 -0800126 return found_edge;
Brian Silvermane0a95462014-02-17 00:41:09 -0800127}
128
Austin Schuhf9286cd2014-02-11 00:51:09 -0800129bool ZeroedStateFeedbackLoop::GetPositionOfEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800130 const constants::Values::Claws::Claw &claw_values, double *edge_encoder,
Austin Schuhf9286cd2014-02-11 00:51:09 -0800131 double *edge_angle) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800132 // TODO(austin): Validate that the hall effect edge makes sense.
133 // We must now be on the side of the edge that we expect to be, and the
134 // encoder must have been on either side of the edge before and after.
135
Austin Schuhcda86af2014-02-16 16:16:39 -0800136 // TODO(austin): Compute the last off range min and max and compare the edge
137 // value to the middle of the range. This will be quite a bit more reliable.
138
Brian Silvermane0a95462014-02-17 00:41:09 -0800139 if (DoGetPositionOfEdge(claw_values.front, edge_encoder, edge_angle,
140 front_, "front")) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800141 return true;
142 }
Brian Silvermane0a95462014-02-17 00:41:09 -0800143 if (DoGetPositionOfEdge(claw_values.calibration, edge_encoder, edge_angle,
144 calibration_, "calibration")) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800145 return true;
146 }
Brian Silvermane0a95462014-02-17 00:41:09 -0800147 if (DoGetPositionOfEdge(claw_values.back, edge_encoder, edge_angle,
148 back_, "back")) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800149 return true;
150 }
151 return false;
152}
153
Austin Schuhcda86af2014-02-16 16:16:39 -0800154void TopZeroedStateFeedbackLoop::SetCalibration(double edge_encoder,
155 double edge_angle) {
156 double old_offset = offset_;
157 offset_ = edge_angle - edge_encoder;
158 const double doffset = offset_ - old_offset;
159 motor_->ChangeTopOffset(doffset);
160}
161
162void BottomZeroedStateFeedbackLoop::SetCalibration(double edge_encoder,
163 double edge_angle) {
164 double old_offset = offset_;
165 offset_ = edge_angle - edge_encoder;
166 const double doffset = offset_ - old_offset;
167 motor_->ChangeBottomOffset(doffset);
168}
169
170void ClawMotor::ChangeTopOffset(double doffset) {
171 claw_.ChangeTopOffset(doffset);
172 if (has_top_claw_goal_) {
173 top_claw_goal_ += doffset;
174 }
175}
176
177void ClawMotor::ChangeBottomOffset(double doffset) {
178 claw_.ChangeBottomOffset(doffset);
179 if (has_bottom_claw_goal_) {
180 bottom_claw_goal_ += doffset;
181 }
182}
183
184void ClawLimitedLoop::ChangeTopOffset(double doffset) {
185 Y_(1, 0) += doffset;
186 X_hat(1, 0) += doffset;
187 LOG(INFO, "Changing top offset by %f\n", doffset);
188}
189void ClawLimitedLoop::ChangeBottomOffset(double doffset) {
190 Y_(0, 0) += doffset;
191 X_hat(0, 0) += doffset;
192 X_hat(1, 0) -= doffset;
193 LOG(INFO, "Changing bottom offset by %f\n", doffset);
194}
joe7376ff52014-02-16 18:28:42 -0800195
Austin Schuh069143b2014-02-17 02:46:26 -0800196void LimitClawGoal(double *bottom_goal, double *top_goal,
197 const frc971::constants::Values &values) {
198 // first update position based on angle limit
199
200 const double separation = *top_goal - *bottom_goal;
201 if (separation > values.claw.claw_max_separation) {
202 LOG(DEBUG, "Greater than\n");
203 const double dsep = (separation - values.claw.claw_max_separation) / 2.0;
204 *bottom_goal += dsep;
205 *top_goal -= dsep;
206 LOG(DEBUG, "Goals now bottom: %f, top: %f\n", *bottom_goal, *top_goal);
207 }
208 if (separation < values.claw.claw_min_separation) {
209 LOG(DEBUG, "Less than\n");
210 const double dsep = (separation - values.claw.claw_min_separation) / 2.0;
211 *bottom_goal += dsep;
212 *top_goal -= dsep;
213 LOG(DEBUG, "Goals now bottom: %f, top: %f\n", *bottom_goal, *top_goal);
214 }
215
216 // now move both goals in unison
217 if (*bottom_goal < values.claw.lower_claw.lower_limit) {
218 *top_goal += values.claw.lower_claw.lower_limit - *bottom_goal;
219 *bottom_goal = values.claw.lower_claw.lower_limit;
220 }
221 if (*bottom_goal > values.claw.lower_claw.upper_limit) {
222 *top_goal -= *bottom_goal - values.claw.lower_claw.upper_limit;
223 *bottom_goal = values.claw.lower_claw.upper_limit;
224 }
225
226 if (*top_goal < values.claw.upper_claw.lower_limit) {
227 *bottom_goal += values.claw.upper_claw.lower_limit - *top_goal;
228 *top_goal = values.claw.upper_claw.lower_limit;
229 }
230 if (*top_goal > values.claw.upper_claw.upper_limit) {
231 *bottom_goal -= *top_goal - values.claw.upper_claw.upper_limit;
232 *top_goal = values.claw.upper_claw.upper_limit;
233 }
234}
Austin Schuhcda86af2014-02-16 16:16:39 -0800235
Austin Schuhe7f90d12014-02-17 00:48:25 -0800236bool ClawMotor::is_ready() const {
237 return (
238 (top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED &&
239 bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED) ||
240 (::aos::robot_state->autonomous &&
241 ((top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
242 top_claw_.zeroing_state() ==
243 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION) &&
244 (bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
245 bottom_claw_.zeroing_state() ==
246 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION))));
247}
248
249bool ClawMotor::is_zeroing() const { return !is_ready(); }
250
Austin Schuh3bb9a442014-02-02 16:01:45 -0800251// Positive angle is up, and positive power is up.
Austin Schuhcc0bf312014-02-09 00:39:29 -0800252void ClawMotor::RunIteration(const control_loops::ClawGroup::Goal *goal,
253 const control_loops::ClawGroup::Position *position,
254 control_loops::ClawGroup::Output *output,
Austin Schuh3bb9a442014-02-02 16:01:45 -0800255 ::aos::control_loops::Status *status) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800256 constexpr double dt = 0.01;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800257
258 // Disable the motors now so that all early returns will return with the
259 // motors disabled.
260 if (output) {
261 output->top_claw_voltage = 0;
262 output->bottom_claw_voltage = 0;
263 output->intake_voltage = 0;
264 }
265
Austin Schuh1a499942014-02-17 01:51:58 -0800266 if (reset()) {
267 bottom_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::UNKNOWN_POSITION);
268 top_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::UNKNOWN_POSITION);
Austin Schuhf84a1302014-02-19 00:23:30 -0800269 top_claw_.Reset();
270 bottom_claw_.Reset();
Austin Schuh1a499942014-02-17 01:51:58 -0800271 }
272
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800273 if (::aos::robot_state.get() == nullptr) {
274 return;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800275 }
276
Austin Schuhf9286cd2014-02-11 00:51:09 -0800277 const frc971::constants::Values &values = constants::GetValues();
278
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800279 if (position) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800280 Eigen::Matrix<double, 2, 1> Y;
281 Y << position->bottom.position + bottom_claw_.offset(),
282 position->top.position + top_claw_.offset();
283 claw_.Correct(Y);
284
Austin Schuhf9286cd2014-02-11 00:51:09 -0800285 top_claw_.SetPositionValues(position->top);
286 bottom_claw_.SetPositionValues(position->bottom);
287
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800288 if (!has_top_claw_goal_) {
289 has_top_claw_goal_ = true;
Austin Schuhcda86af2014-02-16 16:16:39 -0800290 top_claw_goal_ = top_claw_.absolute_position();
Austin Schuhe7f90d12014-02-17 00:48:25 -0800291 initial_separation_ =
Austin Schuhcda86af2014-02-16 16:16:39 -0800292 top_claw_.absolute_position() - bottom_claw_.absolute_position();
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800293 }
294 if (!has_bottom_claw_goal_) {
295 has_bottom_claw_goal_ = true;
Austin Schuhcda86af2014-02-16 16:16:39 -0800296 bottom_claw_goal_ = bottom_claw_.absolute_position();
Austin Schuhe7f90d12014-02-17 00:48:25 -0800297 initial_separation_ =
Austin Schuhcda86af2014-02-16 16:16:39 -0800298 top_claw_.absolute_position() - bottom_claw_.absolute_position();
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800299 }
Austin Schuhcda86af2014-02-16 16:16:39 -0800300 LOG(DEBUG, "Claw position is (top: %f bottom: %f\n",
301 top_claw_.absolute_position(), bottom_claw_.absolute_position());
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800302 }
303
Austin Schuh069143b2014-02-17 02:46:26 -0800304 const bool autonomous = ::aos::robot_state->autonomous;
305 const bool enabled = ::aos::robot_state->enabled;
306
307 double bottom_claw_velocity_ = 0.0;
308 double top_claw_velocity_ = 0.0;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800309
310 if ((top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED &&
311 bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED) ||
312 (autonomous &&
313 ((top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
314 top_claw_.zeroing_state() ==
315 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION) &&
316 (bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
317 bottom_claw_.zeroing_state() ==
318 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION)))) {
319 // Ready to use the claw.
320 // Limit the goals here.
Austin Schuhf9286cd2014-02-11 00:51:09 -0800321 bottom_claw_goal_ = goal->bottom_angle;
Brian Silverman7c021c42014-02-17 15:15:56 -0800322 top_claw_goal_ = goal->bottom_angle + goal->separation_angle;
Austin Schuhcda86af2014-02-16 16:16:39 -0800323 has_bottom_claw_goal_ = true;
324 has_top_claw_goal_ = true;
325 doing_calibration_fine_tune_ = false;
326
Austin Schuhe7f90d12014-02-17 00:48:25 -0800327 mode_ = READY;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800328 } else if (top_claw_.zeroing_state() !=
329 ZeroedStateFeedbackLoop::UNKNOWN_POSITION &&
330 bottom_claw_.zeroing_state() !=
331 ZeroedStateFeedbackLoop::UNKNOWN_POSITION) {
332 // Time to fine tune the zero.
333 // Limit the goals here.
Austin Schuh0c733422014-02-17 01:17:12 -0800334 if (!enabled) {
335 // If we are disabled, start the fine tune process over again.
336 doing_calibration_fine_tune_ = false;
337 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800338 if (bottom_claw_.zeroing_state() != ZeroedStateFeedbackLoop::CALIBRATED) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800339 // always get the bottom claw to calibrated first
340 LOG(DEBUG, "Calibrating the bottom of the claw\n");
341 if (!doing_calibration_fine_tune_) {
342 if (::std::abs(bottom_absolute_position() -
Austin Schuhd27931c2014-02-16 19:18:20 -0800343 values.claw.start_fine_tune_pos) <
344 values.claw.claw_unimportant_epsilon) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800345 doing_calibration_fine_tune_ = true;
Austin Schuhd27931c2014-02-16 19:18:20 -0800346 bottom_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800347 top_claw_velocity_ = bottom_claw_velocity_ =
348 values.claw.claw_zeroing_speed;
Austin Schuhcda86af2014-02-16 16:16:39 -0800349 LOG(DEBUG, "Ready to fine tune the bottom\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800350 mode_ = FINE_TUNE_BOTTOM;
Austin Schuhcda86af2014-02-16 16:16:39 -0800351 } else {
352 // send bottom to zeroing start
Austin Schuhd27931c2014-02-16 19:18:20 -0800353 bottom_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuhcda86af2014-02-16 16:16:39 -0800354 LOG(DEBUG, "Going to the start position for the bottom\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800355 mode_ = PREP_FINE_TUNE_BOTTOM;
Austin Schuhcda86af2014-02-16 16:16:39 -0800356 }
357 } else {
Austin Schuhe7f90d12014-02-17 00:48:25 -0800358 mode_ = FINE_TUNE_BOTTOM;
Austin Schuhd27931c2014-02-16 19:18:20 -0800359 bottom_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800360 top_claw_velocity_ = bottom_claw_velocity_ =
361 values.claw.claw_zeroing_speed;
Brian Silvermane0a95462014-02-17 00:41:09 -0800362 if (top_claw_.front_or_back_triggered() ||
363 bottom_claw_.front_or_back_triggered()) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800364 // We shouldn't hit a limit, but if we do, go back to the zeroing
365 // point and try again.
366 doing_calibration_fine_tune_ = false;
Austin Schuhd27931c2014-02-16 19:18:20 -0800367 bottom_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuh069143b2014-02-17 02:46:26 -0800368 top_claw_velocity_ = bottom_claw_velocity_ = 0.0;
Austin Schuhcda86af2014-02-16 16:16:39 -0800369 LOG(DEBUG, "Found a limit, starting over.\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800370 mode_ = PREP_FINE_TUNE_BOTTOM;
Austin Schuhcda86af2014-02-16 16:16:39 -0800371 }
Austin Schuh288c8c32014-02-16 17:20:17 -0800372
Brian Silvermane0a95462014-02-17 00:41:09 -0800373 if (bottom_claw_.calibration().value()) {
374 if (bottom_claw_.calibration().posedge_count_changed() &&
Austin Schuh288c8c32014-02-16 17:20:17 -0800375 position) {
376 // do calibration
377 bottom_claw_.SetCalibration(
378 position->bottom.posedge_value,
Austin Schuhd27931c2014-02-16 19:18:20 -0800379 values.claw.lower_claw.calibration.lower_angle);
Austin Schuh288c8c32014-02-16 17:20:17 -0800380 bottom_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::CALIBRATED);
381 // calibrated so we are done fine tuning bottom
382 doing_calibration_fine_tune_ = false;
383 LOG(DEBUG, "Calibrated the bottom correctly!\n");
384 } else {
385 doing_calibration_fine_tune_ = false;
Austin Schuhd27931c2014-02-16 19:18:20 -0800386 bottom_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuh069143b2014-02-17 02:46:26 -0800387 top_claw_velocity_ = bottom_claw_velocity_ = 0.0;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800388 mode_ = PREP_FINE_TUNE_BOTTOM;
Austin Schuh288c8c32014-02-16 17:20:17 -0800389 }
Austin Schuhcda86af2014-02-16 16:16:39 -0800390 } else {
391 LOG(DEBUG, "Fine tuning\n");
392 }
393 }
394 // now set the top claw to track
395
Austin Schuhd27931c2014-02-16 19:18:20 -0800396 top_claw_goal_ = bottom_claw_goal_ + values.claw.claw_zeroing_separation;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800397 } else {
Austin Schuhcda86af2014-02-16 16:16:39 -0800398 // bottom claw must be calibrated, start on the top
399 if (!doing_calibration_fine_tune_) {
Austin Schuhd27931c2014-02-16 19:18:20 -0800400 if (::std::abs(top_absolute_position() -
401 values.claw.start_fine_tune_pos) <
402 values.claw.claw_unimportant_epsilon) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800403 doing_calibration_fine_tune_ = true;
Austin Schuhd27931c2014-02-16 19:18:20 -0800404 top_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800405 top_claw_velocity_ = bottom_claw_velocity_ =
406 values.claw.claw_zeroing_speed;
Austin Schuhcda86af2014-02-16 16:16:39 -0800407 LOG(DEBUG, "Ready to fine tune the top\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800408 mode_ = FINE_TUNE_TOP;
Austin Schuhcda86af2014-02-16 16:16:39 -0800409 } else {
410 // send top to zeroing start
Austin Schuhd27931c2014-02-16 19:18:20 -0800411 top_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuhcda86af2014-02-16 16:16:39 -0800412 LOG(DEBUG, "Going to the start position for the top\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800413 mode_ = PREP_FINE_TUNE_TOP;
Austin Schuhcda86af2014-02-16 16:16:39 -0800414 }
415 } else {
Austin Schuhe7f90d12014-02-17 00:48:25 -0800416 mode_ = FINE_TUNE_TOP;
Austin Schuhd27931c2014-02-16 19:18:20 -0800417 top_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800418 top_claw_velocity_ = bottom_claw_velocity_ =
419 values.claw.claw_zeroing_speed;
Brian Silvermane0a95462014-02-17 00:41:09 -0800420 if (top_claw_.front_or_back_triggered() ||
421 bottom_claw_.front_or_back_triggered()) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800422 // this should not happen, but now we know it won't
423 doing_calibration_fine_tune_ = false;
Austin Schuhd27931c2014-02-16 19:18:20 -0800424 top_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuh069143b2014-02-17 02:46:26 -0800425 top_claw_velocity_ = bottom_claw_velocity_ = 0.0;
Austin Schuhcda86af2014-02-16 16:16:39 -0800426 LOG(DEBUG, "Found a limit, starting over.\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800427 mode_ = PREP_FINE_TUNE_TOP;
Austin Schuhcda86af2014-02-16 16:16:39 -0800428 }
Brian Silvermane0a95462014-02-17 00:41:09 -0800429 if (top_claw_.calibration().value()) {
430 if (top_claw_.calibration().posedge_count_changed() &&
Austin Schuh288c8c32014-02-16 17:20:17 -0800431 position) {
432 // do calibration
Austin Schuhd27931c2014-02-16 19:18:20 -0800433 top_claw_.SetCalibration(
434 position->top.posedge_value,
435 values.claw.upper_claw.calibration.lower_angle);
Austin Schuh288c8c32014-02-16 17:20:17 -0800436 top_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::CALIBRATED);
Austin Schuhe7f90d12014-02-17 00:48:25 -0800437 // calibrated so we are done fine tuning top
Austin Schuh288c8c32014-02-16 17:20:17 -0800438 doing_calibration_fine_tune_ = false;
439 LOG(DEBUG, "Calibrated the top correctly!\n");
440 } else {
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 Schuhe7f90d12014-02-17 00:48:25 -0800444 mode_ = PREP_FINE_TUNE_TOP;
Austin Schuh288c8c32014-02-16 17:20:17 -0800445 }
Austin Schuhcda86af2014-02-16 16:16:39 -0800446 }
447 }
448 // now set the bottom claw to track
Austin Schuhd27931c2014-02-16 19:18:20 -0800449 bottom_claw_goal_ = top_claw_goal_ - values.claw.claw_zeroing_separation;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800450 }
451 } else {
Austin Schuhcda86af2014-02-16 16:16:39 -0800452 doing_calibration_fine_tune_ = false;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800453 if (!was_enabled_ && enabled) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800454 if (position) {
455 top_claw_goal_ = position->top.position;
456 bottom_claw_goal_ = position->bottom.position;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800457 initial_separation_ =
Austin Schuhcda86af2014-02-16 16:16:39 -0800458 position->top.position - position->bottom.position;
Austin Schuhf9286cd2014-02-11 00:51:09 -0800459 } else {
460 has_top_claw_goal_ = false;
461 has_bottom_claw_goal_ = false;
462 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800463 }
Austin Schuhf9286cd2014-02-11 00:51:09 -0800464
Austin Schuh4cb047f2014-02-16 21:10:19 -0800465 if ((bottom_claw_.zeroing_state() !=
466 ZeroedStateFeedbackLoop::UNKNOWN_POSITION ||
Brian Silvermane0a95462014-02-17 00:41:09 -0800467 bottom_claw_.front().value() || top_claw_.front().value()) &&
468 !top_claw_.back().value() && !bottom_claw_.back().value()) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800469 if (enabled) {
470 // Time to slowly move back up to find any position to narrow down the
471 // zero.
Austin Schuhd27931c2014-02-16 19:18:20 -0800472 top_claw_goal_ += values.claw.claw_zeroing_off_speed * dt;
473 bottom_claw_goal_ += values.claw.claw_zeroing_off_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800474 top_claw_velocity_ = bottom_claw_velocity_ =
475 values.claw.claw_zeroing_off_speed;
Austin Schuhcda86af2014-02-16 16:16:39 -0800476 LOG(DEBUG, "Bottom is known.\n");
Austin Schuhf9286cd2014-02-11 00:51:09 -0800477 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800478 } else {
479 // We don't know where either claw is. Slowly start moving down to find
480 // any hall effect.
Austin Schuhf9286cd2014-02-11 00:51:09 -0800481 if (enabled) {
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, "Both are unknown.\n");
Austin Schuhf9286cd2014-02-11 00:51:09 -0800487 }
488 }
489
490 if (enabled) {
491 top_claw_.SetCalibrationOnEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800492 values.claw.upper_claw, ZeroedStateFeedbackLoop::APPROXIMATE_CALIBRATION);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800493 bottom_claw_.SetCalibrationOnEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800494 values.claw.lower_claw, ZeroedStateFeedbackLoop::APPROXIMATE_CALIBRATION);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800495 } else {
Austin Schuh069143b2014-02-17 02:46:26 -0800496 // TODO(austin): Only calibrate on the predetermined edge.
497 // We might be able to just ignore this since the backlash is soooo low. :)
Austin Schuhf9286cd2014-02-11 00:51:09 -0800498 top_claw_.SetCalibrationOnEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800499 values.claw.upper_claw, ZeroedStateFeedbackLoop::DISABLED_CALIBRATION);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800500 bottom_claw_.SetCalibrationOnEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800501 values.claw.lower_claw, ZeroedStateFeedbackLoop::DISABLED_CALIBRATION);
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800502 }
Austin Schuhe7f90d12014-02-17 00:48:25 -0800503 mode_ = UNKNOWN_LOCATION;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800504 }
505
Austin Schuh069143b2014-02-17 02:46:26 -0800506 // Limit the goals if both claws have been (mostly) found.
507 if (mode_ != UNKNOWN_LOCATION) {
508 LimitClawGoal(&bottom_claw_goal_, &top_claw_goal_, values);
509 }
510
Austin Schuhf9286cd2014-02-11 00:51:09 -0800511 if (has_top_claw_goal_ && has_bottom_claw_goal_) {
Austin Schuh069143b2014-02-17 02:46:26 -0800512 claw_.R << bottom_claw_goal_, top_claw_goal_ - bottom_claw_goal_,
513 bottom_claw_velocity_, top_claw_velocity_ - bottom_claw_velocity_;
Austin Schuhcda86af2014-02-16 16:16:39 -0800514 double separation = -971;
515 if (position != nullptr) {
516 separation = position->top.position - position->bottom.position;
517 }
518 LOG(DEBUG, "Goal is %f (bottom) %f, separation is %f\n", claw_.R(0, 0),
519 claw_.R(1, 0), separation);
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800520
Austin Schuh01c652b2014-02-21 23:13:42 -0800521 // Only cap power when one of the halves of the claw is moving slowly and
522 // could wind up.
Austin Schuhe7f90d12014-02-17 00:48:25 -0800523 claw_.set_is_zeroing(mode_ == UNKNOWN_LOCATION || mode_ == FINE_TUNE_TOP ||
524 mode_ == FINE_TUNE_BOTTOM);
Austin Schuhcda86af2014-02-16 16:16:39 -0800525 claw_.Update(output == nullptr);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800526 } else {
Austin Schuhcda86af2014-02-16 16:16:39 -0800527 claw_.Update(true);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800528 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800529
Austin Schuh4cb047f2014-02-16 21:10:19 -0800530 capped_goal_ = false;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800531 switch (mode_) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800532 case READY:
Austin Schuhe7f90d12014-02-17 00:48:25 -0800533 case PREP_FINE_TUNE_TOP:
534 case PREP_FINE_TUNE_BOTTOM:
Austin Schuhcda86af2014-02-16 16:16:39 -0800535 break;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800536 case FINE_TUNE_BOTTOM:
537 case FINE_TUNE_TOP:
Austin Schuh4cb047f2014-02-16 21:10:19 -0800538 case UNKNOWN_LOCATION: {
539 if (claw_.uncapped_average_voltage() > values.claw.max_zeroing_voltage) {
540 double dx = (claw_.uncapped_average_voltage() -
541 values.claw.max_zeroing_voltage) /
542 claw_.K(0, 0);
543 bottom_claw_goal_ -= dx;
544 top_claw_goal_ -= dx;
Austin Schuhcda86af2014-02-16 16:16:39 -0800545 capped_goal_ = true;
Austin Schuh4cb047f2014-02-16 21:10:19 -0800546 LOG(DEBUG, "Moving the goal by %f to prevent windup\n", dx);
Austin Schuhe7f90d12014-02-17 00:48:25 -0800547 LOG(DEBUG, "Uncapped is %f, max is %f, difference is %f\n",
548 claw_.uncapped_average_voltage(), values.claw.max_zeroing_voltage,
549 (claw_.uncapped_average_voltage() -
550 values.claw.max_zeroing_voltage));
Austin Schuh4cb047f2014-02-16 21:10:19 -0800551 } else if (claw_.uncapped_average_voltage() <
552 -values.claw.max_zeroing_voltage) {
553 double dx = (claw_.uncapped_average_voltage() +
554 values.claw.max_zeroing_voltage) /
555 claw_.K(0, 0);
556 bottom_claw_goal_ -= dx;
557 top_claw_goal_ -= dx;
Austin Schuhcda86af2014-02-16 16:16:39 -0800558 capped_goal_ = true;
Austin Schuh4cb047f2014-02-16 21:10:19 -0800559 LOG(DEBUG, "Moving the goal by %f to prevent windup\n", dx);
Austin Schuhcda86af2014-02-16 16:16:39 -0800560 }
Austin Schuh4cb047f2014-02-16 21:10:19 -0800561 } break;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800562 }
563
564 if (output) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800565 output->top_claw_voltage = claw_.U(1, 0) + claw_.U(0, 0);
566 output->bottom_claw_voltage = claw_.U(0, 0);
Austin Schuhf84a1302014-02-19 00:23:30 -0800567
568 if (output->top_claw_voltage > kMaxVoltage) {
569 output->top_claw_voltage = kMaxVoltage;
570 } else if (output->top_claw_voltage < -kMaxVoltage) {
571 output->top_claw_voltage = -kMaxVoltage;
572 }
573
574 if (output->bottom_claw_voltage > kMaxVoltage) {
575 output->bottom_claw_voltage = kMaxVoltage;
576 } else if (output->bottom_claw_voltage < -kMaxVoltage) {
577 output->bottom_claw_voltage = -kMaxVoltage;
578 }
Austin Schuh3bb9a442014-02-02 16:01:45 -0800579 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800580 status->done = false;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800581
582 was_enabled_ = ::aos::robot_state->enabled;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800583}
584
585} // namespace control_loops
586} // namespace frc971