blob: 763f005dcc00b17ecd30db41dc241c1a40bccd36 [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) {
119 // LOG(WARNING, "power to position not correctly implemented\n");
120 const frc971::constants::Values &values = constants::GetValues();
121 double new_pos = ::std::min(::std::max(power, values.shooter.lower_limit),
122 values.shooter.upper_limit);
123 return new_pos;
124}
Ben Fredrickson1e512ff2014-02-15 21:36:52 +0000125
126// Positive is out, and positive power is out.
joe2d92e852014-01-25 14:31:24 -0800127void ShooterMotor::RunIteration(
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000128 const control_loops::ShooterGroup::Goal *goal,
129 const control_loops::ShooterGroup::Position *position,
130 control_loops::ShooterGroup::Output *output,
Ben Fredrickson22c93322014-02-17 05:56:33 +0000131 control_loops::ShooterGroup::Status *status) {
Ben Fredrickson1e512ff2014-02-15 21:36:52 +0000132 constexpr double dt = 0.01;
133
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000134 // we must always have these or we have issues.
135 if (goal == NULL || status == NULL) {
Ben Fredrickson22c93322014-02-17 05:56:33 +0000136 if (output) output->voltage = 0;
137 LOG(ERROR, "Thought I would just check for null and die.\n");
138 return;
139 }
140
Austin Schuh30537882014-02-18 01:07:23 -0800141 if (reset()) {
142 state_ = STATE_INITIALIZE;
143 }
144 if (position) {
145 shooter_.CorrectPosition(position->position);
Ben Fredrickson1e512ff2014-02-15 21:36:52 +0000146 }
joe2d92e852014-01-25 14:31:24 -0800147
148 // Disable the motors now so that all early returns will return with the
149 // motors disabled.
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000150 if (output) output->voltage = 0;
joe2d92e852014-01-25 14:31:24 -0800151
Ben Fredrickson1e512ff2014-02-15 21:36:52 +0000152 const frc971::constants::Values &values = constants::GetValues();
153
Brian Silvermanaae236a2014-02-17 01:49:39 -0800154 // Don't even let the control loops run.
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000155 bool shooter_loop_disable = false;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000156
Brian Silvermanaae236a2014-02-17 01:49:39 -0800157 // Adds voltage to take up slack in gears before shot.
Ben Fredrickson7d980c22014-02-16 21:39:02 +0000158 bool apply_some_voltage = false;
159
Austin Schuhd34569d2014-02-18 20:26:38 -0800160
Austin Schuh30537882014-02-18 01:07:23 -0800161 const bool disabled = !::aos::robot_state->enabled;
Austin Schuhd34569d2014-02-18 20:26:38 -0800162 // If true, move the goal if we saturate.
163 bool cap_goal = false;
164
165 // TODO(austin): Move the offset if we see or don't see a hall effect when we
166 // expect to see one.
167 // Probably not needed yet.
168
169 if (position) {
170 int last_controller_index = shooter_.controller_index();
171 if (position->plunger && position->latch) {
172 // Use the controller without the spring if the latch is set and the
173 // plunger is back
174 shooter_.set_controller_index(1);
175 } else {
176 // Otherwise use the controller with the spring.
177 shooter_.set_controller_index(0);
178 }
179 if (shooter_.controller_index() != last_controller_index) {
180 shooter_.RecalculatePowerGoal();
181 }
182 }
Austin Schuh30537882014-02-18 01:07:23 -0800183
Ben Fredrickson1e512ff2014-02-15 21:36:52 +0000184 switch (state_) {
Ben Fredrickson22c93322014-02-17 05:56:33 +0000185 case STATE_INITIALIZE:
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000186 if (position) {
Austin Schuh30537882014-02-18 01:07:23 -0800187 // Reinitialize the internal filter state.
188 shooter_.InitializeState(position->position);
Austin Schuh30537882014-02-18 01:07:23 -0800189
190 // Start off with the assumption that we are at the value
191 // futhest back given our sensors.
192 if (position->pusher_distal.current) {
193 shooter_.SetCalibration(position->position,
194 values.shooter.pusher_distal.lower_angle);
195 } else if (position->pusher_proximal.current) {
196 shooter_.SetCalibration(position->position,
Austin Schuhd34569d2014-02-18 20:26:38 -0800197 values.shooter.pusher_proximal.upper_angle);
Austin Schuh30537882014-02-18 01:07:23 -0800198 } else {
199 shooter_.SetCalibration(position->position,
200 values.shooter.upper_limit);
201 }
202
203 state_ = STATE_REQUEST_LOAD;
204
205 // Go to the current position.
206 shooter_.SetGoalPosition(shooter_.absolute_position(), 0.0);
207 // If the plunger is all the way back, we want to be latched.
208 latch_piston_ = position->plunger;
209 brake_piston_ = false;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000210 } else {
Austin Schuh30537882014-02-18 01:07:23 -0800211 // If we can't start yet because we don't know where we are, set the
212 // latch and brake to their defaults.
213 latch_piston_ = true;
214 brake_piston_ = true;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000215 }
Ben Fredrickson22c93322014-02-17 05:56:33 +0000216 break;
217 case STATE_REQUEST_LOAD:
Austin Schuh30537882014-02-18 01:07:23 -0800218 if (position) {
Austin Schuh30537882014-02-18 01:07:23 -0800219 if (position->plunger && position->latch) {
220 // The plunger is back and we are latched, get ready to shoot.
221 state_ = STATE_PREPARE_SHOT;
222 latch_piston_ = true;
223 } else if (position->pusher_distal.current) {
224 // We started on the sensor, back up until we are found.
225 // If the plunger is all the way back and not latched, it won't be
226 // there for long.
227 state_ = STATE_LOAD_BACKTRACK;
228 latch_piston_ = false;
229 } else {
230 // Off the sensor, start loading.
231 Load();
232 latch_piston_ = false;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000233 }
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000234 }
235
Austin Schuh30537882014-02-18 01:07:23 -0800236 // Hold our current position.
237 shooter_.SetGoalPosition(shooter_.absolute_position(), 0.0);
238 brake_piston_ = false;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000239 break;
240 case STATE_LOAD_BACKTRACK:
Austin Schuh30537882014-02-18 01:07:23 -0800241 // If we are here, then that means we started past the edge where we want
242 // to zero. Move backwards until we don't see the sensor anymore.
243 // The plunger is contacting the pusher (or will be shortly).
244
Austin Schuh30537882014-02-18 01:07:23 -0800245 if (!disabled) {
Ben Fredrickson22c93322014-02-17 05:56:33 +0000246 shooter_.SetGoalPosition(
Austin Schuhfaeee632014-02-18 01:24:05 -0800247 shooter_.goal_position() + values.shooter.zeroing_speed * dt,
248 values.shooter.zeroing_speed);
Ben Fredrickson22c93322014-02-17 05:56:33 +0000249 }
Austin Schuhd34569d2014-02-18 20:26:38 -0800250 cap_goal = true;
251 shooter_.set_max_voltage(12.0);
Ben Fredrickson22c93322014-02-17 05:56:33 +0000252
Austin Schuh30537882014-02-18 01:07:23 -0800253 if (position) {
254 if (!position->pusher_distal.current) {
255 Load();
256 }
257 }
258
259 latch_piston_ = false;
260 brake_piston_ = false;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000261 break;
262 case STATE_LOAD:
Austin Schuh30537882014-02-18 01:07:23 -0800263 // If we are disabled right now, reset the timer.
264 if (disabled) {
265 Load();
266 // Latch defaults to true when disabled. Leave it latched until we have
267 // useful sensor data.
268 latch_piston_ = true;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000269 }
Austin Schuh30537882014-02-18 01:07:23 -0800270 // Go to 0, which should be the latch position, or trigger a hall effect
271 // on the way. If we don't see edges where we are supposed to, the
272 // offset will be updated by code above.
273 shooter_.SetGoalPosition(0.0, 0.0);
Ben Fredrickson22c93322014-02-17 05:56:33 +0000274
Austin Schuh30537882014-02-18 01:07:23 -0800275 if (position) {
276 // If we see a posedge on any of the hall effects,
277 if (position->pusher_proximal.posedge_count !=
278 last_proximal_posedge_count_) {
279 LOG(DEBUG, "Setting calibration using proximal sensor\n");
280 shooter_.SetCalibration(position->pusher_proximal.posedge_value,
281 values.shooter.pusher_proximal.upper_angle);
282 }
283 if (position->pusher_distal.posedge_count !=
284 last_distal_posedge_count_) {
285 LOG(DEBUG, "Setting calibration using distal sensor\n");
286 shooter_.SetCalibration(position->pusher_distal.posedge_value,
287 values.shooter.pusher_distal.upper_angle);
288 }
Ben Fredrickson22c93322014-02-17 05:56:33 +0000289
Austin Schuh30537882014-02-18 01:07:23 -0800290 // Latch if the plunger is far enough back to trigger the hall effect.
291 // This happens when the distal sensor is triggered.
292 latch_piston_ = position->pusher_distal.current;
293
294 // Check if we are latched and back.
295 if (position->plunger && position->latch) {
296 state_ = STATE_PREPARE_SHOT;
297 } else if (position->plunger &&
298 ::std::abs(shooter_.absolute_position() -
299 shooter_.goal_position()) < 0.001) {
300 // We are at the goal, but not latched.
301 state_ = STATE_LOADING_PROBLEM;
302 loading_problem_end_time_ = Time::Now() + Time::InSeconds(0.5);
303 }
Ben Fredrickson22c93322014-02-17 05:56:33 +0000304 }
Austin Schuh30537882014-02-18 01:07:23 -0800305 if (load_timeout_ < Time::Now()) {
306 if (position) {
307 if (!position->pusher_distal.current ||
308 !position->pusher_proximal.current) {
309 state_ = STATE_ESTOP;
310 }
311 }
312 } else if (goal->unload_requested) {
313 Unload();
314 }
315 brake_piston_ = false;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000316 break;
317 case STATE_LOADING_PROBLEM:
Austin Schuh30537882014-02-18 01:07:23 -0800318 if (disabled) {
319 Load();
320 }
321 // We got to the goal, but the latch hasn't registered as down. It might
322 // be stuck, or on it's way but not there yet.
Ben Fredrickson22c93322014-02-17 05:56:33 +0000323 if (Time::Now() > loading_problem_end_time_) {
Austin Schuh30537882014-02-18 01:07:23 -0800324 // Timeout by unloading.
325 Unload();
326 } else if (position && position->plunger && position->latch) {
327 // If both trigger, we are latched.
Ben Fredrickson22c93322014-02-17 05:56:33 +0000328 state_ = STATE_PREPARE_SHOT;
329 }
Austin Schuh30537882014-02-18 01:07:23 -0800330 // Move a bit further back to help it trigger.
331 // If the latch is slow due to the air flowing through the tubes or
332 // inertia, but is otherwise free, this won't have much time to do
333 // anything and is safe. Otherwise this gives us a bit more room to free
334 // up the latch.
335 shooter_.SetGoalPosition(values.shooter.lower_limit, 0.0);
Ben Fredrickson22c93322014-02-17 05:56:33 +0000336 LOG(DEBUG, "Waiting on latch: plunger %d, latch: %d\n",
Austin Schuh60c56662014-02-17 14:37:19 -0800337 position->plunger, position->latch);
Ben Fredrickson22c93322014-02-17 05:56:33 +0000338
Austin Schuh30537882014-02-18 01:07:23 -0800339 latch_piston_ = true;
340 brake_piston_ = false;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000341 break;
342 case STATE_PREPARE_SHOT:
Austin Schuh30537882014-02-18 01:07:23 -0800343 // Move the shooter to the shot power set point and then lock the brake.
344 // TODO(austin): Timeout. Low priority.
345
Ben Fredrickson22c93322014-02-17 05:56:33 +0000346 shooter_.SetGoalPosition(PowerToPosition(goal->shot_power), 0.0);
Austin Schuh30537882014-02-18 01:07:23 -0800347
348 LOG(DEBUG, "PDIFF: absolute_position: %.2f, pow: %.2f\n",
Austin Schuhbe1401f2014-02-18 03:18:41 -0800349 shooter_.absolute_position(), PowerToPosition(goal->shot_power));
Austin Schuh30537882014-02-18 01:07:23 -0800350 if (::std::abs(shooter_.absolute_position() -
Austin Schuhbe1401f2014-02-18 03:18:41 -0800351 PowerToPosition(goal->shot_power)) +
352 ::std::abs(shooter_.absolute_velocity()) <
353 0.001) {
Austin Schuh30537882014-02-18 01:07:23 -0800354 // We are there, set the brake and move on.
355 latch_piston_ = true;
356 brake_piston_ = true;
357 shooter_brake_set_time_ = Time::Now() + Time::InSeconds(0.05);
Ben Fredrickson22c93322014-02-17 05:56:33 +0000358 state_ = STATE_READY;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000359 } else {
Austin Schuh30537882014-02-18 01:07:23 -0800360 latch_piston_ = true;
361 brake_piston_ = false;
362 }
363 if (goal->unload_requested) {
364 Unload();
Ben Fredrickson22c93322014-02-17 05:56:33 +0000365 }
366 break;
367 case STATE_READY:
Austin Schuh30537882014-02-18 01:07:23 -0800368 LOG(DEBUG, "In ready\n");
Austin Schuhbe1401f2014-02-18 03:18:41 -0800369 // Wait until the brake is set, and a shot is requested or the shot power
370 // is changed.
371 if (::std::abs(shooter_.absolute_position() -
372 PowerToPosition(goal->shot_power)) > 0.002) {
373 // TODO(austin): Add a state to release the brake.
374
375 // TODO(austin): Do we want to set the brake here or after shooting?
376 // Depends on air usage.
377 LOG(DEBUG, "Preparing shot again.\n");
378 state_ = STATE_PREPARE_SHOT;
379 } else if (Time::Now() > shooter_brake_set_time_) {
380 // We have waited long enough for the brake to set, turn the shooter
381 // control loop off.
Ben Fredrickson22c93322014-02-17 05:56:33 +0000382 shooter_loop_disable = true;
Austin Schuh30537882014-02-18 01:07:23 -0800383 LOG(DEBUG, "Brake is now set\n");
384 if (goal->shot_requested && !disabled) {
385 LOG(DEBUG, "Shooting now\n");
386 shooter_loop_disable = true;
387 prepare_fire_end_time_ =
388 Time::Now(Time::kDefaultClock) + Time::InMS(40.0);
389 apply_some_voltage = true;
390 state_ = STATE_PREPARE_FIRE;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000391 }
Austin Schuh30537882014-02-18 01:07:23 -0800392 } else {
393 LOG(DEBUG, "Nothing %d %d\n", goal->shot_requested, !disabled);
Ben Fredrickson22c93322014-02-17 05:56:33 +0000394 }
Ben Fredricksona6d77542014-02-17 07:54:43 +0000395 shooter_.SetGoalPosition(PowerToPosition(goal->shot_power), 0.0);
396
Austin Schuh30537882014-02-18 01:07:23 -0800397 latch_piston_ = true;
398 brake_piston_ = true;
399
400 if (goal->unload_requested) {
401 Unload();
402 }
Ben Fredrickson22c93322014-02-17 05:56:33 +0000403 break;
Austin Schuh30537882014-02-18 01:07:23 -0800404
405 case STATE_PREPARE_FIRE:
406 // Apply a bit of voltage to bias the gears for a little bit of time, and
407 // then fire.
Ben Fredrickson22c93322014-02-17 05:56:33 +0000408 shooter_loop_disable = true;
Austin Schuh30537882014-02-18 01:07:23 -0800409 if (disabled) {
410 // If we are disabled, reset the backlash bias timer.
Ben Fredrickson22c93322014-02-17 05:56:33 +0000411 prepare_fire_end_time_ =
412 Time::Now(Time::kDefaultClock) + Time::InMS(40.0);
Austin Schuh30537882014-02-18 01:07:23 -0800413 break;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000414 }
Austin Schuh30537882014-02-18 01:07:23 -0800415 if (Time::Now() > prepare_fire_end_time_) {
416 cycles_not_moved_ = 0;
417 firing_starting_position_ = shooter_.absolute_position();
418 shot_end_time_ = Time::Now() + Time::InSeconds(1);
Ben Fredrickson22c93322014-02-17 05:56:33 +0000419 state_ = STATE_FIRE;
Austin Schuhf5642a92014-02-18 01:42:32 -0800420 latch_piston_ = false;
Austin Schuh30537882014-02-18 01:07:23 -0800421 } else {
422 apply_some_voltage = true;
Austin Schuhf5642a92014-02-18 01:42:32 -0800423 latch_piston_ = true;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000424 }
425
Austin Schuh30537882014-02-18 01:07:23 -0800426 brake_piston_ = true;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000427 break;
Austin Schuh30537882014-02-18 01:07:23 -0800428
Ben Fredrickson22c93322014-02-17 05:56:33 +0000429 case STATE_FIRE:
Austin Schuh30537882014-02-18 01:07:23 -0800430 if (disabled) {
431 if (position) {
432 if (position->plunger) {
433 // If disabled and the plunger is still back there, reset the
434 // timeout.
435 shot_end_time_ = Time::Now() + Time::InSeconds(1);
436 }
437 }
438 }
Ben Fredrickson22c93322014-02-17 05:56:33 +0000439 shooter_loop_disable = true;
Austin Schuh30537882014-02-18 01:07:23 -0800440 // Count the number of contiguous cycles during which we haven't moved.
441 if (::std::abs(last_position_.position - shooter_.absolute_position()) <
442 0.0005) {
443 ++cycles_not_moved_;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000444 } else {
445 cycles_not_moved_ = 0;
446 }
Austin Schuh30537882014-02-18 01:07:23 -0800447
448 // If we have moved any amount since the start and the shooter has now
449 // been still for a couple cycles, the shot finished.
450 // Also move on if it times out.
451 if ((::std::abs(firing_starting_position_ -
452 shooter_.absolute_position()) > 0.0005 &&
453 cycles_not_moved_ > 3) ||
454 Time::Now() > shot_end_time_) {
Ben Fredrickson22c93322014-02-17 05:56:33 +0000455 state_ = STATE_REQUEST_LOAD;
456 }
Austin Schuh30537882014-02-18 01:07:23 -0800457 latch_piston_ = false;
458 brake_piston_ = true;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000459 break;
460 case STATE_UNLOAD:
Austin Schuh30537882014-02-18 01:07:23 -0800461 // Reset the timeouts.
462 if (disabled) Unload();
463
464 // If it is latched and the plunger is back, move the pusher back to catch
465 // the plunger.
Austin Schuhf84a1302014-02-19 00:23:30 -0800466 bool all_back;
467 if (position) {
468 all_back = position->plunger && position->latch;
469 } else {
470 all_back = last_position_.plunger && last_position_.latch;
471 }
472
473 if (all_back) {
Austin Schuh30537882014-02-18 01:07:23 -0800474 // Pull back to 0, 0.
475 shooter_.SetGoalPosition(0.0, 0.0);
476 if (shooter_.absolute_position() < 0.005) {
477 // When we are close enough, 'fire'.
478 latch_piston_ = false;
479 } else {
480 latch_piston_ = true;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000481 }
482 } else {
Austin Schuh30537882014-02-18 01:07:23 -0800483 // The plunger isn't all the way back, or it is and it is unlatched, so
484 // we can now unload.
485 shooter_.SetGoalPosition(shooter_.absolute_position(), 0.0);
486 latch_piston_ = false;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000487 state_ = STATE_UNLOAD_MOVE;
Austin Schuh30537882014-02-18 01:07:23 -0800488 unload_timeout_ = Time::Now() + Time::InSeconds(2.0);
Ben Fredrickson22c93322014-02-17 05:56:33 +0000489 }
490
Austin Schuh30537882014-02-18 01:07:23 -0800491 if (Time::Now() > unload_timeout_) {
492 // We have been stuck trying to unload for way too long, give up and
493 // turn everything off.
494 state_ = STATE_ESTOP;
495 }
496
497 brake_piston_ = false;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000498 break;
Austin Schuh30537882014-02-18 01:07:23 -0800499 case STATE_UNLOAD_MOVE: {
500 if (disabled) {
501 unload_timeout_ = Time::Now() + Time::InSeconds(2.0);
502 shooter_.SetGoalPosition(shooter_.absolute_position(), 0.0);
503 }
Austin Schuhd34569d2014-02-18 20:26:38 -0800504 cap_goal = true;
505 shooter_.set_max_voltage(6.0);
Austin Schuh30537882014-02-18 01:07:23 -0800506
507 // Slowly move back until we hit the upper limit.
Austin Schuhd34569d2014-02-18 20:26:38 -0800508 // If we were at the limit last cycle, we are done unloading.
509 // This is because if we saturate, we might hit the limit before we are
510 // actually there.
511 if (shooter_.goal_position() >= values.shooter.upper_limit) {
Austin Schuh30537882014-02-18 01:07:23 -0800512 shooter_.SetGoalPosition(values.shooter.upper_limit, 0.0);
513 // We don't want the loop fighting the spring when we are unloaded.
514 // Turn it off.
515 shooter_loop_disable = true;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000516 state_ = STATE_READY_UNLOAD;
517 } else {
Austin Schuhd34569d2014-02-18 20:26:38 -0800518 shooter_.SetGoalPosition(
519 ::std::min(
520 values.shooter.upper_limit,
521 shooter_.goal_position() + values.shooter.zeroing_speed * dt),
522 values.shooter.zeroing_speed);
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000523 }
524
Austin Schuh30537882014-02-18 01:07:23 -0800525 latch_piston_ = false;
526 brake_piston_ = false;
527 } break;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000528 case STATE_READY_UNLOAD:
Austin Schuh30537882014-02-18 01:07:23 -0800529 if (goal->load_requested) {
Ben Fredrickson22c93322014-02-17 05:56:33 +0000530 state_ = STATE_REQUEST_LOAD;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000531 }
Austin Schuh30537882014-02-18 01:07:23 -0800532 // If we are ready to load again,
533 shooter_loop_disable = true;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000534
Austin Schuh30537882014-02-18 01:07:23 -0800535 latch_piston_ = false;
536 brake_piston_ = false;
537 break;
538
539 case STATE_ESTOP:
540 // Totally lost, go to a safe state.
541 shooter_loop_disable = true;
542 latch_piston_ = true;
543 brake_piston_ = true;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000544 break;
joe2d92e852014-01-25 14:31:24 -0800545 }
546
Ben Fredrickson7d980c22014-02-16 21:39:02 +0000547 if (apply_some_voltage) {
Ben Fredrickson22c93322014-02-17 05:56:33 +0000548 shooter_.Update(true);
Austin Schuhd34569d2014-02-18 20:26:38 -0800549 shooter_.ZeroPower();
Ben Fredrickson22c93322014-02-17 05:56:33 +0000550 if (output) output->voltage = 2.0;
Ben Fredrickson7d980c22014-02-16 21:39:02 +0000551 } else if (!shooter_loop_disable) {
Austin Schuh30537882014-02-18 01:07:23 -0800552 LOG(DEBUG, "Running the loop, goal is %f, position is %f\n",
553 shooter_.goal_position(), shooter_.absolute_position());
Austin Schuhd34569d2014-02-18 20:26:38 -0800554 if (!cap_goal) {
555 shooter_.set_max_voltage(12.0);
556 }
Ben Fredrickson22c93322014-02-17 05:56:33 +0000557 shooter_.Update(output == NULL);
Austin Schuhd34569d2014-02-18 20:26:38 -0800558 if (cap_goal) {
559 shooter_.CapGoal();
560 }
Ben Fredrickson22c93322014-02-17 05:56:33 +0000561 if (output) output->voltage = shooter_.voltage();
Ben Fredrickson7d980c22014-02-16 21:39:02 +0000562 } else {
Ben Fredrickson22c93322014-02-17 05:56:33 +0000563 shooter_.Update(true);
Austin Schuhd34569d2014-02-18 20:26:38 -0800564 shooter_.ZeroPower();
Ben Fredrickson22c93322014-02-17 05:56:33 +0000565 if (output) output->voltage = 0.0;
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000566 }
Ben Fredrickson7d980c22014-02-16 21:39:02 +0000567
Austin Schuh30537882014-02-18 01:07:23 -0800568 if (output) {
569 output->latch_piston = latch_piston_;
570 output->brake_piston = brake_piston_;
571 }
572
Austin Schuhd34569d2014-02-18 20:26:38 -0800573 status->done = ::std::abs(shooter_.absolute_position() -
574 PowerToPosition(goal->shot_power)) < 0.004;
Austin Schuh30537882014-02-18 01:07:23 -0800575
576 if (position) {
577 last_position_ = *position;
578 LOG(DEBUG,
Austin Schuhbe1401f2014-02-18 03:18:41 -0800579 "pos > absolute: %f velocity: %f state= %d\n",
580 shooter_.absolute_position(), shooter_.absolute_velocity(),
Austin Schuh30537882014-02-18 01:07:23 -0800581 state_);
582 }
583 if (position) {
584 last_distal_posedge_count_ = position->pusher_distal.posedge_count;
585 last_proximal_posedge_count_ = position->pusher_proximal.posedge_count;
586 }
joe2d92e852014-01-25 14:31:24 -0800587}
588
589} // namespace control_loops
590} // namespace frc971