blob: 417df9ff252e8bd2925004c818bd5f0fb6c662fe [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"
Brian Silvermanf48fab32014-03-09 14:32:24 -07009#include "aos/common/logging/queue_logging.h"
Austin Schuh3bb9a442014-02-02 16:01:45 -080010
11#include "frc971/constants.h"
Austin Schuhcda86af2014-02-16 16:16:39 -080012#include "frc971/control_loops/claw/claw_motor_plant.h"
13
Austin Schuh3bb9a442014-02-02 16:01:45 -080014// Zeroing plan.
15// There are 2 types of zeros. Enabled and disabled ones.
16// Disabled ones are only valid during auto mode, and can be used to speed up
17// the enabled zero process. We need to re-zero during teleop in case the auto
18// zero was poor and causes us to miss all our shots.
19//
20// We need to be able to zero manually while disabled by moving the joint over
21// the zeros.
22// Zero on the down edge when disabled (gravity in the direction of motion)
23//
24// When enabled, zero on the up edge (gravity opposing the direction of motion)
25// The enabled sequence needs to work as follows. We can crash the claw if we
26// bring them too close to each other or too far from each other. The only safe
27// thing to do is to move them in unison.
28//
29// Start by moving them both towards the front of the bot to either find either
30// the middle hall effect on either jaw, or the front hall effect on the bottom
31// jaw. Any edge that isn't the desired edge will provide an approximate edge
32// location that can be used for the fine tuning step.
33// Once an edge is found on the front claw, move back the other way with both
34// claws until an edge is found for the other claw.
35// Now that we have an approximate zero, we can robustify the limits to keep
36// both claws safe. Then, we can move both claws to a position that is the
37// correct side of the zero and go zero.
38
39// Valid region plan.
Ben Fredrickson81ba2d52014-03-02 08:21:46 +000040// Difference between the arms has a range, and the values of each arm has a
41// range.
Austin Schuh3bb9a442014-02-02 16:01:45 -080042// If a claw runs up against a static limit, don't let the goal change outside
43// the limit.
44// If a claw runs up against a movable limit, move both claws outwards to get
45// out of the condition.
46
47namespace frc971 {
48namespace control_loops {
49
Austin Schuh01c652b2014-02-21 23:13:42 -080050static const double kZeroingVoltage = 4.0;
51static const double kMaxVoltage = 12.0;
Austin Schuhf84a1302014-02-19 00:23:30 -080052
Austin Schuh27b8fb12014-02-22 15:10:05 -080053ClawLimitedLoop::ClawLimitedLoop(StateFeedbackLoop<4, 2, 2> loop)
54 : StateFeedbackLoop<4, 2, 2>(loop),
55 uncapped_average_voltage_(0.0),
56 is_zeroing_(true) {}
57
Austin Schuhcda86af2014-02-16 16:16:39 -080058void ClawLimitedLoop::CapU() {
Austin Schuh4cb047f2014-02-16 21:10:19 -080059 uncapped_average_voltage_ = U(0, 0) + U(1, 0) / 2.0;
60 if (is_zeroing_) {
Austin Schuhf84a1302014-02-19 00:23:30 -080061 LOG(DEBUG, "zeroing\n");
Austin Schuh4cb047f2014-02-16 21:10:19 -080062 const frc971::constants::Values &values = constants::GetValues();
63 if (uncapped_average_voltage_ > values.claw.max_zeroing_voltage) {
64 const double difference =
65 uncapped_average_voltage_ - values.claw.max_zeroing_voltage;
66 U(0, 0) -= difference;
Austin Schuh4cb047f2014-02-16 21:10:19 -080067 } else if (uncapped_average_voltage_ < -values.claw.max_zeroing_voltage) {
68 const double difference =
69 -uncapped_average_voltage_ - values.claw.max_zeroing_voltage;
70 U(0, 0) += difference;
Austin Schuh4cb047f2014-02-16 21:10:19 -080071 }
72 }
73
74 double max_value =
75 ::std::max(::std::abs(U(0, 0)), ::std::abs(U(1, 0) + U(0, 0)));
76
Austin Schuh01c652b2014-02-21 23:13:42 -080077 const double k_max_voltage = is_zeroing_ ? kZeroingVoltage : kMaxVoltage;
78 if (max_value > k_max_voltage) {
Austin Schuh01c652b2014-02-21 23:13:42 -080079 U = U * k_max_voltage / max_value;
Brian Silvermanf48fab32014-03-09 14:32:24 -070080 LOG(DEBUG, "Capping U is now %f %f (max is %f)\n",
81 U(0, 0), U(1, 0), max_value);
Austin Schuh4b7b5d02014-02-10 21:20:34 -080082 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -080083}
84
Austin Schuh27b8fb12014-02-22 15:10:05 -080085ZeroedStateFeedbackLoop::ZeroedStateFeedbackLoop(const char *name,
86 ClawMotor *motor)
87 : offset_(0.0),
88 name_(name),
89 motor_(motor),
90 zeroing_state_(UNKNOWN_POSITION),
91 posedge_value_(0.0),
92 negedge_value_(0.0),
93 encoder_(0.0),
94 last_encoder_(0.0) {}
95
96void ZeroedStateFeedbackLoop::SetPositionValues(const HalfClawPosition &claw) {
97 front_.Update(claw.front);
98 calibration_.Update(claw.calibration);
99 back_.Update(claw.back);
100
101 bool any_sensor_triggered = any_triggered();
102 if (any_sensor_triggered && any_triggered_last_) {
103 // We are still on the hall effect and nothing has changed.
104 min_hall_effect_on_angle_ =
105 ::std::min(min_hall_effect_on_angle_, claw.position);
106 max_hall_effect_on_angle_ =
107 ::std::max(max_hall_effect_on_angle_, claw.position);
108 } else if (!any_sensor_triggered && !any_triggered_last_) {
109 // We are still off the hall effect and nothing has changed.
110 min_hall_effect_off_angle_ =
111 ::std::min(min_hall_effect_off_angle_, claw.position);
112 max_hall_effect_off_angle_ =
113 ::std::max(max_hall_effect_off_angle_, claw.position);
114 } else if (any_sensor_triggered && !any_triggered_last_) {
115 // Saw a posedge on the hall effect. Reset the limits.
116 min_hall_effect_on_angle_ = ::std::min(claw.posedge_value, claw.position);
117 max_hall_effect_on_angle_ = ::std::max(claw.posedge_value, claw.position);
118 } else if (!any_sensor_triggered && any_triggered_last_) {
119 // Saw a negedge on the hall effect. Reset the limits.
120 min_hall_effect_off_angle_ = ::std::min(claw.negedge_value, claw.position);
121 max_hall_effect_off_angle_ = ::std::max(claw.negedge_value, claw.position);
122 }
123
124 posedge_value_ = claw.posedge_value;
125 negedge_value_ = claw.negedge_value;
126 last_encoder_ = encoder_;
127 if (front().value() || calibration().value() || back().value()) {
128 last_on_encoder_ = encoder_;
129 } else {
130 last_off_encoder_ = encoder_;
131 }
132 encoder_ = claw.position;
133 any_triggered_last_ = any_sensor_triggered;
134}
135
136void ZeroedStateFeedbackLoop::Reset(const HalfClawPosition &claw) {
137 set_zeroing_state(ZeroedStateFeedbackLoop::UNKNOWN_POSITION);
138
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000139 front_.Reset(claw.front);
140 calibration_.Reset(claw.calibration);
141 back_.Reset(claw.back);
Austin Schuh27b8fb12014-02-22 15:10:05 -0800142 // close up the min and max edge positions as they are no longer valid and
143 // will be expanded in future iterations
144 min_hall_effect_on_angle_ = claw.position;
145 max_hall_effect_on_angle_ = claw.position;
146 min_hall_effect_off_angle_ = claw.position;
147 max_hall_effect_off_angle_ = claw.position;
148 any_triggered_last_ = any_triggered();
149}
150
151bool TopZeroedStateFeedbackLoop::SetCalibrationOnEdge(
152 const constants::Values::Claws::Claw &claw_values,
153 JointZeroingState zeroing_state) {
154 double edge_encoder;
155 double edge_angle;
156 if (GetPositionOfEdge(claw_values, &edge_encoder, &edge_angle)) {
157 LOG(INFO, "Calibration edge edge should be %f.\n", edge_angle);
158 SetCalibration(edge_encoder, edge_angle);
159 set_zeroing_state(zeroing_state);
160 return true;
161 }
162 return false;
163}
164
165bool BottomZeroedStateFeedbackLoop::SetCalibrationOnEdge(
166 const constants::Values::Claws::Claw &claw_values,
167 JointZeroingState zeroing_state) {
168 double edge_encoder;
169 double edge_angle;
170 if (GetPositionOfEdge(claw_values, &edge_encoder, &edge_angle)) {
171 LOG(INFO, "Calibration edge.\n");
172 SetCalibration(edge_encoder, edge_angle);
173 set_zeroing_state(zeroing_state);
174 return true;
175 }
176 return false;
177}
178
Austin Schuhcc0bf312014-02-09 00:39:29 -0800179ClawMotor::ClawMotor(control_loops::ClawGroup *my_claw)
Brian Silverman71fbee02014-03-13 17:24:54 -0700180 : aos::control_loops::ControlLoop<control_loops::ClawGroup, true, true,
181 false>(my_claw),
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800182 has_top_claw_goal_(false),
183 top_claw_goal_(0.0),
Austin Schuhcda86af2014-02-16 16:16:39 -0800184 top_claw_(this),
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800185 has_bottom_claw_goal_(false),
186 bottom_claw_goal_(0.0),
Austin Schuhcda86af2014-02-16 16:16:39 -0800187 bottom_claw_(this),
188 claw_(MakeClawLoop()),
Ben Fredrickson9b388422014-02-13 06:15:31 +0000189 was_enabled_(false),
Austin Schuh4cb047f2014-02-16 21:10:19 -0800190 doing_calibration_fine_tune_(false),
Austin Schuhe7f90d12014-02-17 00:48:25 -0800191 capped_goal_(false),
192 mode_(UNKNOWN_LOCATION) {}
Austin Schuh3bb9a442014-02-02 16:01:45 -0800193
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800194const int ZeroedStateFeedbackLoop::kZeroingMaxVoltage;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800195
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000196bool ZeroedStateFeedbackLoop::SawFilteredPosedge(
197 const HallEffectTracker &this_sensor, const HallEffectTracker &sensorA,
198 const HallEffectTracker &sensorB) {
199 if (posedge_filter_ == nullptr && this_sensor.posedge_count_changed() &&
200 !sensorA.posedge_count_changed() && !sensorB.posedge_count_changed() &&
201 this_sensor.value() && !this_sensor.last_value()) {
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000202 posedge_filter_ = &this_sensor;
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000203 } else if (posedge_filter_ == &this_sensor &&
204 !this_sensor.posedge_count_changed() &&
205 !sensorA.posedge_count_changed() &&
206 !sensorB.posedge_count_changed() && this_sensor.value()) {
207 posedge_filter_ = nullptr;
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000208 return true;
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000209 } else if (posedge_filter_ == &this_sensor) {
210 posedge_filter_ = nullptr;
211 }
212 return false;
213}
214
215bool ZeroedStateFeedbackLoop::SawFilteredNegedge(
216 const HallEffectTracker &this_sensor, const HallEffectTracker &sensorA,
217 const HallEffectTracker &sensorB) {
218 if (negedge_filter_ == nullptr && this_sensor.negedge_count_changed() &&
219 !sensorA.negedge_count_changed() && !sensorB.negedge_count_changed() &&
220 !this_sensor.value() && this_sensor.last_value()) {
221 negedge_filter_ = &this_sensor;
222 } else if (negedge_filter_ == &this_sensor &&
223 !this_sensor.negedge_count_changed() &&
224 !sensorA.negedge_count_changed() &&
225 !sensorB.negedge_count_changed() && !this_sensor.value()) {
226 negedge_filter_ = nullptr;
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000227 return true;
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000228 } else if (negedge_filter_ == &this_sensor) {
229 negedge_filter_ = nullptr;
230 }
231 return false;
232}
233
Brian Silvermane0a95462014-02-17 00:41:09 -0800234bool ZeroedStateFeedbackLoop::DoGetPositionOfEdge(
235 const constants::Values::Claws::AnglePair &angles, double *edge_encoder,
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000236 double *edge_angle, const HallEffectTracker &this_sensor,
237 const HallEffectTracker &sensorA, const HallEffectTracker &sensorB,
Brian Silvermane0a95462014-02-17 00:41:09 -0800238 const char *hall_effect_name) {
Austin Schuhf84a1302014-02-19 00:23:30 -0800239 bool found_edge = false;
Austin Schuh27b8fb12014-02-22 15:10:05 -0800240
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000241 if (SawFilteredPosedge(this_sensor, sensorA, sensorB)) {
Austin Schuh27b8fb12014-02-22 15:10:05 -0800242 if (min_hall_effect_off_angle_ == max_hall_effect_off_angle_) {
Brian Silvermanf48fab32014-03-09 14:32:24 -0700243 LOG(WARNING, "%s: Uncertain which side, rejecting posedge\n", name_);
Brian Silvermane0a95462014-02-17 00:41:09 -0800244 } else {
Austin Schuh27b8fb12014-02-22 15:10:05 -0800245 const double average_last_encoder =
246 (min_hall_effect_off_angle_ + max_hall_effect_off_angle_) / 2.0;
247 if (posedge_value_ < average_last_encoder) {
248 *edge_angle = angles.upper_decreasing_angle;
249 LOG(INFO, "%s Posedge upper of %s -> %f posedge: %f avg_encoder: %f\n",
250 name_, hall_effect_name, *edge_angle, posedge_value_,
251 average_last_encoder);
252 } else {
253 *edge_angle = angles.lower_angle;
254 LOG(INFO, "%s Posedge lower of %s -> %f posedge: %f avg_encoder: %f\n",
255 name_, hall_effect_name, *edge_angle, posedge_value_,
256 average_last_encoder);
257 }
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000258 *edge_encoder = posedge_value_;
Austin Schuh27b8fb12014-02-22 15:10:05 -0800259 found_edge = true;
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000260 }
261 }
262
263 if (SawFilteredNegedge(this_sensor, sensorA, sensorB)) {
264 if (min_hall_effect_on_angle_ == max_hall_effect_on_angle_) {
Brian Silvermanf48fab32014-03-09 14:32:24 -0700265 LOG(WARNING, "%s: Uncertain which side, rejecting negedge\n", name_);
Brian Silvermane0a95462014-02-17 00:41:09 -0800266 } else {
Austin Schuh27b8fb12014-02-22 15:10:05 -0800267 const double average_last_encoder =
268 (min_hall_effect_on_angle_ + max_hall_effect_on_angle_) / 2.0;
269 if (negedge_value_ > average_last_encoder) {
270 *edge_angle = angles.upper_angle;
271 LOG(INFO, "%s Negedge upper of %s -> %f negedge: %f avg_encoder: %f\n",
272 name_, hall_effect_name, *edge_angle, negedge_value_,
273 average_last_encoder);
274 } else {
275 *edge_angle = angles.lower_decreasing_angle;
276 LOG(INFO, "%s Negedge lower of %s -> %f negedge: %f avg_encoder: %f\n",
277 name_, hall_effect_name, *edge_angle, negedge_value_,
278 average_last_encoder);
279 }
280 *edge_encoder = negedge_value_;
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000281 found_edge = true;
Brian Silvermane0a95462014-02-17 00:41:09 -0800282 }
Austin Schuh27b8fb12014-02-22 15:10:05 -0800283 }
284
Austin Schuhf84a1302014-02-19 00:23:30 -0800285 return found_edge;
Brian Silvermane0a95462014-02-17 00:41:09 -0800286}
287
Austin Schuhf9286cd2014-02-11 00:51:09 -0800288bool ZeroedStateFeedbackLoop::GetPositionOfEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800289 const constants::Values::Claws::Claw &claw_values, double *edge_encoder,
Austin Schuhf9286cd2014-02-11 00:51:09 -0800290 double *edge_angle) {
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000291 if (DoGetPositionOfEdge(claw_values.front, edge_encoder, edge_angle, front_,
292 calibration_, back_, "front")) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800293 return true;
294 }
Brian Silvermane0a95462014-02-17 00:41:09 -0800295 if (DoGetPositionOfEdge(claw_values.calibration, edge_encoder, edge_angle,
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000296 calibration_, front_, back_, "calibration")) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800297 return true;
298 }
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000299 if (DoGetPositionOfEdge(claw_values.back, edge_encoder, edge_angle, back_,
300 calibration_, front_, "back")) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800301 return true;
302 }
303 return false;
304}
305
Austin Schuhcda86af2014-02-16 16:16:39 -0800306void TopZeroedStateFeedbackLoop::SetCalibration(double edge_encoder,
307 double edge_angle) {
308 double old_offset = offset_;
309 offset_ = edge_angle - edge_encoder;
310 const double doffset = offset_ - old_offset;
311 motor_->ChangeTopOffset(doffset);
312}
313
314void BottomZeroedStateFeedbackLoop::SetCalibration(double edge_encoder,
315 double edge_angle) {
316 double old_offset = offset_;
317 offset_ = edge_angle - edge_encoder;
318 const double doffset = offset_ - old_offset;
319 motor_->ChangeBottomOffset(doffset);
320}
321
322void ClawMotor::ChangeTopOffset(double doffset) {
323 claw_.ChangeTopOffset(doffset);
324 if (has_top_claw_goal_) {
325 top_claw_goal_ += doffset;
326 }
327}
328
329void ClawMotor::ChangeBottomOffset(double doffset) {
330 claw_.ChangeBottomOffset(doffset);
331 if (has_bottom_claw_goal_) {
332 bottom_claw_goal_ += doffset;
333 }
334}
335
336void ClawLimitedLoop::ChangeTopOffset(double doffset) {
337 Y_(1, 0) += doffset;
338 X_hat(1, 0) += doffset;
339 LOG(INFO, "Changing top offset by %f\n", doffset);
340}
341void ClawLimitedLoop::ChangeBottomOffset(double doffset) {
342 Y_(0, 0) += doffset;
343 X_hat(0, 0) += doffset;
344 X_hat(1, 0) -= doffset;
345 LOG(INFO, "Changing bottom offset by %f\n", doffset);
346}
joe7376ff52014-02-16 18:28:42 -0800347
Austin Schuh069143b2014-02-17 02:46:26 -0800348void LimitClawGoal(double *bottom_goal, double *top_goal,
349 const frc971::constants::Values &values) {
350 // first update position based on angle limit
351
352 const double separation = *top_goal - *bottom_goal;
353 if (separation > values.claw.claw_max_separation) {
Austin Schuh069143b2014-02-17 02:46:26 -0800354 const double dsep = (separation - values.claw.claw_max_separation) / 2.0;
355 *bottom_goal += dsep;
356 *top_goal -= dsep;
357 LOG(DEBUG, "Goals now bottom: %f, top: %f\n", *bottom_goal, *top_goal);
358 }
359 if (separation < values.claw.claw_min_separation) {
Austin Schuh069143b2014-02-17 02:46:26 -0800360 const double dsep = (separation - values.claw.claw_min_separation) / 2.0;
361 *bottom_goal += dsep;
362 *top_goal -= dsep;
363 LOG(DEBUG, "Goals now bottom: %f, top: %f\n", *bottom_goal, *top_goal);
364 }
365
366 // now move both goals in unison
367 if (*bottom_goal < values.claw.lower_claw.lower_limit) {
368 *top_goal += values.claw.lower_claw.lower_limit - *bottom_goal;
369 *bottom_goal = values.claw.lower_claw.lower_limit;
370 }
371 if (*bottom_goal > values.claw.lower_claw.upper_limit) {
372 *top_goal -= *bottom_goal - values.claw.lower_claw.upper_limit;
373 *bottom_goal = values.claw.lower_claw.upper_limit;
374 }
375
376 if (*top_goal < values.claw.upper_claw.lower_limit) {
377 *bottom_goal += values.claw.upper_claw.lower_limit - *top_goal;
378 *top_goal = values.claw.upper_claw.lower_limit;
379 }
380 if (*top_goal > values.claw.upper_claw.upper_limit) {
381 *bottom_goal -= *top_goal - values.claw.upper_claw.upper_limit;
382 *top_goal = values.claw.upper_claw.upper_limit;
383 }
384}
Austin Schuhcda86af2014-02-16 16:16:39 -0800385
Austin Schuhe7f90d12014-02-17 00:48:25 -0800386bool ClawMotor::is_ready() const {
387 return (
388 (top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED &&
389 bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED) ||
Brian Silverman71fbee02014-03-13 17:24:54 -0700390 (((::aos::robot_state.get() == NULL) ? true
391 : ::aos::robot_state->autonomous) &&
Austin Schuhe7f90d12014-02-17 00:48:25 -0800392 ((top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
393 top_claw_.zeroing_state() ==
394 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION) &&
395 (bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
396 bottom_claw_.zeroing_state() ==
397 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION))));
398}
399
400bool ClawMotor::is_zeroing() const { return !is_ready(); }
401
Austin Schuh3bb9a442014-02-02 16:01:45 -0800402// Positive angle is up, and positive power is up.
Austin Schuhcc0bf312014-02-09 00:39:29 -0800403void ClawMotor::RunIteration(const control_loops::ClawGroup::Goal *goal,
404 const control_loops::ClawGroup::Position *position,
405 control_loops::ClawGroup::Output *output,
James Kuszmaul9ead1de2014-02-28 21:24:39 -0800406 control_loops::ClawGroup::Status *status) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800407 constexpr double dt = 0.01;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800408
409 // Disable the motors now so that all early returns will return with the
410 // motors disabled.
411 if (output) {
412 output->top_claw_voltage = 0;
413 output->bottom_claw_voltage = 0;
414 output->intake_voltage = 0;
Ben Fredrickson61893d52014-03-02 09:43:23 +0000415 output->tusk_voltage = 0;
416 }
417
Brian Silverman71fbee02014-03-13 17:24:54 -0700418 if (goal) {
419 if (::std::isnan(goal->bottom_angle) ||
420 ::std::isnan(goal->separation_angle) || ::std::isnan(goal->intake) ||
421 ::std::isnan(goal->centering)) {
422 return;
423 }
Austin Schuh3bb9a442014-02-02 16:01:45 -0800424 }
425
Austin Schuh1a499942014-02-17 01:51:58 -0800426 if (reset()) {
Austin Schuh27b8fb12014-02-22 15:10:05 -0800427 top_claw_.Reset(position->top);
428 bottom_claw_.Reset(position->bottom);
Austin Schuh1a499942014-02-17 01:51:58 -0800429 }
430
Austin Schuhf9286cd2014-02-11 00:51:09 -0800431 const frc971::constants::Values &values = constants::GetValues();
432
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800433 if (position) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800434 Eigen::Matrix<double, 2, 1> Y;
435 Y << position->bottom.position + bottom_claw_.offset(),
436 position->top.position + top_claw_.offset();
437 claw_.Correct(Y);
438
Austin Schuhf9286cd2014-02-11 00:51:09 -0800439 top_claw_.SetPositionValues(position->top);
440 bottom_claw_.SetPositionValues(position->bottom);
441
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800442 if (!has_top_claw_goal_) {
443 has_top_claw_goal_ = true;
Austin Schuhcda86af2014-02-16 16:16:39 -0800444 top_claw_goal_ = top_claw_.absolute_position();
Austin Schuhe7f90d12014-02-17 00:48:25 -0800445 initial_separation_ =
Austin Schuhcda86af2014-02-16 16:16:39 -0800446 top_claw_.absolute_position() - bottom_claw_.absolute_position();
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800447 }
448 if (!has_bottom_claw_goal_) {
449 has_bottom_claw_goal_ = true;
Austin Schuhcda86af2014-02-16 16:16:39 -0800450 bottom_claw_goal_ = bottom_claw_.absolute_position();
Austin Schuhe7f90d12014-02-17 00:48:25 -0800451 initial_separation_ =
Austin Schuhcda86af2014-02-16 16:16:39 -0800452 top_claw_.absolute_position() - bottom_claw_.absolute_position();
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800453 }
Brian Silvermanf48fab32014-03-09 14:32:24 -0700454 LOG_STRUCT(DEBUG, "absolute position",
455 ClawPositionToLog(top_claw_.absolute_position(),
456 bottom_claw_.absolute_position()));
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800457 }
458
Brian Silverman71fbee02014-03-13 17:24:54 -0700459 bool autonomous, enabled;
460 if (::aos::robot_state.get() == nullptr) {
461 autonomous = true;
462 enabled = false;
463 } else {
464 autonomous = ::aos::robot_state->autonomous;
465 enabled = ::aos::robot_state->enabled;
466 }
Austin Schuh069143b2014-02-17 02:46:26 -0800467
468 double bottom_claw_velocity_ = 0.0;
469 double top_claw_velocity_ = 0.0;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800470
Brian Silverman71fbee02014-03-13 17:24:54 -0700471 if (goal != NULL &&
472 ((top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED &&
473 bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED) ||
474 (autonomous &&
475 ((top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
476 top_claw_.zeroing_state() ==
477 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION) &&
478 (bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
479 bottom_claw_.zeroing_state() ==
480 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION))))) {
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800481 // Ready to use the claw.
482 // Limit the goals here.
Austin Schuhf9286cd2014-02-11 00:51:09 -0800483 bottom_claw_goal_ = goal->bottom_angle;
Brian Silverman7c021c42014-02-17 15:15:56 -0800484 top_claw_goal_ = goal->bottom_angle + goal->separation_angle;
Austin Schuhcda86af2014-02-16 16:16:39 -0800485 has_bottom_claw_goal_ = true;
486 has_top_claw_goal_ = true;
487 doing_calibration_fine_tune_ = false;
488
Austin Schuhe7f90d12014-02-17 00:48:25 -0800489 mode_ = READY;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800490 } else if (top_claw_.zeroing_state() !=
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000491 ZeroedStateFeedbackLoop::UNKNOWN_POSITION &&
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800492 bottom_claw_.zeroing_state() !=
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000493 ZeroedStateFeedbackLoop::UNKNOWN_POSITION) {
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800494 // Time to fine tune the zero.
495 // Limit the goals here.
Austin Schuh0c733422014-02-17 01:17:12 -0800496 if (!enabled) {
497 // If we are disabled, start the fine tune process over again.
498 doing_calibration_fine_tune_ = false;
499 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800500 if (bottom_claw_.zeroing_state() != ZeroedStateFeedbackLoop::CALIBRATED) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800501 // always get the bottom claw to calibrated first
502 LOG(DEBUG, "Calibrating the bottom of the claw\n");
503 if (!doing_calibration_fine_tune_) {
504 if (::std::abs(bottom_absolute_position() -
Austin Schuhd27931c2014-02-16 19:18:20 -0800505 values.claw.start_fine_tune_pos) <
506 values.claw.claw_unimportant_epsilon) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800507 doing_calibration_fine_tune_ = true;
Austin Schuhd27931c2014-02-16 19:18:20 -0800508 bottom_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800509 top_claw_velocity_ = bottom_claw_velocity_ =
510 values.claw.claw_zeroing_speed;
Austin Schuhcda86af2014-02-16 16:16:39 -0800511 LOG(DEBUG, "Ready to fine tune the bottom\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800512 mode_ = FINE_TUNE_BOTTOM;
Austin Schuhcda86af2014-02-16 16:16:39 -0800513 } else {
514 // send bottom to zeroing start
Austin Schuhd27931c2014-02-16 19:18:20 -0800515 bottom_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuhcda86af2014-02-16 16:16:39 -0800516 LOG(DEBUG, "Going to the start position for the bottom\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800517 mode_ = PREP_FINE_TUNE_BOTTOM;
Austin Schuhcda86af2014-02-16 16:16:39 -0800518 }
519 } else {
Austin Schuhe7f90d12014-02-17 00:48:25 -0800520 mode_ = FINE_TUNE_BOTTOM;
Austin Schuhd27931c2014-02-16 19:18:20 -0800521 bottom_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800522 top_claw_velocity_ = bottom_claw_velocity_ =
523 values.claw.claw_zeroing_speed;
Brian Silvermane0a95462014-02-17 00:41:09 -0800524 if (top_claw_.front_or_back_triggered() ||
525 bottom_claw_.front_or_back_triggered()) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800526 // We shouldn't hit a limit, but if we do, go back to the zeroing
527 // point and try again.
528 doing_calibration_fine_tune_ = false;
Austin Schuhd27931c2014-02-16 19:18:20 -0800529 bottom_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuh069143b2014-02-17 02:46:26 -0800530 top_claw_velocity_ = bottom_claw_velocity_ = 0.0;
Austin Schuhcda86af2014-02-16 16:16:39 -0800531 LOG(DEBUG, "Found a limit, starting over.\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800532 mode_ = PREP_FINE_TUNE_BOTTOM;
Austin Schuhcda86af2014-02-16 16:16:39 -0800533 }
Austin Schuh288c8c32014-02-16 17:20:17 -0800534
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000535 if (position && bottom_claw_.SawFilteredPosedge(
536 bottom_claw_.calibration(), bottom_claw_.front(),
537 bottom_claw_.back())) {
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000538 // do calibration
539 bottom_claw_.SetCalibration(
540 position->bottom.posedge_value,
541 values.claw.lower_claw.calibration.lower_angle);
542 bottom_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::CALIBRATED);
543 // calibrated so we are done fine tuning bottom
544 doing_calibration_fine_tune_ = false;
545 LOG(DEBUG, "Calibrated the bottom correctly!\n");
546 } else if (bottom_claw_.calibration().last_value()) {
547 doing_calibration_fine_tune_ = false;
548 bottom_claw_goal_ = values.claw.start_fine_tune_pos;
549 top_claw_velocity_ = bottom_claw_velocity_ = 0.0;
550 mode_ = PREP_FINE_TUNE_BOTTOM;
Austin Schuhcda86af2014-02-16 16:16:39 -0800551 } else {
552 LOG(DEBUG, "Fine tuning\n");
553 }
554 }
555 // now set the top claw to track
556
Austin Schuhd27931c2014-02-16 19:18:20 -0800557 top_claw_goal_ = bottom_claw_goal_ + values.claw.claw_zeroing_separation;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800558 } else {
Austin Schuhcda86af2014-02-16 16:16:39 -0800559 // bottom claw must be calibrated, start on the top
560 if (!doing_calibration_fine_tune_) {
Austin Schuhd27931c2014-02-16 19:18:20 -0800561 if (::std::abs(top_absolute_position() -
562 values.claw.start_fine_tune_pos) <
563 values.claw.claw_unimportant_epsilon) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800564 doing_calibration_fine_tune_ = true;
Austin Schuhd27931c2014-02-16 19:18:20 -0800565 top_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800566 top_claw_velocity_ = bottom_claw_velocity_ =
567 values.claw.claw_zeroing_speed;
Austin Schuhcda86af2014-02-16 16:16:39 -0800568 LOG(DEBUG, "Ready to fine tune the top\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800569 mode_ = FINE_TUNE_TOP;
Austin Schuhcda86af2014-02-16 16:16:39 -0800570 } else {
571 // send top to zeroing start
Austin Schuhd27931c2014-02-16 19:18:20 -0800572 top_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuhcda86af2014-02-16 16:16:39 -0800573 LOG(DEBUG, "Going to the start position for the top\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800574 mode_ = PREP_FINE_TUNE_TOP;
Austin Schuhcda86af2014-02-16 16:16:39 -0800575 }
576 } else {
Austin Schuhe7f90d12014-02-17 00:48:25 -0800577 mode_ = FINE_TUNE_TOP;
Austin Schuhd27931c2014-02-16 19:18:20 -0800578 top_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800579 top_claw_velocity_ = bottom_claw_velocity_ =
580 values.claw.claw_zeroing_speed;
Brian Silvermane0a95462014-02-17 00:41:09 -0800581 if (top_claw_.front_or_back_triggered() ||
582 bottom_claw_.front_or_back_triggered()) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800583 // this should not happen, but now we know it won't
584 doing_calibration_fine_tune_ = false;
Austin Schuhd27931c2014-02-16 19:18:20 -0800585 top_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuh069143b2014-02-17 02:46:26 -0800586 top_claw_velocity_ = bottom_claw_velocity_ = 0.0;
Austin Schuhcda86af2014-02-16 16:16:39 -0800587 LOG(DEBUG, "Found a limit, starting over.\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800588 mode_ = PREP_FINE_TUNE_TOP;
Austin Schuhcda86af2014-02-16 16:16:39 -0800589 }
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000590
591 if (position &&
592 top_claw_.SawFilteredPosedge(top_claw_.calibration(),
593 top_claw_.front(), top_claw_.back())) {
594 // do calibration
595 top_claw_.SetCalibration(
596 position->top.posedge_value,
597 values.claw.upper_claw.calibration.lower_angle);
598 top_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::CALIBRATED);
599 // calibrated so we are done fine tuning top
600 doing_calibration_fine_tune_ = false;
601 LOG(DEBUG, "Calibrated the top correctly!\n");
602 } else if (top_claw_.calibration().last_value()) {
603 doing_calibration_fine_tune_ = false;
604 top_claw_goal_ = values.claw.start_fine_tune_pos;
605 top_claw_velocity_ = bottom_claw_velocity_ = 0.0;
606 mode_ = PREP_FINE_TUNE_TOP;
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000607 }
Austin Schuhcda86af2014-02-16 16:16:39 -0800608 }
609 // now set the bottom claw to track
Austin Schuhd27931c2014-02-16 19:18:20 -0800610 bottom_claw_goal_ = top_claw_goal_ - values.claw.claw_zeroing_separation;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800611 }
612 } else {
Austin Schuhcda86af2014-02-16 16:16:39 -0800613 doing_calibration_fine_tune_ = false;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800614 if (!was_enabled_ && enabled) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800615 if (position) {
Brian Silverman72035692014-03-14 10:18:27 -0700616 top_claw_goal_ = position->top.position + top_claw_.offset();
617 bottom_claw_goal_ = position->bottom.position + bottom_claw_.offset();
Austin Schuhe7f90d12014-02-17 00:48:25 -0800618 initial_separation_ =
Austin Schuhcda86af2014-02-16 16:16:39 -0800619 position->top.position - position->bottom.position;
Austin Schuhf9286cd2014-02-11 00:51:09 -0800620 } else {
621 has_top_claw_goal_ = false;
622 has_bottom_claw_goal_ = false;
623 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800624 }
Austin Schuhf9286cd2014-02-11 00:51:09 -0800625
Austin Schuh4cb047f2014-02-16 21:10:19 -0800626 if ((bottom_claw_.zeroing_state() !=
627 ZeroedStateFeedbackLoop::UNKNOWN_POSITION ||
Brian Silvermane0a95462014-02-17 00:41:09 -0800628 bottom_claw_.front().value() || top_claw_.front().value()) &&
629 !top_claw_.back().value() && !bottom_claw_.back().value()) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800630 if (enabled) {
631 // Time to slowly move back up to find any position to narrow down the
632 // zero.
Austin Schuhd27931c2014-02-16 19:18:20 -0800633 top_claw_goal_ += values.claw.claw_zeroing_off_speed * dt;
634 bottom_claw_goal_ += values.claw.claw_zeroing_off_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800635 top_claw_velocity_ = bottom_claw_velocity_ =
636 values.claw.claw_zeroing_off_speed;
Austin Schuhcda86af2014-02-16 16:16:39 -0800637 LOG(DEBUG, "Bottom is known.\n");
Austin Schuhf9286cd2014-02-11 00:51:09 -0800638 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800639 } else {
640 // We don't know where either claw is. Slowly start moving down to find
641 // any hall effect.
Austin Schuhf9286cd2014-02-11 00:51:09 -0800642 if (enabled) {
Austin Schuhd27931c2014-02-16 19:18:20 -0800643 top_claw_goal_ -= values.claw.claw_zeroing_off_speed * dt;
644 bottom_claw_goal_ -= values.claw.claw_zeroing_off_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800645 top_claw_velocity_ = bottom_claw_velocity_ =
646 -values.claw.claw_zeroing_off_speed;
Austin Schuhcda86af2014-02-16 16:16:39 -0800647 LOG(DEBUG, "Both are unknown.\n");
Austin Schuhf9286cd2014-02-11 00:51:09 -0800648 }
649 }
650
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000651 if (position) {
652 if (enabled) {
653 top_claw_.SetCalibrationOnEdge(
654 values.claw.upper_claw,
655 ZeroedStateFeedbackLoop::APPROXIMATE_CALIBRATION);
656 bottom_claw_.SetCalibrationOnEdge(
657 values.claw.lower_claw,
658 ZeroedStateFeedbackLoop::APPROXIMATE_CALIBRATION);
659 } else {
660 // TODO(austin): Only calibrate on the predetermined edge.
661 // We might be able to just ignore this since the backlash is soooo
662 // low.
663 // :)
664 top_claw_.SetCalibrationOnEdge(
665 values.claw.upper_claw,
666 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION);
667 bottom_claw_.SetCalibrationOnEdge(
668 values.claw.lower_claw,
669 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION);
670 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800671 }
Austin Schuhe7f90d12014-02-17 00:48:25 -0800672 mode_ = UNKNOWN_LOCATION;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800673 }
674
Austin Schuh069143b2014-02-17 02:46:26 -0800675 // Limit the goals if both claws have been (mostly) found.
676 if (mode_ != UNKNOWN_LOCATION) {
677 LimitClawGoal(&bottom_claw_goal_, &top_claw_goal_, values);
678 }
679
Austin Schuhf9286cd2014-02-11 00:51:09 -0800680 if (has_top_claw_goal_ && has_bottom_claw_goal_) {
Austin Schuh069143b2014-02-17 02:46:26 -0800681 claw_.R << bottom_claw_goal_, top_claw_goal_ - bottom_claw_goal_,
682 bottom_claw_velocity_, top_claw_velocity_ - bottom_claw_velocity_;
Austin Schuhcda86af2014-02-16 16:16:39 -0800683 double separation = -971;
684 if (position != nullptr) {
685 separation = position->top.position - position->bottom.position;
686 }
Brian Silvermanf48fab32014-03-09 14:32:24 -0700687 LOG_STRUCT(DEBUG, "actual goal",
688 ClawGoalToLog(claw_.R(0, 0), claw_.R(1, 0), separation));
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800689
Austin Schuh01c652b2014-02-21 23:13:42 -0800690 // Only cap power when one of the halves of the claw is moving slowly and
691 // could wind up.
Austin Schuhe7f90d12014-02-17 00:48:25 -0800692 claw_.set_is_zeroing(mode_ == UNKNOWN_LOCATION || mode_ == FINE_TUNE_TOP ||
693 mode_ == FINE_TUNE_BOTTOM);
Austin Schuhcda86af2014-02-16 16:16:39 -0800694 claw_.Update(output == nullptr);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800695 } else {
Austin Schuhcda86af2014-02-16 16:16:39 -0800696 claw_.Update(true);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800697 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800698
Austin Schuh4cb047f2014-02-16 21:10:19 -0800699 capped_goal_ = false;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800700 switch (mode_) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800701 case READY:
Austin Schuhe7f90d12014-02-17 00:48:25 -0800702 case PREP_FINE_TUNE_TOP:
703 case PREP_FINE_TUNE_BOTTOM:
Austin Schuhcda86af2014-02-16 16:16:39 -0800704 break;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800705 case FINE_TUNE_BOTTOM:
706 case FINE_TUNE_TOP:
Austin Schuh4cb047f2014-02-16 21:10:19 -0800707 case UNKNOWN_LOCATION: {
708 if (claw_.uncapped_average_voltage() > values.claw.max_zeroing_voltage) {
709 double dx = (claw_.uncapped_average_voltage() -
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000710 values.claw.max_zeroing_voltage) / claw_.K(0, 0);
Austin Schuh4cb047f2014-02-16 21:10:19 -0800711 bottom_claw_goal_ -= dx;
712 top_claw_goal_ -= dx;
Austin Schuhcda86af2014-02-16 16:16:39 -0800713 capped_goal_ = true;
Brian Silvermanf48fab32014-03-09 14:32:24 -0700714 LOG(DEBUG, "Moving the goal by %f to prevent windup."
715 " Uncapped is %f, max is %f, difference is %f\n",
716 dx,
Austin Schuhe7f90d12014-02-17 00:48:25 -0800717 claw_.uncapped_average_voltage(), values.claw.max_zeroing_voltage,
718 (claw_.uncapped_average_voltage() -
719 values.claw.max_zeroing_voltage));
Austin Schuh4cb047f2014-02-16 21:10:19 -0800720 } else if (claw_.uncapped_average_voltage() <
721 -values.claw.max_zeroing_voltage) {
722 double dx = (claw_.uncapped_average_voltage() +
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000723 values.claw.max_zeroing_voltage) / claw_.K(0, 0);
Austin Schuh4cb047f2014-02-16 21:10:19 -0800724 bottom_claw_goal_ -= dx;
725 top_claw_goal_ -= dx;
Austin Schuhcda86af2014-02-16 16:16:39 -0800726 capped_goal_ = true;
Austin Schuh4cb047f2014-02-16 21:10:19 -0800727 LOG(DEBUG, "Moving the goal by %f to prevent windup\n", dx);
Austin Schuhcda86af2014-02-16 16:16:39 -0800728 }
Austin Schuh4cb047f2014-02-16 21:10:19 -0800729 } break;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800730 }
731
732 if (output) {
Ben Fredrickson2f76ddf2014-02-23 05:58:23 +0000733 if (goal) {
734 //setup the intake
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000735 output->intake_voltage =
736 (goal->intake > 12.0) ? 12 : (goal->intake < -12.0) ? -12.0
737 : goal->intake;
Ben Fredrickson2f76ddf2014-02-23 05:58:23 +0000738 output->tusk_voltage = goal->centering;
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000739 output->tusk_voltage =
740 (goal->centering > 12.0) ? 12 : (goal->centering < -12.0)
741 ? -12.0
742 : goal->centering;
Ben Fredrickson2f76ddf2014-02-23 05:58:23 +0000743 }
Austin Schuhcda86af2014-02-16 16:16:39 -0800744 output->top_claw_voltage = claw_.U(1, 0) + claw_.U(0, 0);
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000745 output->bottom_claw_voltage = claw_.U(0, 0);
Austin Schuhf84a1302014-02-19 00:23:30 -0800746
747 if (output->top_claw_voltage > kMaxVoltage) {
748 output->top_claw_voltage = kMaxVoltage;
749 } else if (output->top_claw_voltage < -kMaxVoltage) {
750 output->top_claw_voltage = -kMaxVoltage;
751 }
752
753 if (output->bottom_claw_voltage > kMaxVoltage) {
754 output->bottom_claw_voltage = kMaxVoltage;
755 } else if (output->bottom_claw_voltage < -kMaxVoltage) {
756 output->bottom_claw_voltage = -kMaxVoltage;
757 }
Austin Schuh3bb9a442014-02-02 16:01:45 -0800758 }
James Kuszmaul4abaf482014-02-26 21:16:35 -0800759
James Kuszmaul4abaf482014-02-26 21:16:35 -0800760 status->bottom = bottom_absolute_position();
761 status->separation = top_absolute_position() - bottom_absolute_position();
762 status->bottom_velocity = claw_.X_hat(2, 0);
763 status->separation_velocity = claw_.X_hat(3, 0);
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800764
Brian Silverman71fbee02014-03-13 17:24:54 -0700765 if (goal) {
766 bool bottom_done =
767 ::std::abs(bottom_absolute_position() - goal->bottom_angle) < 0.020;
768 bool bottom_velocity_done = ::std::abs(status->bottom_velocity) < 0.2;
769 bool separation_done =
770 ::std::abs((top_absolute_position() - bottom_absolute_position()) -
771 goal->separation_angle) < 0.020;
772 bool separation_done_with_ball =
773 ::std::abs((top_absolute_position() - bottom_absolute_position()) -
774 goal->separation_angle) < 0.06;
775 status->done = is_ready() && separation_done && bottom_done && bottom_velocity_done;
776 status->done_with_ball =
777 is_ready() && separation_done_with_ball && bottom_done && bottom_velocity_done;
778 } else {
779 status->done = status->done_with_ball = false;
780 }
Austin Schuha556b012014-03-02 11:55:52 -0800781
Austin Schuh4f8633f2014-03-02 13:59:46 -0800782 status->zeroed = is_ready();
Brian Silverman80fc94c2014-03-09 16:56:01 -0700783 status->zeroed_for_auto =
784 (top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
785 top_claw_.zeroing_state() ==
786 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION) &&
787 (bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
788 bottom_claw_.zeroing_state() ==
789 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION);
Austin Schuh4f8633f2014-03-02 13:59:46 -0800790
Brian Silverman71fbee02014-03-13 17:24:54 -0700791 was_enabled_ = enabled;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800792}
793
794} // namespace control_loops
795} // namespace frc971
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000796