blob: 11f930fb5e6e2e0d00635eff2e040c80773c6162 [file] [log] [blame]
Austin Schuh00558222013-03-03 14:16:16 -08001#include "frc971/control_loops/index/index.h"
Austin Schuhd78ab542013-03-01 22:22:19 -08002
3#include <stdio.h>
4
5#include <algorithm>
6
7#include "aos/aos_core.h"
8
9#include "aos/common/messages/RobotState.q.h"
10#include "aos/common/control_loop/control_loops.q.h"
11#include "aos/common/logging/logging.h"
12
13#include "frc971/constants.h"
Austin Schuh00558222013-03-03 14:16:16 -080014#include "frc971/control_loops/index/index_motor_plant.h"
Austin Schuhd78ab542013-03-01 22:22:19 -080015
16using ::aos::time::Time;
17
18namespace frc971 {
19namespace control_loops {
20
21IndexMotor::IndexMotor(control_loops::IndexLoop *my_index)
22 : aos::control_loops::ControlLoop<control_loops::IndexLoop>(my_index),
Austin Schuh93485832013-03-04 00:01:34 -080023 wrist_loop_(new IndexStateFeedbackLoop(MakeIndexLoop())),
Austin Schuhd78ab542013-03-01 22:22:19 -080024 hopper_disc_count_(0),
25 total_disc_count_(0),
Austin Schuhf8c52252013-03-03 02:25:49 -080026 safe_goal_(Goal::HOLD),
27 loader_goal_(LoaderGoal::READY),
28 loader_state_(LoaderState::READY),
Austin Schuhd78ab542013-03-01 22:22:19 -080029 loader_up_(false),
30 disc_clamped_(false),
31 disc_ejected_(false),
Austin Schuhbcdb90c2013-03-03 23:24:58 -080032 last_bottom_disc_detect_(false),
33 no_prior_position_(true),
34 missing_position_count_(0) {
Austin Schuhd78ab542013-03-01 22:22:19 -080035}
36
Austin Schuhf8c52252013-03-03 02:25:49 -080037/*static*/ const double IndexMotor::kTransferStartPosition = 0.0;
38/*static*/ const double IndexMotor::kIndexStartPosition = 0.2159;
39/*static*/ const double IndexMotor::kIndexFreeLength =
40 IndexMotor::ConvertDiscAngleToDiscPosition((360 * 2 + 14) * M_PI / 180);
41/*static*/ const double IndexMotor::kLoaderFreeStopPosition =
42 kIndexStartPosition + kIndexFreeLength;
43/*static*/ const double IndexMotor::kReadyToLiftPosition =
44 kLoaderFreeStopPosition + 0.2921;
45/*static*/ const double IndexMotor::kGrabberLength = 0.03175;
46/*static*/ const double IndexMotor::kGrabberStartPosition =
47 kReadyToLiftPosition - kGrabberLength;
48/*static*/ const double IndexMotor::kGrabberMovementVelocity = 0.5;
49/*static*/ const double IndexMotor::kLifterStopPosition =
50 kReadyToLiftPosition + 0.161925;
51/*static*/ const double IndexMotor::kLifterMovementVelocity = 1.0;
52/*static*/ const double IndexMotor::kEjectorStopPosition =
53 kLifterStopPosition + 0.01;
54/*static*/ const double IndexMotor::kEjectorMovementVelocity = 1.0;
55/*static*/ const double IndexMotor::kBottomDiscDetectStart = -0.08;
56/*static*/ const double IndexMotor::kBottomDiscDetectStop = 0.200025;
57
58// TODO(aschuh): Figure these out.
59/*static*/ const double IndexMotor::kTopDiscDetectStart = 18.0;
60/*static*/ const double IndexMotor::kTopDiscDetectStop = 19.0;
61
Austin Schuhd78ab542013-03-01 22:22:19 -080062const /*static*/ double IndexMotor::kDiscRadius = 10.875 * 0.0254 / 2;
63const /*static*/ double IndexMotor::kRollerRadius = 2.0 * 0.0254 / 2;
Austin Schuhf8c52252013-03-03 02:25:49 -080064const /*static*/ double IndexMotor::kTransferRollerRadius = 1.25 * 0.0254 / 2;
Austin Schuhd78ab542013-03-01 22:22:19 -080065
Austin Schuhf8c52252013-03-03 02:25:49 -080066/*static*/ const int IndexMotor::kGrabbingDelay = 5;
67/*static*/ const int IndexMotor::kLiftingDelay = 20;
68/*static*/ const int IndexMotor::kShootingDelay = 5;
69/*static*/ const int IndexMotor::kLoweringDelay = 20;
Austin Schuhd78ab542013-03-01 22:22:19 -080070
Austin Schuh93485832013-03-04 00:01:34 -080071// TODO(aschuh): Tune these.
72/*static*/ const double
73 IndexMotor::IndexStateFeedbackLoop::kMinMotionVoltage = 5.0;
74/*static*/ const double
75 IndexMotor::IndexStateFeedbackLoop::kNoMotionCuttoffCount = 30;
76
Austin Schuhd78ab542013-03-01 22:22:19 -080077// Distance to move the indexer when grabbing a disc.
78const double kNextPosition = 10.0;
79
80/*static*/ double IndexMotor::ConvertDiscAngleToIndex(const double angle) {
81 return (angle * (1 + (kDiscRadius * 2 + kRollerRadius) / kRollerRadius));
82}
83
Austin Schuhf8c52252013-03-03 02:25:49 -080084/*static*/ double IndexMotor::ConvertDiscAngleToDiscPosition(
85 const double angle) {
Austin Schuhd78ab542013-03-01 22:22:19 -080086 return angle * (kDiscRadius + kRollerRadius);
87}
88
Austin Schuhf8c52252013-03-03 02:25:49 -080089/*static*/ double IndexMotor::ConvertDiscPositionToDiscAngle(
90 const double position) {
91 return position / (kDiscRadius + kRollerRadius);
92}
93
Austin Schuhd78ab542013-03-01 22:22:19 -080094/*static*/ double IndexMotor::ConvertIndexToDiscAngle(const double angle) {
95 return (angle / (1 + (kDiscRadius * 2 + kRollerRadius) / kRollerRadius));
96}
97
98/*static*/ double IndexMotor::ConvertIndexToDiscPosition(const double angle) {
99 return IndexMotor::ConvertDiscAngleToDiscPosition(
100 ConvertIndexToDiscAngle(angle));
101}
102
Austin Schuhf8c52252013-03-03 02:25:49 -0800103/*static*/ double IndexMotor::ConvertTransferToDiscPosition(
104 const double angle) {
105 const double gear_ratio = (1 + (kDiscRadius * 2 + kTransferRollerRadius) /
106 kTransferRollerRadius);
107 return angle / gear_ratio * (kDiscRadius + kTransferRollerRadius);
108}
109
110/*static*/ double IndexMotor::ConvertDiscPositionToIndex(
111 const double position) {
112 return IndexMotor::ConvertDiscAngleToIndex(
113 ConvertDiscPositionToDiscAngle(position));
114}
115
116bool IndexMotor::MinDiscPosition(double *disc_position) {
117 bool found_start = false;
118 for (unsigned int i = 0; i < frisbees_.size(); ++i) {
119 const Frisbee &frisbee = frisbees_[i];
120 if (!found_start) {
121 if (frisbee.has_position()) {
122 *disc_position = frisbee.position();
123 found_start = true;
124 }
125 } else {
126 *disc_position = ::std::min(frisbee.position(),
127 *disc_position);
128 }
129 }
130 return found_start;
131}
132
133bool IndexMotor::MaxDiscPosition(double *disc_position) {
134 bool found_start = false;
135 for (unsigned int i = 0; i < frisbees_.size(); ++i) {
136 const Frisbee &frisbee = frisbees_[i];
137 if (!found_start) {
138 if (frisbee.has_position()) {
139 *disc_position = frisbee.position();
140 found_start = true;
141 }
142 } else {
143 *disc_position = ::std::max(frisbee.position(),
144 *disc_position);
145 }
146 }
147 return found_start;
148}
149
Austin Schuh93485832013-03-04 00:01:34 -0800150void IndexMotor::IndexStateFeedbackLoop::CapU() {
151 // If the voltage has been low for a large number of cycles, cut the motor
152 // power. This is generally very bad controls practice since this isn't LTI,
153 // but we don't really care about tracking anything other than large step
154 // inputs, and the loader doesn't need to be that accurate.
155 if (::std::abs(U(0, 0)) < kMinMotionVoltage) {
156 ++low_voltage_count_;
157 if (low_voltage_count_ > kNoMotionCuttoffCount) {
158 printf("Limiting power from %f to 0\n", U(0, 0));
159 U(0, 0) = 0.0;
160 }
161 } else {
162 low_voltage_count_ = 0;
163 }
164
165 for (int i = 0; i < kNumOutputs; ++i) {
166 if (U[i] > plant.U_max[i]) {
167 U[i] = plant.U_max[i];
168 } else if (U[i] < plant.U_min[i]) {
169 U[i] = plant.U_min[i];
170 }
171 }
172}
173
174
Austin Schuhd78ab542013-03-01 22:22:19 -0800175// Positive angle is towards the shooter, and positive power is towards the
176// shooter.
177void IndexMotor::RunIteration(
178 const control_loops::IndexLoop::Goal *goal,
179 const control_loops::IndexLoop::Position *position,
180 control_loops::IndexLoop::Output *output,
181 control_loops::IndexLoop::Status *status) {
Austin Schuhbcdb90c2013-03-03 23:24:58 -0800182 // Make goal easy to work with and sanity check it.
Austin Schuhd78ab542013-03-01 22:22:19 -0800183 Goal goal_enum = static_cast<Goal>(goal->goal_state);
Austin Schuhbcdb90c2013-03-03 23:24:58 -0800184 if (goal->goal_state < 0 || goal->goal_state > 4) {
185 LOG(ERROR, "Goal state is %d which is out of range. Going to HOLD.\n",
186 goal->goal_state);
187 goal_enum = Goal::HOLD;
188 }
Austin Schuhd78ab542013-03-01 22:22:19 -0800189
190 // Disable the motors now so that all early returns will return with the
191 // motors disabled.
Austin Schuhb6d898b2013-03-03 15:34:35 -0800192 double intake_voltage = 0.0;
Austin Schuhf8c52252013-03-03 02:25:49 -0800193 double transfer_voltage = 0.0;
Austin Schuhd78ab542013-03-01 22:22:19 -0800194 if (output) {
Austin Schuhb6d898b2013-03-03 15:34:35 -0800195 output->intake_voltage = 0.0;
Austin Schuhd78ab542013-03-01 22:22:19 -0800196 output->transfer_voltage = 0.0;
197 output->index_voltage = 0.0;
198 }
199
200 status->ready_to_intake = false;
201
Austin Schuhf8c52252013-03-03 02:25:49 -0800202 // Compute a safe index position that we can use.
Austin Schuhd78ab542013-03-01 22:22:19 -0800203 if (position) {
204 wrist_loop_->Y << position->index_position;
Austin Schuhbcdb90c2013-03-03 23:24:58 -0800205 // Set the goal to be the current position if this is the first time through
206 // so we don't always spin the indexer to the 0 position before starting.
207 if (no_prior_position_) {
208 wrist_loop_->R << wrist_loop_->Y(0, 0), 0.0;
209 no_prior_position_ = false;
210 }
211
212 // If the cRIO is gone for 1/2 of a second, assume that it rebooted.
213 if (missing_position_count_ > 50) {
214 // Adjust the disc positions so that they don't have to move.
215 const double disc_offset =
216 position->index_position - wrist_loop_->X_hat(0, 0);
217 for (auto frisbee = frisbees_.begin();
218 frisbee != frisbees_.end(); ++frisbee) {
219 frisbee->OffsetDisc(disc_offset);
220 }
221 }
222 missing_position_count_ = 0;
223 } else {
224 ++missing_position_count_;
Austin Schuhd78ab542013-03-01 22:22:19 -0800225 }
226 const double index_position = wrist_loop_->X_hat(0, 0);
227
Austin Schuhf8c52252013-03-03 02:25:49 -0800228 // TODO(aschuh): Watch for top disc detect and update the frisbee
229 // position.
230
Austin Schuhf8c52252013-03-03 02:25:49 -0800231 // Bool to track if it is safe for the goal to change yet.
Austin Schuhd78ab542013-03-01 22:22:19 -0800232 bool safe_to_change_state_ = true;
233 switch (safe_goal_) {
Austin Schuhf8c52252013-03-03 02:25:49 -0800234 case Goal::HOLD:
Austin Schuhd78ab542013-03-01 22:22:19 -0800235 // The goal should already be good, so sit tight with everything the same
236 // as it was.
Austin Schuhd78ab542013-03-01 22:22:19 -0800237 break;
Austin Schuhf8c52252013-03-03 02:25:49 -0800238 case Goal::READY_LOWER:
239 case Goal::INTAKE:
Austin Schuhd78ab542013-03-01 22:22:19 -0800240 {
241 Time now = Time::Now();
Austin Schuhd78ab542013-03-01 22:22:19 -0800242 // Posedge of the disc entering the beam break.
243 if (position) {
Austin Schuh89955e42013-03-03 02:37:08 -0800244 // TODO(aschuh): Catch the edges on the FPGA since this is too slow.
245 // This means that we need to pass back enough data so that we can
246 // miss packets and everything works.
Austin Schuhd78ab542013-03-01 22:22:19 -0800247 if (position->bottom_disc_detect && !last_bottom_disc_detect_) {
248 transfer_frisbee_.Reset();
249 transfer_frisbee_.bottom_posedge_time_ = now;
250 printf("Posedge of bottom disc %f\n",
251 transfer_frisbee_.bottom_posedge_time_.ToSeconds());
252 ++hopper_disc_count_;
Austin Schuhf8c52252013-03-03 02:25:49 -0800253 ++total_disc_count_;
Austin Schuhd78ab542013-03-01 22:22:19 -0800254 }
255
256 // Disc exited the beam break now.
257 if (!position->bottom_disc_detect && last_bottom_disc_detect_) {
258 transfer_frisbee_.bottom_negedge_time_ = now;
259 printf("Negedge of bottom disc %f\n",
260 transfer_frisbee_.bottom_negedge_time_.ToSeconds());
261 frisbees_.push_front(transfer_frisbee_);
262 }
263
264 if (position->bottom_disc_detect) {
Austin Schuhb6d898b2013-03-03 15:34:35 -0800265 intake_voltage = transfer_voltage = 12.0;
Austin Schuhd78ab542013-03-01 22:22:19 -0800266 // Must wait until the disc gets out before we can change state.
267 safe_to_change_state_ = false;
268
Austin Schuhf8c52252013-03-03 02:25:49 -0800269 // TODO(aschuh): A disc on the way through needs to start moving
270 // the indexer if it isn't already moving. Maybe?
Austin Schuhd78ab542013-03-01 22:22:19 -0800271
272 Time elapsed_posedge_time = now -
273 transfer_frisbee_.bottom_posedge_time_;
274 if (elapsed_posedge_time >= Time::InSeconds(0.3)) {
275 // It has been too long. The disc must be jammed.
276 LOG(ERROR, "Been way too long. Jammed disc?\n");
277 printf("Been way too long. Jammed disc?\n");
278 }
279 }
280
Austin Schuhf8c52252013-03-03 02:25:49 -0800281 // Check all non-indexed discs and see if they should be indexed.
Austin Schuhb6d898b2013-03-03 15:34:35 -0800282 for (auto frisbee = frisbees_.begin();
Austin Schuhbcdb90c2013-03-03 23:24:58 -0800283 frisbee != frisbees_.end(); ++frisbee) {
Austin Schuhb6d898b2013-03-03 15:34:35 -0800284 if (!frisbee->has_been_indexed_) {
285 intake_voltage = transfer_voltage = 12.0;
Austin Schuhf8c52252013-03-03 02:25:49 -0800286 Time elapsed_negedge_time = now -
Austin Schuhb6d898b2013-03-03 15:34:35 -0800287 frisbee->bottom_negedge_time_;
Austin Schuhf8c52252013-03-03 02:25:49 -0800288 if (elapsed_negedge_time >= Time::InSeconds(0.005)) {
Austin Schuhd78ab542013-03-01 22:22:19 -0800289 // Should have just engaged.
290 // Save the indexer position, and the time.
291
292 // It has been long enough since the disc entered the indexer.
293 // Treat now as the time at which it contacted the indexer.
294 LOG(INFO, "Grabbed on the index now at %f\n", index_position);
295 printf("Grabbed on the index now at %f\n", index_position);
Austin Schuhb6d898b2013-03-03 15:34:35 -0800296 frisbee->has_been_indexed_ = true;
297 frisbee->index_start_position_ = index_position;
Austin Schuhd78ab542013-03-01 22:22:19 -0800298 }
299 }
Austin Schuhb6d898b2013-03-03 15:34:35 -0800300 if (!frisbee->has_been_indexed_) {
Austin Schuhf8c52252013-03-03 02:25:49 -0800301 // All discs must be indexed before it is safe to stop indexing.
Austin Schuhd78ab542013-03-01 22:22:19 -0800302 safe_to_change_state_ = false;
303 }
304 }
305
Austin Schuhf8c52252013-03-03 02:25:49 -0800306 // Figure out where the indexer should be to move the discs down to
307 // the right position.
308 double max_disc_position;
309 if (MaxDiscPosition(&max_disc_position)) {
310 printf("There is a disc down here!\n");
311 // TODO(aschuh): Figure out what to do if grabbing the next one
312 // would cause things to jam into the loader.
313 // Say we aren't ready any more. Undefined behavior will result if
314 // that isn't observed.
315 double bottom_disc_position =
316 max_disc_position + ConvertDiscAngleToIndex(M_PI);
317 wrist_loop_->R << bottom_disc_position, 0.0;
Austin Schuhd78ab542013-03-01 22:22:19 -0800318
Austin Schuhf8c52252013-03-03 02:25:49 -0800319 // Verify that we are close enough to the goal so that we should be
320 // fine accepting the next disc.
321 double disc_error_meters = ConvertIndexToDiscPosition(
322 wrist_loop_->X_hat(0, 0) - bottom_disc_position);
323 // We are ready for the next disc if the first one is in the first
324 // half circle of the indexer. It will take time for the disc to
325 // come into the indexer, so we will be able to move it out of the
326 // way in time.
327 // This choice also makes sure that we don't claim that we aren't
328 // ready between full speed intaking.
329 if (-ConvertDiscAngleToIndex(M_PI) < disc_error_meters &&
330 disc_error_meters < 0.04) {
331 // We are only ready if we aren't being asked to change state or
332 // are full.
333 status->ready_to_intake =
334 (safe_goal_ == goal_enum) && hopper_disc_count_ < 4;
335 } else {
336 status->ready_to_intake = false;
Austin Schuhd78ab542013-03-01 22:22:19 -0800337 }
Austin Schuhf8c52252013-03-03 02:25:49 -0800338 } else {
339 // No discs! We are always ready for more if we aren't being
340 // asked to change state.
341 status->ready_to_intake = (safe_goal_ == goal_enum);
Austin Schuhd78ab542013-03-01 22:22:19 -0800342 }
Austin Schuhf8c52252013-03-03 02:25:49 -0800343
344 // Turn on the transfer roller if we are ready.
345 if (status->ready_to_intake && hopper_disc_count_ < 4 &&
346 safe_goal_ == Goal::INTAKE) {
Austin Schuhb6d898b2013-03-03 15:34:35 -0800347 intake_voltage = transfer_voltage = 12.0;
Austin Schuhf8c52252013-03-03 02:25:49 -0800348 }
Austin Schuhd78ab542013-03-01 22:22:19 -0800349 }
Austin Schuhf8c52252013-03-03 02:25:49 -0800350 printf("INTAKE\n");
Austin Schuhd78ab542013-03-01 22:22:19 -0800351 }
352 break;
Austin Schuhf8c52252013-03-03 02:25:49 -0800353 case Goal::READY_SHOOTER:
354 case Goal::SHOOT:
355 // Check if we have any discs to shoot or load and handle them.
356 double min_disc_position;
357 if (MinDiscPosition(&min_disc_position)) {
358 const double ready_disc_position =
359 min_disc_position + ConvertDiscPositionToIndex(kIndexFreeLength) -
360 ConvertDiscAngleToIndex(M_PI / 6.0);
361
362 const double grabbed_disc_position =
363 min_disc_position +
364 ConvertDiscPositionToIndex(kReadyToLiftPosition -
365 kIndexStartPosition + 0.03);
366
367 // Check the state of the loader FSM.
368 // If it is ready to load discs, position the disc so that it is ready
369 // to be grabbed.
370 // If it isn't ready, there is a disc in there. It needs to finish it's
371 // cycle first.
372 if (loader_state_ != LoaderState::READY) {
373 // We already have a disc in the loader.
374 // Stage the discs back a bit.
375 wrist_loop_->R << ready_disc_position, 0.0;
376
Austin Schuhbcdb90c2013-03-03 23:24:58 -0800377 // Shoot if we are grabbed and being asked to shoot.
378 if (loader_state_ == LoaderState::GRABBED &&
379 safe_goal_ == Goal::SHOOT) {
380 loader_goal_ = LoaderGoal::SHOOT_AND_RESET;
381 }
382
Austin Schuhf8c52252013-03-03 02:25:49 -0800383 // Must wait until it has been grabbed to continue.
384 if (loader_state_ == LoaderState::GRABBING) {
385 safe_to_change_state_ = false;
386 }
387 } else {
388 // No disc up top right now.
389 wrist_loop_->R << grabbed_disc_position, 0.0;
390
391 // See if the disc has gotten pretty far up yet.
392 if (wrist_loop_->X_hat(0, 0) > ready_disc_position) {
393 // Point of no return. We are committing to grabbing it now.
394 safe_to_change_state_ = false;
395 const double robust_grabbed_disc_position =
396 (grabbed_disc_position -
397 ConvertDiscPositionToIndex(kGrabberLength));
398
399 // If close, start grabbing and/or shooting.
400 if (wrist_loop_->X_hat(0, 0) > robust_grabbed_disc_position) {
401 // Start the state machine.
402 if (safe_goal_ == Goal::SHOOT) {
403 loader_goal_ = LoaderGoal::SHOOT_AND_RESET;
404 } else {
405 loader_goal_ = LoaderGoal::GRAB;
406 }
407 // This frisbee is now gone. Take it out of the queue.
408 frisbees_.pop_back();
409 --hopper_disc_count_;
410 }
411 }
412 }
413 }
414
415 printf("READY_SHOOTER or SHOOT\n");
Austin Schuhd78ab542013-03-01 22:22:19 -0800416 break;
Austin Schuhf8c52252013-03-03 02:25:49 -0800417 }
418
419 // The only way out of the loader is to shoot the disc. The FSM can only go
420 // forwards.
421 switch (loader_state_) {
422 case LoaderState::READY:
423 printf("Loader READY\n");
424 // Open and down, ready to accept a disc.
425 loader_up_ = false;
426 disc_clamped_ = false;
427 disc_ejected_ = false;
428 if (loader_goal_ == LoaderGoal::GRAB ||
429 loader_goal_ == LoaderGoal::SHOOT_AND_RESET) {
430 if (loader_goal_ == LoaderGoal::GRAB) {
431 printf("Told to GRAB, moving on\n");
432 } else {
433 printf("Told to SHOOT_AND_RESET, moving on\n");
434 }
435 loader_state_ = LoaderState::GRABBING;
436 loader_countdown_ = kGrabbingDelay;
437 } else {
438 break;
439 }
440 case LoaderState::GRABBING:
441 printf("Loader GRABBING %d\n", loader_countdown_);
442 // Closing the grabber.
443 loader_up_ = false;
444 disc_clamped_ = true;
445 disc_ejected_ = false;
446 if (loader_countdown_ > 0) {
447 --loader_countdown_;
448 break;
449 } else {
450 loader_state_ = LoaderState::GRABBED;
451 }
452 case LoaderState::GRABBED:
453 printf("Loader GRABBED\n");
454 // Grabber closed.
455 loader_up_ = false;
456 disc_clamped_ = true;
457 disc_ejected_ = false;
458 if (loader_goal_ == LoaderGoal::SHOOT_AND_RESET) {
459 // TODO(aschuh): Only shoot if the shooter is up to speed.
460 // Seems like that would have us shooting a bit later than we could be,
461 // but it also probably spins back up real fast.
462 loader_state_ = LoaderState::LIFTING;
463 loader_countdown_ = kLiftingDelay;
464 printf("Told to SHOOT_AND_RESET, moving on\n");
465 } else if (loader_goal_ == LoaderGoal::READY) {
466 LOG(ERROR, "Can't go to ready when we have something grabbed.\n");
467 printf("Can't go to ready when we have something grabbed.\n");
468 break;
469 } else {
470 break;
471 }
472 case LoaderState::LIFTING:
473 printf("Loader LIFTING %d\n", loader_countdown_);
474 // Lifting the disc.
475 loader_up_ = true;
476 disc_clamped_ = true;
477 disc_ejected_ = false;
478 if (loader_countdown_ > 0) {
479 --loader_countdown_;
480 break;
481 } else {
482 loader_state_ = LoaderState::LIFTED;
483 }
484 case LoaderState::LIFTED:
485 printf("Loader LIFTED\n");
486 // Disc lifted. Time to eject it out.
487 loader_up_ = true;
488 disc_clamped_ = true;
489 disc_ejected_ = false;
490 loader_state_ = LoaderState::SHOOTING;
491 loader_countdown_ = kShootingDelay;
492 case LoaderState::SHOOTING:
493 printf("Loader SHOOTING %d\n", loader_countdown_);
494 // Ejecting the disc into the shooter.
495 loader_up_ = true;
496 disc_clamped_ = false;
497 disc_ejected_ = true;
498 if (loader_countdown_ > 0) {
499 --loader_countdown_;
500 break;
501 } else {
502 loader_state_ = LoaderState::SHOOT;
503 }
504 case LoaderState::SHOOT:
505 printf("Loader SHOOT\n");
506 // The disc has been shot.
507 loader_up_ = true;
508 disc_clamped_ = false;
509 disc_ejected_ = true;
510 loader_state_ = LoaderState::LOWERING;
511 loader_countdown_ = kLoweringDelay;
512 case LoaderState::LOWERING:
513 printf("Loader LOWERING %d\n", loader_countdown_);
514 // Lowering the loader back down.
515 loader_up_ = false;
516 disc_clamped_ = false;
517 disc_ejected_ = true;
518 if (loader_countdown_ > 0) {
519 --loader_countdown_;
520 break;
521 } else {
522 loader_state_ = LoaderState::LOWERED;
523 }
524 case LoaderState::LOWERED:
525 printf("Loader LOWERED\n");
526 // The indexer is lowered.
527 loader_up_ = false;
528 disc_clamped_ = false;
529 disc_ejected_ = false;
530 loader_state_ = LoaderState::READY;
531 // Once we have shot, we need to hang out in READY until otherwise
532 // notified.
533 loader_goal_ = LoaderGoal::READY;
Austin Schuhd78ab542013-03-01 22:22:19 -0800534 break;
535 }
536
537 // Update the observer.
538 wrist_loop_->Update(position != NULL, output == NULL);
539
540 if (position) {
Austin Schuhf8c52252013-03-03 02:25:49 -0800541 LOG(DEBUG, "pos=%f\n", position->index_position);
Austin Schuhd78ab542013-03-01 22:22:19 -0800542 last_bottom_disc_detect_ = position->bottom_disc_detect;
543 }
544
545 status->hopper_disc_count = hopper_disc_count_;
546 status->total_disc_count = total_disc_count_;
Austin Schuhf8c52252013-03-03 02:25:49 -0800547 status->preloaded = (loader_state_ != LoaderState::READY);
Austin Schuhd78ab542013-03-01 22:22:19 -0800548
549 if (output) {
Austin Schuhb6d898b2013-03-03 15:34:35 -0800550 output->intake_voltage = intake_voltage;
Austin Schuhf8c52252013-03-03 02:25:49 -0800551 output->transfer_voltage = transfer_voltage;
Austin Schuhd78ab542013-03-01 22:22:19 -0800552 output->index_voltage = wrist_loop_->U(0, 0);
Austin Schuhf8c52252013-03-03 02:25:49 -0800553 output->loader_up = loader_up_;
554 output->disc_clamped = disc_clamped_;
555 output->disc_ejected = disc_ejected_;
Austin Schuhd78ab542013-03-01 22:22:19 -0800556 }
557
558 if (safe_to_change_state_) {
559 safe_goal_ = goal_enum;
560 }
561}
562
563} // namespace control_loops
564} // namespace frc971