blob: f896f17186788e2e9cf242a2cca67b18c209f8e8 [file] [log] [blame]
joe93778a62014-02-15 13:22:14 -08001#include "frc971/control_loops/shooter/shooter.h"
joe2d92e852014-01-25 14:31:24 -08002
3#include <stdio.h>
4
5#include <algorithm>
6
7#include "aos/common/control_loop/control_loops.q.h"
Ben Fredricksonedf0e092014-02-16 10:46:50 +00008#include "aos/common/control_loop/control_loops.q.h"
joe2d92e852014-01-25 14:31:24 -08009#include "aos/common/logging/logging.h"
10
11#include "frc971/constants.h"
joe93778a62014-02-15 13:22:14 -080012#include "frc971/control_loops/shooter/shooter_motor_plant.h"
joe2d92e852014-01-25 14:31:24 -080013
14namespace frc971 {
15namespace control_loops {
16
Ben Fredricksonedf0e092014-02-16 10:46:50 +000017using ::aos::time::Time;
Ben Fredrickson22c93322014-02-17 05:56:33 +000018
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000019void ZeroedStateFeedbackLoop::CapU() {
20 const double old_voltage = voltage_;
21 voltage_ += U(0, 0);
22
23 uncapped_voltage_ = voltage_;
24
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000025 // Make sure that reality and the observer can't get too far off. There is a
26 // delay by one cycle between the applied voltage and X_hat(2, 0), so compare
27 // against last cycle's voltage.
Austin Schuhbe1401f2014-02-18 03:18:41 -080028 if (X_hat(2, 0) > last_voltage_ + 4.0) {
29 voltage_ -= X_hat(2, 0) - (last_voltage_ + 4.0);
30 LOG(INFO, "Capping due to runawway\n");
31 } else if (X_hat(2, 0) < last_voltage_ - 4.0) {
32 voltage_ += X_hat(2, 0) - (last_voltage_ - 4.0);
33 LOG(INFO, "Capping due to runawway\n");
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000034 }
35
Austin Schuhd34569d2014-02-18 20:26:38 -080036 voltage_ = std::min(max_voltage_, voltage_);
37 voltage_ = std::max(-max_voltage_, voltage_);
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000038 U(0, 0) = voltage_ - old_voltage;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000039
Austin Schuhbe1401f2014-02-18 03:18:41 -080040 LOG(INFO, "X_hat is %f, applied is %f\n", X_hat(2, 0), voltage_);
41
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000042 last_voltage_ = voltage_;
Austin Schuhd34569d2014-02-18 20:26:38 -080043 capped_goal_ = false;
44}
45
46void ZeroedStateFeedbackLoop::CapGoal() {
47 if (uncapped_voltage() > max_voltage_) {
48 double dx;
49 if (controller_index() == 0) {
50 dx = (uncapped_voltage() - max_voltage_) /
51 (K(0, 0) - A(1, 0) * K(0, 2) / A(1, 2));
52 R(0, 0) -= dx;
53 R(2, 0) -= -A(1, 0) / A(1, 2) * dx;
54 } else {
55 dx = (uncapped_voltage() - max_voltage_) / K(0, 0);
56 R(0, 0) -= dx;
57 }
58 capped_goal_ = true;
59 LOG(DEBUG, "Moving the goal by %f to prevent windup\n", dx);
60 } else if (uncapped_voltage() < -max_voltage_) {
61 double dx;
62 if (controller_index() == 0) {
63 dx = (uncapped_voltage() + max_voltage_) /
64 (K(0, 0) - A(1, 0) * K(0, 2) / A(1, 2));
65 R(0, 0) -= dx;
66 R(2, 0) -= -A(1, 0) / A(1, 2) * dx;
67 } else {
68 dx = (uncapped_voltage() + max_voltage_) / K(0, 0);
69 R(0, 0) -= dx;
70 }
71 capped_goal_ = true;
72 LOG(DEBUG, "Moving the goal by %f to prevent windup\n", dx);
73 } else {
74 capped_goal_ = false;
75 }
76}
77
78void ZeroedStateFeedbackLoop::RecalculatePowerGoal() {
79 if (controller_index() == 0) {
80 R(2, 0) = (-A(1, 0) / A(1, 2) * R(0, 0) - A(1, 1) / A(1, 2) * R(1, 0));
81 } else {
82 R(2, 0) = -A(1, 1) / A(1, 2) * R(1, 0);
83 }
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000084}
85
Austin Schuh30537882014-02-18 01:07:23 -080086void ZeroedStateFeedbackLoop::SetCalibration(double encoder_val,
87 double known_position) {
88 LOG(INFO, "Setting calibration such that %f -> %f\n", encoder_val,
89 known_position);
90 LOG(INFO, "Position was %f\n", absolute_position());
91 double previous_offset = offset_;
92 offset_ = known_position - encoder_val;
93 double doffset = offset_ - previous_offset;
94 LOG(INFO, "Changing offset from %f to %f\n", previous_offset, offset_);
95 X_hat(0, 0) += doffset;
96 // Offset our measurements because the offset is baked into them.
97 Y_(0, 0) += doffset;
98 // Offset the goal so we don't move.
99 R(0, 0) += doffset;
Austin Schuhd34569d2014-02-18 20:26:38 -0800100 if (controller_index() == 0) {
101 R(2, 0) += -A(1, 0) / A(1, 2) * (doffset);
102 }
Austin Schuh30537882014-02-18 01:07:23 -0800103 LOG(INFO, "Validation: position is %f\n", absolute_position());
104}
105
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000106ShooterMotor::ShooterMotor(control_loops::ShooterGroup *my_shooter)
107 : aos::control_loops::ControlLoop<control_loops::ShooterGroup>(my_shooter),
108 shooter_(MakeShooterLoop()),
Ben Fredrickson22c93322014-02-17 05:56:33 +0000109 state_(STATE_INITIALIZE),
110 loading_problem_end_time_(0, 0),
Austin Schuh30537882014-02-18 01:07:23 -0800111 load_timeout_(0, 0),
Ben Fredrickson22c93322014-02-17 05:56:33 +0000112 shooter_brake_set_time_(0, 0),
Austin Schuh30537882014-02-18 01:07:23 -0800113 unload_timeout_(0, 0),
Ben Fredrickson22c93322014-02-17 05:56:33 +0000114 prepare_fire_end_time_(0, 0),
115 shot_end_time_(0, 0),
Austin Schuh30537882014-02-18 01:07:23 -0800116 cycles_not_moved_(0) {}
117
118double ShooterMotor::PowerToPosition(double power) {
Austin Schuh30537882014-02-18 01:07:23 -0800119 const frc971::constants::Values &values = constants::GetValues();
Ben Fredricksonda334d12014-02-23 09:09:23 +0000120 double maxpower = 0.5 * kSpringConstant *
121 (kMaxExtension * kMaxExtension -
122 (kMaxExtension - values.shooter.upper_limit) *
123 (kMaxExtension - values.shooter.upper_limit));
124 if (power < 0) {
Ben Fredrickson7c9314f2014-02-23 09:26:17 +0000125 //LOG(ERROR, "Power too low giving minimum (%f) (%f).\n", power,
126 // 0.0);
Ben Fredricksonda334d12014-02-23 09:09:23 +0000127 power = 0;
128 } else if (power > maxpower) {
Ben Fredrickson7c9314f2014-02-23 09:26:17 +0000129 //LOG(ERROR, "Power too high giving maximum (%f) (%f).\n", power,
130 // maxpower);
Ben Fredricksonda334d12014-02-23 09:09:23 +0000131 power = maxpower;
132 }
133
134 double mp = kMaxExtension * kMaxExtension - (power + power) / kSpringConstant;
135 double new_pos = 0.10;
136 if (mp < 0) {
137 LOG(ERROR,
138 "Power calculation has negative number before square root (%f).\n", mp);
139 } else {
140 new_pos = kMaxExtension - ::std::sqrt(mp);
141 }
142
143 new_pos = ::std::min(::std::max(new_pos, values.shooter.lower_limit),
Austin Schuh30537882014-02-18 01:07:23 -0800144 values.shooter.upper_limit);
145 return new_pos;
146}
Ben Fredrickson1e512ff2014-02-15 21:36:52 +0000147
148// Positive is out, and positive power is out.
joe2d92e852014-01-25 14:31:24 -0800149void ShooterMotor::RunIteration(
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000150 const control_loops::ShooterGroup::Goal *goal,
151 const control_loops::ShooterGroup::Position *position,
152 control_loops::ShooterGroup::Output *output,
Ben Fredrickson22c93322014-02-17 05:56:33 +0000153 control_loops::ShooterGroup::Status *status) {
Ben Fredrickson1e512ff2014-02-15 21:36:52 +0000154 constexpr double dt = 0.01;
155
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000156 // we must always have these or we have issues.
157 if (goal == NULL || status == NULL) {
Ben Fredrickson22c93322014-02-17 05:56:33 +0000158 if (output) output->voltage = 0;
159 LOG(ERROR, "Thought I would just check for null and die.\n");
160 return;
161 }
162
Austin Schuh30537882014-02-18 01:07:23 -0800163 if (reset()) {
164 state_ = STATE_INITIALIZE;
165 }
166 if (position) {
167 shooter_.CorrectPosition(position->position);
Ben Fredrickson1e512ff2014-02-15 21:36:52 +0000168 }
joe2d92e852014-01-25 14:31:24 -0800169
170 // Disable the motors now so that all early returns will return with the
171 // motors disabled.
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000172 if (output) output->voltage = 0;
joe2d92e852014-01-25 14:31:24 -0800173
Ben Fredrickson1e512ff2014-02-15 21:36:52 +0000174 const frc971::constants::Values &values = constants::GetValues();
175
Brian Silvermanaae236a2014-02-17 01:49:39 -0800176 // Don't even let the control loops run.
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000177 bool shooter_loop_disable = false;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000178
Brian Silvermanaae236a2014-02-17 01:49:39 -0800179 // Adds voltage to take up slack in gears before shot.
Ben Fredrickson7d980c22014-02-16 21:39:02 +0000180 bool apply_some_voltage = false;
181
Austin Schuhd34569d2014-02-18 20:26:38 -0800182
Austin Schuh30537882014-02-18 01:07:23 -0800183 const bool disabled = !::aos::robot_state->enabled;
Austin Schuhd34569d2014-02-18 20:26:38 -0800184 // If true, move the goal if we saturate.
185 bool cap_goal = false;
186
187 // TODO(austin): Move the offset if we see or don't see a hall effect when we
188 // expect to see one.
189 // Probably not needed yet.
190
191 if (position) {
192 int last_controller_index = shooter_.controller_index();
193 if (position->plunger && position->latch) {
194 // Use the controller without the spring if the latch is set and the
195 // plunger is back
196 shooter_.set_controller_index(1);
197 } else {
198 // Otherwise use the controller with the spring.
199 shooter_.set_controller_index(0);
200 }
201 if (shooter_.controller_index() != last_controller_index) {
202 shooter_.RecalculatePowerGoal();
203 }
204 }
Austin Schuh30537882014-02-18 01:07:23 -0800205
Ben Fredrickson1e512ff2014-02-15 21:36:52 +0000206 switch (state_) {
Ben Fredrickson22c93322014-02-17 05:56:33 +0000207 case STATE_INITIALIZE:
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000208 if (position) {
Austin Schuh30537882014-02-18 01:07:23 -0800209 // Reinitialize the internal filter state.
210 shooter_.InitializeState(position->position);
Austin Schuh30537882014-02-18 01:07:23 -0800211
212 // Start off with the assumption that we are at the value
213 // futhest back given our sensors.
214 if (position->pusher_distal.current) {
215 shooter_.SetCalibration(position->position,
216 values.shooter.pusher_distal.lower_angle);
217 } else if (position->pusher_proximal.current) {
218 shooter_.SetCalibration(position->position,
Austin Schuhd34569d2014-02-18 20:26:38 -0800219 values.shooter.pusher_proximal.upper_angle);
Austin Schuh30537882014-02-18 01:07:23 -0800220 } else {
221 shooter_.SetCalibration(position->position,
222 values.shooter.upper_limit);
223 }
224
225 state_ = STATE_REQUEST_LOAD;
226
227 // Go to the current position.
228 shooter_.SetGoalPosition(shooter_.absolute_position(), 0.0);
229 // If the plunger is all the way back, we want to be latched.
230 latch_piston_ = position->plunger;
231 brake_piston_ = false;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000232 } else {
Austin Schuh30537882014-02-18 01:07:23 -0800233 // If we can't start yet because we don't know where we are, set the
234 // latch and brake to their defaults.
235 latch_piston_ = true;
236 brake_piston_ = true;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000237 }
Ben Fredrickson22c93322014-02-17 05:56:33 +0000238 break;
239 case STATE_REQUEST_LOAD:
Austin Schuh30537882014-02-18 01:07:23 -0800240 if (position) {
Ben Fredrickson26a0dee2014-02-23 04:38:23 +0000241 if (position->pusher_distal.current ||
242 position->pusher_proximal.current) {
Austin Schuh30537882014-02-18 01:07:23 -0800243 // We started on the sensor, back up until we are found.
244 // If the plunger is all the way back and not latched, it won't be
245 // there for long.
246 state_ = STATE_LOAD_BACKTRACK;
Austin Schuh06cbbf12014-02-22 02:07:31 -0800247
248 // The plunger is already back and latched. Don't release it.
249 if (position->plunger && position->latch) {
250 latch_piston_ = true;
251 } else {
252 latch_piston_ = false;
253 }
254 } else if (position->plunger && position->latch) {
255 // The plunger is back and we are latched. We most likely got here
256 // from Initialize, in which case we want to 'load' again anyways to
257 // zero.
258 Load();
259 latch_piston_ = true;
Austin Schuh30537882014-02-18 01:07:23 -0800260 } else {
261 // Off the sensor, start loading.
262 Load();
263 latch_piston_ = false;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000264 }
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000265 }
266
Austin Schuh30537882014-02-18 01:07:23 -0800267 // Hold our current position.
268 shooter_.SetGoalPosition(shooter_.absolute_position(), 0.0);
269 brake_piston_ = false;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000270 break;
271 case STATE_LOAD_BACKTRACK:
Austin Schuh30537882014-02-18 01:07:23 -0800272 // If we are here, then that means we started past the edge where we want
273 // to zero. Move backwards until we don't see the sensor anymore.
274 // The plunger is contacting the pusher (or will be shortly).
275
Austin Schuh30537882014-02-18 01:07:23 -0800276 if (!disabled) {
Ben Fredrickson22c93322014-02-17 05:56:33 +0000277 shooter_.SetGoalPosition(
Austin Schuhfaeee632014-02-18 01:24:05 -0800278 shooter_.goal_position() + values.shooter.zeroing_speed * dt,
279 values.shooter.zeroing_speed);
Ben Fredrickson22c93322014-02-17 05:56:33 +0000280 }
Austin Schuhd34569d2014-02-18 20:26:38 -0800281 cap_goal = true;
Austin Schuh06cbbf12014-02-22 02:07:31 -0800282 shooter_.set_max_voltage(4.0);
Ben Fredrickson22c93322014-02-17 05:56:33 +0000283
Austin Schuh30537882014-02-18 01:07:23 -0800284 if (position) {
Ben Fredrickson26a0dee2014-02-23 04:38:23 +0000285 if (!position->pusher_distal.current &&
286 !position->pusher_proximal.current) {
Austin Schuh30537882014-02-18 01:07:23 -0800287 Load();
288 }
Austin Schuh6b428602014-02-22 21:02:00 -0800289 latch_piston_ = position->plunger;
Austin Schuh30537882014-02-18 01:07:23 -0800290 }
291
Austin Schuh30537882014-02-18 01:07:23 -0800292 brake_piston_ = false;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000293 break;
294 case STATE_LOAD:
Austin Schuh30537882014-02-18 01:07:23 -0800295 // If we are disabled right now, reset the timer.
296 if (disabled) {
297 Load();
298 // Latch defaults to true when disabled. Leave it latched until we have
299 // useful sensor data.
300 latch_piston_ = true;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000301 }
Austin Schuh30537882014-02-18 01:07:23 -0800302 // Go to 0, which should be the latch position, or trigger a hall effect
303 // on the way. If we don't see edges where we are supposed to, the
304 // offset will be updated by code above.
305 shooter_.SetGoalPosition(0.0, 0.0);
Ben Fredrickson22c93322014-02-17 05:56:33 +0000306
Austin Schuh30537882014-02-18 01:07:23 -0800307 if (position) {
308 // If we see a posedge on any of the hall effects,
309 if (position->pusher_proximal.posedge_count !=
310 last_proximal_posedge_count_) {
311 LOG(DEBUG, "Setting calibration using proximal sensor\n");
312 shooter_.SetCalibration(position->pusher_proximal.posedge_value,
313 values.shooter.pusher_proximal.upper_angle);
314 }
315 if (position->pusher_distal.posedge_count !=
316 last_distal_posedge_count_) {
317 LOG(DEBUG, "Setting calibration using distal sensor\n");
318 shooter_.SetCalibration(position->pusher_distal.posedge_value,
319 values.shooter.pusher_distal.upper_angle);
320 }
Ben Fredrickson22c93322014-02-17 05:56:33 +0000321
Austin Schuh30537882014-02-18 01:07:23 -0800322 // Latch if the plunger is far enough back to trigger the hall effect.
323 // This happens when the distal sensor is triggered.
Austin Schuh06cbbf12014-02-22 02:07:31 -0800324 latch_piston_ = position->pusher_distal.current || position->plunger;
Austin Schuh30537882014-02-18 01:07:23 -0800325
Austin Schuh06cbbf12014-02-22 02:07:31 -0800326 // Check if we are latched and back. Make sure the plunger is all the
327 // way back as well.
328 if (position->plunger && position->latch &&
329 position->pusher_distal.current) {
Austin Schuh30537882014-02-18 01:07:23 -0800330 state_ = STATE_PREPARE_SHOT;
331 } else if (position->plunger &&
332 ::std::abs(shooter_.absolute_position() -
333 shooter_.goal_position()) < 0.001) {
334 // We are at the goal, but not latched.
335 state_ = STATE_LOADING_PROBLEM;
Austin Schuh06cbbf12014-02-22 02:07:31 -0800336 loading_problem_end_time_ = Time::Now() + kLoadProblemEndTimeout;
Austin Schuh30537882014-02-18 01:07:23 -0800337 }
Ben Fredrickson22c93322014-02-17 05:56:33 +0000338 }
Austin Schuh30537882014-02-18 01:07:23 -0800339 if (load_timeout_ < Time::Now()) {
340 if (position) {
341 if (!position->pusher_distal.current ||
342 !position->pusher_proximal.current) {
343 state_ = STATE_ESTOP;
344 }
345 }
346 } else if (goal->unload_requested) {
347 Unload();
348 }
349 brake_piston_ = false;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000350 break;
351 case STATE_LOADING_PROBLEM:
Austin Schuh30537882014-02-18 01:07:23 -0800352 if (disabled) {
353 Load();
354 }
355 // We got to the goal, but the latch hasn't registered as down. It might
356 // be stuck, or on it's way but not there yet.
Ben Fredrickson22c93322014-02-17 05:56:33 +0000357 if (Time::Now() > loading_problem_end_time_) {
Austin Schuh30537882014-02-18 01:07:23 -0800358 // Timeout by unloading.
359 Unload();
360 } else if (position && position->plunger && position->latch) {
361 // If both trigger, we are latched.
Ben Fredrickson22c93322014-02-17 05:56:33 +0000362 state_ = STATE_PREPARE_SHOT;
363 }
Austin Schuh30537882014-02-18 01:07:23 -0800364 // Move a bit further back to help it trigger.
365 // If the latch is slow due to the air flowing through the tubes or
366 // inertia, but is otherwise free, this won't have much time to do
367 // anything and is safe. Otherwise this gives us a bit more room to free
368 // up the latch.
369 shooter_.SetGoalPosition(values.shooter.lower_limit, 0.0);
Ben Fredrickson22c93322014-02-17 05:56:33 +0000370 LOG(DEBUG, "Waiting on latch: plunger %d, latch: %d\n",
Austin Schuh60c56662014-02-17 14:37:19 -0800371 position->plunger, position->latch);
Ben Fredrickson22c93322014-02-17 05:56:33 +0000372
Austin Schuh30537882014-02-18 01:07:23 -0800373 latch_piston_ = true;
374 brake_piston_ = false;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000375 break;
376 case STATE_PREPARE_SHOT:
Austin Schuh30537882014-02-18 01:07:23 -0800377 // Move the shooter to the shot power set point and then lock the brake.
378 // TODO(austin): Timeout. Low priority.
379
Ben Fredrickson22c93322014-02-17 05:56:33 +0000380 shooter_.SetGoalPosition(PowerToPosition(goal->shot_power), 0.0);
Austin Schuh30537882014-02-18 01:07:23 -0800381
382 LOG(DEBUG, "PDIFF: absolute_position: %.2f, pow: %.2f\n",
Austin Schuhbe1401f2014-02-18 03:18:41 -0800383 shooter_.absolute_position(), PowerToPosition(goal->shot_power));
Austin Schuh30537882014-02-18 01:07:23 -0800384 if (::std::abs(shooter_.absolute_position() -
Austin Schuhbe1401f2014-02-18 03:18:41 -0800385 PowerToPosition(goal->shot_power)) +
386 ::std::abs(shooter_.absolute_velocity()) <
387 0.001) {
Austin Schuh30537882014-02-18 01:07:23 -0800388 // We are there, set the brake and move on.
389 latch_piston_ = true;
390 brake_piston_ = true;
Austin Schuh06cbbf12014-02-22 02:07:31 -0800391 shooter_brake_set_time_ = Time::Now() + kShooterBrakeSetTime;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000392 state_ = STATE_READY;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000393 } else {
Austin Schuh30537882014-02-18 01:07:23 -0800394 latch_piston_ = true;
395 brake_piston_ = false;
396 }
397 if (goal->unload_requested) {
398 Unload();
Ben Fredrickson22c93322014-02-17 05:56:33 +0000399 }
400 break;
401 case STATE_READY:
Austin Schuh30537882014-02-18 01:07:23 -0800402 LOG(DEBUG, "In ready\n");
Austin Schuhbe1401f2014-02-18 03:18:41 -0800403 // Wait until the brake is set, and a shot is requested or the shot power
404 // is changed.
Austin Schuh6b428602014-02-22 21:02:00 -0800405 if (Time::Now() > shooter_brake_set_time_) {
Austin Schuhbe1401f2014-02-18 03:18:41 -0800406 // We have waited long enough for the brake to set, turn the shooter
407 // control loop off.
Ben Fredrickson22c93322014-02-17 05:56:33 +0000408 shooter_loop_disable = true;
Austin Schuh30537882014-02-18 01:07:23 -0800409 LOG(DEBUG, "Brake is now set\n");
410 if (goal->shot_requested && !disabled) {
411 LOG(DEBUG, "Shooting now\n");
412 shooter_loop_disable = true;
Austin Schuh06cbbf12014-02-22 02:07:31 -0800413 prepare_fire_end_time_ = Time::Now() + kPrepareFireEndTime;
Austin Schuh30537882014-02-18 01:07:23 -0800414 apply_some_voltage = true;
415 state_ = STATE_PREPARE_FIRE;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000416 }
Ben Fredrickson22c93322014-02-17 05:56:33 +0000417 }
Austin Schuh6b428602014-02-22 21:02:00 -0800418 if (state_ == STATE_READY &&
419 ::std::abs(shooter_.absolute_position() -
420 PowerToPosition(goal->shot_power)) > 0.002) {
421 // TODO(austin): Add a state to release the brake.
422
423 // TODO(austin): Do we want to set the brake here or after shooting?
424 // Depends on air usage.
425 LOG(DEBUG, "Preparing shot again.\n");
426 state_ = STATE_PREPARE_SHOT;
427 }
428
Ben Fredricksona6d77542014-02-17 07:54:43 +0000429 shooter_.SetGoalPosition(PowerToPosition(goal->shot_power), 0.0);
430
Austin Schuh30537882014-02-18 01:07:23 -0800431 latch_piston_ = true;
432 brake_piston_ = true;
433
434 if (goal->unload_requested) {
435 Unload();
436 }
Ben Fredrickson22c93322014-02-17 05:56:33 +0000437 break;
Austin Schuh30537882014-02-18 01:07:23 -0800438
439 case STATE_PREPARE_FIRE:
440 // Apply a bit of voltage to bias the gears for a little bit of time, and
441 // then fire.
Ben Fredrickson22c93322014-02-17 05:56:33 +0000442 shooter_loop_disable = true;
Austin Schuh30537882014-02-18 01:07:23 -0800443 if (disabled) {
444 // If we are disabled, reset the backlash bias timer.
Austin Schuh06cbbf12014-02-22 02:07:31 -0800445 prepare_fire_end_time_ = Time::Now() + kPrepareFireEndTime;
Austin Schuh30537882014-02-18 01:07:23 -0800446 break;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000447 }
Austin Schuh30537882014-02-18 01:07:23 -0800448 if (Time::Now() > prepare_fire_end_time_) {
449 cycles_not_moved_ = 0;
450 firing_starting_position_ = shooter_.absolute_position();
Austin Schuh06cbbf12014-02-22 02:07:31 -0800451 shot_end_time_ = Time::Now() + kShotEndTimeout;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000452 state_ = STATE_FIRE;
Austin Schuhf5642a92014-02-18 01:42:32 -0800453 latch_piston_ = false;
Austin Schuh30537882014-02-18 01:07:23 -0800454 } else {
455 apply_some_voltage = true;
Austin Schuhf5642a92014-02-18 01:42:32 -0800456 latch_piston_ = true;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000457 }
458
Austin Schuh30537882014-02-18 01:07:23 -0800459 brake_piston_ = true;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000460 break;
Austin Schuh30537882014-02-18 01:07:23 -0800461
Ben Fredrickson22c93322014-02-17 05:56:33 +0000462 case STATE_FIRE:
Austin Schuh30537882014-02-18 01:07:23 -0800463 if (disabled) {
464 if (position) {
465 if (position->plunger) {
466 // If disabled and the plunger is still back there, reset the
467 // timeout.
Austin Schuh06cbbf12014-02-22 02:07:31 -0800468 shot_end_time_ = Time::Now() + kShotEndTimeout;
Austin Schuh30537882014-02-18 01:07:23 -0800469 }
470 }
471 }
Ben Fredrickson22c93322014-02-17 05:56:33 +0000472 shooter_loop_disable = true;
Austin Schuh30537882014-02-18 01:07:23 -0800473 // Count the number of contiguous cycles during which we haven't moved.
474 if (::std::abs(last_position_.position - shooter_.absolute_position()) <
475 0.0005) {
476 ++cycles_not_moved_;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000477 } else {
478 cycles_not_moved_ = 0;
479 }
Austin Schuh30537882014-02-18 01:07:23 -0800480
481 // If we have moved any amount since the start and the shooter has now
482 // been still for a couple cycles, the shot finished.
483 // Also move on if it times out.
484 if ((::std::abs(firing_starting_position_ -
485 shooter_.absolute_position()) > 0.0005 &&
486 cycles_not_moved_ > 3) ||
487 Time::Now() > shot_end_time_) {
Ben Fredrickson22c93322014-02-17 05:56:33 +0000488 state_ = STATE_REQUEST_LOAD;
489 }
Austin Schuh30537882014-02-18 01:07:23 -0800490 latch_piston_ = false;
491 brake_piston_ = true;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000492 break;
493 case STATE_UNLOAD:
Austin Schuh30537882014-02-18 01:07:23 -0800494 // Reset the timeouts.
495 if (disabled) Unload();
496
497 // If it is latched and the plunger is back, move the pusher back to catch
498 // the plunger.
Austin Schuhf84a1302014-02-19 00:23:30 -0800499 bool all_back;
500 if (position) {
501 all_back = position->plunger && position->latch;
502 } else {
503 all_back = last_position_.plunger && last_position_.latch;
504 }
505
506 if (all_back) {
Austin Schuh30537882014-02-18 01:07:23 -0800507 // Pull back to 0, 0.
508 shooter_.SetGoalPosition(0.0, 0.0);
509 if (shooter_.absolute_position() < 0.005) {
510 // When we are close enough, 'fire'.
511 latch_piston_ = false;
512 } else {
513 latch_piston_ = true;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000514 }
515 } else {
Austin Schuh30537882014-02-18 01:07:23 -0800516 // The plunger isn't all the way back, or it is and it is unlatched, so
517 // we can now unload.
518 shooter_.SetGoalPosition(shooter_.absolute_position(), 0.0);
519 latch_piston_ = false;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000520 state_ = STATE_UNLOAD_MOVE;
Austin Schuh06cbbf12014-02-22 02:07:31 -0800521 unload_timeout_ = Time::Now() + kUnloadTimeout;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000522 }
523
Austin Schuh30537882014-02-18 01:07:23 -0800524 if (Time::Now() > unload_timeout_) {
525 // We have been stuck trying to unload for way too long, give up and
526 // turn everything off.
527 state_ = STATE_ESTOP;
528 }
529
530 brake_piston_ = false;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000531 break;
Austin Schuh30537882014-02-18 01:07:23 -0800532 case STATE_UNLOAD_MOVE: {
533 if (disabled) {
Austin Schuh06cbbf12014-02-22 02:07:31 -0800534 unload_timeout_ = Time::Now() + kUnloadTimeout;
Austin Schuh30537882014-02-18 01:07:23 -0800535 shooter_.SetGoalPosition(shooter_.absolute_position(), 0.0);
536 }
Austin Schuhd34569d2014-02-18 20:26:38 -0800537 cap_goal = true;
Austin Schuh6b428602014-02-22 21:02:00 -0800538 shooter_.set_max_voltage(6.0);
Austin Schuh30537882014-02-18 01:07:23 -0800539
540 // Slowly move back until we hit the upper limit.
Austin Schuhd34569d2014-02-18 20:26:38 -0800541 // If we were at the limit last cycle, we are done unloading.
542 // This is because if we saturate, we might hit the limit before we are
543 // actually there.
544 if (shooter_.goal_position() >= values.shooter.upper_limit) {
Austin Schuh30537882014-02-18 01:07:23 -0800545 shooter_.SetGoalPosition(values.shooter.upper_limit, 0.0);
546 // We don't want the loop fighting the spring when we are unloaded.
547 // Turn it off.
548 shooter_loop_disable = true;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000549 state_ = STATE_READY_UNLOAD;
550 } else {
Austin Schuhd34569d2014-02-18 20:26:38 -0800551 shooter_.SetGoalPosition(
552 ::std::min(
553 values.shooter.upper_limit,
Austin Schuh6b428602014-02-22 21:02:00 -0800554 shooter_.goal_position() + values.shooter.unload_speed * dt),
555 values.shooter.unload_speed);
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000556 }
557
Austin Schuh30537882014-02-18 01:07:23 -0800558 latch_piston_ = false;
559 brake_piston_ = false;
560 } break;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000561 case STATE_READY_UNLOAD:
Austin Schuh30537882014-02-18 01:07:23 -0800562 if (goal->load_requested) {
Ben Fredrickson22c93322014-02-17 05:56:33 +0000563 state_ = STATE_REQUEST_LOAD;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000564 }
Austin Schuh30537882014-02-18 01:07:23 -0800565 // If we are ready to load again,
566 shooter_loop_disable = true;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000567
Austin Schuh30537882014-02-18 01:07:23 -0800568 latch_piston_ = false;
569 brake_piston_ = false;
570 break;
571
572 case STATE_ESTOP:
573 // Totally lost, go to a safe state.
574 shooter_loop_disable = true;
575 latch_piston_ = true;
576 brake_piston_ = true;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000577 break;
joe2d92e852014-01-25 14:31:24 -0800578 }
579
Ben Fredrickson7d980c22014-02-16 21:39:02 +0000580 if (apply_some_voltage) {
Ben Fredrickson22c93322014-02-17 05:56:33 +0000581 shooter_.Update(true);
Austin Schuhd34569d2014-02-18 20:26:38 -0800582 shooter_.ZeroPower();
Ben Fredrickson22c93322014-02-17 05:56:33 +0000583 if (output) output->voltage = 2.0;
Ben Fredrickson7d980c22014-02-16 21:39:02 +0000584 } else if (!shooter_loop_disable) {
Austin Schuh30537882014-02-18 01:07:23 -0800585 LOG(DEBUG, "Running the loop, goal is %f, position is %f\n",
586 shooter_.goal_position(), shooter_.absolute_position());
Austin Schuhd34569d2014-02-18 20:26:38 -0800587 if (!cap_goal) {
588 shooter_.set_max_voltage(12.0);
589 }
Ben Fredrickson22c93322014-02-17 05:56:33 +0000590 shooter_.Update(output == NULL);
Austin Schuhd34569d2014-02-18 20:26:38 -0800591 if (cap_goal) {
592 shooter_.CapGoal();
593 }
Ben Fredrickson22c93322014-02-17 05:56:33 +0000594 if (output) output->voltage = shooter_.voltage();
Ben Fredrickson7d980c22014-02-16 21:39:02 +0000595 } else {
Ben Fredrickson22c93322014-02-17 05:56:33 +0000596 shooter_.Update(true);
Austin Schuhd34569d2014-02-18 20:26:38 -0800597 shooter_.ZeroPower();
Ben Fredrickson22c93322014-02-17 05:56:33 +0000598 if (output) output->voltage = 0.0;
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000599 }
Ben Fredrickson7d980c22014-02-16 21:39:02 +0000600
Austin Schuh30537882014-02-18 01:07:23 -0800601 if (output) {
602 output->latch_piston = latch_piston_;
603 output->brake_piston = brake_piston_;
604 }
605
Austin Schuhd34569d2014-02-18 20:26:38 -0800606 status->done = ::std::abs(shooter_.absolute_position() -
607 PowerToPosition(goal->shot_power)) < 0.004;
Austin Schuh30537882014-02-18 01:07:23 -0800608
609 if (position) {
610 last_position_ = *position;
Ben Fredricksona9dcfa42014-02-23 02:05:59 +0000611 LOG(DEBUG, "pos > absolute: %f velocity: %f state= %d l= %d pp= %d, pd= %d "
612 "p= %d b=%d\n",
Austin Schuhbe1401f2014-02-18 03:18:41 -0800613 shooter_.absolute_position(), shooter_.absolute_velocity(),
Ben Fredricksona9dcfa42014-02-23 02:05:59 +0000614 state_, position->latch, position->pusher_proximal.current,
615 position->pusher_distal.current,
616 position->plunger, brake_piston_);
Austin Schuh30537882014-02-18 01:07:23 -0800617 }
618 if (position) {
619 last_distal_posedge_count_ = position->pusher_distal.posedge_count;
620 last_proximal_posedge_count_ = position->pusher_proximal.posedge_count;
621 }
joe2d92e852014-01-25 14:31:24 -0800622}
623
624} // namespace control_loops
625} // namespace frc971