blob: bfc5be9b616f4300c5526b01b2f9ba59df000fca [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;
Austin Schuh6328daf2013-03-05 00:53:15 -080048/*static*/ const double IndexMotor::kGrabberMovementVelocity = 0.7;
Austin Schuhf8c52252013-03-03 02:25:49 -080049/*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;
Austin Schuh6328daf2013-03-05 00:53:15 -080057/*static*/ const double IndexMotor::kBottomDiscIndexDelay = 0.01;
Austin Schuhf8c52252013-03-03 02:25:49 -080058
59// TODO(aschuh): Figure these out.
60/*static*/ const double IndexMotor::kTopDiscDetectStart = 18.0;
61/*static*/ const double IndexMotor::kTopDiscDetectStop = 19.0;
62
Austin Schuhd78ab542013-03-01 22:22:19 -080063const /*static*/ double IndexMotor::kDiscRadius = 10.875 * 0.0254 / 2;
64const /*static*/ double IndexMotor::kRollerRadius = 2.0 * 0.0254 / 2;
Austin Schuhf8c52252013-03-03 02:25:49 -080065const /*static*/ double IndexMotor::kTransferRollerRadius = 1.25 * 0.0254 / 2;
Austin Schuhd78ab542013-03-01 22:22:19 -080066
Austin Schuhf8c52252013-03-03 02:25:49 -080067/*static*/ const int IndexMotor::kGrabbingDelay = 5;
68/*static*/ const int IndexMotor::kLiftingDelay = 20;
69/*static*/ const int IndexMotor::kShootingDelay = 5;
70/*static*/ const int IndexMotor::kLoweringDelay = 20;
Austin Schuhd78ab542013-03-01 22:22:19 -080071
Austin Schuh93485832013-03-04 00:01:34 -080072// TODO(aschuh): Tune these.
73/*static*/ const double
74 IndexMotor::IndexStateFeedbackLoop::kMinMotionVoltage = 5.0;
75/*static*/ const double
76 IndexMotor::IndexStateFeedbackLoop::kNoMotionCuttoffCount = 30;
77
Austin Schuhd78ab542013-03-01 22:22:19 -080078// Distance to move the indexer when grabbing a disc.
79const double kNextPosition = 10.0;
80
81/*static*/ double IndexMotor::ConvertDiscAngleToIndex(const double angle) {
82 return (angle * (1 + (kDiscRadius * 2 + kRollerRadius) / kRollerRadius));
83}
84
Austin Schuhf8c52252013-03-03 02:25:49 -080085/*static*/ double IndexMotor::ConvertDiscAngleToDiscPosition(
86 const double angle) {
Austin Schuhd78ab542013-03-01 22:22:19 -080087 return angle * (kDiscRadius + kRollerRadius);
88}
89
Austin Schuhf8c52252013-03-03 02:25:49 -080090/*static*/ double IndexMotor::ConvertDiscPositionToDiscAngle(
91 const double position) {
92 return position / (kDiscRadius + kRollerRadius);
93}
94
Austin Schuhd78ab542013-03-01 22:22:19 -080095/*static*/ double IndexMotor::ConvertIndexToDiscAngle(const double angle) {
96 return (angle / (1 + (kDiscRadius * 2 + kRollerRadius) / kRollerRadius));
97}
98
99/*static*/ double IndexMotor::ConvertIndexToDiscPosition(const double angle) {
100 return IndexMotor::ConvertDiscAngleToDiscPosition(
101 ConvertIndexToDiscAngle(angle));
102}
103
Austin Schuhf8c52252013-03-03 02:25:49 -0800104/*static*/ double IndexMotor::ConvertTransferToDiscPosition(
105 const double angle) {
106 const double gear_ratio = (1 + (kDiscRadius * 2 + kTransferRollerRadius) /
107 kTransferRollerRadius);
108 return angle / gear_ratio * (kDiscRadius + kTransferRollerRadius);
109}
110
111/*static*/ double IndexMotor::ConvertDiscPositionToIndex(
112 const double position) {
113 return IndexMotor::ConvertDiscAngleToIndex(
114 ConvertDiscPositionToDiscAngle(position));
115}
116
117bool IndexMotor::MinDiscPosition(double *disc_position) {
118 bool found_start = false;
119 for (unsigned int i = 0; i < frisbees_.size(); ++i) {
120 const Frisbee &frisbee = frisbees_[i];
121 if (!found_start) {
122 if (frisbee.has_position()) {
123 *disc_position = frisbee.position();
124 found_start = true;
125 }
126 } else {
127 *disc_position = ::std::min(frisbee.position(),
128 *disc_position);
129 }
130 }
131 return found_start;
132}
133
134bool IndexMotor::MaxDiscPosition(double *disc_position) {
135 bool found_start = false;
136 for (unsigned int i = 0; i < frisbees_.size(); ++i) {
137 const Frisbee &frisbee = frisbees_[i];
138 if (!found_start) {
139 if (frisbee.has_position()) {
140 *disc_position = frisbee.position();
141 found_start = true;
142 }
143 } else {
144 *disc_position = ::std::max(frisbee.position(),
145 *disc_position);
146 }
147 }
148 return found_start;
149}
150
Austin Schuh93485832013-03-04 00:01:34 -0800151void IndexMotor::IndexStateFeedbackLoop::CapU() {
152 // If the voltage has been low for a large number of cycles, cut the motor
153 // power. This is generally very bad controls practice since this isn't LTI,
154 // but we don't really care about tracking anything other than large step
155 // inputs, and the loader doesn't need to be that accurate.
156 if (::std::abs(U(0, 0)) < kMinMotionVoltage) {
157 ++low_voltage_count_;
158 if (low_voltage_count_ > kNoMotionCuttoffCount) {
159 printf("Limiting power from %f to 0\n", U(0, 0));
160 U(0, 0) = 0.0;
161 }
162 } else {
163 low_voltage_count_ = 0;
164 }
165
166 for (int i = 0; i < kNumOutputs; ++i) {
167 if (U[i] > plant.U_max[i]) {
168 U[i] = plant.U_max[i];
169 } else if (U[i] < plant.U_min[i]) {
170 U[i] = plant.U_min[i];
171 }
172 }
173}
174
175
Austin Schuhd78ab542013-03-01 22:22:19 -0800176// Positive angle is towards the shooter, and positive power is towards the
177// shooter.
178void IndexMotor::RunIteration(
179 const control_loops::IndexLoop::Goal *goal,
180 const control_loops::IndexLoop::Position *position,
181 control_loops::IndexLoop::Output *output,
182 control_loops::IndexLoop::Status *status) {
Austin Schuhbcdb90c2013-03-03 23:24:58 -0800183 // Make goal easy to work with and sanity check it.
Austin Schuhd78ab542013-03-01 22:22:19 -0800184 Goal goal_enum = static_cast<Goal>(goal->goal_state);
Austin Schuhbcdb90c2013-03-03 23:24:58 -0800185 if (goal->goal_state < 0 || goal->goal_state > 4) {
186 LOG(ERROR, "Goal state is %d which is out of range. Going to HOLD.\n",
187 goal->goal_state);
188 goal_enum = Goal::HOLD;
189 }
Austin Schuhd78ab542013-03-01 22:22:19 -0800190
191 // Disable the motors now so that all early returns will return with the
192 // motors disabled.
Austin Schuhb6d898b2013-03-03 15:34:35 -0800193 double intake_voltage = 0.0;
Austin Schuhf8c52252013-03-03 02:25:49 -0800194 double transfer_voltage = 0.0;
Austin Schuhd78ab542013-03-01 22:22:19 -0800195 if (output) {
Austin Schuhb6d898b2013-03-03 15:34:35 -0800196 output->intake_voltage = 0.0;
Austin Schuhd78ab542013-03-01 22:22:19 -0800197 output->transfer_voltage = 0.0;
198 output->index_voltage = 0.0;
199 }
200
201 status->ready_to_intake = false;
202
Austin Schuhf8c52252013-03-03 02:25:49 -0800203 // Compute a safe index position that we can use.
Austin Schuhd78ab542013-03-01 22:22:19 -0800204 if (position) {
205 wrist_loop_->Y << position->index_position;
Austin Schuhbcdb90c2013-03-03 23:24:58 -0800206 // Set the goal to be the current position if this is the first time through
207 // so we don't always spin the indexer to the 0 position before starting.
208 if (no_prior_position_) {
209 wrist_loop_->R << wrist_loop_->Y(0, 0), 0.0;
210 no_prior_position_ = false;
Austin Schuh6328daf2013-03-05 00:53:15 -0800211 last_bottom_disc_posedge_count_ = position->bottom_disc_posedge_count;
212 last_bottom_disc_negedge_count_ = position->bottom_disc_negedge_count;
213 last_bottom_disc_negedge_wait_count_ =
214 position->bottom_disc_negedge_wait_count;
Austin Schuhbcdb90c2013-03-03 23:24:58 -0800215 }
216
217 // If the cRIO is gone for 1/2 of a second, assume that it rebooted.
218 if (missing_position_count_ > 50) {
Austin Schuh6328daf2013-03-05 00:53:15 -0800219 last_bottom_disc_posedge_count_ = position->bottom_disc_posedge_count;
220 last_bottom_disc_negedge_count_ = position->bottom_disc_negedge_count;
221 last_bottom_disc_negedge_wait_count_ =
222 position->bottom_disc_negedge_wait_count;
Austin Schuhbcdb90c2013-03-03 23:24:58 -0800223 // Adjust the disc positions so that they don't have to move.
224 const double disc_offset =
225 position->index_position - wrist_loop_->X_hat(0, 0);
226 for (auto frisbee = frisbees_.begin();
227 frisbee != frisbees_.end(); ++frisbee) {
228 frisbee->OffsetDisc(disc_offset);
229 }
230 }
231 missing_position_count_ = 0;
232 } else {
233 ++missing_position_count_;
Austin Schuhd78ab542013-03-01 22:22:19 -0800234 }
235 const double index_position = wrist_loop_->X_hat(0, 0);
236
Austin Schuhf8c52252013-03-03 02:25:49 -0800237 // TODO(aschuh): Watch for top disc detect and update the frisbee
238 // position.
239
Austin Schuhf8c52252013-03-03 02:25:49 -0800240 // Bool to track if it is safe for the goal to change yet.
Austin Schuhd78ab542013-03-01 22:22:19 -0800241 bool safe_to_change_state_ = true;
242 switch (safe_goal_) {
Austin Schuhf8c52252013-03-03 02:25:49 -0800243 case Goal::HOLD:
Austin Schuhd78ab542013-03-01 22:22:19 -0800244 // The goal should already be good, so sit tight with everything the same
245 // as it was.
Austin Schuhd78ab542013-03-01 22:22:19 -0800246 break;
Austin Schuhf8c52252013-03-03 02:25:49 -0800247 case Goal::READY_LOWER:
248 case Goal::INTAKE:
Austin Schuhd78ab542013-03-01 22:22:19 -0800249 {
250 Time now = Time::Now();
Austin Schuhd78ab542013-03-01 22:22:19 -0800251 if (position) {
Austin Schuh6328daf2013-03-05 00:53:15 -0800252 // Posedge of the disc entering the beam break.
253 if (position->bottom_disc_posedge_count !=
254 last_bottom_disc_posedge_count_) {
Austin Schuhd78ab542013-03-01 22:22:19 -0800255 transfer_frisbee_.Reset();
256 transfer_frisbee_.bottom_posedge_time_ = now;
257 printf("Posedge of bottom disc %f\n",
258 transfer_frisbee_.bottom_posedge_time_.ToSeconds());
259 ++hopper_disc_count_;
Austin Schuhf8c52252013-03-03 02:25:49 -0800260 ++total_disc_count_;
Austin Schuhd78ab542013-03-01 22:22:19 -0800261 }
262
263 // Disc exited the beam break now.
Austin Schuh6328daf2013-03-05 00:53:15 -0800264 if (position->bottom_disc_negedge_count !=
265 last_bottom_disc_negedge_count_) {
Austin Schuhd78ab542013-03-01 22:22:19 -0800266 transfer_frisbee_.bottom_negedge_time_ = now;
267 printf("Negedge of bottom disc %f\n",
268 transfer_frisbee_.bottom_negedge_time_.ToSeconds());
269 frisbees_.push_front(transfer_frisbee_);
270 }
271
272 if (position->bottom_disc_detect) {
Austin Schuhb6d898b2013-03-03 15:34:35 -0800273 intake_voltage = transfer_voltage = 12.0;
Austin Schuhd78ab542013-03-01 22:22:19 -0800274 // Must wait until the disc gets out before we can change state.
275 safe_to_change_state_ = false;
276
Austin Schuhf8c52252013-03-03 02:25:49 -0800277 // TODO(aschuh): A disc on the way through needs to start moving
278 // the indexer if it isn't already moving. Maybe?
Austin Schuhd78ab542013-03-01 22:22:19 -0800279
280 Time elapsed_posedge_time = now -
281 transfer_frisbee_.bottom_posedge_time_;
282 if (elapsed_posedge_time >= Time::InSeconds(0.3)) {
283 // It has been too long. The disc must be jammed.
284 LOG(ERROR, "Been way too long. Jammed disc?\n");
285 printf("Been way too long. Jammed disc?\n");
286 }
287 }
288
Austin Schuhf8c52252013-03-03 02:25:49 -0800289 // Check all non-indexed discs and see if they should be indexed.
Austin Schuhb6d898b2013-03-03 15:34:35 -0800290 for (auto frisbee = frisbees_.begin();
Austin Schuhbcdb90c2013-03-03 23:24:58 -0800291 frisbee != frisbees_.end(); ++frisbee) {
Austin Schuhb6d898b2013-03-03 15:34:35 -0800292 if (!frisbee->has_been_indexed_) {
293 intake_voltage = transfer_voltage = 12.0;
Austin Schuhd78ab542013-03-01 22:22:19 -0800294
Austin Schuh6328daf2013-03-05 00:53:15 -0800295 if (last_bottom_disc_negedge_wait_count_ !=
296 position->bottom_disc_negedge_wait_count) {
297 // We have an index difference.
298 // Save the indexer position, and the time.
299 if (last_bottom_disc_negedge_wait_count_ + 1 !=
300 position->bottom_disc_negedge_wait_count) {
301 LOG(ERROR, "Funny, we got 2 edges since we last checked.\n");
302 }
303
304 // Save the captured position as the position at which the disc
305 // touched the indexer.
Austin Schuhd78ab542013-03-01 22:22:19 -0800306 LOG(INFO, "Grabbed on the index now at %f\n", index_position);
307 printf("Grabbed on the index now at %f\n", index_position);
Austin Schuhb6d898b2013-03-03 15:34:35 -0800308 frisbee->has_been_indexed_ = true;
Austin Schuh6328daf2013-03-05 00:53:15 -0800309 frisbee->index_start_position_ =
310 position->bottom_disc_negedge_wait_position;
Austin Schuhd78ab542013-03-01 22:22:19 -0800311 }
312 }
Austin Schuhb6d898b2013-03-03 15:34:35 -0800313 if (!frisbee->has_been_indexed_) {
Austin Schuhf8c52252013-03-03 02:25:49 -0800314 // All discs must be indexed before it is safe to stop indexing.
Austin Schuhd78ab542013-03-01 22:22:19 -0800315 safe_to_change_state_ = false;
316 }
317 }
318
Austin Schuhf8c52252013-03-03 02:25:49 -0800319 // Figure out where the indexer should be to move the discs down to
320 // the right position.
321 double max_disc_position;
322 if (MaxDiscPosition(&max_disc_position)) {
323 printf("There is a disc down here!\n");
324 // TODO(aschuh): Figure out what to do if grabbing the next one
325 // would cause things to jam into the loader.
326 // Say we aren't ready any more. Undefined behavior will result if
327 // that isn't observed.
328 double bottom_disc_position =
329 max_disc_position + ConvertDiscAngleToIndex(M_PI);
330 wrist_loop_->R << bottom_disc_position, 0.0;
Austin Schuhd78ab542013-03-01 22:22:19 -0800331
Austin Schuhf8c52252013-03-03 02:25:49 -0800332 // Verify that we are close enough to the goal so that we should be
333 // fine accepting the next disc.
334 double disc_error_meters = ConvertIndexToDiscPosition(
335 wrist_loop_->X_hat(0, 0) - bottom_disc_position);
336 // We are ready for the next disc if the first one is in the first
337 // half circle of the indexer. It will take time for the disc to
338 // come into the indexer, so we will be able to move it out of the
339 // way in time.
340 // This choice also makes sure that we don't claim that we aren't
341 // ready between full speed intaking.
342 if (-ConvertDiscAngleToIndex(M_PI) < disc_error_meters &&
343 disc_error_meters < 0.04) {
344 // We are only ready if we aren't being asked to change state or
345 // are full.
346 status->ready_to_intake =
347 (safe_goal_ == goal_enum) && hopper_disc_count_ < 4;
348 } else {
349 status->ready_to_intake = false;
Austin Schuhd78ab542013-03-01 22:22:19 -0800350 }
Austin Schuhf8c52252013-03-03 02:25:49 -0800351 } else {
352 // No discs! We are always ready for more if we aren't being
353 // asked to change state.
354 status->ready_to_intake = (safe_goal_ == goal_enum);
Austin Schuhd78ab542013-03-01 22:22:19 -0800355 }
Austin Schuhf8c52252013-03-03 02:25:49 -0800356
357 // Turn on the transfer roller if we are ready.
358 if (status->ready_to_intake && hopper_disc_count_ < 4 &&
359 safe_goal_ == Goal::INTAKE) {
Austin Schuhb6d898b2013-03-03 15:34:35 -0800360 intake_voltage = transfer_voltage = 12.0;
Austin Schuhf8c52252013-03-03 02:25:49 -0800361 }
Austin Schuhd78ab542013-03-01 22:22:19 -0800362 }
Austin Schuhf8c52252013-03-03 02:25:49 -0800363 printf("INTAKE\n");
Austin Schuhd78ab542013-03-01 22:22:19 -0800364 }
365 break;
Austin Schuhf8c52252013-03-03 02:25:49 -0800366 case Goal::READY_SHOOTER:
367 case Goal::SHOOT:
368 // Check if we have any discs to shoot or load and handle them.
369 double min_disc_position;
370 if (MinDiscPosition(&min_disc_position)) {
371 const double ready_disc_position =
372 min_disc_position + ConvertDiscPositionToIndex(kIndexFreeLength) -
373 ConvertDiscAngleToIndex(M_PI / 6.0);
374
375 const double grabbed_disc_position =
376 min_disc_position +
377 ConvertDiscPositionToIndex(kReadyToLiftPosition -
378 kIndexStartPosition + 0.03);
379
380 // Check the state of the loader FSM.
381 // If it is ready to load discs, position the disc so that it is ready
382 // to be grabbed.
383 // If it isn't ready, there is a disc in there. It needs to finish it's
384 // cycle first.
385 if (loader_state_ != LoaderState::READY) {
386 // We already have a disc in the loader.
387 // Stage the discs back a bit.
388 wrist_loop_->R << ready_disc_position, 0.0;
389
Austin Schuhbcdb90c2013-03-03 23:24:58 -0800390 // Shoot if we are grabbed and being asked to shoot.
391 if (loader_state_ == LoaderState::GRABBED &&
392 safe_goal_ == Goal::SHOOT) {
393 loader_goal_ = LoaderGoal::SHOOT_AND_RESET;
394 }
395
Austin Schuhf8c52252013-03-03 02:25:49 -0800396 // Must wait until it has been grabbed to continue.
397 if (loader_state_ == LoaderState::GRABBING) {
398 safe_to_change_state_ = false;
399 }
400 } else {
401 // No disc up top right now.
402 wrist_loop_->R << grabbed_disc_position, 0.0;
403
404 // See if the disc has gotten pretty far up yet.
405 if (wrist_loop_->X_hat(0, 0) > ready_disc_position) {
406 // Point of no return. We are committing to grabbing it now.
407 safe_to_change_state_ = false;
408 const double robust_grabbed_disc_position =
409 (grabbed_disc_position -
410 ConvertDiscPositionToIndex(kGrabberLength));
411
412 // If close, start grabbing and/or shooting.
413 if (wrist_loop_->X_hat(0, 0) > robust_grabbed_disc_position) {
414 // Start the state machine.
415 if (safe_goal_ == Goal::SHOOT) {
416 loader_goal_ = LoaderGoal::SHOOT_AND_RESET;
417 } else {
418 loader_goal_ = LoaderGoal::GRAB;
419 }
420 // This frisbee is now gone. Take it out of the queue.
421 frisbees_.pop_back();
422 --hopper_disc_count_;
423 }
424 }
425 }
426 }
427
428 printf("READY_SHOOTER or SHOOT\n");
Austin Schuhd78ab542013-03-01 22:22:19 -0800429 break;
Austin Schuhf8c52252013-03-03 02:25:49 -0800430 }
431
432 // The only way out of the loader is to shoot the disc. The FSM can only go
433 // forwards.
434 switch (loader_state_) {
435 case LoaderState::READY:
436 printf("Loader READY\n");
437 // Open and down, ready to accept a disc.
438 loader_up_ = false;
439 disc_clamped_ = false;
440 disc_ejected_ = false;
441 if (loader_goal_ == LoaderGoal::GRAB ||
442 loader_goal_ == LoaderGoal::SHOOT_AND_RESET) {
443 if (loader_goal_ == LoaderGoal::GRAB) {
444 printf("Told to GRAB, moving on\n");
445 } else {
446 printf("Told to SHOOT_AND_RESET, moving on\n");
447 }
448 loader_state_ = LoaderState::GRABBING;
449 loader_countdown_ = kGrabbingDelay;
450 } else {
451 break;
452 }
453 case LoaderState::GRABBING:
454 printf("Loader GRABBING %d\n", loader_countdown_);
455 // Closing the grabber.
456 loader_up_ = false;
457 disc_clamped_ = true;
458 disc_ejected_ = false;
459 if (loader_countdown_ > 0) {
460 --loader_countdown_;
461 break;
462 } else {
463 loader_state_ = LoaderState::GRABBED;
464 }
465 case LoaderState::GRABBED:
466 printf("Loader GRABBED\n");
467 // Grabber closed.
468 loader_up_ = false;
469 disc_clamped_ = true;
470 disc_ejected_ = false;
471 if (loader_goal_ == LoaderGoal::SHOOT_AND_RESET) {
472 // TODO(aschuh): Only shoot if the shooter is up to speed.
473 // Seems like that would have us shooting a bit later than we could be,
474 // but it also probably spins back up real fast.
475 loader_state_ = LoaderState::LIFTING;
476 loader_countdown_ = kLiftingDelay;
477 printf("Told to SHOOT_AND_RESET, moving on\n");
478 } else if (loader_goal_ == LoaderGoal::READY) {
479 LOG(ERROR, "Can't go to ready when we have something grabbed.\n");
480 printf("Can't go to ready when we have something grabbed.\n");
481 break;
482 } else {
483 break;
484 }
485 case LoaderState::LIFTING:
486 printf("Loader LIFTING %d\n", loader_countdown_);
487 // Lifting the disc.
488 loader_up_ = true;
489 disc_clamped_ = true;
490 disc_ejected_ = false;
491 if (loader_countdown_ > 0) {
492 --loader_countdown_;
493 break;
494 } else {
495 loader_state_ = LoaderState::LIFTED;
496 }
497 case LoaderState::LIFTED:
498 printf("Loader LIFTED\n");
499 // Disc lifted. Time to eject it out.
500 loader_up_ = true;
501 disc_clamped_ = true;
502 disc_ejected_ = false;
503 loader_state_ = LoaderState::SHOOTING;
504 loader_countdown_ = kShootingDelay;
505 case LoaderState::SHOOTING:
506 printf("Loader SHOOTING %d\n", loader_countdown_);
507 // Ejecting the disc into the shooter.
508 loader_up_ = true;
509 disc_clamped_ = false;
510 disc_ejected_ = true;
511 if (loader_countdown_ > 0) {
512 --loader_countdown_;
513 break;
514 } else {
515 loader_state_ = LoaderState::SHOOT;
516 }
517 case LoaderState::SHOOT:
518 printf("Loader SHOOT\n");
519 // The disc has been shot.
520 loader_up_ = true;
521 disc_clamped_ = false;
522 disc_ejected_ = true;
523 loader_state_ = LoaderState::LOWERING;
524 loader_countdown_ = kLoweringDelay;
525 case LoaderState::LOWERING:
526 printf("Loader LOWERING %d\n", loader_countdown_);
527 // Lowering the loader back down.
528 loader_up_ = false;
529 disc_clamped_ = false;
530 disc_ejected_ = true;
531 if (loader_countdown_ > 0) {
532 --loader_countdown_;
533 break;
534 } else {
535 loader_state_ = LoaderState::LOWERED;
536 }
537 case LoaderState::LOWERED:
538 printf("Loader LOWERED\n");
539 // The indexer is lowered.
540 loader_up_ = false;
541 disc_clamped_ = false;
542 disc_ejected_ = false;
543 loader_state_ = LoaderState::READY;
544 // Once we have shot, we need to hang out in READY until otherwise
545 // notified.
546 loader_goal_ = LoaderGoal::READY;
Austin Schuhd78ab542013-03-01 22:22:19 -0800547 break;
548 }
549
550 // Update the observer.
551 wrist_loop_->Update(position != NULL, output == NULL);
552
553 if (position) {
Austin Schuhf8c52252013-03-03 02:25:49 -0800554 LOG(DEBUG, "pos=%f\n", position->index_position);
Austin Schuhd78ab542013-03-01 22:22:19 -0800555 last_bottom_disc_detect_ = position->bottom_disc_detect;
Austin Schuh6328daf2013-03-05 00:53:15 -0800556 last_bottom_disc_detect_ = position->bottom_disc_detect;
557 last_bottom_disc_posedge_count_ = position->bottom_disc_posedge_count;
558 last_bottom_disc_negedge_count_ = position->bottom_disc_negedge_count;
559 last_bottom_disc_negedge_wait_count_ =
560 position->bottom_disc_negedge_wait_count;
Austin Schuhd78ab542013-03-01 22:22:19 -0800561 }
562
563 status->hopper_disc_count = hopper_disc_count_;
564 status->total_disc_count = total_disc_count_;
Austin Schuhf8c52252013-03-03 02:25:49 -0800565 status->preloaded = (loader_state_ != LoaderState::READY);
Austin Schuhd78ab542013-03-01 22:22:19 -0800566
567 if (output) {
Austin Schuhb6d898b2013-03-03 15:34:35 -0800568 output->intake_voltage = intake_voltage;
Austin Schuhf8c52252013-03-03 02:25:49 -0800569 output->transfer_voltage = transfer_voltage;
Austin Schuhd78ab542013-03-01 22:22:19 -0800570 output->index_voltage = wrist_loop_->U(0, 0);
Austin Schuhf8c52252013-03-03 02:25:49 -0800571 output->loader_up = loader_up_;
572 output->disc_clamped = disc_clamped_;
573 output->disc_ejected = disc_ejected_;
Austin Schuhd78ab542013-03-01 22:22:19 -0800574 }
575
576 if (safe_to_change_state_) {
577 safe_goal_ = goal_enum;
578 }
579}
580
581} // namespace control_loops
582} // namespace frc971