blob: 4e2c9aaf592312cf5756821885e9c7f3f38aa0f8 [file] [log] [blame]
Austin Schuhbfb04122019-05-22 21:16:51 -07001#include "y2014/actors/autonomous_actor.h"
2
3#include <stdio.h>
4
5#include <chrono>
6#include <memory>
7
8#include "aos/actions/actions.h"
9#include "aos/logging/logging.h"
10#include "aos/logging/queue_logging.h"
11#include "aos/time/time.h"
12#include "aos/util/phased_loop.h"
13#include "frc971/autonomous/auto.q.h"
14#include "frc971/control_loops/drivetrain/drivetrain.q.h"
15#include "y2014/actors/shoot_actor.h"
16#include "y2014/constants.h"
17#include "y2014/control_loops/claw/claw.q.h"
18#include "y2014/control_loops/drivetrain/drivetrain_base.h"
19#include "y2014/control_loops/shooter/shooter.q.h"
20#include "y2014/queues/auto_mode.q.h"
21#include "y2014/queues/hot_goal.q.h"
22
23namespace y2014 {
24namespace actors {
25
26namespace chrono = ::std::chrono;
27namespace this_thread = ::std::this_thread;
28using ::aos::monotonic_clock;
29using ::frc971::ProfileParameters;
30
Austin Schuh1bf8a212019-05-26 22:13:14 -070031AutonomousActor::AutonomousActor(::aos::EventLoop *event_loop)
Austin Schuhbfb04122019-05-22 21:16:51 -070032 : frc971::autonomous::BaseAutonomousActor(
Austin Schuh1bf8a212019-05-26 22:13:14 -070033 event_loop, control_loops::GetDrivetrainConfig()),
Austin Schuh7eed2de2019-05-25 14:34:40 -070034 auto_mode_fetcher_(event_loop->MakeFetcher<::y2014::sensors::AutoMode>(
35 ".y2014.sensors.auto_mode")),
Austin Schuha3e576b2019-05-22 21:22:23 -070036 hot_goal_fetcher_(
Austin Schuh1bf8a212019-05-26 22:13:14 -070037 event_loop->MakeFetcher<::y2014::HotGoal>(".y2014.hot_goal")),
Austin Schuhb2461f42019-06-29 18:17:06 -070038 claw_goal_sender_(
39 event_loop->MakeSender<::y2014::control_loops::ClawQueue::Goal>(
40 ".y2014.control_loops.claw_queue.goal")),
41 claw_goal_fetcher_(
42 event_loop->MakeFetcher<::y2014::control_loops::ClawQueue::Goal>(
43 ".y2014.control_loops.claw_queue.goal")),
44 claw_status_fetcher_(
45 event_loop->MakeFetcher<::y2014::control_loops::ClawQueue::Status>(
46 ".y2014.control_loops.claw_queue.status")),
47 shooter_goal_sender_(
48 event_loop->MakeSender<::y2014::control_loops::ShooterQueue::Goal>(
49 ".y2014.control_loops.shooter_queue.goal")),
Austin Schuh1bf8a212019-05-26 22:13:14 -070050 shoot_action_factory_(actors::ShootActor::MakeFactory(event_loop)) {}
Austin Schuhbfb04122019-05-22 21:16:51 -070051
52void AutonomousActor::PositionClawVertically(double intake_power,
53 double centering_power) {
Austin Schuhb2461f42019-06-29 18:17:06 -070054 auto goal_message = claw_goal_sender_.MakeMessage();
55 goal_message->bottom_angle = 0.0;
56 goal_message->separation_angle = 0.0;
57 goal_message->intake = intake_power;
58 goal_message->centering = centering_power;
59
60 if (!goal_message.Send()) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070061 AOS_LOG(WARNING, "sending claw goal failed\n");
Austin Schuhbfb04122019-05-22 21:16:51 -070062 }
63}
64
65void AutonomousActor::PositionClawBackIntake() {
Austin Schuhb2461f42019-06-29 18:17:06 -070066 auto goal_message = claw_goal_sender_.MakeMessage();
67 goal_message->bottom_angle = -2.273474;
68 goal_message->separation_angle = 0.0;
69 goal_message->intake = 12.0;
70 goal_message->centering = 12.0;
71 if (!goal_message.Send()) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070072 AOS_LOG(WARNING, "sending claw goal failed\n");
Austin Schuhbfb04122019-05-22 21:16:51 -070073 }
74}
75
76void AutonomousActor::PositionClawUpClosed() {
77 // Move the claw to where we're going to shoot from but keep it closed until
78 // it gets there.
Austin Schuhb2461f42019-06-29 18:17:06 -070079 auto goal_message = claw_goal_sender_.MakeMessage();
80 goal_message->bottom_angle = 0.86;
81 goal_message->separation_angle = 0.0;
82 goal_message->intake = 4.0;
83 goal_message->centering = 1.0;
84 if (!goal_message.Send()) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070085 AOS_LOG(WARNING, "sending claw goal failed\n");
Austin Schuhbfb04122019-05-22 21:16:51 -070086 }
87}
88
89void AutonomousActor::PositionClawForShot() {
Austin Schuhb2461f42019-06-29 18:17:06 -070090 auto goal_message = claw_goal_sender_.MakeMessage();
91 goal_message->bottom_angle = 0.86;
92 goal_message->separation_angle = 0.10;
93 goal_message->intake = 4.0;
94 goal_message->centering = 1.0;
95 if (!goal_message.Send()) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070096 AOS_LOG(WARNING, "sending claw goal failed\n");
Austin Schuhbfb04122019-05-22 21:16:51 -070097 }
98}
99
100void AutonomousActor::SetShotPower(double power) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700101 AOS_LOG(INFO, "Setting shot power to %f\n", power);
Austin Schuhb2461f42019-06-29 18:17:06 -0700102 auto goal_message = shooter_goal_sender_.MakeMessage();
103 goal_message->shot_power = power;
104 goal_message->shot_requested = false;
105 goal_message->unload_requested = false;
106 goal_message->load_requested = false;
107 if (!goal_message.Send()) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700108 AOS_LOG(WARNING, "sending shooter goal failed\n");
Austin Schuhbfb04122019-05-22 21:16:51 -0700109 }
110}
111
112const ProfileParameters kFastDrive = {3.0, 2.5};
113const ProfileParameters kSlowDrive = {2.5, 2.5};
114const ProfileParameters kFastWithBallDrive = {3.0, 2.0};
115const ProfileParameters kSlowWithBallDrive = {2.5, 2.0};
116const ProfileParameters kFastTurn = {3.0, 10.0};
117
118void AutonomousActor::Shoot() {
119 // Shoot.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700120 auto shoot_action = shoot_action_factory_.Make(0.0);
Austin Schuhbfb04122019-05-22 21:16:51 -0700121 shoot_action->Start();
122 WaitUntilDoneOrCanceled(::std::move(shoot_action));
123}
124
125bool AutonomousActor::WaitUntilClawDone() {
126 while (true) {
127 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(10),
Austin Schuhd32b3622019-06-23 18:49:06 -0700128 event_loop()->monotonic_now(),
Austin Schuhbfb04122019-05-22 21:16:51 -0700129 ::std::chrono::milliseconds(10) / 2);
130 // Poll the running bit and auto done bits.
131 phased_loop.SleepUntilNext();
Austin Schuhb2461f42019-06-29 18:17:06 -0700132 claw_status_fetcher_.Fetch();
133 claw_goal_fetcher_.Fetch();
Austin Schuhbfb04122019-05-22 21:16:51 -0700134 if (ShouldCancel()) {
135 return false;
136 }
Austin Schuhb2461f42019-06-29 18:17:06 -0700137 if (claw_status_fetcher_.get() == nullptr ||
138 claw_goal_fetcher_.get() == nullptr) {
Austin Schuhbfb04122019-05-22 21:16:51 -0700139 continue;
140 }
Austin Schuhb2461f42019-06-29 18:17:06 -0700141 bool ans = claw_status_fetcher_->zeroed &&
142 (::std::abs(claw_status_fetcher_->bottom_velocity) < 1.0) &&
143 (::std::abs(claw_status_fetcher_->bottom -
144 claw_goal_fetcher_->bottom_angle) < 0.10) &&
145 (::std::abs(claw_status_fetcher_->separation -
146 claw_goal_fetcher_->separation_angle) < 0.4);
Austin Schuhbfb04122019-05-22 21:16:51 -0700147 if (ans) {
148 return true;
149 }
150 }
151}
152
153class HotGoalDecoder {
154 public:
Austin Schuha3e576b2019-05-22 21:22:23 -0700155 HotGoalDecoder(::aos::Fetcher<::y2014::HotGoal> *hot_goal_fetcher)
156 : hot_goal_fetcher_(hot_goal_fetcher) {
157 ResetCounts();
158 }
Austin Schuhbfb04122019-05-22 21:16:51 -0700159
160 void ResetCounts() {
Austin Schuha3e576b2019-05-22 21:22:23 -0700161 hot_goal_fetcher_->Fetch();
162 if (hot_goal_fetcher_->get()) {
163 start_counts_ = *hot_goal_fetcher_->get();
Austin Schuhf257f3c2019-10-27 21:00:43 -0700164 AOS_LOG_STRUCT(INFO, "counts reset to", start_counts_);
Austin Schuhbfb04122019-05-22 21:16:51 -0700165 start_counts_valid_ = true;
166 } else {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700167 AOS_LOG(WARNING, "no hot goal message. ignoring\n");
Austin Schuhbfb04122019-05-22 21:16:51 -0700168 start_counts_valid_ = false;
169 }
170 }
171
Austin Schuha3e576b2019-05-22 21:22:23 -0700172 void Update() {
173 hot_goal_fetcher_->Fetch();
174 if (hot_goal_fetcher_->get())
Austin Schuhf257f3c2019-10-27 21:00:43 -0700175 AOS_LOG_STRUCT(INFO, "new counts", *hot_goal_fetcher_->get());
Austin Schuhbfb04122019-05-22 21:16:51 -0700176 }
177
178 bool left_triggered() const {
Austin Schuha3e576b2019-05-22 21:22:23 -0700179 if (!start_counts_valid_ || !hot_goal_fetcher_->get()) return false;
180 return (hot_goal_fetcher_->get()->left_count - start_counts_.left_count) >
181 kThreshold;
Austin Schuhbfb04122019-05-22 21:16:51 -0700182 }
183
184 bool right_triggered() const {
Austin Schuha3e576b2019-05-22 21:22:23 -0700185 if (!start_counts_valid_ || !hot_goal_fetcher_->get()) return false;
186 return (hot_goal_fetcher_->get()->right_count - start_counts_.right_count) >
187 kThreshold;
Austin Schuhbfb04122019-05-22 21:16:51 -0700188 }
189
190 bool is_left() const {
Austin Schuha3e576b2019-05-22 21:22:23 -0700191 if (!start_counts_valid_ || !hot_goal_fetcher_->get()) return false;
Austin Schuhbfb04122019-05-22 21:16:51 -0700192 const uint64_t left_difference =
Austin Schuha3e576b2019-05-22 21:22:23 -0700193 hot_goal_fetcher_->get()->left_count - start_counts_.left_count;
Austin Schuhbfb04122019-05-22 21:16:51 -0700194 const uint64_t right_difference =
Austin Schuha3e576b2019-05-22 21:22:23 -0700195 hot_goal_fetcher_->get()->right_count - start_counts_.right_count;
Austin Schuhbfb04122019-05-22 21:16:51 -0700196 if (left_difference > kThreshold) {
197 if (right_difference > kThreshold) {
198 // We've seen a lot of both, so pick the one we've seen the most of.
199 return left_difference > right_difference;
200 } else {
201 // We've seen enough left but not enough right, so go with it.
202 return true;
203 }
204 } else {
205 // We haven't seen enough left, so it's not left.
206 return false;
207 }
208 }
209
210 bool is_right() const {
Austin Schuha3e576b2019-05-22 21:22:23 -0700211 if (!start_counts_valid_ || !hot_goal_fetcher_->get()) return false;
Austin Schuhbfb04122019-05-22 21:16:51 -0700212 const uint64_t left_difference =
Austin Schuha3e576b2019-05-22 21:22:23 -0700213 hot_goal_fetcher_->get()->left_count - start_counts_.left_count;
Austin Schuhbfb04122019-05-22 21:16:51 -0700214 const uint64_t right_difference =
Austin Schuha3e576b2019-05-22 21:22:23 -0700215 hot_goal_fetcher_->get()->right_count - start_counts_.right_count;
Austin Schuhbfb04122019-05-22 21:16:51 -0700216 if (right_difference > kThreshold) {
217 if (left_difference > kThreshold) {
218 // We've seen a lot of both, so pick the one we've seen the most of.
219 return right_difference > left_difference;
220 } else {
221 // We've seen enough right but not enough left, so go with it.
222 return true;
223 }
224 } else {
225 // We haven't seen enough right, so it's not right.
226 return false;
227 }
228 }
229
230 private:
231 static const uint64_t kThreshold = 5;
232
233 ::y2014::HotGoal start_counts_;
234 bool start_counts_valid_;
Austin Schuha3e576b2019-05-22 21:22:23 -0700235
236 ::aos::Fetcher<::y2014::HotGoal> *hot_goal_fetcher_;
Austin Schuhbfb04122019-05-22 21:16:51 -0700237};
238
239bool AutonomousActor::RunAction(
240 const ::frc971::autonomous::AutonomousActionParams & /*params*/) {
241 enum class AutoVersion : uint8_t {
242 kStraight,
243 kDoubleHot,
244 kSingleHot,
245 };
246
247 // The front of the robot is 1.854 meters from the wall
248 static const double kShootDistance = 3.15;
249 static const double kPickupDistance = 0.5;
250 static const double kTurnAngle = 0.3;
251
Austin Schuh77ed5432019-07-07 20:41:36 -0700252 const monotonic_clock::time_point start_time = monotonic_now();
Austin Schuhf257f3c2019-10-27 21:00:43 -0700253 AOS_LOG(INFO, "Handling auto mode\n");
Austin Schuhbfb04122019-05-22 21:16:51 -0700254
255 AutoVersion auto_version;
Austin Schuh7eed2de2019-05-25 14:34:40 -0700256 auto_mode_fetcher_.Fetch();
257 if (!auto_mode_fetcher_.get()) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700258 AOS_LOG(WARNING, "not sure which auto mode to use\n");
Austin Schuhbfb04122019-05-22 21:16:51 -0700259 auto_version = AutoVersion::kStraight;
260 } else {
261 static const double kSelectorMin = 0.2, kSelectorMax = 4.4;
262
263 const double kSelectorStep = (kSelectorMax - kSelectorMin) / 3.0;
Austin Schuh7eed2de2019-05-25 14:34:40 -0700264 if (auto_mode_fetcher_->voltage < kSelectorStep + kSelectorMin) {
Austin Schuhbfb04122019-05-22 21:16:51 -0700265 auto_version = AutoVersion::kSingleHot;
Austin Schuh7eed2de2019-05-25 14:34:40 -0700266 } else if (auto_mode_fetcher_->voltage < 2 * kSelectorStep + kSelectorMin) {
Austin Schuhbfb04122019-05-22 21:16:51 -0700267 auto_version = AutoVersion::kStraight;
268 } else {
269 auto_version = AutoVersion::kDoubleHot;
270 }
271 }
Austin Schuhf257f3c2019-10-27 21:00:43 -0700272 AOS_LOG(INFO, "running auto %" PRIu8 "\n",
273 static_cast<uint8_t>(auto_version));
Austin Schuhbfb04122019-05-22 21:16:51 -0700274
275 const ProfileParameters &drive_params =
276 (auto_version == AutoVersion::kStraight) ? kFastDrive : kSlowDrive;
277 const ProfileParameters &drive_with_ball_params =
278 (auto_version == AutoVersion::kStraight) ? kFastWithBallDrive
279 : kSlowWithBallDrive;
280
Austin Schuha3e576b2019-05-22 21:22:23 -0700281 HotGoalDecoder hot_goal_decoder(&hot_goal_fetcher_);
Austin Schuhbfb04122019-05-22 21:16:51 -0700282 // True for left, false for right.
283 bool first_shot_left, second_shot_left_default, second_shot_left;
284
285 Reset();
286
287 // Turn the claw on, keep it straight up until the ball has been grabbed.
Austin Schuhf257f3c2019-10-27 21:00:43 -0700288 AOS_LOG(INFO, "Claw going up at %f\n",
289 ::aos::time::DurationInSeconds(monotonic_now() - start_time));
Austin Schuhbfb04122019-05-22 21:16:51 -0700290 PositionClawVertically(12.0, 4.0);
291 SetShotPower(115.0);
292
293 // Wait for the ball to enter the claw.
294 this_thread::sleep_for(chrono::milliseconds(250));
295 if (ShouldCancel()) return true;
Austin Schuhf257f3c2019-10-27 21:00:43 -0700296 AOS_LOG(INFO, "Readying claw for shot at %f\n",
297 ::aos::time::DurationInSeconds(monotonic_now() - start_time));
Austin Schuhbfb04122019-05-22 21:16:51 -0700298
299 if (ShouldCancel()) return true;
300 // Drive to the goal.
301 StartDrive(-kShootDistance, 0.0, drive_params, kFastTurn);
302 this_thread::sleep_for(chrono::milliseconds(750));
303 PositionClawForShot();
Austin Schuhf257f3c2019-10-27 21:00:43 -0700304 AOS_LOG(INFO, "Waiting until drivetrain is finished\n");
Austin Schuhbfb04122019-05-22 21:16:51 -0700305 WaitForDriveProfileDone();
306 if (ShouldCancel()) return true;
307
308 hot_goal_decoder.Update();
309 if (hot_goal_decoder.is_left()) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700310 AOS_LOG(INFO, "first shot left\n");
Austin Schuhbfb04122019-05-22 21:16:51 -0700311 first_shot_left = true;
312 second_shot_left_default = false;
313 } else if (hot_goal_decoder.is_right()) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700314 AOS_LOG(INFO, "first shot right\n");
Austin Schuhbfb04122019-05-22 21:16:51 -0700315 first_shot_left = false;
316 second_shot_left_default = true;
317 } else {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700318 AOS_LOG(INFO, "first shot defaulting left\n");
Austin Schuhbfb04122019-05-22 21:16:51 -0700319 first_shot_left = true;
320 second_shot_left_default = true;
321 }
322 if (auto_version == AutoVersion::kDoubleHot) {
323 if (ShouldCancel()) return true;
324 StartDrive(0, first_shot_left ? kTurnAngle : -kTurnAngle,
325 drive_with_ball_params, kFastTurn);
326 WaitForDriveProfileDone();
327 if (ShouldCancel()) return true;
328 } else if (auto_version == AutoVersion::kSingleHot) {
329 do {
330 // TODO(brians): Wait for next message with timeout or something.
331 this_thread::sleep_for(chrono::milliseconds(3));
Austin Schuha3e576b2019-05-22 21:22:23 -0700332 hot_goal_decoder.Update();
Austin Schuhbfb04122019-05-22 21:16:51 -0700333 if (ShouldCancel()) return true;
334 } while (!hot_goal_decoder.left_triggered() &&
Austin Schuh77ed5432019-07-07 20:41:36 -0700335 (monotonic_now() - start_time) < chrono::seconds(9));
Austin Schuhbfb04122019-05-22 21:16:51 -0700336 } else if (auto_version == AutoVersion::kStraight) {
337 this_thread::sleep_for(chrono::milliseconds(400));
338 }
339
340 // Shoot.
Austin Schuhf257f3c2019-10-27 21:00:43 -0700341 AOS_LOG(INFO, "Shooting at %f\n",
342 ::aos::time::DurationInSeconds(monotonic_now() - start_time));
Austin Schuhbfb04122019-05-22 21:16:51 -0700343 Shoot();
344 this_thread::sleep_for(chrono::milliseconds(50));
345
346 if (auto_version == AutoVersion::kDoubleHot) {
347 if (ShouldCancel()) return true;
348 StartDrive(0, first_shot_left ? -kTurnAngle : kTurnAngle,
349 drive_with_ball_params, kFastTurn);
350 WaitForDriveProfileDone();
351 if (ShouldCancel()) return true;
352 } else if (auto_version == AutoVersion::kSingleHot) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700353 AOS_LOG(INFO, "auto done at %f\n",
354 ::aos::time::DurationInSeconds(monotonic_now() - start_time));
Austin Schuhbfb04122019-05-22 21:16:51 -0700355 PositionClawVertically(0.0, 0.0);
356 return true;
357 }
358
359 {
360 if (ShouldCancel()) return true;
361 // Intake the new ball.
Austin Schuhf257f3c2019-10-27 21:00:43 -0700362 AOS_LOG(INFO, "Claw ready for intake at %f\n",
363 ::aos::time::DurationInSeconds(monotonic_now() - start_time));
Austin Schuhbfb04122019-05-22 21:16:51 -0700364 PositionClawBackIntake();
365 StartDrive(kShootDistance + kPickupDistance, 0.0, drive_params, kFastTurn);
Austin Schuhf257f3c2019-10-27 21:00:43 -0700366 AOS_LOG(INFO, "Waiting until drivetrain is finished\n");
Austin Schuhbfb04122019-05-22 21:16:51 -0700367 WaitForDriveProfileDone();
368 if (ShouldCancel()) return true;
Austin Schuhf257f3c2019-10-27 21:00:43 -0700369 AOS_LOG(INFO, "Wait for the claw at %f\n",
370 ::aos::time::DurationInSeconds(monotonic_now() - start_time));
Austin Schuhbfb04122019-05-22 21:16:51 -0700371 if (!WaitUntilClawDone()) return true;
372 }
373
374 // Drive back.
375 {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700376 AOS_LOG(INFO, "Driving back at %f\n",
377 ::aos::time::DurationInSeconds(monotonic_now() - start_time));
Austin Schuhbfb04122019-05-22 21:16:51 -0700378 StartDrive(-(kShootDistance + kPickupDistance), 0.0, drive_params,
379 kFastTurn);
380 this_thread::sleep_for(chrono::milliseconds(300));
381 hot_goal_decoder.ResetCounts();
382 if (ShouldCancel()) return true;
383 PositionClawUpClosed();
384 if (!WaitUntilClawDone()) return true;
385 PositionClawForShot();
Austin Schuhf257f3c2019-10-27 21:00:43 -0700386 AOS_LOG(INFO, "Waiting until drivetrain is finished\n");
Austin Schuhbfb04122019-05-22 21:16:51 -0700387 WaitForDriveProfileDone();
388 if (ShouldCancel()) return true;
389 if (!WaitUntilClawDone()) return true;
390 }
391
392 hot_goal_decoder.Update();
393 if (hot_goal_decoder.is_left()) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700394 AOS_LOG(INFO, "second shot left\n");
Austin Schuhbfb04122019-05-22 21:16:51 -0700395 second_shot_left = true;
396 } else if (hot_goal_decoder.is_right()) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700397 AOS_LOG(INFO, "second shot right\n");
Austin Schuhbfb04122019-05-22 21:16:51 -0700398 second_shot_left = false;
399 } else {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700400 AOS_LOG(INFO, "second shot defaulting %s\n",
401 second_shot_left_default ? "left" : "right");
Austin Schuhbfb04122019-05-22 21:16:51 -0700402 second_shot_left = second_shot_left_default;
403 }
404 if (auto_version == AutoVersion::kDoubleHot) {
405 if (ShouldCancel()) return true;
406 StartDrive(0, second_shot_left ? kTurnAngle : -kTurnAngle, drive_params,
407 kFastTurn);
408 WaitForDriveProfileDone();
409 if (ShouldCancel()) return true;
410 } else if (auto_version == AutoVersion::kStraight) {
411 this_thread::sleep_for(chrono::milliseconds(400));
412 }
413
Austin Schuhf257f3c2019-10-27 21:00:43 -0700414 AOS_LOG(INFO, "Shooting at %f\n",
415 ::aos::time::DurationInSeconds(monotonic_now() - start_time));
Austin Schuhbfb04122019-05-22 21:16:51 -0700416 // Shoot
417 Shoot();
418 if (ShouldCancel()) return true;
419
420 // Get ready to zero when we come back up.
421 this_thread::sleep_for(chrono::milliseconds(50));
422 PositionClawVertically(0.0, 0.0);
423 return true;
424}
425
426} // namespace actors
427} // namespace y2014