blob: 76a037c134c0bf8649f2dfbdc16c7f23bef31ecf [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 Schuhbfb04122019-05-22 21:16:51 -070061 LOG(WARNING, "sending claw goal failed\n");
62 }
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 Schuhbfb04122019-05-22 21:16:51 -070072 LOG(WARNING, "sending claw goal failed\n");
73 }
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 Schuhbfb04122019-05-22 21:16:51 -070085 LOG(WARNING, "sending claw goal failed\n");
86 }
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 Schuhbfb04122019-05-22 21:16:51 -070096 LOG(WARNING, "sending claw goal failed\n");
97 }
98}
99
100void AutonomousActor::SetShotPower(double power) {
101 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 Schuhbfb04122019-05-22 21:16:51 -0700108 LOG(WARNING, "sending shooter goal failed\n");
109 }
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 Schuhbfb04122019-05-22 21:16:51 -0700164 LOG_STRUCT(INFO, "counts reset to", start_counts_);
165 start_counts_valid_ = true;
166 } else {
167 LOG(WARNING, "no hot goal message. ignoring\n");
168 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())
175 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 Schuhbfb04122019-05-22 21:16:51 -0700253 LOG(INFO, "Handling auto mode\n");
254
255 AutoVersion auto_version;
Austin Schuh7eed2de2019-05-25 14:34:40 -0700256 auto_mode_fetcher_.Fetch();
257 if (!auto_mode_fetcher_.get()) {
Austin Schuhbfb04122019-05-22 21:16:51 -0700258 LOG(WARNING, "not sure which auto mode to use\n");
259 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 }
272 LOG(INFO, "running auto %" PRIu8 "\n", static_cast<uint8_t>(auto_version));
273
274 const ProfileParameters &drive_params =
275 (auto_version == AutoVersion::kStraight) ? kFastDrive : kSlowDrive;
276 const ProfileParameters &drive_with_ball_params =
277 (auto_version == AutoVersion::kStraight) ? kFastWithBallDrive
278 : kSlowWithBallDrive;
279
Austin Schuha3e576b2019-05-22 21:22:23 -0700280 HotGoalDecoder hot_goal_decoder(&hot_goal_fetcher_);
Austin Schuhbfb04122019-05-22 21:16:51 -0700281 // True for left, false for right.
282 bool first_shot_left, second_shot_left_default, second_shot_left;
283
284 Reset();
285
286 // Turn the claw on, keep it straight up until the ball has been grabbed.
287 LOG(INFO, "Claw going up at %f\n",
Austin Schuh77ed5432019-07-07 20:41:36 -0700288 ::aos::time::DurationInSeconds(monotonic_now() - start_time));
Austin Schuhbfb04122019-05-22 21:16:51 -0700289 PositionClawVertically(12.0, 4.0);
290 SetShotPower(115.0);
291
292 // Wait for the ball to enter the claw.
293 this_thread::sleep_for(chrono::milliseconds(250));
294 if (ShouldCancel()) return true;
295 LOG(INFO, "Readying claw for shot at %f\n",
Austin Schuh77ed5432019-07-07 20:41:36 -0700296 ::aos::time::DurationInSeconds(monotonic_now() - start_time));
Austin Schuhbfb04122019-05-22 21:16:51 -0700297
298 if (ShouldCancel()) return true;
299 // Drive to the goal.
300 StartDrive(-kShootDistance, 0.0, drive_params, kFastTurn);
301 this_thread::sleep_for(chrono::milliseconds(750));
302 PositionClawForShot();
303 LOG(INFO, "Waiting until drivetrain is finished\n");
304 WaitForDriveProfileDone();
305 if (ShouldCancel()) return true;
306
307 hot_goal_decoder.Update();
308 if (hot_goal_decoder.is_left()) {
309 LOG(INFO, "first shot left\n");
310 first_shot_left = true;
311 second_shot_left_default = false;
312 } else if (hot_goal_decoder.is_right()) {
313 LOG(INFO, "first shot right\n");
314 first_shot_left = false;
315 second_shot_left_default = true;
316 } else {
317 LOG(INFO, "first shot defaulting left\n");
318 first_shot_left = true;
319 second_shot_left_default = true;
320 }
321 if (auto_version == AutoVersion::kDoubleHot) {
322 if (ShouldCancel()) return true;
323 StartDrive(0, first_shot_left ? kTurnAngle : -kTurnAngle,
324 drive_with_ball_params, kFastTurn);
325 WaitForDriveProfileDone();
326 if (ShouldCancel()) return true;
327 } else if (auto_version == AutoVersion::kSingleHot) {
328 do {
329 // TODO(brians): Wait for next message with timeout or something.
330 this_thread::sleep_for(chrono::milliseconds(3));
Austin Schuha3e576b2019-05-22 21:22:23 -0700331 hot_goal_decoder.Update();
Austin Schuhbfb04122019-05-22 21:16:51 -0700332 if (ShouldCancel()) return true;
333 } while (!hot_goal_decoder.left_triggered() &&
Austin Schuh77ed5432019-07-07 20:41:36 -0700334 (monotonic_now() - start_time) < chrono::seconds(9));
Austin Schuhbfb04122019-05-22 21:16:51 -0700335 } else if (auto_version == AutoVersion::kStraight) {
336 this_thread::sleep_for(chrono::milliseconds(400));
337 }
338
339 // Shoot.
340 LOG(INFO, "Shooting at %f\n",
Austin Schuh77ed5432019-07-07 20:41:36 -0700341 ::aos::time::DurationInSeconds(monotonic_now() - start_time));
Austin Schuhbfb04122019-05-22 21:16:51 -0700342 Shoot();
343 this_thread::sleep_for(chrono::milliseconds(50));
344
345 if (auto_version == AutoVersion::kDoubleHot) {
346 if (ShouldCancel()) return true;
347 StartDrive(0, first_shot_left ? -kTurnAngle : kTurnAngle,
348 drive_with_ball_params, kFastTurn);
349 WaitForDriveProfileDone();
350 if (ShouldCancel()) return true;
351 } else if (auto_version == AutoVersion::kSingleHot) {
352 LOG(INFO, "auto done at %f\n",
Austin Schuh77ed5432019-07-07 20:41:36 -0700353 ::aos::time::DurationInSeconds(monotonic_now() - start_time));
Austin Schuhbfb04122019-05-22 21:16:51 -0700354 PositionClawVertically(0.0, 0.0);
355 return true;
356 }
357
358 {
359 if (ShouldCancel()) return true;
360 // Intake the new ball.
361 LOG(INFO, "Claw ready for intake at %f\n",
Austin Schuh77ed5432019-07-07 20:41:36 -0700362 ::aos::time::DurationInSeconds(monotonic_now() - start_time));
Austin Schuhbfb04122019-05-22 21:16:51 -0700363 PositionClawBackIntake();
364 StartDrive(kShootDistance + kPickupDistance, 0.0, drive_params, kFastTurn);
365 LOG(INFO, "Waiting until drivetrain is finished\n");
366 WaitForDriveProfileDone();
367 if (ShouldCancel()) return true;
368 LOG(INFO, "Wait for the claw at %f\n",
Austin Schuh77ed5432019-07-07 20:41:36 -0700369 ::aos::time::DurationInSeconds(monotonic_now() - start_time));
Austin Schuhbfb04122019-05-22 21:16:51 -0700370 if (!WaitUntilClawDone()) return true;
371 }
372
373 // Drive back.
374 {
375 LOG(INFO, "Driving back at %f\n",
Austin Schuh77ed5432019-07-07 20:41:36 -0700376 ::aos::time::DurationInSeconds(monotonic_now() - start_time));
Austin Schuhbfb04122019-05-22 21:16:51 -0700377 StartDrive(-(kShootDistance + kPickupDistance), 0.0, drive_params,
378 kFastTurn);
379 this_thread::sleep_for(chrono::milliseconds(300));
380 hot_goal_decoder.ResetCounts();
381 if (ShouldCancel()) return true;
382 PositionClawUpClosed();
383 if (!WaitUntilClawDone()) return true;
384 PositionClawForShot();
385 LOG(INFO, "Waiting until drivetrain is finished\n");
386 WaitForDriveProfileDone();
387 if (ShouldCancel()) return true;
388 if (!WaitUntilClawDone()) return true;
389 }
390
391 hot_goal_decoder.Update();
392 if (hot_goal_decoder.is_left()) {
393 LOG(INFO, "second shot left\n");
394 second_shot_left = true;
395 } else if (hot_goal_decoder.is_right()) {
396 LOG(INFO, "second shot right\n");
397 second_shot_left = false;
398 } else {
399 LOG(INFO, "second shot defaulting %s\n",
400 second_shot_left_default ? "left" : "right");
401 second_shot_left = second_shot_left_default;
402 }
403 if (auto_version == AutoVersion::kDoubleHot) {
404 if (ShouldCancel()) return true;
405 StartDrive(0, second_shot_left ? kTurnAngle : -kTurnAngle, drive_params,
406 kFastTurn);
407 WaitForDriveProfileDone();
408 if (ShouldCancel()) return true;
409 } else if (auto_version == AutoVersion::kStraight) {
410 this_thread::sleep_for(chrono::milliseconds(400));
411 }
412
413 LOG(INFO, "Shooting at %f\n",
Austin Schuh77ed5432019-07-07 20:41:36 -0700414 ::aos::time::DurationInSeconds(monotonic_now() - start_time));
Austin Schuhbfb04122019-05-22 21:16:51 -0700415 // Shoot
416 Shoot();
417 if (ShouldCancel()) return true;
418
419 // Get ready to zero when we come back up.
420 this_thread::sleep_for(chrono::milliseconds(50));
421 PositionClawVertically(0.0, 0.0);
422 return true;
423}
424
425} // namespace actors
426} // namespace y2014