blob: 58b2ca02b1a200d1ff8f0909cab6273fa64e9bfa [file] [log] [blame]
Austin Schuh3bb9a442014-02-02 16:01:45 -08001#include "frc971/control_loops/claw/claw.h"
2
Austin Schuh3bb9a442014-02-02 16:01:45 -08003#include <algorithm>
4
5#include "aos/common/control_loop/control_loops.q.h"
6#include "aos/common/logging/logging.h"
Brian Silvermanf48fab32014-03-09 14:32:24 -07007#include "aos/common/logging/queue_logging.h"
Austin Schuh3bb9a442014-02-02 16:01:45 -08008
9#include "frc971/constants.h"
Austin Schuhcda86af2014-02-16 16:16:39 -080010#include "frc971/control_loops/claw/claw_motor_plant.h"
11
Austin Schuh3bb9a442014-02-02 16:01:45 -080012// Zeroing plan.
13// There are 2 types of zeros. Enabled and disabled ones.
14// Disabled ones are only valid during auto mode, and can be used to speed up
15// the enabled zero process. We need to re-zero during teleop in case the auto
16// zero was poor and causes us to miss all our shots.
17//
18// We need to be able to zero manually while disabled by moving the joint over
19// the zeros.
20// Zero on the down edge when disabled (gravity in the direction of motion)
21//
22// When enabled, zero on the up edge (gravity opposing the direction of motion)
23// The enabled sequence needs to work as follows. We can crash the claw if we
24// bring them too close to each other or too far from each other. The only safe
25// thing to do is to move them in unison.
26//
27// Start by moving them both towards the front of the bot to either find either
28// the middle hall effect on either jaw, or the front hall effect on the bottom
29// jaw. Any edge that isn't the desired edge will provide an approximate edge
30// location that can be used for the fine tuning step.
31// Once an edge is found on the front claw, move back the other way with both
32// claws until an edge is found for the other claw.
33// Now that we have an approximate zero, we can robustify the limits to keep
34// both claws safe. Then, we can move both claws to a position that is the
35// correct side of the zero and go zero.
36
37// Valid region plan.
Ben Fredrickson81ba2d52014-03-02 08:21:46 +000038// Difference between the arms has a range, and the values of each arm has a
39// range.
Austin Schuh3bb9a442014-02-02 16:01:45 -080040// 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 Schuh27b8fb12014-02-22 15:10:05 -080051ClawLimitedLoop::ClawLimitedLoop(StateFeedbackLoop<4, 2, 2> loop)
52 : StateFeedbackLoop<4, 2, 2>(loop),
53 uncapped_average_voltage_(0.0),
James Kuszmaulf63b0ae2014-03-25 16:52:11 -070054 is_zeroing_(true),
55 U_Poly_((Eigen::Matrix<double, 4, 2>() << 1, 0,
56 -1, 0,
57 0, 1,
58 0, -1).finished(),
59 (Eigen::Matrix<double, 4, 1>() << kMaxVoltage, kMaxVoltage,
60 kMaxVoltage, kMaxVoltage).finished()) {
61 ::aos::controls::HPolytope<0>::Init();
62}
Austin Schuh27b8fb12014-02-22 15:10:05 -080063
James Kuszmaulf63b0ae2014-03-25 16:52:11 -070064// Caps the voltage prioritizing reducing velocity error over reducing
65// positional error.
66// Uses the polytope libararies which we used to just use for the drivetrain.
67// Uses a region representing the maximum voltage and then transforms it such
68// that the points represent different amounts of positional error and
69// constrains the region such that, if at all possible, it will maintain its
70// current efforts to reduce velocity error.
Austin Schuhcda86af2014-02-16 16:16:39 -080071void ClawLimitedLoop::CapU() {
James Kuszmaulf63b0ae2014-03-25 16:52:11 -070072 Eigen::Matrix<double, 4, 1> error = R - X_hat;
Austin Schuh4cb047f2014-02-16 21:10:19 -080073
James Kuszmauld536a402014-02-18 22:32:12 -080074 double u_top = U(1, 0);
75 double u_bottom = U(0, 0);
Austin Schuhcda86af2014-02-16 16:16:39 -080076
James Kuszmaulf63b0ae2014-03-25 16:52:11 -070077 uncapped_average_voltage_ = (u_top + u_bottom) / 2;
78
79 double max_voltage = is_zeroing_ ? kZeroingVoltage : kMaxVoltage;
80
81 if (::std::abs(u_bottom) > max_voltage or ::std::abs(u_top) > max_voltage) {
82 // H * U <= k
83 // U = UPos + UVel
84 // H * (UPos + UVel) <= k
85 // H * UPos <= k - H * UVel
86
87 // Now, we can do a coordinate transformation and say the following.
88
89 // UPos = position_K * position_error
90 // (H * position_K) * position_error <= k - H * UVel
91
92 Eigen::Matrix<double, 2, 2> position_K;
93 position_K << K(0, 0), K(0, 1),
94 K(1, 0), K(1, 1);
95 Eigen::Matrix<double, 2, 2> velocity_K;
96 velocity_K << K(0, 2), K(0, 3),
97 K(1, 2), K(1, 3);
98
99 Eigen::Matrix<double, 2, 1> position_error;
100 position_error << error(0, 0), error(1, 0);
101 Eigen::Matrix<double, 2, 1> velocity_error;
102 velocity_error << error(2, 0), error(3, 0);
103
104 Eigen::Matrix<double, 4, 1> pos_poly_k =
105 U_Poly_.k() - U_Poly_.H() * velocity_K * velocity_error;
106 Eigen::Matrix<double, 4, 2> pos_poly_H = U_Poly_.H() * position_K;
107 ::aos::controls::HPolytope<2> pos_poly(pos_poly_H, pos_poly_k);
108
109
110 Eigen::Matrix<double, 2, 1> adjusted_pos_error = CoerceGoal(
111 pos_poly, (Eigen::Matrix<double, 1, 2>() << position_error(1, 0),
112 -position_error(0, 0)).finished(),
113 0.0, position_error);
114
115 LOG(DEBUG, "Capping U is now %f %f\n", U(0, 0), U(1, 0));
116 U = velocity_K * velocity_error + position_K * adjusted_pos_error;
James Kuszmauld536a402014-02-18 22:32:12 -0800117 }
118
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800119}
120
Austin Schuh27b8fb12014-02-22 15:10:05 -0800121ZeroedStateFeedbackLoop::ZeroedStateFeedbackLoop(const char *name,
122 ClawMotor *motor)
123 : offset_(0.0),
124 name_(name),
125 motor_(motor),
126 zeroing_state_(UNKNOWN_POSITION),
127 posedge_value_(0.0),
128 negedge_value_(0.0),
129 encoder_(0.0),
130 last_encoder_(0.0) {}
131
132void ZeroedStateFeedbackLoop::SetPositionValues(const HalfClawPosition &claw) {
133 front_.Update(claw.front);
134 calibration_.Update(claw.calibration);
135 back_.Update(claw.back);
136
137 bool any_sensor_triggered = any_triggered();
138 if (any_sensor_triggered && any_triggered_last_) {
139 // We are still on the hall effect and nothing has changed.
140 min_hall_effect_on_angle_ =
141 ::std::min(min_hall_effect_on_angle_, claw.position);
142 max_hall_effect_on_angle_ =
143 ::std::max(max_hall_effect_on_angle_, claw.position);
144 } else if (!any_sensor_triggered && !any_triggered_last_) {
145 // We are still off the hall effect and nothing has changed.
146 min_hall_effect_off_angle_ =
147 ::std::min(min_hall_effect_off_angle_, claw.position);
148 max_hall_effect_off_angle_ =
149 ::std::max(max_hall_effect_off_angle_, claw.position);
150 } else if (any_sensor_triggered && !any_triggered_last_) {
151 // Saw a posedge on the hall effect. Reset the limits.
152 min_hall_effect_on_angle_ = ::std::min(claw.posedge_value, claw.position);
153 max_hall_effect_on_angle_ = ::std::max(claw.posedge_value, claw.position);
154 } else if (!any_sensor_triggered && any_triggered_last_) {
155 // Saw a negedge on the hall effect. Reset the limits.
156 min_hall_effect_off_angle_ = ::std::min(claw.negedge_value, claw.position);
157 max_hall_effect_off_angle_ = ::std::max(claw.negedge_value, claw.position);
158 }
159
160 posedge_value_ = claw.posedge_value;
161 negedge_value_ = claw.negedge_value;
162 last_encoder_ = encoder_;
163 if (front().value() || calibration().value() || back().value()) {
164 last_on_encoder_ = encoder_;
165 } else {
166 last_off_encoder_ = encoder_;
167 }
168 encoder_ = claw.position;
169 any_triggered_last_ = any_sensor_triggered;
170}
171
172void ZeroedStateFeedbackLoop::Reset(const HalfClawPosition &claw) {
173 set_zeroing_state(ZeroedStateFeedbackLoop::UNKNOWN_POSITION);
174
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000175 front_.Reset(claw.front);
176 calibration_.Reset(claw.calibration);
177 back_.Reset(claw.back);
Austin Schuh27b8fb12014-02-22 15:10:05 -0800178 // close up the min and max edge positions as they are no longer valid and
179 // will be expanded in future iterations
180 min_hall_effect_on_angle_ = claw.position;
181 max_hall_effect_on_angle_ = claw.position;
182 min_hall_effect_off_angle_ = claw.position;
183 max_hall_effect_off_angle_ = claw.position;
184 any_triggered_last_ = any_triggered();
185}
186
187bool TopZeroedStateFeedbackLoop::SetCalibrationOnEdge(
188 const constants::Values::Claws::Claw &claw_values,
189 JointZeroingState zeroing_state) {
190 double edge_encoder;
191 double edge_angle;
192 if (GetPositionOfEdge(claw_values, &edge_encoder, &edge_angle)) {
193 LOG(INFO, "Calibration edge edge should be %f.\n", edge_angle);
194 SetCalibration(edge_encoder, edge_angle);
195 set_zeroing_state(zeroing_state);
196 return true;
197 }
198 return false;
199}
200
201bool BottomZeroedStateFeedbackLoop::SetCalibrationOnEdge(
202 const constants::Values::Claws::Claw &claw_values,
203 JointZeroingState zeroing_state) {
204 double edge_encoder;
205 double edge_angle;
206 if (GetPositionOfEdge(claw_values, &edge_encoder, &edge_angle)) {
207 LOG(INFO, "Calibration edge.\n");
208 SetCalibration(edge_encoder, edge_angle);
209 set_zeroing_state(zeroing_state);
210 return true;
211 }
212 return false;
213}
214
Austin Schuhcc0bf312014-02-09 00:39:29 -0800215ClawMotor::ClawMotor(control_loops::ClawGroup *my_claw)
Brian Silverman71fbee02014-03-13 17:24:54 -0700216 : aos::control_loops::ControlLoop<control_loops::ClawGroup, true, true,
217 false>(my_claw),
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800218 has_top_claw_goal_(false),
219 top_claw_goal_(0.0),
Austin Schuhcda86af2014-02-16 16:16:39 -0800220 top_claw_(this),
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800221 has_bottom_claw_goal_(false),
222 bottom_claw_goal_(0.0),
Austin Schuhcda86af2014-02-16 16:16:39 -0800223 bottom_claw_(this),
224 claw_(MakeClawLoop()),
Ben Fredrickson9b388422014-02-13 06:15:31 +0000225 was_enabled_(false),
Austin Schuh4cb047f2014-02-16 21:10:19 -0800226 doing_calibration_fine_tune_(false),
Austin Schuhe7f90d12014-02-17 00:48:25 -0800227 capped_goal_(false),
228 mode_(UNKNOWN_LOCATION) {}
Austin Schuh3bb9a442014-02-02 16:01:45 -0800229
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800230const int ZeroedStateFeedbackLoop::kZeroingMaxVoltage;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800231
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000232bool ZeroedStateFeedbackLoop::SawFilteredPosedge(
233 const HallEffectTracker &this_sensor, const HallEffectTracker &sensorA,
234 const HallEffectTracker &sensorB) {
235 if (posedge_filter_ == nullptr && this_sensor.posedge_count_changed() &&
236 !sensorA.posedge_count_changed() && !sensorB.posedge_count_changed() &&
237 this_sensor.value() && !this_sensor.last_value()) {
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000238 posedge_filter_ = &this_sensor;
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000239 } else if (posedge_filter_ == &this_sensor &&
240 !this_sensor.posedge_count_changed() &&
241 !sensorA.posedge_count_changed() &&
242 !sensorB.posedge_count_changed() && this_sensor.value()) {
243 posedge_filter_ = nullptr;
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000244 return true;
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000245 } else if (posedge_filter_ == &this_sensor) {
246 posedge_filter_ = nullptr;
247 }
248 return false;
249}
250
251bool ZeroedStateFeedbackLoop::SawFilteredNegedge(
252 const HallEffectTracker &this_sensor, const HallEffectTracker &sensorA,
253 const HallEffectTracker &sensorB) {
254 if (negedge_filter_ == nullptr && this_sensor.negedge_count_changed() &&
255 !sensorA.negedge_count_changed() && !sensorB.negedge_count_changed() &&
256 !this_sensor.value() && this_sensor.last_value()) {
257 negedge_filter_ = &this_sensor;
258 } else if (negedge_filter_ == &this_sensor &&
259 !this_sensor.negedge_count_changed() &&
260 !sensorA.negedge_count_changed() &&
261 !sensorB.negedge_count_changed() && !this_sensor.value()) {
262 negedge_filter_ = nullptr;
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000263 return true;
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000264 } else if (negedge_filter_ == &this_sensor) {
265 negedge_filter_ = nullptr;
266 }
267 return false;
268}
269
Brian Silvermane0a95462014-02-17 00:41:09 -0800270bool ZeroedStateFeedbackLoop::DoGetPositionOfEdge(
271 const constants::Values::Claws::AnglePair &angles, double *edge_encoder,
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000272 double *edge_angle, const HallEffectTracker &this_sensor,
273 const HallEffectTracker &sensorA, const HallEffectTracker &sensorB,
Brian Silvermane0a95462014-02-17 00:41:09 -0800274 const char *hall_effect_name) {
Austin Schuhf84a1302014-02-19 00:23:30 -0800275 bool found_edge = false;
Austin Schuh27b8fb12014-02-22 15:10:05 -0800276
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000277 if (SawFilteredPosedge(this_sensor, sensorA, sensorB)) {
Austin Schuh27b8fb12014-02-22 15:10:05 -0800278 if (min_hall_effect_off_angle_ == max_hall_effect_off_angle_) {
Brian Silvermanf48fab32014-03-09 14:32:24 -0700279 LOG(WARNING, "%s: Uncertain which side, rejecting posedge\n", name_);
Brian Silvermane0a95462014-02-17 00:41:09 -0800280 } else {
Austin Schuh27b8fb12014-02-22 15:10:05 -0800281 const double average_last_encoder =
282 (min_hall_effect_off_angle_ + max_hall_effect_off_angle_) / 2.0;
283 if (posedge_value_ < average_last_encoder) {
284 *edge_angle = angles.upper_decreasing_angle;
285 LOG(INFO, "%s Posedge upper of %s -> %f posedge: %f avg_encoder: %f\n",
286 name_, hall_effect_name, *edge_angle, posedge_value_,
287 average_last_encoder);
288 } else {
289 *edge_angle = angles.lower_angle;
290 LOG(INFO, "%s Posedge lower of %s -> %f posedge: %f avg_encoder: %f\n",
291 name_, hall_effect_name, *edge_angle, posedge_value_,
292 average_last_encoder);
293 }
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000294 *edge_encoder = posedge_value_;
Austin Schuh27b8fb12014-02-22 15:10:05 -0800295 found_edge = true;
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000296 }
297 }
298
299 if (SawFilteredNegedge(this_sensor, sensorA, sensorB)) {
300 if (min_hall_effect_on_angle_ == max_hall_effect_on_angle_) {
Brian Silvermanf48fab32014-03-09 14:32:24 -0700301 LOG(WARNING, "%s: Uncertain which side, rejecting negedge\n", name_);
Brian Silvermane0a95462014-02-17 00:41:09 -0800302 } else {
Austin Schuh27b8fb12014-02-22 15:10:05 -0800303 const double average_last_encoder =
304 (min_hall_effect_on_angle_ + max_hall_effect_on_angle_) / 2.0;
305 if (negedge_value_ > average_last_encoder) {
306 *edge_angle = angles.upper_angle;
307 LOG(INFO, "%s Negedge upper of %s -> %f negedge: %f avg_encoder: %f\n",
308 name_, hall_effect_name, *edge_angle, negedge_value_,
309 average_last_encoder);
310 } else {
311 *edge_angle = angles.lower_decreasing_angle;
312 LOG(INFO, "%s Negedge lower of %s -> %f negedge: %f avg_encoder: %f\n",
313 name_, hall_effect_name, *edge_angle, negedge_value_,
314 average_last_encoder);
315 }
316 *edge_encoder = negedge_value_;
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000317 found_edge = true;
Brian Silvermane0a95462014-02-17 00:41:09 -0800318 }
Austin Schuh27b8fb12014-02-22 15:10:05 -0800319 }
320
Austin Schuhf84a1302014-02-19 00:23:30 -0800321 return found_edge;
Brian Silvermane0a95462014-02-17 00:41:09 -0800322}
323
Austin Schuhf9286cd2014-02-11 00:51:09 -0800324bool ZeroedStateFeedbackLoop::GetPositionOfEdge(
Austin Schuhd27931c2014-02-16 19:18:20 -0800325 const constants::Values::Claws::Claw &claw_values, double *edge_encoder,
Austin Schuhf9286cd2014-02-11 00:51:09 -0800326 double *edge_angle) {
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000327 if (DoGetPositionOfEdge(claw_values.front, edge_encoder, edge_angle, front_,
328 calibration_, back_, "front")) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800329 return true;
330 }
Brian Silvermane0a95462014-02-17 00:41:09 -0800331 if (DoGetPositionOfEdge(claw_values.calibration, edge_encoder, edge_angle,
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000332 calibration_, front_, back_, "calibration")) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800333 return true;
334 }
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000335 if (DoGetPositionOfEdge(claw_values.back, edge_encoder, edge_angle, back_,
336 calibration_, front_, "back")) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800337 return true;
338 }
339 return false;
340}
341
Austin Schuhcda86af2014-02-16 16:16:39 -0800342void TopZeroedStateFeedbackLoop::SetCalibration(double edge_encoder,
343 double edge_angle) {
344 double old_offset = offset_;
345 offset_ = edge_angle - edge_encoder;
346 const double doffset = offset_ - old_offset;
347 motor_->ChangeTopOffset(doffset);
348}
349
350void BottomZeroedStateFeedbackLoop::SetCalibration(double edge_encoder,
351 double edge_angle) {
352 double old_offset = offset_;
353 offset_ = edge_angle - edge_encoder;
354 const double doffset = offset_ - old_offset;
355 motor_->ChangeBottomOffset(doffset);
356}
357
358void ClawMotor::ChangeTopOffset(double doffset) {
359 claw_.ChangeTopOffset(doffset);
360 if (has_top_claw_goal_) {
361 top_claw_goal_ += doffset;
362 }
363}
364
365void ClawMotor::ChangeBottomOffset(double doffset) {
366 claw_.ChangeBottomOffset(doffset);
367 if (has_bottom_claw_goal_) {
368 bottom_claw_goal_ += doffset;
369 }
370}
371
372void ClawLimitedLoop::ChangeTopOffset(double doffset) {
373 Y_(1, 0) += doffset;
374 X_hat(1, 0) += doffset;
375 LOG(INFO, "Changing top offset by %f\n", doffset);
376}
377void ClawLimitedLoop::ChangeBottomOffset(double doffset) {
378 Y_(0, 0) += doffset;
379 X_hat(0, 0) += doffset;
380 X_hat(1, 0) -= doffset;
381 LOG(INFO, "Changing bottom offset by %f\n", doffset);
382}
joe7376ff52014-02-16 18:28:42 -0800383
Austin Schuh069143b2014-02-17 02:46:26 -0800384void LimitClawGoal(double *bottom_goal, double *top_goal,
385 const frc971::constants::Values &values) {
386 // first update position based on angle limit
387
388 const double separation = *top_goal - *bottom_goal;
389 if (separation > values.claw.claw_max_separation) {
Austin Schuh069143b2014-02-17 02:46:26 -0800390 const double dsep = (separation - values.claw.claw_max_separation) / 2.0;
391 *bottom_goal += dsep;
392 *top_goal -= dsep;
393 LOG(DEBUG, "Goals now bottom: %f, top: %f\n", *bottom_goal, *top_goal);
394 }
395 if (separation < values.claw.claw_min_separation) {
Austin Schuh069143b2014-02-17 02:46:26 -0800396 const double dsep = (separation - values.claw.claw_min_separation) / 2.0;
397 *bottom_goal += dsep;
398 *top_goal -= dsep;
399 LOG(DEBUG, "Goals now bottom: %f, top: %f\n", *bottom_goal, *top_goal);
400 }
401
402 // now move both goals in unison
403 if (*bottom_goal < values.claw.lower_claw.lower_limit) {
404 *top_goal += values.claw.lower_claw.lower_limit - *bottom_goal;
405 *bottom_goal = values.claw.lower_claw.lower_limit;
406 }
407 if (*bottom_goal > values.claw.lower_claw.upper_limit) {
408 *top_goal -= *bottom_goal - values.claw.lower_claw.upper_limit;
409 *bottom_goal = values.claw.lower_claw.upper_limit;
410 }
411
412 if (*top_goal < values.claw.upper_claw.lower_limit) {
413 *bottom_goal += values.claw.upper_claw.lower_limit - *top_goal;
414 *top_goal = values.claw.upper_claw.lower_limit;
415 }
416 if (*top_goal > values.claw.upper_claw.upper_limit) {
417 *bottom_goal -= *top_goal - values.claw.upper_claw.upper_limit;
418 *top_goal = values.claw.upper_claw.upper_limit;
419 }
420}
Austin Schuhcda86af2014-02-16 16:16:39 -0800421
Austin Schuhe7f90d12014-02-17 00:48:25 -0800422bool ClawMotor::is_ready() const {
423 return (
424 (top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED &&
425 bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED) ||
Brian Silverman71fbee02014-03-13 17:24:54 -0700426 (((::aos::robot_state.get() == NULL) ? true
427 : ::aos::robot_state->autonomous) &&
Austin Schuhe7f90d12014-02-17 00:48:25 -0800428 ((top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
429 top_claw_.zeroing_state() ==
430 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION) &&
431 (bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
432 bottom_claw_.zeroing_state() ==
433 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION))));
434}
435
436bool ClawMotor::is_zeroing() const { return !is_ready(); }
437
Austin Schuh3bb9a442014-02-02 16:01:45 -0800438// Positive angle is up, and positive power is up.
Austin Schuhcc0bf312014-02-09 00:39:29 -0800439void ClawMotor::RunIteration(const control_loops::ClawGroup::Goal *goal,
440 const control_loops::ClawGroup::Position *position,
441 control_loops::ClawGroup::Output *output,
James Kuszmaul9ead1de2014-02-28 21:24:39 -0800442 control_loops::ClawGroup::Status *status) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800443 constexpr double dt = 0.01;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800444
445 // Disable the motors now so that all early returns will return with the
446 // motors disabled.
447 if (output) {
448 output->top_claw_voltage = 0;
449 output->bottom_claw_voltage = 0;
450 output->intake_voltage = 0;
Ben Fredrickson61893d52014-03-02 09:43:23 +0000451 output->tusk_voltage = 0;
452 }
453
Brian Silverman71fbee02014-03-13 17:24:54 -0700454 if (goal) {
455 if (::std::isnan(goal->bottom_angle) ||
456 ::std::isnan(goal->separation_angle) || ::std::isnan(goal->intake) ||
457 ::std::isnan(goal->centering)) {
458 return;
459 }
Austin Schuh3bb9a442014-02-02 16:01:45 -0800460 }
461
Austin Schuh1a499942014-02-17 01:51:58 -0800462 if (reset()) {
Austin Schuh27b8fb12014-02-22 15:10:05 -0800463 top_claw_.Reset(position->top);
464 bottom_claw_.Reset(position->bottom);
Austin Schuh1a499942014-02-17 01:51:58 -0800465 }
466
Austin Schuhf9286cd2014-02-11 00:51:09 -0800467 const frc971::constants::Values &values = constants::GetValues();
468
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800469 if (position) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800470 Eigen::Matrix<double, 2, 1> Y;
471 Y << position->bottom.position + bottom_claw_.offset(),
472 position->top.position + top_claw_.offset();
473 claw_.Correct(Y);
474
Austin Schuhf9286cd2014-02-11 00:51:09 -0800475 top_claw_.SetPositionValues(position->top);
476 bottom_claw_.SetPositionValues(position->bottom);
477
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800478 if (!has_top_claw_goal_) {
479 has_top_claw_goal_ = true;
Austin Schuhcda86af2014-02-16 16:16:39 -0800480 top_claw_goal_ = top_claw_.absolute_position();
Austin Schuhe7f90d12014-02-17 00:48:25 -0800481 initial_separation_ =
Austin Schuhcda86af2014-02-16 16:16:39 -0800482 top_claw_.absolute_position() - bottom_claw_.absolute_position();
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800483 }
484 if (!has_bottom_claw_goal_) {
485 has_bottom_claw_goal_ = true;
Austin Schuhcda86af2014-02-16 16:16:39 -0800486 bottom_claw_goal_ = bottom_claw_.absolute_position();
Austin Schuhe7f90d12014-02-17 00:48:25 -0800487 initial_separation_ =
Austin Schuhcda86af2014-02-16 16:16:39 -0800488 top_claw_.absolute_position() - bottom_claw_.absolute_position();
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800489 }
Brian Silvermanf48fab32014-03-09 14:32:24 -0700490 LOG_STRUCT(DEBUG, "absolute position",
491 ClawPositionToLog(top_claw_.absolute_position(),
492 bottom_claw_.absolute_position()));
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800493 }
494
Brian Silverman71fbee02014-03-13 17:24:54 -0700495 bool autonomous, enabled;
496 if (::aos::robot_state.get() == nullptr) {
497 autonomous = true;
498 enabled = false;
499 } else {
500 autonomous = ::aos::robot_state->autonomous;
501 enabled = ::aos::robot_state->enabled;
502 }
Austin Schuh069143b2014-02-17 02:46:26 -0800503
504 double bottom_claw_velocity_ = 0.0;
505 double top_claw_velocity_ = 0.0;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800506
Brian Silverman71fbee02014-03-13 17:24:54 -0700507 if (goal != NULL &&
508 ((top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED &&
509 bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED) ||
510 (autonomous &&
511 ((top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
512 top_claw_.zeroing_state() ==
513 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION) &&
514 (bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
515 bottom_claw_.zeroing_state() ==
516 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION))))) {
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800517 // Ready to use the claw.
518 // Limit the goals here.
Austin Schuhf9286cd2014-02-11 00:51:09 -0800519 bottom_claw_goal_ = goal->bottom_angle;
Brian Silverman7c021c42014-02-17 15:15:56 -0800520 top_claw_goal_ = goal->bottom_angle + goal->separation_angle;
Austin Schuhcda86af2014-02-16 16:16:39 -0800521 has_bottom_claw_goal_ = true;
522 has_top_claw_goal_ = true;
523 doing_calibration_fine_tune_ = false;
524
Austin Schuhe7f90d12014-02-17 00:48:25 -0800525 mode_ = READY;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800526 } else if (top_claw_.zeroing_state() !=
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000527 ZeroedStateFeedbackLoop::UNKNOWN_POSITION &&
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800528 bottom_claw_.zeroing_state() !=
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000529 ZeroedStateFeedbackLoop::UNKNOWN_POSITION) {
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800530 // Time to fine tune the zero.
531 // Limit the goals here.
Austin Schuh0c733422014-02-17 01:17:12 -0800532 if (!enabled) {
533 // If we are disabled, start the fine tune process over again.
534 doing_calibration_fine_tune_ = false;
535 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800536 if (bottom_claw_.zeroing_state() != ZeroedStateFeedbackLoop::CALIBRATED) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800537 // always get the bottom claw to calibrated first
538 LOG(DEBUG, "Calibrating the bottom of the claw\n");
539 if (!doing_calibration_fine_tune_) {
540 if (::std::abs(bottom_absolute_position() -
Austin Schuhd27931c2014-02-16 19:18:20 -0800541 values.claw.start_fine_tune_pos) <
542 values.claw.claw_unimportant_epsilon) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800543 doing_calibration_fine_tune_ = true;
Austin Schuhd27931c2014-02-16 19:18:20 -0800544 bottom_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800545 top_claw_velocity_ = bottom_claw_velocity_ =
546 values.claw.claw_zeroing_speed;
Austin Schuhcda86af2014-02-16 16:16:39 -0800547 LOG(DEBUG, "Ready to fine tune the bottom\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800548 mode_ = FINE_TUNE_BOTTOM;
Austin Schuhcda86af2014-02-16 16:16:39 -0800549 } else {
550 // send bottom to zeroing start
Austin Schuhd27931c2014-02-16 19:18:20 -0800551 bottom_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuhcda86af2014-02-16 16:16:39 -0800552 LOG(DEBUG, "Going to the start position for the bottom\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800553 mode_ = PREP_FINE_TUNE_BOTTOM;
Austin Schuhcda86af2014-02-16 16:16:39 -0800554 }
555 } else {
Austin Schuhe7f90d12014-02-17 00:48:25 -0800556 mode_ = FINE_TUNE_BOTTOM;
Austin Schuhd27931c2014-02-16 19:18:20 -0800557 bottom_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800558 top_claw_velocity_ = bottom_claw_velocity_ =
559 values.claw.claw_zeroing_speed;
Brian Silvermane0a95462014-02-17 00:41:09 -0800560 if (top_claw_.front_or_back_triggered() ||
561 bottom_claw_.front_or_back_triggered()) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800562 // We shouldn't hit a limit, but if we do, go back to the zeroing
563 // point and try again.
564 doing_calibration_fine_tune_ = false;
Austin Schuhd27931c2014-02-16 19:18:20 -0800565 bottom_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuh069143b2014-02-17 02:46:26 -0800566 top_claw_velocity_ = bottom_claw_velocity_ = 0.0;
Austin Schuhcda86af2014-02-16 16:16:39 -0800567 LOG(DEBUG, "Found a limit, starting over.\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800568 mode_ = PREP_FINE_TUNE_BOTTOM;
Austin Schuhcda86af2014-02-16 16:16:39 -0800569 }
Austin Schuh288c8c32014-02-16 17:20:17 -0800570
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000571 if (position && bottom_claw_.SawFilteredPosedge(
572 bottom_claw_.calibration(), bottom_claw_.front(),
573 bottom_claw_.back())) {
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000574 // do calibration
575 bottom_claw_.SetCalibration(
576 position->bottom.posedge_value,
577 values.claw.lower_claw.calibration.lower_angle);
578 bottom_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::CALIBRATED);
579 // calibrated so we are done fine tuning bottom
580 doing_calibration_fine_tune_ = false;
581 LOG(DEBUG, "Calibrated the bottom correctly!\n");
582 } else if (bottom_claw_.calibration().last_value()) {
583 doing_calibration_fine_tune_ = false;
584 bottom_claw_goal_ = values.claw.start_fine_tune_pos;
585 top_claw_velocity_ = bottom_claw_velocity_ = 0.0;
586 mode_ = PREP_FINE_TUNE_BOTTOM;
Austin Schuhcda86af2014-02-16 16:16:39 -0800587 } else {
588 LOG(DEBUG, "Fine tuning\n");
589 }
590 }
591 // now set the top claw to track
592
Austin Schuhd27931c2014-02-16 19:18:20 -0800593 top_claw_goal_ = bottom_claw_goal_ + values.claw.claw_zeroing_separation;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800594 } else {
Austin Schuhcda86af2014-02-16 16:16:39 -0800595 // bottom claw must be calibrated, start on the top
596 if (!doing_calibration_fine_tune_) {
Austin Schuhd27931c2014-02-16 19:18:20 -0800597 if (::std::abs(top_absolute_position() -
598 values.claw.start_fine_tune_pos) <
599 values.claw.claw_unimportant_epsilon) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800600 doing_calibration_fine_tune_ = true;
Austin Schuhd27931c2014-02-16 19:18:20 -0800601 top_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800602 top_claw_velocity_ = bottom_claw_velocity_ =
603 values.claw.claw_zeroing_speed;
Austin Schuhcda86af2014-02-16 16:16:39 -0800604 LOG(DEBUG, "Ready to fine tune the top\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800605 mode_ = FINE_TUNE_TOP;
Austin Schuhcda86af2014-02-16 16:16:39 -0800606 } else {
607 // send top to zeroing start
Austin Schuhd27931c2014-02-16 19:18:20 -0800608 top_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuhcda86af2014-02-16 16:16:39 -0800609 LOG(DEBUG, "Going to the start position for the top\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800610 mode_ = PREP_FINE_TUNE_TOP;
Austin Schuhcda86af2014-02-16 16:16:39 -0800611 }
612 } else {
Austin Schuhe7f90d12014-02-17 00:48:25 -0800613 mode_ = FINE_TUNE_TOP;
Austin Schuhd27931c2014-02-16 19:18:20 -0800614 top_claw_goal_ += values.claw.claw_zeroing_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800615 top_claw_velocity_ = bottom_claw_velocity_ =
616 values.claw.claw_zeroing_speed;
Brian Silvermane0a95462014-02-17 00:41:09 -0800617 if (top_claw_.front_or_back_triggered() ||
618 bottom_claw_.front_or_back_triggered()) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800619 // this should not happen, but now we know it won't
620 doing_calibration_fine_tune_ = false;
Austin Schuhd27931c2014-02-16 19:18:20 -0800621 top_claw_goal_ = values.claw.start_fine_tune_pos;
Austin Schuh069143b2014-02-17 02:46:26 -0800622 top_claw_velocity_ = bottom_claw_velocity_ = 0.0;
Austin Schuhcda86af2014-02-16 16:16:39 -0800623 LOG(DEBUG, "Found a limit, starting over.\n");
Austin Schuhe7f90d12014-02-17 00:48:25 -0800624 mode_ = PREP_FINE_TUNE_TOP;
Austin Schuhcda86af2014-02-16 16:16:39 -0800625 }
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000626
627 if (position &&
628 top_claw_.SawFilteredPosedge(top_claw_.calibration(),
629 top_claw_.front(), top_claw_.back())) {
630 // do calibration
631 top_claw_.SetCalibration(
632 position->top.posedge_value,
633 values.claw.upper_claw.calibration.lower_angle);
634 top_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::CALIBRATED);
635 // calibrated so we are done fine tuning top
636 doing_calibration_fine_tune_ = false;
637 LOG(DEBUG, "Calibrated the top correctly!\n");
638 } else if (top_claw_.calibration().last_value()) {
639 doing_calibration_fine_tune_ = false;
640 top_claw_goal_ = values.claw.start_fine_tune_pos;
641 top_claw_velocity_ = bottom_claw_velocity_ = 0.0;
642 mode_ = PREP_FINE_TUNE_TOP;
Austin Schuhcda86af2014-02-16 16:16:39 -0800643 }
644 }
645 // now set the bottom claw to track
Austin Schuhd27931c2014-02-16 19:18:20 -0800646 bottom_claw_goal_ = top_claw_goal_ - values.claw.claw_zeroing_separation;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800647 }
648 } else {
Austin Schuhcda86af2014-02-16 16:16:39 -0800649 doing_calibration_fine_tune_ = false;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800650 if (!was_enabled_ && enabled) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800651 if (position) {
Brian Silverman72035692014-03-14 10:18:27 -0700652 top_claw_goal_ = position->top.position + top_claw_.offset();
653 bottom_claw_goal_ = position->bottom.position + bottom_claw_.offset();
Austin Schuhe7f90d12014-02-17 00:48:25 -0800654 initial_separation_ =
Austin Schuhcda86af2014-02-16 16:16:39 -0800655 position->top.position - position->bottom.position;
Austin Schuhf9286cd2014-02-11 00:51:09 -0800656 } else {
657 has_top_claw_goal_ = false;
658 has_bottom_claw_goal_ = false;
659 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800660 }
Austin Schuhf9286cd2014-02-11 00:51:09 -0800661
Austin Schuh4cb047f2014-02-16 21:10:19 -0800662 if ((bottom_claw_.zeroing_state() !=
663 ZeroedStateFeedbackLoop::UNKNOWN_POSITION ||
Brian Silvermane0a95462014-02-17 00:41:09 -0800664 bottom_claw_.front().value() || top_claw_.front().value()) &&
665 !top_claw_.back().value() && !bottom_claw_.back().value()) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800666 if (enabled) {
667 // Time to slowly move back up to find any position to narrow down the
668 // zero.
Austin Schuhd27931c2014-02-16 19:18:20 -0800669 top_claw_goal_ += values.claw.claw_zeroing_off_speed * dt;
670 bottom_claw_goal_ += values.claw.claw_zeroing_off_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800671 top_claw_velocity_ = bottom_claw_velocity_ =
672 values.claw.claw_zeroing_off_speed;
Austin Schuhcda86af2014-02-16 16:16:39 -0800673 LOG(DEBUG, "Bottom is known.\n");
Austin Schuhf9286cd2014-02-11 00:51:09 -0800674 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800675 } else {
676 // We don't know where either claw is. Slowly start moving down to find
677 // any hall effect.
Austin Schuhf9286cd2014-02-11 00:51:09 -0800678 if (enabled) {
Austin Schuhd27931c2014-02-16 19:18:20 -0800679 top_claw_goal_ -= values.claw.claw_zeroing_off_speed * dt;
680 bottom_claw_goal_ -= values.claw.claw_zeroing_off_speed * dt;
Austin Schuh069143b2014-02-17 02:46:26 -0800681 top_claw_velocity_ = bottom_claw_velocity_ =
682 -values.claw.claw_zeroing_off_speed;
Austin Schuhcda86af2014-02-16 16:16:39 -0800683 LOG(DEBUG, "Both are unknown.\n");
Austin Schuhf9286cd2014-02-11 00:51:09 -0800684 }
685 }
686
Ben Fredricksoneaecbbb2014-02-23 12:12:03 +0000687 if (position) {
688 if (enabled) {
689 top_claw_.SetCalibrationOnEdge(
690 values.claw.upper_claw,
691 ZeroedStateFeedbackLoop::APPROXIMATE_CALIBRATION);
692 bottom_claw_.SetCalibrationOnEdge(
693 values.claw.lower_claw,
694 ZeroedStateFeedbackLoop::APPROXIMATE_CALIBRATION);
695 } else {
696 // TODO(austin): Only calibrate on the predetermined edge.
697 // We might be able to just ignore this since the backlash is soooo
698 // low.
699 // :)
700 top_claw_.SetCalibrationOnEdge(
701 values.claw.upper_claw,
702 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION);
703 bottom_claw_.SetCalibrationOnEdge(
704 values.claw.lower_claw,
705 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION);
706 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800707 }
Austin Schuhe7f90d12014-02-17 00:48:25 -0800708 mode_ = UNKNOWN_LOCATION;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800709 }
710
Austin Schuh069143b2014-02-17 02:46:26 -0800711 // Limit the goals if both claws have been (mostly) found.
712 if (mode_ != UNKNOWN_LOCATION) {
713 LimitClawGoal(&bottom_claw_goal_, &top_claw_goal_, values);
714 }
715
Austin Schuhf9286cd2014-02-11 00:51:09 -0800716 if (has_top_claw_goal_ && has_bottom_claw_goal_) {
Austin Schuh069143b2014-02-17 02:46:26 -0800717 claw_.R << bottom_claw_goal_, top_claw_goal_ - bottom_claw_goal_,
718 bottom_claw_velocity_, top_claw_velocity_ - bottom_claw_velocity_;
Austin Schuhcda86af2014-02-16 16:16:39 -0800719 double separation = -971;
720 if (position != nullptr) {
721 separation = position->top.position - position->bottom.position;
722 }
Brian Silvermanf48fab32014-03-09 14:32:24 -0700723 LOG_STRUCT(DEBUG, "actual goal",
724 ClawGoalToLog(claw_.R(0, 0), claw_.R(1, 0), separation));
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800725
Austin Schuh01c652b2014-02-21 23:13:42 -0800726 // Only cap power when one of the halves of the claw is moving slowly and
727 // could wind up.
Austin Schuhe7f90d12014-02-17 00:48:25 -0800728 claw_.set_is_zeroing(mode_ == UNKNOWN_LOCATION || mode_ == FINE_TUNE_TOP ||
729 mode_ == FINE_TUNE_BOTTOM);
Austin Schuhcda86af2014-02-16 16:16:39 -0800730 claw_.Update(output == nullptr);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800731 } else {
Austin Schuhcda86af2014-02-16 16:16:39 -0800732 claw_.Update(true);
Austin Schuhf9286cd2014-02-11 00:51:09 -0800733 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800734
Austin Schuh4cb047f2014-02-16 21:10:19 -0800735 capped_goal_ = false;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800736 switch (mode_) {
Austin Schuhcda86af2014-02-16 16:16:39 -0800737 case READY:
Austin Schuhe7f90d12014-02-17 00:48:25 -0800738 case PREP_FINE_TUNE_TOP:
739 case PREP_FINE_TUNE_BOTTOM:
Austin Schuhcda86af2014-02-16 16:16:39 -0800740 break;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800741 case FINE_TUNE_BOTTOM:
742 case FINE_TUNE_TOP:
Austin Schuh4cb047f2014-02-16 21:10:19 -0800743 case UNKNOWN_LOCATION: {
James Kuszmaul0e866512014-02-21 13:12:52 -0800744 Eigen::Matrix<double, 2, 1> U = claw_.K() * (claw_.R - claw_.X_hat);
James Kuszmaulf63b0ae2014-03-25 16:52:11 -0700745 LOG(DEBUG, "Uncapped voltages: Top: %f, Bottom: %f\n", U(1, 0), U(0, 0));
Austin Schuh4cb047f2014-02-16 21:10:19 -0800746 if (claw_.uncapped_average_voltage() > values.claw.max_zeroing_voltage) {
James Kuszmaul0e866512014-02-21 13:12:52 -0800747 double dx_bot = (U(0, 0) -
Austin Schuh4cb047f2014-02-16 21:10:19 -0800748 values.claw.max_zeroing_voltage) /
749 claw_.K(0, 0);
James Kuszmaul0e866512014-02-21 13:12:52 -0800750 double dx_top = (U(1, 0) -
751 values.claw.max_zeroing_voltage) /
752 claw_.K(0, 0);
753 double dx = ::std::max(dx_top, dx_bot);
Austin Schuh4cb047f2014-02-16 21:10:19 -0800754 bottom_claw_goal_ -= dx;
755 top_claw_goal_ -= dx;
James Kuszmaul0e866512014-02-21 13:12:52 -0800756 Eigen::Matrix<double, 4, 1> R;
757 R << bottom_claw_goal_, top_claw_goal_ - bottom_claw_goal_, claw_.R(2, 0), claw_.R(3, 0);
758 U = claw_.K() * (R - claw_.X_hat);
Austin Schuhcda86af2014-02-16 16:16:39 -0800759 capped_goal_ = true;
Brian Silvermanf48fab32014-03-09 14:32:24 -0700760 LOG(DEBUG, "Moving the goal by %f to prevent windup."
761 " Uncapped is %f, max is %f, difference is %f\n",
762 dx,
Austin Schuhe7f90d12014-02-17 00:48:25 -0800763 claw_.uncapped_average_voltage(), values.claw.max_zeroing_voltage,
764 (claw_.uncapped_average_voltage() -
765 values.claw.max_zeroing_voltage));
Austin Schuh4cb047f2014-02-16 21:10:19 -0800766 } else if (claw_.uncapped_average_voltage() <
767 -values.claw.max_zeroing_voltage) {
James Kuszmaul0e866512014-02-21 13:12:52 -0800768 double dx_bot = (U(0, 0) +
Austin Schuh4cb047f2014-02-16 21:10:19 -0800769 values.claw.max_zeroing_voltage) /
770 claw_.K(0, 0);
James Kuszmaul0e866512014-02-21 13:12:52 -0800771 double dx_top = (U(1, 0) +
772 values.claw.max_zeroing_voltage) /
773 claw_.K(0, 0);
774 double dx = ::std::min(dx_top, dx_bot);
Austin Schuh4cb047f2014-02-16 21:10:19 -0800775 bottom_claw_goal_ -= dx;
776 top_claw_goal_ -= dx;
James Kuszmaul0e866512014-02-21 13:12:52 -0800777 Eigen::Matrix<double, 4, 1> R;
778 R << bottom_claw_goal_, top_claw_goal_ - bottom_claw_goal_, claw_.R(2, 0), claw_.R(3, 0);
779 U = claw_.K() * (R - claw_.X_hat);
Austin Schuhcda86af2014-02-16 16:16:39 -0800780 capped_goal_ = true;
Austin Schuh4cb047f2014-02-16 21:10:19 -0800781 LOG(DEBUG, "Moving the goal by %f to prevent windup\n", dx);
Austin Schuhcda86af2014-02-16 16:16:39 -0800782 }
Austin Schuh4cb047f2014-02-16 21:10:19 -0800783 } break;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800784 }
785
786 if (output) {
Ben Fredrickson2f76ddf2014-02-23 05:58:23 +0000787 if (goal) {
788 //setup the intake
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000789 output->intake_voltage =
790 (goal->intake > 12.0) ? 12 : (goal->intake < -12.0) ? -12.0
791 : goal->intake;
Ben Fredrickson2f76ddf2014-02-23 05:58:23 +0000792 output->tusk_voltage = goal->centering;
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000793 output->tusk_voltage =
794 (goal->centering > 12.0) ? 12 : (goal->centering < -12.0)
795 ? -12.0
796 : goal->centering;
Ben Fredrickson2f76ddf2014-02-23 05:58:23 +0000797 }
James Kuszmauld536a402014-02-18 22:32:12 -0800798 output->top_claw_voltage = claw_.U(1, 0);
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000799 output->bottom_claw_voltage = claw_.U(0, 0);
Austin Schuhf84a1302014-02-19 00:23:30 -0800800
801 if (output->top_claw_voltage > kMaxVoltage) {
802 output->top_claw_voltage = kMaxVoltage;
803 } else if (output->top_claw_voltage < -kMaxVoltage) {
804 output->top_claw_voltage = -kMaxVoltage;
805 }
806
807 if (output->bottom_claw_voltage > kMaxVoltage) {
808 output->bottom_claw_voltage = kMaxVoltage;
809 } else if (output->bottom_claw_voltage < -kMaxVoltage) {
810 output->bottom_claw_voltage = -kMaxVoltage;
811 }
Austin Schuh3bb9a442014-02-02 16:01:45 -0800812 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800813
James Kuszmaul4abaf482014-02-26 21:16:35 -0800814 status->bottom = bottom_absolute_position();
815 status->separation = top_absolute_position() - bottom_absolute_position();
816 status->bottom_velocity = claw_.X_hat(2, 0);
817 status->separation_velocity = claw_.X_hat(3, 0);
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800818
Brian Silverman71fbee02014-03-13 17:24:54 -0700819 if (goal) {
820 bool bottom_done =
821 ::std::abs(bottom_absolute_position() - goal->bottom_angle) < 0.020;
822 bool bottom_velocity_done = ::std::abs(status->bottom_velocity) < 0.2;
823 bool separation_done =
824 ::std::abs((top_absolute_position() - bottom_absolute_position()) -
825 goal->separation_angle) < 0.020;
826 bool separation_done_with_ball =
827 ::std::abs((top_absolute_position() - bottom_absolute_position()) -
828 goal->separation_angle) < 0.06;
829 status->done = is_ready() && separation_done && bottom_done && bottom_velocity_done;
830 status->done_with_ball =
831 is_ready() && separation_done_with_ball && bottom_done && bottom_velocity_done;
832 } else {
833 status->done = status->done_with_ball = false;
834 }
Austin Schuha556b012014-03-02 11:55:52 -0800835
Austin Schuh4f8633f2014-03-02 13:59:46 -0800836 status->zeroed = is_ready();
Brian Silverman80fc94c2014-03-09 16:56:01 -0700837 status->zeroed_for_auto =
838 (top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
839 top_claw_.zeroing_state() ==
840 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION) &&
841 (bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
842 bottom_claw_.zeroing_state() ==
843 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION);
Austin Schuh4f8633f2014-03-02 13:59:46 -0800844
Brian Silverman71fbee02014-03-13 17:24:54 -0700845 was_enabled_ = enabled;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800846}
847
848} // namespace control_loops
849} // namespace frc971
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000850