blob: 59247310e1088d785864386900562ad02229821d [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 Schuhf84a1302014-02-19 00:23:30 -080048static const double kMaxVoltage = 1.5;
49
Austin Schuhcda86af2014-02-16 16:16:39 -080050void ClawLimitedLoop::CapU() {
Austin Schuh4cb047f2014-02-16 21:10:19 -080051 uncapped_average_voltage_ = U(0, 0) + U(1, 0) / 2.0;
52 if (is_zeroing_) {
Austin Schuhf84a1302014-02-19 00:23:30 -080053 LOG(DEBUG, "zeroing\n");
Austin Schuh4cb047f2014-02-16 21:10:19 -080054 const frc971::constants::Values &values = constants::GetValues();
55 if (uncapped_average_voltage_ > values.claw.max_zeroing_voltage) {
56 const double difference =
57 uncapped_average_voltage_ - values.claw.max_zeroing_voltage;
58 U(0, 0) -= difference;
Austin Schuh4cb047f2014-02-16 21:10:19 -080059 } else if (uncapped_average_voltage_ < -values.claw.max_zeroing_voltage) {
60 const double difference =
61 -uncapped_average_voltage_ - values.claw.max_zeroing_voltage;
62 U(0, 0) += difference;
Austin Schuh4cb047f2014-02-16 21:10:19 -080063 }
64 }
65
66 double max_value =
67 ::std::max(::std::abs(U(0, 0)), ::std::abs(U(1, 0) + U(0, 0)));
68
Austin Schuhf84a1302014-02-19 00:23:30 -080069 if (max_value > kMaxVoltage) {
Austin Schuhcda86af2014-02-16 16:16:39 -080070 LOG(DEBUG, "Capping U because max is %f\n", max_value);
Austin Schuhf84a1302014-02-19 00:23:30 -080071 U = U * kMaxVoltage / max_value;
Austin Schuhcda86af2014-02-16 16:16:39 -080072 LOG(DEBUG, "Capping U is now %f %f\n", U(0, 0), U(1, 0));
Austin Schuh4b7b5d02014-02-10 21:20:34 -080073 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -080074}
75
Austin Schuhcc0bf312014-02-09 00:39:29 -080076ClawMotor::ClawMotor(control_loops::ClawGroup *my_claw)
77 : aos::control_loops::ControlLoop<control_loops::ClawGroup>(my_claw),
Austin Schuh4b7b5d02014-02-10 21:20:34 -080078 has_top_claw_goal_(false),
79 top_claw_goal_(0.0),
Austin Schuhcda86af2014-02-16 16:16:39 -080080 top_claw_(this),
Austin Schuh4b7b5d02014-02-10 21:20:34 -080081 has_bottom_claw_goal_(false),
82 bottom_claw_goal_(0.0),
Austin Schuhcda86af2014-02-16 16:16:39 -080083 bottom_claw_(this),
84 claw_(MakeClawLoop()),
Ben Fredrickson9b388422014-02-13 06:15:31 +000085 was_enabled_(false),
Austin Schuh4cb047f2014-02-16 21:10:19 -080086 doing_calibration_fine_tune_(false),
Austin Schuhe7f90d12014-02-17 00:48:25 -080087 capped_goal_(false),
88 mode_(UNKNOWN_LOCATION) {}
Austin Schuh3bb9a442014-02-02 16:01:45 -080089
Austin Schuh4b7b5d02014-02-10 21:20:34 -080090const int ZeroedStateFeedbackLoop::kZeroingMaxVoltage;
Austin Schuh3bb9a442014-02-02 16:01:45 -080091
Brian Silvermane0a95462014-02-17 00:41:09 -080092bool ZeroedStateFeedbackLoop::DoGetPositionOfEdge(
93 const constants::Values::Claws::AnglePair &angles, double *edge_encoder,
94 double *edge_angle, const HallEffectTracker &sensor,
95 const char *hall_effect_name) {
Austin Schuhf84a1302014-02-19 00:23:30 -080096 bool found_edge = false;
Brian Silvermane0a95462014-02-17 00:41:09 -080097 if (sensor.posedge_count_changed()) {
Austin Schuhf84a1302014-02-19 00:23:30 -080098 if (posedge_value_ < last_off_encoder_) {
Brian Silvermane0a95462014-02-17 00:41:09 -080099 *edge_angle = angles.upper_angle;
Austin Schuhf84a1302014-02-19 00:23:30 -0800100 LOG(INFO, "%s Posedge upper of %s -> %f posedge: %f last_encoder: %f\n", name_,
101 hall_effect_name, *edge_angle, posedge_value_, last_off_encoder_);
Brian Silvermane0a95462014-02-17 00:41:09 -0800102 } else {
103 *edge_angle = angles.lower_angle;
Austin Schuhf84a1302014-02-19 00:23:30 -0800104 LOG(INFO, "%s Posedge lower of %s -> %f posedge: %f last_encoder: %f\n", name_,
105 hall_effect_name, *edge_angle, posedge_value_, last_off_encoder_);
Brian Silvermane0a95462014-02-17 00:41:09 -0800106 }
107 *edge_encoder = posedge_value_;
Austin Schuhf84a1302014-02-19 00:23:30 -0800108 found_edge = true;
Brian Silvermane0a95462014-02-17 00:41:09 -0800109 }
110 if (sensor.negedge_count_changed()) {
Austin Schuhf84a1302014-02-19 00:23:30 -0800111 if (negedge_value_ > last_on_encoder_) {
Brian Silvermane0a95462014-02-17 00:41:09 -0800112 *edge_angle = angles.upper_angle;
Austin Schuhf84a1302014-02-19 00:23:30 -0800113 LOG(INFO, "%s Negedge upper of %s -> %f negedge: %f last_encoder: %f\n", name_,
114 hall_effect_name, *edge_angle, negedge_value_, last_on_encoder_);
Brian Silvermane0a95462014-02-17 00:41:09 -0800115 } else {
116 *edge_angle = angles.lower_angle;
Austin Schuhf84a1302014-02-19 00:23:30 -0800117 LOG(INFO, "%s Negedge lower of %s -> %f negedge: %f last_encoder: %f\n", name_,
118 hall_effect_name, *edge_angle, negedge_value_, last_on_encoder_);
Brian Silvermane0a95462014-02-17 00:41:09 -0800119 }
120 *edge_encoder = negedge_value_;
Austin Schuhf84a1302014-02-19 00:23:30 -0800121 found_edge = true;
Brian Silvermane0a95462014-02-17 00:41:09 -0800122 }
123
Austin Schuhf84a1302014-02-19 00:23:30 -0800124 return found_edge;
Brian Silvermane0a95462014-02-17 00:41:09 -0800125}
126
Austin Schuhf9286cd2014-02-11 00:51:09 -0800127bool ZeroedStateFeedbackLoop::GetPositionOfEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800128 const constants::Values::Claws::Claw &claw_values, double *edge_encoder,
Austin Schuhf9286cd2014-02-11 00:51:09 -0800129 double *edge_angle) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800130 // TODO(austin): Validate that the hall effect edge makes sense.
131 // We must now be on the side of the edge that we expect to be, and the
132 // encoder must have been on either side of the edge before and after.
133
Austin Schuhcda86af2014-02-16 16:16:39 -0800134 // TODO(austin): Compute the last off range min and max and compare the edge
135 // value to the middle of the range. This will be quite a bit more reliable.
136
Brian Silvermane0a95462014-02-17 00:41:09 -0800137 if (DoGetPositionOfEdge(claw_values.front, edge_encoder, edge_angle,
138 front_, "front")) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800139 return true;
140 }
Brian Silvermane0a95462014-02-17 00:41:09 -0800141 if (DoGetPositionOfEdge(claw_values.calibration, edge_encoder, edge_angle,
142 calibration_, "calibration")) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800143 return true;
144 }
Brian Silvermane0a95462014-02-17 00:41:09 -0800145 if (DoGetPositionOfEdge(claw_values.back, edge_encoder, edge_angle,
146 back_, "back")) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800147 return true;
148 }
149 return false;
150}
151
Austin Schuhcda86af2014-02-16 16:16:39 -0800152void TopZeroedStateFeedbackLoop::SetCalibration(double edge_encoder,
153 double edge_angle) {
154 double old_offset = offset_;
155 offset_ = edge_angle - edge_encoder;
156 const double doffset = offset_ - old_offset;
157 motor_->ChangeTopOffset(doffset);
158}
159
160void BottomZeroedStateFeedbackLoop::SetCalibration(double edge_encoder,
161 double edge_angle) {
162 double old_offset = offset_;
163 offset_ = edge_angle - edge_encoder;
164 const double doffset = offset_ - old_offset;
165 motor_->ChangeBottomOffset(doffset);
166}
167
168void ClawMotor::ChangeTopOffset(double doffset) {
169 claw_.ChangeTopOffset(doffset);
170 if (has_top_claw_goal_) {
171 top_claw_goal_ += doffset;
172 }
173}
174
175void ClawMotor::ChangeBottomOffset(double doffset) {
176 claw_.ChangeBottomOffset(doffset);
177 if (has_bottom_claw_goal_) {
178 bottom_claw_goal_ += doffset;
179 }
180}
181
182void ClawLimitedLoop::ChangeTopOffset(double doffset) {
183 Y_(1, 0) += doffset;
184 X_hat(1, 0) += doffset;
185 LOG(INFO, "Changing top offset by %f\n", doffset);
186}
187void ClawLimitedLoop::ChangeBottomOffset(double doffset) {
188 Y_(0, 0) += doffset;
189 X_hat(0, 0) += doffset;
190 X_hat(1, 0) -= doffset;
191 LOG(INFO, "Changing bottom offset by %f\n", doffset);
192}
joe7376ff52014-02-16 18:28:42 -0800193
Austin Schuh069143b2014-02-17 02:46:26 -0800194void LimitClawGoal(double *bottom_goal, double *top_goal,
195 const frc971::constants::Values &values) {
196 // first update position based on angle limit
197
198 const double separation = *top_goal - *bottom_goal;
199 if (separation > values.claw.claw_max_separation) {
200 LOG(DEBUG, "Greater than\n");
201 const double dsep = (separation - values.claw.claw_max_separation) / 2.0;
202 *bottom_goal += dsep;
203 *top_goal -= dsep;
204 LOG(DEBUG, "Goals now bottom: %f, top: %f\n", *bottom_goal, *top_goal);
205 }
206 if (separation < values.claw.claw_min_separation) {
207 LOG(DEBUG, "Less than\n");
208 const double dsep = (separation - values.claw.claw_min_separation) / 2.0;
209 *bottom_goal += dsep;
210 *top_goal -= dsep;
211 LOG(DEBUG, "Goals now bottom: %f, top: %f\n", *bottom_goal, *top_goal);
212 }
213
214 // now move both goals in unison
215 if (*bottom_goal < values.claw.lower_claw.lower_limit) {
216 *top_goal += values.claw.lower_claw.lower_limit - *bottom_goal;
217 *bottom_goal = values.claw.lower_claw.lower_limit;
218 }
219 if (*bottom_goal > values.claw.lower_claw.upper_limit) {
220 *top_goal -= *bottom_goal - values.claw.lower_claw.upper_limit;
221 *bottom_goal = values.claw.lower_claw.upper_limit;
222 }
223
224 if (*top_goal < values.claw.upper_claw.lower_limit) {
225 *bottom_goal += values.claw.upper_claw.lower_limit - *top_goal;
226 *top_goal = values.claw.upper_claw.lower_limit;
227 }
228 if (*top_goal > values.claw.upper_claw.upper_limit) {
229 *bottom_goal -= *top_goal - values.claw.upper_claw.upper_limit;
230 *top_goal = values.claw.upper_claw.upper_limit;
231 }
232}
Austin Schuhcda86af2014-02-16 16:16:39 -0800233
Austin Schuhe7f90d12014-02-17 00:48:25 -0800234bool ClawMotor::is_ready() const {
235 return (
236 (top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED &&
237 bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED) ||
238 (::aos::robot_state->autonomous &&
239 ((top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
240 top_claw_.zeroing_state() ==
241 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION) &&
242 (bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
243 bottom_claw_.zeroing_state() ==
244 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION))));
245}
246
247bool ClawMotor::is_zeroing() const { return !is_ready(); }
248
Austin Schuh3bb9a442014-02-02 16:01:45 -0800249// Positive angle is up, and positive power is up.
Austin Schuhcc0bf312014-02-09 00:39:29 -0800250void ClawMotor::RunIteration(const control_loops::ClawGroup::Goal *goal,
251 const control_loops::ClawGroup::Position *position,
252 control_loops::ClawGroup::Output *output,
Austin Schuh3bb9a442014-02-02 16:01:45 -0800253 ::aos::control_loops::Status *status) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800254 constexpr double dt = 0.01;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800255
256 // Disable the motors now so that all early returns will return with the
257 // motors disabled.
258 if (output) {
259 output->top_claw_voltage = 0;
260 output->bottom_claw_voltage = 0;
261 output->intake_voltage = 0;
262 }
263
Austin Schuh1a499942014-02-17 01:51:58 -0800264 if (reset()) {
265 bottom_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::UNKNOWN_POSITION);
266 top_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::UNKNOWN_POSITION);
Austin Schuhf84a1302014-02-19 00:23:30 -0800267 top_claw_.Reset();
268 bottom_claw_.Reset();
Austin Schuh1a499942014-02-17 01:51:58 -0800269 }
270
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800271 if (::aos::robot_state.get() == nullptr) {
272 return;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800273 }
274
Austin Schuhf9286cd2014-02-11 00:51:09 -0800275 const frc971::constants::Values &values = constants::GetValues();
276
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800277 if (position) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800278 Eigen::Matrix<double, 2, 1> Y;
279 Y << position->bottom.position + bottom_claw_.offset(),
280 position->top.position + top_claw_.offset();
281 claw_.Correct(Y);
282
Austin Schuhf9286cd2014-02-11 00:51:09 -0800283 top_claw_.SetPositionValues(position->top);
284 bottom_claw_.SetPositionValues(position->bottom);
285
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800286 if (!has_top_claw_goal_) {
287 has_top_claw_goal_ = true;
Austin Schuhcda86af2014-02-16 16:16:39 -0800288 top_claw_goal_ = top_claw_.absolute_position();
Austin Schuhe7f90d12014-02-17 00:48:25 -0800289 initial_separation_ =
Austin Schuhcda86af2014-02-16 16:16:39 -0800290 top_claw_.absolute_position() - bottom_claw_.absolute_position();
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800291 }
292 if (!has_bottom_claw_goal_) {
293 has_bottom_claw_goal_ = true;
Austin Schuhcda86af2014-02-16 16:16:39 -0800294 bottom_claw_goal_ = bottom_claw_.absolute_position();
Austin Schuhe7f90d12014-02-17 00:48:25 -0800295 initial_separation_ =
Austin Schuhcda86af2014-02-16 16:16:39 -0800296 top_claw_.absolute_position() - bottom_claw_.absolute_position();
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800297 }
Austin Schuhcda86af2014-02-16 16:16:39 -0800298 LOG(DEBUG, "Claw position is (top: %f bottom: %f\n",
299 top_claw_.absolute_position(), bottom_claw_.absolute_position());
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800300 }
301
Austin Schuh069143b2014-02-17 02:46:26 -0800302 const bool autonomous = ::aos::robot_state->autonomous;
303 const bool enabled = ::aos::robot_state->enabled;
304
305 double bottom_claw_velocity_ = 0.0;
306 double top_claw_velocity_ = 0.0;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800307
308 if ((top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED &&
309 bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED) ||
310 (autonomous &&
311 ((top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
312 top_claw_.zeroing_state() ==
313 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION) &&
314 (bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
315 bottom_claw_.zeroing_state() ==
316 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION)))) {
317 // Ready to use the claw.
318 // Limit the goals here.
Austin Schuhf9286cd2014-02-11 00:51:09 -0800319 bottom_claw_goal_ = goal->bottom_angle;
Brian Silverman7c021c42014-02-17 15:15:56 -0800320 top_claw_goal_ = goal->bottom_angle + goal->separation_angle;
Austin Schuhcda86af2014-02-16 16:16:39 -0800321 has_bottom_claw_goal_ = true;
322 has_top_claw_goal_ = true;
323 doing_calibration_fine_tune_ = false;
324
Austin Schuhe7f90d12014-02-17 00:48:25 -0800325 mode_ = READY;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800326 } else if (top_claw_.zeroing_state() !=
327 ZeroedStateFeedbackLoop::UNKNOWN_POSITION &&
328 bottom_claw_.zeroing_state() !=
329 ZeroedStateFeedbackLoop::UNKNOWN_POSITION) {
330 // Time to fine tune the zero.
331 // Limit the goals here.
Austin Schuh0c733422014-02-17 01:17:12 -0800332 if (!enabled) {
333 // If we are disabled, start the fine tune process over again.
334 doing_calibration_fine_tune_ = false;
335 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800336 if (bottom_claw_.zeroing_state() != ZeroedStateFeedbackLoop::CALIBRATED) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800337 // always get the bottom claw to calibrated first
338 LOG(DEBUG, "Calibrating the bottom of the claw\n");
339 if (!doing_calibration_fine_tune_) {
340 if (::std::abs(bottom_absolute_position() -
Austin Schuhd27931c2014-02-16 19:18:20 -0800341 values.claw.start_fine_tune_pos) <
342 values.claw.claw_unimportant_epsilon) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800343 doing_calibration_fine_tune_ = true;
Austin Schuhd27931c2014-02-16 19:18:20 -0800344 bottom_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800345 top_claw_velocity_ = bottom_claw_velocity_ =
346 values.claw.claw_zeroing_speed;
Austin Schuhcda86af2014-02-16 16:16:39 -0800347 LOG(DEBUG, "Ready to fine tune the bottom\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800348 mode_ = FINE_TUNE_BOTTOM;
Austin Schuhcda86af2014-02-16 16:16:39 -0800349 } else {
350 // send bottom to zeroing start
Austin Schuhd27931c2014-02-16 19:18:20 -0800351 bottom_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuhcda86af2014-02-16 16:16:39 -0800352 LOG(DEBUG, "Going to the start position for the bottom\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800353 mode_ = PREP_FINE_TUNE_BOTTOM;
Austin Schuhcda86af2014-02-16 16:16:39 -0800354 }
355 } else {
Austin Schuhe7f90d12014-02-17 00:48:25 -0800356 mode_ = FINE_TUNE_BOTTOM;
Austin Schuhd27931c2014-02-16 19:18:20 -0800357 bottom_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800358 top_claw_velocity_ = bottom_claw_velocity_ =
359 values.claw.claw_zeroing_speed;
Brian Silvermane0a95462014-02-17 00:41:09 -0800360 if (top_claw_.front_or_back_triggered() ||
361 bottom_claw_.front_or_back_triggered()) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800362 // We shouldn't hit a limit, but if we do, go back to the zeroing
363 // point and try again.
364 doing_calibration_fine_tune_ = false;
Austin Schuhd27931c2014-02-16 19:18:20 -0800365 bottom_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuh069143b2014-02-17 02:46:26 -0800366 top_claw_velocity_ = bottom_claw_velocity_ = 0.0;
Austin Schuhcda86af2014-02-16 16:16:39 -0800367 LOG(DEBUG, "Found a limit, starting over.\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800368 mode_ = PREP_FINE_TUNE_BOTTOM;
Austin Schuhcda86af2014-02-16 16:16:39 -0800369 }
Austin Schuh288c8c32014-02-16 17:20:17 -0800370
Brian Silvermane0a95462014-02-17 00:41:09 -0800371 if (bottom_claw_.calibration().value()) {
372 if (bottom_claw_.calibration().posedge_count_changed() &&
Austin Schuh288c8c32014-02-16 17:20:17 -0800373 position) {
374 // do calibration
375 bottom_claw_.SetCalibration(
376 position->bottom.posedge_value,
Austin Schuhd27931c2014-02-16 19:18:20 -0800377 values.claw.lower_claw.calibration.lower_angle);
Austin Schuh288c8c32014-02-16 17:20:17 -0800378 bottom_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::CALIBRATED);
379 // calibrated so we are done fine tuning bottom
380 doing_calibration_fine_tune_ = false;
381 LOG(DEBUG, "Calibrated the bottom correctly!\n");
382 } else {
383 doing_calibration_fine_tune_ = false;
Austin Schuhd27931c2014-02-16 19:18:20 -0800384 bottom_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuh069143b2014-02-17 02:46:26 -0800385 top_claw_velocity_ = bottom_claw_velocity_ = 0.0;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800386 mode_ = PREP_FINE_TUNE_BOTTOM;
Austin Schuh288c8c32014-02-16 17:20:17 -0800387 }
Austin Schuhcda86af2014-02-16 16:16:39 -0800388 } else {
389 LOG(DEBUG, "Fine tuning\n");
390 }
391 }
392 // now set the top claw to track
393
Austin Schuhd27931c2014-02-16 19:18:20 -0800394 top_claw_goal_ = bottom_claw_goal_ + values.claw.claw_zeroing_separation;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800395 } else {
Austin Schuhcda86af2014-02-16 16:16:39 -0800396 // bottom claw must be calibrated, start on the top
397 if (!doing_calibration_fine_tune_) {
Austin Schuhd27931c2014-02-16 19:18:20 -0800398 if (::std::abs(top_absolute_position() -
399 values.claw.start_fine_tune_pos) <
400 values.claw.claw_unimportant_epsilon) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800401 doing_calibration_fine_tune_ = true;
Austin Schuhd27931c2014-02-16 19:18:20 -0800402 top_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800403 top_claw_velocity_ = bottom_claw_velocity_ =
404 values.claw.claw_zeroing_speed;
Austin Schuhcda86af2014-02-16 16:16:39 -0800405 LOG(DEBUG, "Ready to fine tune the top\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800406 mode_ = FINE_TUNE_TOP;
Austin Schuhcda86af2014-02-16 16:16:39 -0800407 } else {
408 // send top to zeroing start
Austin Schuhd27931c2014-02-16 19:18:20 -0800409 top_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuhcda86af2014-02-16 16:16:39 -0800410 LOG(DEBUG, "Going to the start position for the top\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800411 mode_ = PREP_FINE_TUNE_TOP;
Austin Schuhcda86af2014-02-16 16:16:39 -0800412 }
413 } else {
Austin Schuhe7f90d12014-02-17 00:48:25 -0800414 mode_ = FINE_TUNE_TOP;
Austin Schuhd27931c2014-02-16 19:18:20 -0800415 top_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800416 top_claw_velocity_ = bottom_claw_velocity_ =
417 values.claw.claw_zeroing_speed;
Brian Silvermane0a95462014-02-17 00:41:09 -0800418 if (top_claw_.front_or_back_triggered() ||
419 bottom_claw_.front_or_back_triggered()) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800420 // this should not happen, but now we know it won't
421 doing_calibration_fine_tune_ = false;
Austin Schuhd27931c2014-02-16 19:18:20 -0800422 top_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuh069143b2014-02-17 02:46:26 -0800423 top_claw_velocity_ = bottom_claw_velocity_ = 0.0;
Austin Schuhcda86af2014-02-16 16:16:39 -0800424 LOG(DEBUG, "Found a limit, starting over.\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800425 mode_ = PREP_FINE_TUNE_TOP;
Austin Schuhcda86af2014-02-16 16:16:39 -0800426 }
Brian Silvermane0a95462014-02-17 00:41:09 -0800427 if (top_claw_.calibration().value()) {
428 if (top_claw_.calibration().posedge_count_changed() &&
Austin Schuh288c8c32014-02-16 17:20:17 -0800429 position) {
430 // do calibration
Austin Schuhd27931c2014-02-16 19:18:20 -0800431 top_claw_.SetCalibration(
432 position->top.posedge_value,
433 values.claw.upper_claw.calibration.lower_angle);
Austin Schuh288c8c32014-02-16 17:20:17 -0800434 top_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::CALIBRATED);
Austin Schuhe7f90d12014-02-17 00:48:25 -0800435 // calibrated so we are done fine tuning top
Austin Schuh288c8c32014-02-16 17:20:17 -0800436 doing_calibration_fine_tune_ = false;
437 LOG(DEBUG, "Calibrated the top correctly!\n");
438 } else {
439 doing_calibration_fine_tune_ = false;
Austin Schuhd27931c2014-02-16 19:18:20 -0800440 top_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuh069143b2014-02-17 02:46:26 -0800441 top_claw_velocity_ = bottom_claw_velocity_ = 0.0;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800442 mode_ = PREP_FINE_TUNE_TOP;
Austin Schuh288c8c32014-02-16 17:20:17 -0800443 }
Austin Schuhcda86af2014-02-16 16:16:39 -0800444 }
445 }
446 // now set the bottom claw to track
Austin Schuhd27931c2014-02-16 19:18:20 -0800447 bottom_claw_goal_ = top_claw_goal_ - values.claw.claw_zeroing_separation;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800448 }
449 } else {
Austin Schuhcda86af2014-02-16 16:16:39 -0800450 doing_calibration_fine_tune_ = false;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800451 if (!was_enabled_ && enabled) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800452 if (position) {
453 top_claw_goal_ = position->top.position;
454 bottom_claw_goal_ = position->bottom.position;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800455 initial_separation_ =
Austin Schuhcda86af2014-02-16 16:16:39 -0800456 position->top.position - position->bottom.position;
Austin Schuhf9286cd2014-02-11 00:51:09 -0800457 } else {
458 has_top_claw_goal_ = false;
459 has_bottom_claw_goal_ = false;
460 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800461 }
Austin Schuhf9286cd2014-02-11 00:51:09 -0800462
Austin Schuh4cb047f2014-02-16 21:10:19 -0800463 if ((bottom_claw_.zeroing_state() !=
464 ZeroedStateFeedbackLoop::UNKNOWN_POSITION ||
Brian Silvermane0a95462014-02-17 00:41:09 -0800465 bottom_claw_.front().value() || top_claw_.front().value()) &&
466 !top_claw_.back().value() && !bottom_claw_.back().value()) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800467 if (enabled) {
468 // Time to slowly move back up to find any position to narrow down the
469 // zero.
Austin Schuhd27931c2014-02-16 19:18:20 -0800470 top_claw_goal_ += values.claw.claw_zeroing_off_speed * dt;
471 bottom_claw_goal_ += values.claw.claw_zeroing_off_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800472 top_claw_velocity_ = bottom_claw_velocity_ =
473 values.claw.claw_zeroing_off_speed;
Austin Schuhcda86af2014-02-16 16:16:39 -0800474 LOG(DEBUG, "Bottom is known.\n");
Austin Schuhf9286cd2014-02-11 00:51:09 -0800475 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800476 } else {
477 // We don't know where either claw is. Slowly start moving down to find
478 // any hall effect.
Austin Schuhf9286cd2014-02-11 00:51:09 -0800479 if (enabled) {
Austin Schuhd27931c2014-02-16 19:18:20 -0800480 top_claw_goal_ -= values.claw.claw_zeroing_off_speed * dt;
481 bottom_claw_goal_ -= values.claw.claw_zeroing_off_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800482 top_claw_velocity_ = bottom_claw_velocity_ =
483 -values.claw.claw_zeroing_off_speed;
Austin Schuhcda86af2014-02-16 16:16:39 -0800484 LOG(DEBUG, "Both are unknown.\n");
Austin Schuhf9286cd2014-02-11 00:51:09 -0800485 }
486 }
487
488 if (enabled) {
489 top_claw_.SetCalibrationOnEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800490 values.claw.upper_claw, ZeroedStateFeedbackLoop::APPROXIMATE_CALIBRATION);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800491 bottom_claw_.SetCalibrationOnEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800492 values.claw.lower_claw, ZeroedStateFeedbackLoop::APPROXIMATE_CALIBRATION);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800493 } else {
Austin Schuh069143b2014-02-17 02:46:26 -0800494 // TODO(austin): Only calibrate on the predetermined edge.
495 // We might be able to just ignore this since the backlash is soooo low. :)
Austin Schuhf9286cd2014-02-11 00:51:09 -0800496 top_claw_.SetCalibrationOnEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800497 values.claw.upper_claw, ZeroedStateFeedbackLoop::DISABLED_CALIBRATION);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800498 bottom_claw_.SetCalibrationOnEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800499 values.claw.lower_claw, ZeroedStateFeedbackLoop::DISABLED_CALIBRATION);
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800500 }
Austin Schuhe7f90d12014-02-17 00:48:25 -0800501 mode_ = UNKNOWN_LOCATION;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800502 }
503
Austin Schuh069143b2014-02-17 02:46:26 -0800504 // Limit the goals if both claws have been (mostly) found.
505 if (mode_ != UNKNOWN_LOCATION) {
506 LimitClawGoal(&bottom_claw_goal_, &top_claw_goal_, values);
507 }
508
Austin Schuhf9286cd2014-02-11 00:51:09 -0800509 if (has_top_claw_goal_ && has_bottom_claw_goal_) {
Austin Schuh069143b2014-02-17 02:46:26 -0800510 claw_.R << bottom_claw_goal_, top_claw_goal_ - bottom_claw_goal_,
511 bottom_claw_velocity_, top_claw_velocity_ - bottom_claw_velocity_;
Austin Schuhcda86af2014-02-16 16:16:39 -0800512 double separation = -971;
513 if (position != nullptr) {
514 separation = position->top.position - position->bottom.position;
515 }
516 LOG(DEBUG, "Goal is %f (bottom) %f, separation is %f\n", claw_.R(0, 0),
517 claw_.R(1, 0), separation);
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800518
Austin Schuh4cb047f2014-02-16 21:10:19 -0800519 // Only cap power when one of the halves of the claw is unknown.
Austin Schuhe7f90d12014-02-17 00:48:25 -0800520 claw_.set_is_zeroing(mode_ == UNKNOWN_LOCATION || mode_ == FINE_TUNE_TOP ||
521 mode_ == FINE_TUNE_BOTTOM);
Austin Schuhcda86af2014-02-16 16:16:39 -0800522 claw_.Update(output == nullptr);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800523 } else {
Austin Schuhcda86af2014-02-16 16:16:39 -0800524 claw_.Update(true);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800525 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800526
Austin Schuh4cb047f2014-02-16 21:10:19 -0800527 capped_goal_ = false;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800528 switch (mode_) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800529 case READY:
Austin Schuhe7f90d12014-02-17 00:48:25 -0800530 case PREP_FINE_TUNE_TOP:
531 case PREP_FINE_TUNE_BOTTOM:
Austin Schuhcda86af2014-02-16 16:16:39 -0800532 break;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800533 case FINE_TUNE_BOTTOM:
534 case FINE_TUNE_TOP:
Austin Schuh4cb047f2014-02-16 21:10:19 -0800535 case UNKNOWN_LOCATION: {
536 if (claw_.uncapped_average_voltage() > values.claw.max_zeroing_voltage) {
537 double dx = (claw_.uncapped_average_voltage() -
538 values.claw.max_zeroing_voltage) /
539 claw_.K(0, 0);
540 bottom_claw_goal_ -= dx;
541 top_claw_goal_ -= dx;
Austin Schuhcda86af2014-02-16 16:16:39 -0800542 capped_goal_ = true;
Austin Schuh4cb047f2014-02-16 21:10:19 -0800543 LOG(DEBUG, "Moving the goal by %f to prevent windup\n", dx);
Austin Schuhe7f90d12014-02-17 00:48:25 -0800544 LOG(DEBUG, "Uncapped is %f, max is %f, difference is %f\n",
545 claw_.uncapped_average_voltage(), values.claw.max_zeroing_voltage,
546 (claw_.uncapped_average_voltage() -
547 values.claw.max_zeroing_voltage));
Austin Schuh4cb047f2014-02-16 21:10:19 -0800548 } else if (claw_.uncapped_average_voltage() <
549 -values.claw.max_zeroing_voltage) {
550 double dx = (claw_.uncapped_average_voltage() +
551 values.claw.max_zeroing_voltage) /
552 claw_.K(0, 0);
553 bottom_claw_goal_ -= dx;
554 top_claw_goal_ -= dx;
Austin Schuhcda86af2014-02-16 16:16:39 -0800555 capped_goal_ = true;
Austin Schuh4cb047f2014-02-16 21:10:19 -0800556 LOG(DEBUG, "Moving the goal by %f to prevent windup\n", dx);
Austin Schuhcda86af2014-02-16 16:16:39 -0800557 }
Austin Schuh4cb047f2014-02-16 21:10:19 -0800558 } break;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800559 }
560
561 if (output) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800562 output->top_claw_voltage = claw_.U(1, 0) + claw_.U(0, 0);
563 output->bottom_claw_voltage = claw_.U(0, 0);
Austin Schuhf84a1302014-02-19 00:23:30 -0800564
565 if (output->top_claw_voltage > kMaxVoltage) {
566 output->top_claw_voltage = kMaxVoltage;
567 } else if (output->top_claw_voltage < -kMaxVoltage) {
568 output->top_claw_voltage = -kMaxVoltage;
569 }
570
571 if (output->bottom_claw_voltage > kMaxVoltage) {
572 output->bottom_claw_voltage = kMaxVoltage;
573 } else if (output->bottom_claw_voltage < -kMaxVoltage) {
574 output->bottom_claw_voltage = -kMaxVoltage;
575 }
Austin Schuh3bb9a442014-02-02 16:01:45 -0800576 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800577 status->done = false;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800578
579 was_enabled_ = ::aos::robot_state->enabled;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800580}
581
582} // namespace control_loops
583} // namespace frc971