blob: fc794b1a01cb077fb1944d246967db58b2c2404b [file] [log] [blame]
Ariv Diggi0af59c02023-10-07 13:15:39 -07001#include "y2023_bot3/autonomous/autonomous_actor.h"
2
3#include <chrono>
4#include <cinttypes>
5#include <cmath>
6
7#include "aos/logging/logging.h"
8#include "aos/util/math.h"
9#include "frc971/control_loops/drivetrain/localizer_generated.h"
10#include "y2023_bot3/autonomous/auto_splines.h"
11#include "y2023_bot3/constants.h"
12#include "y2023_bot3/control_loops/drivetrain/drivetrain_base.h"
13
14DEFINE_bool(spline_auto, false, "Run simple test S-spline auto mode.");
Filip Kujawaef687152023-11-14 22:11:32 -080015DEFINE_bool(charged_up, true,
16 "If true run charged up autonomous mode. 2 Piece non-cable side");
17DEFINE_bool(charged_up_middle, false,
18 "If true run charged up middle autonomous mode. Starts middle, "
19 "places cube mid, mobility");
20DEFINE_bool(one_piece, false,
21 "End charged_up autonomous after first cube is placed.");
Ariv Diggi0af59c02023-10-07 13:15:39 -070022
23namespace y2023_bot3 {
24namespace autonomous {
25
26using ::frc971::ProfileParametersT;
27
28ProfileParametersT MakeProfileParameters(float max_velocity,
29 float max_acceleration) {
30 ProfileParametersT result;
31 result.max_velocity = max_velocity;
32 result.max_acceleration = max_acceleration;
33 return result;
34}
35
36using ::aos::monotonic_clock;
37using frc971::CreateProfileParameters;
38using ::frc971::ProfileParametersT;
39using frc971::control_loops::CreateStaticZeroingSingleDOFProfiledSubsystemGoal;
40using frc971::control_loops::StaticZeroingSingleDOFProfiledSubsystemGoal;
41using frc971::control_loops::drivetrain::LocalizerControl;
42namespace chrono = ::std::chrono;
43
44AutonomousActor::AutonomousActor(::aos::EventLoop *event_loop)
45 : frc971::autonomous::BaseAutonomousActor(
46 event_loop, control_loops::drivetrain::GetDrivetrainConfig()),
47 localizer_control_sender_(
48 event_loop->MakeSender<
49 ::frc971::control_loops::drivetrain::LocalizerControl>(
50 "/drivetrain")),
51 joystick_state_fetcher_(
52 event_loop->MakeFetcher<aos::JoystickState>("/aos")),
53 robot_state_fetcher_(event_loop->MakeFetcher<aos::RobotState>("/aos")),
54 auto_splines_(),
55 superstructure_goal_sender_(
56 event_loop
57 ->MakeSender<::y2023_bot3::control_loops::superstructure::Goal>(
58 "/superstructure")),
59 superstructure_status_fetcher_(
60 event_loop->MakeFetcher<
61 ::y2023_bot3::control_loops::superstructure::Status>(
62 "/superstructure")) {
63 drivetrain_status_fetcher_.Fetch();
64 replan_timer_ = event_loop->AddTimer([this]() { Replan(); });
65
66 event_loop->OnRun([this, event_loop]() {
67 replan_timer_->Schedule(event_loop->monotonic_now());
68 button_poll_->Schedule(event_loop->monotonic_now(),
69 chrono::milliseconds(50));
70 });
71
72 // TODO(james): Really need to refactor this code since we keep using it.
73 button_poll_ = event_loop->AddTimer([this]() {
74 const aos::monotonic_clock::time_point now =
75 this->event_loop()->context().monotonic_event_time;
76 if (robot_state_fetcher_.Fetch()) {
77 if (robot_state_fetcher_->user_button()) {
78 user_indicated_safe_to_reset_ = true;
79 MaybeSendStartingPosition();
80 }
81 }
82 if (joystick_state_fetcher_.Fetch()) {
83 if (joystick_state_fetcher_->has_alliance() &&
84 (joystick_state_fetcher_->alliance() != alliance_)) {
85 alliance_ = joystick_state_fetcher_->alliance();
86 is_planned_ = false;
87 // Only kick the planning out by 2 seconds. If we end up enabled in
88 // that second, then we will kick it out further based on the code
89 // below.
90 replan_timer_->Schedule(now + std::chrono::seconds(2));
91 }
92 if (joystick_state_fetcher_->enabled()) {
93 if (!is_planned_) {
94 // Only replan once we've been disabled for 5 seconds.
95 replan_timer_->Schedule(now + std::chrono::seconds(5));
96 }
97 }
98 }
99 });
100}
101
102void AutonomousActor::Replan() {
103 if (!drivetrain_status_fetcher_.Fetch()) {
104 replan_timer_->Schedule(event_loop()->monotonic_now() + chrono::seconds(1));
105 AOS_LOG(INFO, "Drivetrain not up, replanning in 1 second");
106 return;
107 }
108
109 if (alliance_ == aos::Alliance::kInvalid) {
110 return;
111 }
112 sent_starting_position_ = false;
113 if (FLAGS_spline_auto) {
114 test_spline_ =
115 PlanSpline(std::bind(&AutonomousSplines::TestSpline, &auto_splines_,
116 std::placeholders::_1, alliance_),
117 SplineDirection::kForward);
118
119 starting_position_ = test_spline_->starting_position();
Filip Kujawaef687152023-11-14 22:11:32 -0800120 } else if (FLAGS_charged_up) {
121 charged_up_splines_ = {
122 PlanSpline(std::bind(&AutonomousSplines::Spline1, &auto_splines_,
123 std::placeholders::_1, alliance_),
124 SplineDirection::kBackward),
125 PlanSpline(std::bind(&AutonomousSplines::Spline2, &auto_splines_,
126 std::placeholders::_1, alliance_),
127 SplineDirection::kForward),
128 PlanSpline(std::bind(&AutonomousSplines::Spline3, &auto_splines_,
129 std::placeholders::_1, alliance_),
130 SplineDirection::kBackward),
131 PlanSpline(std::bind(&AutonomousSplines::Spline4, &auto_splines_,
132 std::placeholders::_1, alliance_),
133 SplineDirection::kForward)};
134 starting_position_ = charged_up_splines_.value()[0].starting_position();
135 CHECK(starting_position_);
136 } else if (FLAGS_charged_up_middle) {
137 charged_up_middle_splines_ = {
138 PlanSpline(std::bind(&AutonomousSplines::SplineMiddle1, &auto_splines_,
139 std::placeholders::_1, alliance_),
140 SplineDirection::kForward)};
Ariv Diggi0af59c02023-10-07 13:15:39 -0700141 }
142 is_planned_ = true;
143
144 MaybeSendStartingPosition();
Filip Kujawaef687152023-11-14 22:11:32 -0800145} // namespace autonomous
Ariv Diggi0af59c02023-10-07 13:15:39 -0700146
147void AutonomousActor::MaybeSendStartingPosition() {
148 if (is_planned_ && user_indicated_safe_to_reset_ &&
149 !sent_starting_position_) {
150 CHECK(starting_position_);
151 SendStartingPosition(starting_position_.value());
152 }
153}
154
155void AutonomousActor::Reset() {
156 InitializeEncoders();
157 ResetDrivetrain();
158
159 joystick_state_fetcher_.Fetch();
160 CHECK(joystick_state_fetcher_.get() != nullptr)
161 << "Expect at least one JoystickState message before running auto...";
162 alliance_ = joystick_state_fetcher_->alliance();
163
164 preloaded_ = false;
Filip Kujawaef687152023-11-14 22:11:32 -0800165 roller_goal_ = control_loops::superstructure::RollerGoal::IDLE;
166 pivot_goal_ = control_loops::superstructure::PivotGoal::NEUTRAL;
Ariv Diggi0af59c02023-10-07 13:15:39 -0700167 SendSuperstructureGoal();
168}
169
170bool AutonomousActor::RunAction(
171 const ::frc971::autonomous::AutonomousActionParams *params) {
172 Reset();
173
174 AOS_LOG(INFO, "Params are %d\n", params->mode());
175
176 if (!user_indicated_safe_to_reset_) {
177 AOS_LOG(WARNING, "Didn't send starting position prior to starting auto.");
178 CHECK(starting_position_);
179 SendStartingPosition(starting_position_.value());
180 }
181 // Clear this so that we don't accidentally resend things as soon as we
182 // replan later.
183 user_indicated_safe_to_reset_ = false;
184 is_planned_ = false;
185 starting_position_.reset();
186
187 AOS_LOG(INFO, "Params are %d\n", params->mode());
188 if (alliance_ == aos::Alliance::kInvalid) {
189 AOS_LOG(INFO, "Aborting autonomous due to invalid alliance selection.");
190 return false;
191 }
192
Filip Kujawaef687152023-11-14 22:11:32 -0800193 if (FLAGS_charged_up) {
194 ChargedUp();
195 } else {
196 AOS_LOG(INFO, "No autonomous mode selected.");
197 return false;
198 }
199
Ariv Diggi0af59c02023-10-07 13:15:39 -0700200 return true;
201}
202
203void AutonomousActor::SendStartingPosition(const Eigen::Vector3d &start) {
204 // Set up the starting position for the blue alliance.
205
206 auto builder = localizer_control_sender_.MakeBuilder();
207
208 LocalizerControl::Builder localizer_control_builder =
209 builder.MakeBuilder<LocalizerControl>();
210 localizer_control_builder.add_x(start(0));
211 localizer_control_builder.add_y(start(1));
212 localizer_control_builder.add_theta(start(2));
213 localizer_control_builder.add_theta_uncertainty(0.00001);
214 AOS_LOG(INFO, "User button pressed, x: %f y: %f theta: %f", start(0),
215 start(1), start(2));
216 if (builder.Send(localizer_control_builder.Finish()) !=
217 aos::RawSender::Error::kOk) {
218 AOS_LOG(ERROR, "Failed to reset localizer.\n");
219 }
220}
221
Filip Kujawaef687152023-11-14 22:11:32 -0800222// Charged Up 2 Game Object Autonomous (non-cable side)
223void AutonomousActor::ChargedUp() {
224 aos::monotonic_clock::time_point start_time = aos::monotonic_clock::now();
225
226 CHECK(charged_up_splines_);
227
228 auto &splines = *charged_up_splines_;
229
230 AOS_LOG(INFO, "Going to preload");
231
232 // Tell the superstructure that a cube was preloaded
233 if (!WaitForPreloaded()) {
234 return;
235 }
236
237 // Place & Spit firt cube high
238 AOS_LOG(INFO, "Moving arm to front high scoring position");
239
240 HighScore();
241 std::this_thread::sleep_for(chrono::milliseconds(600));
242
243 SpitHigh();
244 std::this_thread::sleep_for(chrono::milliseconds(600));
245
246 StopSpitting();
247
248 std::this_thread::sleep_for(chrono::milliseconds(200));
249 AOS_LOG(
250 INFO, "Placed first cube (HIGH) %lf s\n",
251 aos::time::DurationInSeconds(aos::monotonic_clock::now() - start_time));
252
253 if (FLAGS_one_piece) {
254 return;
255 }
256
257 // Drive to second cube
258 if (!splines[0].WaitForPlan()) {
259 return;
260 }
261 splines[0].Start();
262
263 // Move arm into position to intake cube and intake.
264 AOS_LOG(INFO, "Moving arm to back pickup position");
265
266 Pickup();
267
268 std::this_thread::sleep_for(chrono::milliseconds(500));
269 Intake();
270
271 AOS_LOG(
272 INFO, "Turning on rollers %lf s\n",
273 aos::time::DurationInSeconds(aos::monotonic_clock::now() - start_time));
274
275 if (!splines[0].WaitForSplineDistanceRemaining(0.02)) {
276 return;
277 }
278
279 AOS_LOG(
280 INFO, "Got there %lf s\n",
281 aos::time::DurationInSeconds(aos::monotonic_clock::now() - start_time));
282
283 // Drive back to grid
284 if (!splines[1].WaitForPlan()) {
285 return;
286 }
287 splines[1].Start();
288 std::this_thread::sleep_for(chrono::milliseconds(600));
289
290 // Place Low
291 AOS_LOG(INFO, "Moving arm to front mid scoring position");
292
293 MidScore();
294
295 std::this_thread::sleep_for(chrono::milliseconds(600));
296 if (!splines[1].WaitForSplineDistanceRemaining(0.1)) return;
297
298 Spit();
299 std::this_thread::sleep_for(chrono::milliseconds(400));
300 StopSpitting();
301
302 AOS_LOG(
303 INFO, "Placed second cube (MID) %lf s\n",
304 aos::time::DurationInSeconds(aos::monotonic_clock::now() - start_time));
305
306 // Drive to third cube
307 if (!splines[2].WaitForPlan()) {
308 return;
309 }
310 splines[2].Start();
311
312 std::this_thread::sleep_for(chrono::milliseconds(500));
313 // Move arm into position to intake cube and intake.
314 AOS_LOG(INFO, "Moving arm to back pickup position");
315
316 Pickup();
317
318 std::this_thread::sleep_for(chrono::milliseconds(250));
319 Intake();
320
321 AOS_LOG(
322 INFO, "Turning on rollers %lf s\n",
323 aos::time::DurationInSeconds(aos::monotonic_clock::now() - start_time));
324
325 if (!splines[2].WaitForSplineDistanceRemaining(0.02)) {
326 return;
327 }
328
329 AOS_LOG(
330 INFO, "Got there %lf s\n",
331 aos::time::DurationInSeconds(aos::monotonic_clock::now() - start_time));
332
333 // Drive back to grid
334 if (!splines[3].WaitForPlan()) {
335 return;
336 }
337 splines[3].Start();
338 std::this_thread::sleep_for(chrono::milliseconds(600));
339
340 // Place Low
341 AOS_LOG(INFO, "Moving arm to front low scoring position");
342
343 LowScore();
344
345 std::this_thread::sleep_for(chrono::milliseconds(600));
346 if (!splines[3].WaitForSplineDistanceRemaining(0.1)) return;
347
348 Spit();
349 std::this_thread::sleep_for(chrono::milliseconds(600));
350 StopSpitting();
351
352 AOS_LOG(
353 INFO, "Placed low cube (LOW) %lf s\n",
354 aos::time::DurationInSeconds(aos::monotonic_clock::now() - start_time));
355}
356
357// Charged Up Place and Mobility Autonomous (middle)
358void AutonomousActor::ChargedUpMiddle() {
359 aos::monotonic_clock::time_point start_time = aos::monotonic_clock::now();
360
361 CHECK(charged_up_middle_splines_);
362
363 auto &splines = *charged_up_middle_splines_;
364
365 AOS_LOG(INFO, "Going to preload");
366
367 // Tell the superstructure that a cube was preloaded
368 if (!WaitForPreloaded()) {
369 return;
370 }
371
372 // Place & Spit firt cube mid
373 AOS_LOG(INFO, "Moving arm to front mid scoring position");
374
375 MidScore();
376 std::this_thread::sleep_for(chrono::milliseconds(300));
377
378 Spit();
379 std::this_thread::sleep_for(chrono::milliseconds(300));
380
381 StopSpitting();
382
383 std::this_thread::sleep_for(chrono::milliseconds(100));
384 AOS_LOG(
385 INFO, "Placed first cube (Mid) %lf s\n",
386 aos::time::DurationInSeconds(aos::monotonic_clock::now() - start_time));
387
388 // Drive to second cube
389
390 if (!splines[0].WaitForPlan()) {
391 return;
392 }
393 splines[0].Start();
394}
395
Ariv Diggi0af59c02023-10-07 13:15:39 -0700396void AutonomousActor::SendSuperstructureGoal() {
397 auto builder = superstructure_goal_sender_.MakeBuilder();
398
399 control_loops::superstructure::Goal::Builder superstructure_builder =
400 builder.MakeBuilder<control_loops::superstructure::Goal>();
401
Filip Kujawaef687152023-11-14 22:11:32 -0800402 superstructure_builder.add_pivot_goal(pivot_goal_);
403 superstructure_builder.add_roller_goal(roller_goal_);
404 superstructure_builder.add_preloaded_with_cube(preloaded_);
405
Ariv Diggi0af59c02023-10-07 13:15:39 -0700406 if (builder.Send(superstructure_builder.Finish()) !=
407 aos::RawSender::Error::kOk) {
408 AOS_LOG(ERROR, "Sending superstructure goal failed.\n");
409 }
410}
411
Filip Kujawaef687152023-11-14 22:11:32 -0800412[[nodiscard]] bool AutonomousActor::WaitForPreloaded() {
413 set_preloaded(true);
414 SendSuperstructureGoal();
415
416 ::aos::time::PhasedLoop phased_loop(frc971::controls::kLoopFrequency,
417 event_loop()->monotonic_now(),
418 ActorBase::kLoopOffset);
419
420 bool loaded = false;
421 while (!loaded) {
422 if (ShouldCancel()) {
423 return false;
424 }
425
426 phased_loop.SleepUntilNext();
427 superstructure_status_fetcher_.Fetch();
428 CHECK(superstructure_status_fetcher_.get() != nullptr);
429
430 loaded = (superstructure_status_fetcher_->end_effector_state() ==
431 control_loops::superstructure::EndEffectorState::LOADED);
432 }
433
434 set_preloaded(false);
435 SendSuperstructureGoal();
436
437 return true;
438}
439
440void AutonomousActor::HighScore() {
441 set_pivot_goal(control_loops::superstructure::PivotGoal::SCORE_HIGH_FRONT);
442 SendSuperstructureGoal();
443}
444void AutonomousActor::MidScore() {
445 set_pivot_goal(control_loops::superstructure::PivotGoal::SCORE_MID_FRONT);
446 SendSuperstructureGoal();
447}
448void AutonomousActor::LowScore() {
449 set_pivot_goal(control_loops::superstructure::PivotGoal::SCORE_LOW_FRONT);
450 SendSuperstructureGoal();
451}
452void AutonomousActor::Spit() {
453 set_roller_goal(control_loops::superstructure::RollerGoal::SPIT);
454 SendSuperstructureGoal();
455}
456void AutonomousActor::SpitHigh() {
457 set_roller_goal(control_loops::superstructure::RollerGoal::SPIT_HIGH);
458 SendSuperstructureGoal();
459}
460
461void AutonomousActor::StopSpitting() {
462 set_roller_goal(control_loops::superstructure::RollerGoal::IDLE);
463 SendSuperstructureGoal();
464}
465void AutonomousActor::Intake() {
466 set_roller_goal(control_loops::superstructure::RollerGoal::INTAKE_CUBE);
467 SendSuperstructureGoal();
468}
469
470void AutonomousActor::Pickup() {
471 set_pivot_goal(control_loops::superstructure::PivotGoal::PICKUP_BACK);
472 SendSuperstructureGoal();
473}
474
475void AutonomousActor::Neutral() {
476 set_pivot_goal(control_loops::superstructure::PivotGoal::NEUTRAL);
477 SendSuperstructureGoal();
478}
479
Ariv Diggi0af59c02023-10-07 13:15:39 -0700480} // namespace autonomous
481} // namespace y2023_bot3