blob: 0a242eb96167fe079b7b299f43ca1cf1e95255b3 [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")),
38 shoot_action_factory_(actors::ShootActor::MakeFactory(event_loop)) {}
Austin Schuhbfb04122019-05-22 21:16:51 -070039
40void AutonomousActor::PositionClawVertically(double intake_power,
41 double centering_power) {
42 if (!control_loops::claw_queue.goal.MakeWithBuilder()
43 .bottom_angle(0.0)
44 .separation_angle(0.0)
45 .intake(intake_power)
46 .centering(centering_power)
47 .Send()) {
48 LOG(WARNING, "sending claw goal failed\n");
49 }
50}
51
52void AutonomousActor::PositionClawBackIntake() {
53 if (!control_loops::claw_queue.goal.MakeWithBuilder()
54 .bottom_angle(-2.273474)
55 .separation_angle(0.0)
56 .intake(12.0)
57 .centering(12.0)
58 .Send()) {
59 LOG(WARNING, "sending claw goal failed\n");
60 }
61}
62
63void AutonomousActor::PositionClawUpClosed() {
64 // Move the claw to where we're going to shoot from but keep it closed until
65 // it gets there.
66 if (!control_loops::claw_queue.goal.MakeWithBuilder()
67 .bottom_angle(0.86)
68 .separation_angle(0.0)
69 .intake(4.0)
70 .centering(1.0)
71 .Send()) {
72 LOG(WARNING, "sending claw goal failed\n");
73 }
74}
75
76void AutonomousActor::PositionClawForShot() {
77 if (!control_loops::claw_queue.goal.MakeWithBuilder()
78 .bottom_angle(0.86)
79 .separation_angle(0.10)
80 .intake(4.0)
81 .centering(1.0)
82 .Send()) {
83 LOG(WARNING, "sending claw goal failed\n");
84 }
85}
86
87void AutonomousActor::SetShotPower(double power) {
88 LOG(INFO, "Setting shot power to %f\n", power);
89 if (!control_loops::shooter_queue.goal.MakeWithBuilder()
90 .shot_power(power)
91 .shot_requested(false)
92 .unload_requested(false)
93 .load_requested(false)
94 .Send()) {
95 LOG(WARNING, "sending shooter goal failed\n");
96 }
97}
98
99const ProfileParameters kFastDrive = {3.0, 2.5};
100const ProfileParameters kSlowDrive = {2.5, 2.5};
101const ProfileParameters kFastWithBallDrive = {3.0, 2.0};
102const ProfileParameters kSlowWithBallDrive = {2.5, 2.0};
103const ProfileParameters kFastTurn = {3.0, 10.0};
104
105void AutonomousActor::Shoot() {
106 // Shoot.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700107 auto shoot_action = shoot_action_factory_.Make(0.0);
Austin Schuhbfb04122019-05-22 21:16:51 -0700108 shoot_action->Start();
109 WaitUntilDoneOrCanceled(::std::move(shoot_action));
110}
111
112bool AutonomousActor::WaitUntilClawDone() {
113 while (true) {
114 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(10),
115 ::std::chrono::milliseconds(10) / 2);
116 // Poll the running bit and auto done bits.
117 phased_loop.SleepUntilNext();
118 control_loops::claw_queue.status.FetchLatest();
119 control_loops::claw_queue.goal.FetchLatest();
120 if (ShouldCancel()) {
121 return false;
122 }
123 if (control_loops::claw_queue.status.get() == nullptr ||
124 control_loops::claw_queue.goal.get() == nullptr) {
125 continue;
126 }
127 bool ans =
128 control_loops::claw_queue.status->zeroed &&
129 (::std::abs(control_loops::claw_queue.status->bottom_velocity) < 1.0) &&
130 (::std::abs(control_loops::claw_queue.status->bottom -
131 control_loops::claw_queue.goal->bottom_angle) < 0.10) &&
132 (::std::abs(control_loops::claw_queue.status->separation -
133 control_loops::claw_queue.goal->separation_angle) < 0.4);
134 if (ans) {
135 return true;
136 }
137 }
138}
139
140class HotGoalDecoder {
141 public:
Austin Schuha3e576b2019-05-22 21:22:23 -0700142 HotGoalDecoder(::aos::Fetcher<::y2014::HotGoal> *hot_goal_fetcher)
143 : hot_goal_fetcher_(hot_goal_fetcher) {
144 ResetCounts();
145 }
Austin Schuhbfb04122019-05-22 21:16:51 -0700146
147 void ResetCounts() {
Austin Schuha3e576b2019-05-22 21:22:23 -0700148 hot_goal_fetcher_->Fetch();
149 if (hot_goal_fetcher_->get()) {
150 start_counts_ = *hot_goal_fetcher_->get();
Austin Schuhbfb04122019-05-22 21:16:51 -0700151 LOG_STRUCT(INFO, "counts reset to", start_counts_);
152 start_counts_valid_ = true;
153 } else {
154 LOG(WARNING, "no hot goal message. ignoring\n");
155 start_counts_valid_ = false;
156 }
157 }
158
Austin Schuha3e576b2019-05-22 21:22:23 -0700159 void Update() {
160 hot_goal_fetcher_->Fetch();
161 if (hot_goal_fetcher_->get())
162 LOG_STRUCT(INFO, "new counts", *hot_goal_fetcher_->get());
Austin Schuhbfb04122019-05-22 21:16:51 -0700163 }
164
165 bool left_triggered() const {
Austin Schuha3e576b2019-05-22 21:22:23 -0700166 if (!start_counts_valid_ || !hot_goal_fetcher_->get()) return false;
167 return (hot_goal_fetcher_->get()->left_count - start_counts_.left_count) >
168 kThreshold;
Austin Schuhbfb04122019-05-22 21:16:51 -0700169 }
170
171 bool right_triggered() const {
Austin Schuha3e576b2019-05-22 21:22:23 -0700172 if (!start_counts_valid_ || !hot_goal_fetcher_->get()) return false;
173 return (hot_goal_fetcher_->get()->right_count - start_counts_.right_count) >
174 kThreshold;
Austin Schuhbfb04122019-05-22 21:16:51 -0700175 }
176
177 bool is_left() const {
Austin Schuha3e576b2019-05-22 21:22:23 -0700178 if (!start_counts_valid_ || !hot_goal_fetcher_->get()) return false;
Austin Schuhbfb04122019-05-22 21:16:51 -0700179 const uint64_t left_difference =
Austin Schuha3e576b2019-05-22 21:22:23 -0700180 hot_goal_fetcher_->get()->left_count - start_counts_.left_count;
Austin Schuhbfb04122019-05-22 21:16:51 -0700181 const uint64_t right_difference =
Austin Schuha3e576b2019-05-22 21:22:23 -0700182 hot_goal_fetcher_->get()->right_count - start_counts_.right_count;
Austin Schuhbfb04122019-05-22 21:16:51 -0700183 if (left_difference > kThreshold) {
184 if (right_difference > kThreshold) {
185 // We've seen a lot of both, so pick the one we've seen the most of.
186 return left_difference > right_difference;
187 } else {
188 // We've seen enough left but not enough right, so go with it.
189 return true;
190 }
191 } else {
192 // We haven't seen enough left, so it's not left.
193 return false;
194 }
195 }
196
197 bool is_right() const {
Austin Schuha3e576b2019-05-22 21:22:23 -0700198 if (!start_counts_valid_ || !hot_goal_fetcher_->get()) return false;
Austin Schuhbfb04122019-05-22 21:16:51 -0700199 const uint64_t left_difference =
Austin Schuha3e576b2019-05-22 21:22:23 -0700200 hot_goal_fetcher_->get()->left_count - start_counts_.left_count;
Austin Schuhbfb04122019-05-22 21:16:51 -0700201 const uint64_t right_difference =
Austin Schuha3e576b2019-05-22 21:22:23 -0700202 hot_goal_fetcher_->get()->right_count - start_counts_.right_count;
Austin Schuhbfb04122019-05-22 21:16:51 -0700203 if (right_difference > kThreshold) {
204 if (left_difference > kThreshold) {
205 // We've seen a lot of both, so pick the one we've seen the most of.
206 return right_difference > left_difference;
207 } else {
208 // We've seen enough right but not enough left, so go with it.
209 return true;
210 }
211 } else {
212 // We haven't seen enough right, so it's not right.
213 return false;
214 }
215 }
216
217 private:
218 static const uint64_t kThreshold = 5;
219
220 ::y2014::HotGoal start_counts_;
221 bool start_counts_valid_;
Austin Schuha3e576b2019-05-22 21:22:23 -0700222
223 ::aos::Fetcher<::y2014::HotGoal> *hot_goal_fetcher_;
Austin Schuhbfb04122019-05-22 21:16:51 -0700224};
225
226bool AutonomousActor::RunAction(
227 const ::frc971::autonomous::AutonomousActionParams & /*params*/) {
228 enum class AutoVersion : uint8_t {
229 kStraight,
230 kDoubleHot,
231 kSingleHot,
232 };
233
234 // The front of the robot is 1.854 meters from the wall
235 static const double kShootDistance = 3.15;
236 static const double kPickupDistance = 0.5;
237 static const double kTurnAngle = 0.3;
238
239 monotonic_clock::time_point start_time = monotonic_clock::now();
240 LOG(INFO, "Handling auto mode\n");
241
242 AutoVersion auto_version;
Austin Schuh7eed2de2019-05-25 14:34:40 -0700243 auto_mode_fetcher_.Fetch();
244 if (!auto_mode_fetcher_.get()) {
Austin Schuhbfb04122019-05-22 21:16:51 -0700245 LOG(WARNING, "not sure which auto mode to use\n");
246 auto_version = AutoVersion::kStraight;
247 } else {
248 static const double kSelectorMin = 0.2, kSelectorMax = 4.4;
249
250 const double kSelectorStep = (kSelectorMax - kSelectorMin) / 3.0;
Austin Schuh7eed2de2019-05-25 14:34:40 -0700251 if (auto_mode_fetcher_->voltage < kSelectorStep + kSelectorMin) {
Austin Schuhbfb04122019-05-22 21:16:51 -0700252 auto_version = AutoVersion::kSingleHot;
Austin Schuh7eed2de2019-05-25 14:34:40 -0700253 } else if (auto_mode_fetcher_->voltage < 2 * kSelectorStep + kSelectorMin) {
Austin Schuhbfb04122019-05-22 21:16:51 -0700254 auto_version = AutoVersion::kStraight;
255 } else {
256 auto_version = AutoVersion::kDoubleHot;
257 }
258 }
259 LOG(INFO, "running auto %" PRIu8 "\n", static_cast<uint8_t>(auto_version));
260
261 const ProfileParameters &drive_params =
262 (auto_version == AutoVersion::kStraight) ? kFastDrive : kSlowDrive;
263 const ProfileParameters &drive_with_ball_params =
264 (auto_version == AutoVersion::kStraight) ? kFastWithBallDrive
265 : kSlowWithBallDrive;
266
Austin Schuha3e576b2019-05-22 21:22:23 -0700267 HotGoalDecoder hot_goal_decoder(&hot_goal_fetcher_);
Austin Schuhbfb04122019-05-22 21:16:51 -0700268 // True for left, false for right.
269 bool first_shot_left, second_shot_left_default, second_shot_left;
270
271 Reset();
272
273 // Turn the claw on, keep it straight up until the ball has been grabbed.
274 LOG(INFO, "Claw going up at %f\n",
275 ::aos::time::DurationInSeconds(monotonic_clock::now() - start_time));
276 PositionClawVertically(12.0, 4.0);
277 SetShotPower(115.0);
278
279 // Wait for the ball to enter the claw.
280 this_thread::sleep_for(chrono::milliseconds(250));
281 if (ShouldCancel()) return true;
282 LOG(INFO, "Readying claw for shot at %f\n",
283 ::aos::time::DurationInSeconds(monotonic_clock::now() - start_time));
284
285 if (ShouldCancel()) return true;
286 // Drive to the goal.
287 StartDrive(-kShootDistance, 0.0, drive_params, kFastTurn);
288 this_thread::sleep_for(chrono::milliseconds(750));
289 PositionClawForShot();
290 LOG(INFO, "Waiting until drivetrain is finished\n");
291 WaitForDriveProfileDone();
292 if (ShouldCancel()) return true;
293
294 hot_goal_decoder.Update();
295 if (hot_goal_decoder.is_left()) {
296 LOG(INFO, "first shot left\n");
297 first_shot_left = true;
298 second_shot_left_default = false;
299 } else if (hot_goal_decoder.is_right()) {
300 LOG(INFO, "first shot right\n");
301 first_shot_left = false;
302 second_shot_left_default = true;
303 } else {
304 LOG(INFO, "first shot defaulting left\n");
305 first_shot_left = true;
306 second_shot_left_default = true;
307 }
308 if (auto_version == AutoVersion::kDoubleHot) {
309 if (ShouldCancel()) return true;
310 StartDrive(0, first_shot_left ? kTurnAngle : -kTurnAngle,
311 drive_with_ball_params, kFastTurn);
312 WaitForDriveProfileDone();
313 if (ShouldCancel()) return true;
314 } else if (auto_version == AutoVersion::kSingleHot) {
315 do {
316 // TODO(brians): Wait for next message with timeout or something.
317 this_thread::sleep_for(chrono::milliseconds(3));
Austin Schuha3e576b2019-05-22 21:22:23 -0700318 hot_goal_decoder.Update();
Austin Schuhbfb04122019-05-22 21:16:51 -0700319 if (ShouldCancel()) return true;
320 } while (!hot_goal_decoder.left_triggered() &&
321 (monotonic_clock::now() - start_time) < chrono::seconds(9));
322 } else if (auto_version == AutoVersion::kStraight) {
323 this_thread::sleep_for(chrono::milliseconds(400));
324 }
325
326 // Shoot.
327 LOG(INFO, "Shooting at %f\n",
328 ::aos::time::DurationInSeconds(monotonic_clock::now() - start_time));
329 Shoot();
330 this_thread::sleep_for(chrono::milliseconds(50));
331
332 if (auto_version == AutoVersion::kDoubleHot) {
333 if (ShouldCancel()) return true;
334 StartDrive(0, first_shot_left ? -kTurnAngle : kTurnAngle,
335 drive_with_ball_params, kFastTurn);
336 WaitForDriveProfileDone();
337 if (ShouldCancel()) return true;
338 } else if (auto_version == AutoVersion::kSingleHot) {
339 LOG(INFO, "auto done at %f\n",
340 ::aos::time::DurationInSeconds(monotonic_clock::now() - start_time));
341 PositionClawVertically(0.0, 0.0);
342 return true;
343 }
344
345 {
346 if (ShouldCancel()) return true;
347 // Intake the new ball.
348 LOG(INFO, "Claw ready for intake at %f\n",
349 ::aos::time::DurationInSeconds(monotonic_clock::now() - start_time));
350 PositionClawBackIntake();
351 StartDrive(kShootDistance + kPickupDistance, 0.0, drive_params, kFastTurn);
352 LOG(INFO, "Waiting until drivetrain is finished\n");
353 WaitForDriveProfileDone();
354 if (ShouldCancel()) return true;
355 LOG(INFO, "Wait for the claw at %f\n",
356 ::aos::time::DurationInSeconds(monotonic_clock::now() - start_time));
357 if (!WaitUntilClawDone()) return true;
358 }
359
360 // Drive back.
361 {
362 LOG(INFO, "Driving back at %f\n",
363 ::aos::time::DurationInSeconds(monotonic_clock::now() - start_time));
364 StartDrive(-(kShootDistance + kPickupDistance), 0.0, drive_params,
365 kFastTurn);
366 this_thread::sleep_for(chrono::milliseconds(300));
367 hot_goal_decoder.ResetCounts();
368 if (ShouldCancel()) return true;
369 PositionClawUpClosed();
370 if (!WaitUntilClawDone()) return true;
371 PositionClawForShot();
372 LOG(INFO, "Waiting until drivetrain is finished\n");
373 WaitForDriveProfileDone();
374 if (ShouldCancel()) return true;
375 if (!WaitUntilClawDone()) return true;
376 }
377
378 hot_goal_decoder.Update();
379 if (hot_goal_decoder.is_left()) {
380 LOG(INFO, "second shot left\n");
381 second_shot_left = true;
382 } else if (hot_goal_decoder.is_right()) {
383 LOG(INFO, "second shot right\n");
384 second_shot_left = false;
385 } else {
386 LOG(INFO, "second shot defaulting %s\n",
387 second_shot_left_default ? "left" : "right");
388 second_shot_left = second_shot_left_default;
389 }
390 if (auto_version == AutoVersion::kDoubleHot) {
391 if (ShouldCancel()) return true;
392 StartDrive(0, second_shot_left ? kTurnAngle : -kTurnAngle, drive_params,
393 kFastTurn);
394 WaitForDriveProfileDone();
395 if (ShouldCancel()) return true;
396 } else if (auto_version == AutoVersion::kStraight) {
397 this_thread::sleep_for(chrono::milliseconds(400));
398 }
399
400 LOG(INFO, "Shooting at %f\n",
401 ::aos::time::DurationInSeconds(monotonic_clock::now() - start_time));
402 // Shoot
403 Shoot();
404 if (ShouldCancel()) return true;
405
406 // Get ready to zero when we come back up.
407 this_thread::sleep_for(chrono::milliseconds(50));
408 PositionClawVertically(0.0, 0.0);
409 return true;
410}
411
412} // namespace actors
413} // namespace y2014