blob: 32f697908c9864e475a92c922b050ee1133ea66c [file] [log] [blame]
Austin Schuh80ff2e12014-03-08 12:06:19 -08001#include <stdio.h>
2
3#include <memory>
Austin Schuh47017412013-03-10 11:50:46 -07004
Brian3afd6fc2014-04-02 20:41:49 -07005#include "aos/common/util/phased_loop.h"
Austin Schuh47017412013-03-10 11:50:46 -07006#include "aos/common/time.h"
Austin Schuh6be011a2013-03-19 10:07:02 +00007#include "aos/common/util/trapezoid_profile.h"
Brian Silverman598800f2013-05-09 17:08:42 -07008#include "aos/common/logging/logging.h"
Brian Silverman96d9cea2013-11-12 21:10:50 -08009#include "aos/common/network/team_number.h"
Brian Silverman6f621542014-04-06 16:00:41 -070010#include "aos/common/logging/queue_logging.h"
Brian Silverman598800f2013-05-09 17:08:42 -070011
12#include "frc971/autonomous/auto.q.h"
Austin Schuh6be011a2013-03-19 10:07:02 +000013#include "frc971/constants.h"
14#include "frc971/control_loops/drivetrain/drivetrain.q.h"
Austin Schuh80ff2e12014-03-08 12:06:19 -080015#include "frc971/control_loops/shooter/shooter.q.h"
16#include "frc971/control_loops/claw/claw.q.h"
17#include "frc971/actions/action_client.h"
18#include "frc971/actions/shoot_action.h"
19#include "frc971/actions/drivetrain_action.h"
Brian Silverman45ceeb52014-04-17 15:15:18 -070020#include "frc971/queues/other_sensors.q.h"
Brian Silverman6f621542014-04-06 16:00:41 -070021#include "frc971/queues/hot_goal.q.h"
Austin Schuh47017412013-03-10 11:50:46 -070022
23using ::aos::time::Time;
24
25namespace frc971 {
26namespace autonomous {
27
Austin Schuh80ff2e12014-03-08 12:06:19 -080028namespace time = ::aos::time;
29
Brian Silverman3b89ed82013-03-22 18:59:16 -070030static double left_initial_position, right_initial_position;
31
Austin Schuh6be011a2013-03-19 10:07:02 +000032bool ShouldExitAuto() {
33 ::frc971::autonomous::autonomous.FetchLatest();
34 bool ans = !::frc971::autonomous::autonomous->run_auto;
35 if (ans) {
36 LOG(INFO, "Time to exit auto mode\n");
37 }
38 return ans;
39}
40
Austin Schuh6be011a2013-03-19 10:07:02 +000041void StopDrivetrain() {
42 LOG(INFO, "Stopping the drivetrain\n");
Austin Schuh47017412013-03-10 11:50:46 -070043 control_loops::drivetrain.goal.MakeWithBuilder()
Brian Silverman3b89ed82013-03-22 18:59:16 -070044 .control_loop_driving(true)
Brian Silvermance86bac2013-03-31 19:07:24 -070045 .left_goal(left_initial_position)
46 .left_velocity_goal(0)
47 .right_goal(right_initial_position)
48 .right_velocity_goal(0)
49 .quickturn(false)
50 .Send();
51}
52
53void ResetDrivetrain() {
54 LOG(INFO, "resetting the drivetrain\n");
55 control_loops::drivetrain.goal.MakeWithBuilder()
56 .control_loop_driving(false)
Austin Schuh6be011a2013-03-19 10:07:02 +000057 .highgear(false)
58 .steering(0.0)
59 .throttle(0.0)
Austin Schuh6be011a2013-03-19 10:07:02 +000060 .Send();
61}
62
Brian Silverman3b89ed82013-03-22 18:59:16 -070063void DriveSpin(double radians) {
64 LOG(INFO, "going to spin %f\n", radians);
65
66 ::aos::util::TrapezoidProfile profile(::aos::time::Time::InMS(10));
67 ::Eigen::Matrix<double, 2, 1> driveTrainState;
68 const double goal_velocity = 0.0;
69 const double epsilon = 0.01;
Brian Silverman13be6682013-03-22 21:02:07 -070070 // in drivetrain "meters"
Brian Silverman3b89ed82013-03-22 18:59:16 -070071 const double kRobotWidth = 0.4544;
72
Brian Silverman7992d6e2013-03-24 19:20:54 -070073 profile.set_maximum_acceleration(1.5);
74 profile.set_maximum_velocity(0.8);
Brian Silverman3b89ed82013-03-22 18:59:16 -070075
76 const double side_offset = kRobotWidth * radians / 2.0;
77
78 while (true) {
Brian Silverman7f09f972013-03-22 23:11:39 -070079 ::aos::time::PhasedLoop10MS(5000); // wait until next 10ms tick
Brian Silverman3b89ed82013-03-22 18:59:16 -070080 driveTrainState = profile.Update(side_offset, goal_velocity);
81
82 if (::std::abs(driveTrainState(0, 0) - side_offset) < epsilon) break;
83 if (ShouldExitAuto()) return;
84
85 LOG(DEBUG, "Driving left to %f, right to %f\n",
Brian Silverman7992d6e2013-03-24 19:20:54 -070086 left_initial_position - driveTrainState(0, 0),
87 right_initial_position + driveTrainState(0, 0));
Brian Silverman3b89ed82013-03-22 18:59:16 -070088 control_loops::drivetrain.goal.MakeWithBuilder()
89 .control_loop_driving(true)
90 .highgear(false)
Brian Silverman7992d6e2013-03-24 19:20:54 -070091 .left_goal(left_initial_position - driveTrainState(0, 0))
92 .right_goal(right_initial_position + driveTrainState(0, 0))
93 .left_velocity_goal(-driveTrainState(1, 0))
94 .right_velocity_goal(driveTrainState(1, 0))
Brian Silverman3b89ed82013-03-22 18:59:16 -070095 .Send();
96 }
Brian Silverman7992d6e2013-03-24 19:20:54 -070097 left_initial_position -= side_offset;
98 right_initial_position += side_offset;
Brian Silverman3b89ed82013-03-22 18:59:16 -070099 LOG(INFO, "Done moving\n");
100}
101
Austin Schuh80ff2e12014-03-08 12:06:19 -0800102void PositionClawVertically(double intake_power = 0.0, double centering_power = 0.0) {
103 if (!control_loops::claw_queue_group.goal.MakeWithBuilder()
104 .bottom_angle(0.0)
105 .separation_angle(0.0)
106 .intake(intake_power)
107 .centering(centering_power)
108 .Send()) {
109 LOG(WARNING, "sending claw goal failed\n");
110 }
111}
Brian Silvermance86bac2013-03-31 19:07:24 -0700112
Austin Schuh80ff2e12014-03-08 12:06:19 -0800113void PositionClawBackIntake() {
114 if (!control_loops::claw_queue_group.goal.MakeWithBuilder()
115 .bottom_angle(-2.273474)
116 .separation_angle(0.0)
117 .intake(12.0)
118 .centering(12.0)
119 .Send()) {
120 LOG(WARNING, "sending claw goal failed\n");
121 }
122}
Brian Silvermance86bac2013-03-31 19:07:24 -0700123
Austin Schuh80ff2e12014-03-08 12:06:19 -0800124void PositionClawForShot() {
125 // Turn the claw on, keep it straight up until the ball has been grabbed.
126 if (!control_loops::claw_queue_group.goal.MakeWithBuilder()
Brian Silverman31b5b822014-03-14 18:50:39 -0700127 .bottom_angle(0.86)
Austin Schuha4faacc2014-03-09 00:50:50 -0800128 .separation_angle(0.10)
129 .intake(4.0)
Austin Schuh80ff2e12014-03-08 12:06:19 -0800130 .centering(1.0)
131 .Send()) {
132 LOG(WARNING, "sending claw goal failed\n");
133 }
134}
135
136void SetShotPower(double power) {
Austin Schuha4faacc2014-03-09 00:50:50 -0800137 LOG(INFO, "Setting shot power to %f\n", power);
Austin Schuh80ff2e12014-03-08 12:06:19 -0800138 if (!control_loops::shooter_queue_group.goal.MakeWithBuilder()
139 .shot_power(power)
140 .shot_requested(false)
141 .unload_requested(false)
142 .load_requested(false)
143 .Send()) {
144 LOG(WARNING, "sending shooter goal failed\n");
145 }
146}
147
148void WaitUntilDoneOrCanceled(Action *action) {
149 while (true) {
150 // Poll the running bit and auto done bits.
151 ::aos::time::PhasedLoop10MS(5000);
152 if (!action->Running() || ShouldExitAuto()) {
153 return;
154 }
155 }
156}
157
158void Shoot() {
159 // Shoot.
160 auto shoot_action = actions::MakeShootAction();
161 shoot_action->Start();
162 WaitUntilDoneOrCanceled(shoot_action.get());
163}
164
165::std::unique_ptr<TypedAction< ::frc971::actions::DrivetrainActionQueueGroup>>
Brian Silvermanad9e0002014-04-13 14:55:57 -0700166SetDriveGoal(double distance, double maximum_velocity = 1.7, double theta = 0) {
Austin Schuha4faacc2014-03-09 00:50:50 -0800167 LOG(INFO, "Driving to %f\n", distance);
Austin Schuh80ff2e12014-03-08 12:06:19 -0800168 auto drivetrain_action = actions::MakeDrivetrainAction();
169 drivetrain_action->GetGoal()->left_initial_position = left_initial_position;
170 drivetrain_action->GetGoal()->right_initial_position = right_initial_position;
171 drivetrain_action->GetGoal()->y_offset = distance;
Brian Silvermanad9e0002014-04-13 14:55:57 -0700172 drivetrain_action->GetGoal()->theta_offset = theta;
Austin Schuh80ff2e12014-03-08 12:06:19 -0800173 drivetrain_action->GetGoal()->maximum_velocity = maximum_velocity;
174 drivetrain_action->Start();
Brian Silvermanad9e0002014-04-13 14:55:57 -0700175 left_initial_position +=
176 distance - theta * constants::GetValues().turn_width / 2.0;
177 right_initial_position +=
178 distance + theta * constants::GetValues().turn_width / 2. -
179 theta * constants::GetValues().turn_width / 2.00;
Austin Schuh80ff2e12014-03-08 12:06:19 -0800180 return ::std::move(drivetrain_action);
181}
182
183void InitializeEncoders() {
Austin Schuh577edf62014-04-13 10:33:05 -0700184 control_loops::drivetrain.status.FetchLatest();
185 while (!control_loops::drivetrain.status.get()) {
Brian Silverman2c1e0342014-04-11 16:15:01 -0700186 LOG(WARNING,
187 "No previous drivetrain position packet, trying to fetch again\n");
Austin Schuh577edf62014-04-13 10:33:05 -0700188 control_loops::drivetrain.status.FetchNextBlocking();
Brian Silverman3b89ed82013-03-22 18:59:16 -0700189 }
190 left_initial_position =
Austin Schuh577edf62014-04-13 10:33:05 -0700191 control_loops::drivetrain.status->filtered_left_position;
Brian Silverman3b89ed82013-03-22 18:59:16 -0700192 right_initial_position =
Austin Schuh577edf62014-04-13 10:33:05 -0700193 control_loops::drivetrain.status->filtered_right_position;
Brian Silverman3b89ed82013-03-22 18:59:16 -0700194
Austin Schuh80ff2e12014-03-08 12:06:19 -0800195}
196
Austin Schuha4faacc2014-03-09 00:50:50 -0800197void WaitUntilClawDone() {
198 while (true) {
199 // Poll the running bit and auto done bits.
200 ::aos::time::PhasedLoop10MS(5000);
201 control_loops::claw_queue_group.status.FetchLatest();
202 control_loops::claw_queue_group.goal.FetchLatest();
203 if (ShouldExitAuto()) {
204 return;
205 }
206 if (control_loops::claw_queue_group.status.get() == nullptr ||
207 control_loops::claw_queue_group.goal.get() == nullptr) {
208 continue;
209 }
210 bool ans =
211 control_loops::claw_queue_group.status->zeroed &&
212 (::std::abs(control_loops::claw_queue_group.status->bottom_velocity) <
213 1.0) &&
214 (::std::abs(control_loops::claw_queue_group.status->bottom -
215 control_loops::claw_queue_group.goal->bottom_angle) <
216 0.10) &&
217 (::std::abs(control_loops::claw_queue_group.status->separation -
218 control_loops::claw_queue_group.goal->separation_angle) <
219 0.4);
220 if (ans) {
221 return;
222 }
223 }
224}
225
Brian Silverman4ac1cb82014-04-17 16:00:06 -0700226class HotGoalDecoder {
227 public:
228 HotGoalDecoder() {
229 ResetCounts();
230 }
231
232 void ResetCounts() {
233 hot_goal.FetchLatest();
234 if (hot_goal.get()) {
235 memcpy(&start_counts_, hot_goal.get(), sizeof(start_counts_));
236 LOG_STRUCT(INFO, "counts reset to", start_counts_);
237 start_counts_valid_ = true;
238 } else {
239 LOG(WARNING, "no hot goal message. ignoring\n");
240 start_counts_valid_ = false;
241 }
242 }
243
244 void Update() {
245 hot_goal.FetchLatest();
Brian Silvermanfa577e42014-04-19 12:03:00 -0700246 if (hot_goal.get()) LOG_STRUCT(INFO, "new counts", *hot_goal);
Brian Silverman4ac1cb82014-04-17 16:00:06 -0700247 }
248
249 bool is_left() const {
250 if (!start_counts_valid_ || !hot_goal.get()) return false;
251 const uint64_t left_difference =
252 hot_goal->left_count - start_counts_.left_count;
253 const uint64_t right_difference =
254 hot_goal->right_count - start_counts_.right_count;
255 if (left_difference > kThreshold) {
256 if (right_difference > kThreshold) {
257 return left_difference > right_difference;
258 } else {
259 // We've seen enough left but not enough right, so go with it.
260 return true;
261 }
262 } else {
263 // We haven't seen enough left, so it's not left.
264 return false;
265 }
266 }
267
268 bool is_right() const {
269 if (!start_counts_valid_ || !hot_goal.get()) return false;
270 const uint64_t left_difference =
271 hot_goal->left_count - start_counts_.left_count;
272 const uint64_t right_difference =
273 hot_goal->right_count - start_counts_.right_count;
274 if (right_difference > kThreshold) {
275 if (left_difference > kThreshold) {
276 return right_difference > left_difference;
277 } else {
278 // We've seen enough right but not enough left, so go with it.
279 return true;
280 }
281 } else {
282 // We haven't seen enough right, so it's not right.
283 return false;
284 }
285 }
286
287 private:
288 static const uint64_t kThreshold = 10;
289
290 ::frc971::HotGoal start_counts_;
291 bool start_counts_valid_;
292};
293
Austin Schuh80ff2e12014-03-08 12:06:19 -0800294void HandleAuto() {
Brian Silverman45ceeb52014-04-17 15:15:18 -0700295 enum class AutoVersion : uint8_t {
296 kStraight,
297 kDoubleHot,
298 };
299
Austin Schuha4faacc2014-03-09 00:50:50 -0800300 // The front of the robot is 1.854 meters from the wall
Brian Silvermanad9e0002014-04-13 14:55:57 -0700301 static const double kShootDistance = 3.15;
302 static const double kPickupDistance = 0.5;
303 static const double kTurnAngle = 0.3;
Brian Silverman45ceeb52014-04-17 15:15:18 -0700304
Austin Schuh577edf62014-04-13 10:33:05 -0700305 ::aos::time::Time start_time = ::aos::time::Time::Now();
Austin Schuh80ff2e12014-03-08 12:06:19 -0800306 LOG(INFO, "Handling auto mode\n");
Brian Silvermanb36ae1f2014-04-17 15:13:41 -0700307
Brian Silverman45ceeb52014-04-17 15:15:18 -0700308 AutoVersion auto_version;
309 ::frc971::sensors::auto_mode.FetchLatest();
310 if (!::frc971::sensors::auto_mode.get()) {
311 LOG(WARNING, "not sure which auto mode to use\n");
312 auto_version = AutoVersion::kStraight;
313 } else {
314 auto_version =
315 (::frc971::sensors::auto_mode->voltage > 2.5) ? AutoVersion::kDoubleHot
316 : AutoVersion::kStraight;
317 }
318 LOG(INFO, "running auto %" PRIu8 "\n", auto_version);
319
Brian Silverman4ac1cb82014-04-17 16:00:06 -0700320 HotGoalDecoder hot_goal_decoder;
321 // True for left, false for right.
322 bool first_shot_left, second_shot_left_default, second_shot_left;
Brian Silverman6f621542014-04-06 16:00:41 -0700323
Austin Schuh80ff2e12014-03-08 12:06:19 -0800324 ResetDrivetrain();
325
326 if (ShouldExitAuto()) return;
327 InitializeEncoders();
328
329 // Turn the claw on, keep it straight up until the ball has been grabbed.
Austin Schuh577edf62014-04-13 10:33:05 -0700330 LOG(INFO, "Claw going up at %f\n",
331 (::aos::time::Time::Now() - start_time).ToSeconds());
Austin Schuh80ff2e12014-03-08 12:06:19 -0800332 PositionClawVertically(12.0, 4.0);
Austin Schuha4faacc2014-03-09 00:50:50 -0800333 SetShotPower(115.0);
Austin Schuh80ff2e12014-03-08 12:06:19 -0800334
335 // Wait for the ball to enter the claw.
Austin Schuha4faacc2014-03-09 00:50:50 -0800336 time::SleepFor(time::Time::InSeconds(0.25));
Austin Schuh80ff2e12014-03-08 12:06:19 -0800337 if (ShouldExitAuto()) return;
Austin Schuh577edf62014-04-13 10:33:05 -0700338 LOG(INFO, "Readying claw for shot at %f\n",
339 (::aos::time::Time::Now() - start_time).ToSeconds());
Austin Schuh80ff2e12014-03-08 12:06:19 -0800340
341 {
342 if (ShouldExitAuto()) return;
343 // Drive to the goal.
Brian Silvermanb94069c2014-04-17 14:34:24 -0700344 auto drivetrain_action = SetDriveGoal(-kShootDistance, 2.5);
Austin Schuha4faacc2014-03-09 00:50:50 -0800345 time::SleepFor(time::Time::InSeconds(0.75));
346 PositionClawForShot();
347 LOG(INFO, "Waiting until drivetrain is finished\n");
Austin Schuh80ff2e12014-03-08 12:06:19 -0800348 WaitUntilDoneOrCanceled(drivetrain_action.get());
349 if (ShouldExitAuto()) return;
350 }
Brian Silvermanad9e0002014-04-13 14:55:57 -0700351
Brian Silverman4ac1cb82014-04-17 16:00:06 -0700352 hot_goal_decoder.Update();
353 if (hot_goal_decoder.is_left()) {
354 LOG(INFO, "first shot left\n");
355 first_shot_left = true;
356 second_shot_left_default = false;
357 } else if (hot_goal_decoder.is_right()) {
358 LOG(INFO, "first shot right\n");
359 first_shot_left = false;
360 second_shot_left_default = true;
361 } else {
362 LOG(INFO, "first shot defaulting left\n");
363 first_shot_left = true;
364 second_shot_left_default = true;
365 }
366 if (auto_version == AutoVersion::kDoubleHot) {
Brian Silvermanad9e0002014-04-13 14:55:57 -0700367 if (ShouldExitAuto()) return;
Brian Silverman4ac1cb82014-04-17 16:00:06 -0700368 auto drivetrain_action =
Brian Silvermanfa577e42014-04-19 12:03:00 -0700369 SetDriveGoal(0, 2, first_shot_left ? kTurnAngle : -kTurnAngle);
Brian Silvermanad9e0002014-04-13 14:55:57 -0700370 WaitUntilDoneOrCanceled(drivetrain_action.get());
371 if (ShouldExitAuto()) return;
372 }
Austin Schuh80ff2e12014-03-08 12:06:19 -0800373
374 // Shoot.
Brian Silvermanad9e0002014-04-13 14:55:57 -0700375 LOG(INFO, "Shooting at %f\n",
376 (::aos::time::Time::Now() - start_time).ToSeconds());
Austin Schuh80ff2e12014-03-08 12:06:19 -0800377 Shoot();
Austin Schuh577edf62014-04-13 10:33:05 -0700378 time::SleepFor(time::Time::InSeconds(0.05));
Austin Schuh80ff2e12014-03-08 12:06:19 -0800379
Brian Silverman4ac1cb82014-04-17 16:00:06 -0700380 if (auto_version == AutoVersion::kDoubleHot) {
Austin Schuh80ff2e12014-03-08 12:06:19 -0800381 if (ShouldExitAuto()) return;
Brian Silverman4ac1cb82014-04-17 16:00:06 -0700382 auto drivetrain_action =
Brian Silvermanfa577e42014-04-19 12:03:00 -0700383 SetDriveGoal(0, 2, first_shot_left ? -kTurnAngle : kTurnAngle);
Brian Silvermanad9e0002014-04-13 14:55:57 -0700384 WaitUntilDoneOrCanceled(drivetrain_action.get());
385 if (ShouldExitAuto()) return;
386 }
387
Brian Silverman4ac1cb82014-04-17 16:00:06 -0700388 hot_goal_decoder.ResetCounts();
389
Brian Silvermanad9e0002014-04-13 14:55:57 -0700390 {
391 if (ShouldExitAuto()) return;
Austin Schuh80ff2e12014-03-08 12:06:19 -0800392 // Intake the new ball.
Austin Schuh577edf62014-04-13 10:33:05 -0700393 LOG(INFO, "Claw ready for intake at %f\n",
394 (::aos::time::Time::Now() - start_time).ToSeconds());
Austin Schuh80ff2e12014-03-08 12:06:19 -0800395 PositionClawBackIntake();
Brian Silvermanb94069c2014-04-17 14:34:24 -0700396 auto drivetrain_action =
397 SetDriveGoal(kShootDistance + kPickupDistance, 2.5);
Austin Schuha4faacc2014-03-09 00:50:50 -0800398 LOG(INFO, "Waiting until drivetrain is finished\n");
Austin Schuh80ff2e12014-03-08 12:06:19 -0800399 WaitUntilDoneOrCanceled(drivetrain_action.get());
400 if (ShouldExitAuto()) return;
Austin Schuh577edf62014-04-13 10:33:05 -0700401 LOG(INFO, "Wait for the claw at %f\n",
402 (::aos::time::Time::Now() - start_time).ToSeconds());
Austin Schuha4faacc2014-03-09 00:50:50 -0800403 WaitUntilClawDone();
404 if (ShouldExitAuto()) return;
Austin Schuh80ff2e12014-03-08 12:06:19 -0800405 }
406
407 // Drive back.
408 {
Austin Schuh577edf62014-04-13 10:33:05 -0700409 LOG(INFO, "Driving back at %f\n",
410 (::aos::time::Time::Now() - start_time).ToSeconds());
Brian Silvermanb94069c2014-04-17 14:34:24 -0700411 auto drivetrain_action =
412 SetDriveGoal(-(kShootDistance + kPickupDistance), 2.5);
Austin Schuh577edf62014-04-13 10:33:05 -0700413 time::SleepFor(time::Time::InSeconds(0.3));
Austin Schuh80ff2e12014-03-08 12:06:19 -0800414 if (ShouldExitAuto()) return;
415 PositionClawForShot();
Austin Schuha4faacc2014-03-09 00:50:50 -0800416 LOG(INFO, "Waiting until drivetrain is finished\n");
Austin Schuh80ff2e12014-03-08 12:06:19 -0800417 WaitUntilDoneOrCanceled(drivetrain_action.get());
Austin Schuha4faacc2014-03-09 00:50:50 -0800418 WaitUntilClawDone();
Austin Schuh80ff2e12014-03-08 12:06:19 -0800419 if (ShouldExitAuto()) return;
420 }
421
Brian Silverman4ac1cb82014-04-17 16:00:06 -0700422 hot_goal_decoder.Update();
423 if (hot_goal_decoder.is_left()) {
424 LOG(INFO, "second shot left\n");
425 second_shot_left = true;
426 } else if (hot_goal_decoder.is_right()) {
427 LOG(INFO, "second shot right\n");
428 second_shot_left = false;
429 } else {
430 LOG(INFO, "second shot defaulting %s\n",
431 second_shot_left_default ? "left" : "right");
432 second_shot_left = second_shot_left_default;
433 }
434 if (auto_version == AutoVersion::kDoubleHot) {
Brian Silvermanad9e0002014-04-13 14:55:57 -0700435 if (ShouldExitAuto()) return;
Brian Silverman4ac1cb82014-04-17 16:00:06 -0700436 auto drivetrain_action =
Brian Silvermanfa577e42014-04-19 12:03:00 -0700437 SetDriveGoal(0, 2, second_shot_left ? kTurnAngle : -kTurnAngle);
Brian Silvermanad9e0002014-04-13 14:55:57 -0700438 WaitUntilDoneOrCanceled(drivetrain_action.get());
439 if (ShouldExitAuto()) return;
440 }
441
Austin Schuh577edf62014-04-13 10:33:05 -0700442 LOG(INFO, "Shooting at %f\n",
443 (::aos::time::Time::Now() - start_time).ToSeconds());
Austin Schuh80ff2e12014-03-08 12:06:19 -0800444 // Shoot
445 Shoot();
446 if (ShouldExitAuto()) return;
447
448 // Get ready to zero when we come back up.
Austin Schuh577edf62014-04-13 10:33:05 -0700449 time::SleepFor(time::Time::InSeconds(0.05));
Austin Schuh80ff2e12014-03-08 12:06:19 -0800450 PositionClawVertically(0.0, 0.0);
Austin Schuh47017412013-03-10 11:50:46 -0700451}
452
453} // namespace autonomous
454} // namespace frc971