blob: 77965e4993ff6c8305e6adb65f31a94d8105668a [file] [log] [blame]
Maxwell Hendersonad312342023-01-10 12:07:47 -08001#include "y2023/autonomous/autonomous_actor.h"
2
3#include <chrono>
4#include <cinttypes>
5#include <cmath>
6
7#include "aos/logging/logging.h"
Maxwell Henderson64f37452023-03-11 13:39:21 -08008#include "aos/util/math.h"
Maxwell Hendersonad312342023-01-10 12:07:47 -08009#include "frc971/control_loops/drivetrain/localizer_generated.h"
Maxwell Henderson64f37452023-03-11 13:39:21 -080010#include "y2023/autonomous/auto_splines.h"
11#include "y2023/constants.h"
Maxwell Hendersonad312342023-01-10 12:07:47 -080012#include "y2023/control_loops/drivetrain/drivetrain_base.h"
Maxwell Henderson64f37452023-03-11 13:39:21 -080013#include "y2023/control_loops/superstructure/arm/generated_graph.h"
Maxwell Hendersonad312342023-01-10 12:07:47 -080014
James Kuszmaul713c5ce2023-03-04 18:23:24 -080015DEFINE_bool(spline_auto, true, "Run simple test S-spline auto mode.");
Maxwell Henderson64f37452023-03-11 13:39:21 -080016DEFINE_bool(charged_up, true, "If true run charged up autonomous mode");
James Kuszmaul713c5ce2023-03-04 18:23:24 -080017
Maxwell Hendersonad312342023-01-10 12:07:47 -080018namespace y2023 {
Maxwell Henderson64f37452023-03-11 13:39:21 -080019namespace autonomous {
Maxwell Hendersonad312342023-01-10 12:07:47 -080020
21using ::aos::monotonic_clock;
22using ::frc971::ProfileParametersT;
23using frc971::control_loops::drivetrain::LocalizerControl;
24namespace chrono = ::std::chrono;
25
26AutonomousActor::AutonomousActor(::aos::EventLoop *event_loop)
27 : frc971::autonomous::BaseAutonomousActor(
James Kuszmaul713c5ce2023-03-04 18:23:24 -080028 event_loop, control_loops::drivetrain::GetDrivetrainConfig()),
29 localizer_control_sender_(
30 event_loop->MakeSender<
31 ::frc971::control_loops::drivetrain::LocalizerControl>(
32 "/drivetrain")),
33 joystick_state_fetcher_(
34 event_loop->MakeFetcher<aos::JoystickState>("/aos")),
35 robot_state_fetcher_(event_loop->MakeFetcher<aos::RobotState>("/aos")),
Maxwell Henderson64f37452023-03-11 13:39:21 -080036 auto_splines_(),
37 arm_goal_position_(control_loops::superstructure::arm::NeutralIndex()),
38 points_(control_loops::superstructure::arm::PointList()) {
James Kuszmaul713c5ce2023-03-04 18:23:24 -080039 replan_timer_ = event_loop->AddTimer([this]() { Replan(); });
40
41 event_loop->OnRun([this, event_loop]() {
42 replan_timer_->Setup(event_loop->monotonic_now());
43 button_poll_->Setup(event_loop->monotonic_now(), chrono::milliseconds(50));
44 });
45
46 // TODO(james): Really need to refactor this code since we keep using it.
47 button_poll_ = event_loop->AddTimer([this]() {
48 const aos::monotonic_clock::time_point now =
49 this->event_loop()->context().monotonic_event_time;
50 if (robot_state_fetcher_.Fetch()) {
51 if (robot_state_fetcher_->user_button()) {
52 user_indicated_safe_to_reset_ = true;
53 MaybeSendStartingPosition();
54 }
55 }
56 if (joystick_state_fetcher_.Fetch()) {
57 if (joystick_state_fetcher_->has_alliance() &&
58 (joystick_state_fetcher_->alliance() != alliance_)) {
59 alliance_ = joystick_state_fetcher_->alliance();
60 is_planned_ = false;
Maxwell Henderson64f37452023-03-11 13:39:21 -080061 // Only kick the planning out by 2 seconds. If we end up enabled in
62 // that second, then we will kick it out further based on the code
63 // below.
James Kuszmaul713c5ce2023-03-04 18:23:24 -080064 replan_timer_->Setup(now + std::chrono::seconds(2));
65 }
66 if (joystick_state_fetcher_->enabled()) {
67 if (!is_planned_) {
68 // Only replan once we've been disabled for 5 seconds.
69 replan_timer_->Setup(now + std::chrono::seconds(5));
70 }
71 }
72 }
73 });
74}
75
76void AutonomousActor::Replan() {
77 if (alliance_ == aos::Alliance::kInvalid) {
78 return;
79 }
80 sent_starting_position_ = false;
81 if (FLAGS_spline_auto) {
82 test_spline_ =
83 PlanSpline(std::bind(&AutonomousSplines::TestSpline, &auto_splines_,
84 std::placeholders::_1, alliance_),
85 SplineDirection::kForward);
86
87 starting_position_ = test_spline_->starting_position();
Maxwell Henderson64f37452023-03-11 13:39:21 -080088 } else if (FLAGS_charged_up) {
89 charged_up_splines_ = {
90 PlanSpline(std::bind(&AutonomousSplines::Spline1, &auto_splines_,
91 std::placeholders::_1, alliance_),
92 SplineDirection::kBackward),
93 PlanSpline(std::bind(&AutonomousSplines::Spline2, &auto_splines_,
94 std::placeholders::_1, alliance_),
95 SplineDirection::kForward),
96 PlanSpline(std::bind(&AutonomousSplines::Spline3, &auto_splines_,
97 std::placeholders::_1, alliance_),
98 SplineDirection::kBackward),
99 PlanSpline(std::bind(&AutonomousSplines::Spline4, &auto_splines_,
100 std::placeholders::_1, alliance_),
101 SplineDirection::kForward),
102 PlanSpline(std::bind(&AutonomousSplines::Spline5, &auto_splines_,
103 std::placeholders::_1, alliance_),
104 SplineDirection::kBackward),
105 };
106
107 starting_position_ = charged_up_splines_.value()[0].starting_position();
108 CHECK(starting_position_);
James Kuszmaul713c5ce2023-03-04 18:23:24 -0800109 }
110
111 is_planned_ = true;
112
113 MaybeSendStartingPosition();
114}
115
116void AutonomousActor::MaybeSendStartingPosition() {
117 if (is_planned_ && user_indicated_safe_to_reset_ &&
118 !sent_starting_position_) {
119 CHECK(starting_position_);
120 SendStartingPosition(starting_position_.value());
121 }
122}
Maxwell Hendersonad312342023-01-10 12:07:47 -0800123
124void AutonomousActor::Reset() {
125 InitializeEncoders();
126 ResetDrivetrain();
James Kuszmaul713c5ce2023-03-04 18:23:24 -0800127
128 joystick_state_fetcher_.Fetch();
129 CHECK(joystick_state_fetcher_.get() != nullptr)
130 << "Expect at least one JoystickState message before running auto...";
131 alliance_ = joystick_state_fetcher_->alliance();
Maxwell Hendersonad312342023-01-10 12:07:47 -0800132}
133
134bool AutonomousActor::RunAction(
135 const ::frc971::autonomous::AutonomousActionParams *params) {
136 Reset();
137
138 AOS_LOG(INFO, "Params are %d\n", params->mode());
James Kuszmaul713c5ce2023-03-04 18:23:24 -0800139
140 if (!user_indicated_safe_to_reset_) {
141 AOS_LOG(WARNING, "Didn't send starting position prior to starting auto.");
142 CHECK(starting_position_);
143 SendStartingPosition(starting_position_.value());
144 }
Maxwell Henderson64f37452023-03-11 13:39:21 -0800145 // Clear this so that we don't accidentally resend things as soon as we
146 // replan later.
James Kuszmaul713c5ce2023-03-04 18:23:24 -0800147 user_indicated_safe_to_reset_ = false;
148 is_planned_ = false;
149 starting_position_.reset();
150
151 AOS_LOG(INFO, "Params are %d\n", params->mode());
152 if (alliance_ == aos::Alliance::kInvalid) {
153 AOS_LOG(INFO, "Aborting autonomous due to invalid alliance selection.");
154 return false;
155 }
156 if (FLAGS_spline_auto) {
157 SplineAuto();
158 } else {
159 AOS_LOG(WARNING, "No auto mode selected.");
160 }
Maxwell Hendersonad312342023-01-10 12:07:47 -0800161 return true;
162}
163
James Kuszmaul713c5ce2023-03-04 18:23:24 -0800164void AutonomousActor::SplineAuto() {
165 CHECK(test_spline_);
166
167 if (!test_spline_->WaitForPlan()) return;
168 test_spline_->Start();
169
170 if (!test_spline_->WaitForSplineDistanceRemaining(0.02)) return;
171}
172
173void AutonomousActor::SendStartingPosition(const Eigen::Vector3d &start) {
174 // Set up the starting position for the blue alliance.
175
176 auto builder = localizer_control_sender_.MakeBuilder();
177
178 LocalizerControl::Builder localizer_control_builder =
179 builder.MakeBuilder<LocalizerControl>();
180 localizer_control_builder.add_x(start(0));
181 localizer_control_builder.add_y(start(1));
182 localizer_control_builder.add_theta(start(2));
183 localizer_control_builder.add_theta_uncertainty(0.00001);
184 AOS_LOG(INFO, "User button pressed, x: %f y: %f theta: %f", start(0),
185 start(1), start(2));
186 if (builder.Send(localizer_control_builder.Finish()) !=
187 aos::RawSender::Error::kOk) {
188 AOS_LOG(ERROR, "Failed to reset localizer.\n");
189 }
190}
191
Maxwell Henderson64f37452023-03-11 13:39:21 -0800192// Charged Up 3 Game Object Autonomous.
193void AutonomousActor::ChargedUp() {
194 aos::monotonic_clock::time_point start_time = aos::monotonic_clock::now();
195
196 CHECK(charged_up_splines_);
197
198 auto &splines = *charged_up_splines_;
199
200 // Tell the superstructure a cone was preloaded
201 if (!WaitForPreloaded()) return;
202
203 // Place first cone on mid level
204 MidConeScore();
205
206 // Wait until the arm is at the goal to spit
207 if (!WaitForArmGoal()) return;
208 Spit();
209
210 AOS_LOG(
211 INFO, "Placed first cone %lf s\n",
212 aos::time::DurationInSeconds(aos::monotonic_clock::now() - start_time));
213
214 // Drive and intake the cube nearest to the starting zone
215 if (!splines[0].WaitForPlan()) return;
216 splines[0].Start();
217
218 // Move arm into position to pickup a cube and start cube intake
219 PickupCube();
220 IntakeCube();
221
222 if (!splines[0].WaitForSplineDistanceRemaining(0.02)) return;
223
224 // Drive back to grid and place cube on high level
225 if (!splines[1].WaitForPlan()) return;
226 splines[1].Start();
227
228 HighCubeScore();
229
230 if (!splines[1].WaitForSplineDistanceRemaining(0.02)) return;
231
232 if (!WaitForArmGoal()) return;
233 Spit();
234
235 AOS_LOG(
236 INFO, "Placed first cube %lf s\n",
237 aos::time::DurationInSeconds(aos::monotonic_clock::now() - start_time));
238
239 // Drive and intake the cube second nearest to the starting zone
240 if (!splines[2].WaitForPlan()) return;
241 splines[2].Start();
242
243 PickupCube();
244 IntakeCube();
245
246 if (!splines[2].WaitForSplineDistanceRemaining(0.02)) return;
247
248 // Drive back to grid and place object on mid level
249 if (!splines[3].WaitForPlan()) return;
250 splines[3].Start();
251
252 MidCubeScore();
253
254 if (!splines[3].WaitForSplineDistanceRemaining(0.02)) return;
255
256 if (!WaitForArmGoal()) return;
257 Spit();
258
259 AOS_LOG(
260 INFO, "Placed second cube %lf s\n",
261 aos::time::DurationInSeconds(aos::monotonic_clock::now() - start_time));
262
263 // Drive onto charging station
264 if (!splines[4].WaitForPlan()) return;
265 splines[4].Start();
266
267 if (!splines[4].WaitForSplineDistanceRemaining(0.02)) return;
268}
269
270void AutonomousActor::SendSuperstructureGoal() {
271 auto builder = superstructure_goal_sender_.MakeBuilder();
272
273 control_loops::superstructure::Goal::Builder superstructure_builder =
274 builder.MakeBuilder<control_loops::superstructure::Goal>();
275
276 superstructure_builder.add_arm_goal_position(arm_goal_position_);
277 superstructure_builder.add_preloaded_with_cone(preloaded_);
278 superstructure_builder.add_roller_goal(roller_goal_);
279 superstructure_builder.add_wrist(wrist_goal_);
280
281 if (builder.Send(superstructure_builder.Finish()) !=
282 aos::RawSender::Error::kOk) {
283 AOS_LOG(ERROR, "Sending superstructure goal failed.\n");
284 }
285}
286
287[[nodiscard]] bool AutonomousActor::WaitForPreloaded() {
288 set_preloaded(true);
289 SendSuperstructureGoal();
290
291 ::aos::time::PhasedLoop phased_loop(frc971::controls::kLoopFrequency,
292 event_loop()->monotonic_now(),
293 ActorBase::kLoopOffset);
294
295 bool loaded = false;
296 while (!loaded) {
297 if (ShouldCancel()) {
298 return false;
299 }
300
301 phased_loop.SleepUntilNext();
302 superstructure_status_fetcher_.Fetch();
303 CHECK(superstructure_status_fetcher_.get() != nullptr);
304
305 loaded = (superstructure_status_fetcher_->end_effector_state() ==
306 control_loops::superstructure::EndEffectorState::LOADED);
307 }
308
309 set_preloaded(false);
310 SendSuperstructureGoal();
311
312 return true;
313}
314
315void AutonomousActor::MidConeScore() {
316 set_arm_goal_position(
317 control_loops::superstructure::arm::ScoreFrontMidConeUpIndex());
318 set_wrist_goal(0.05);
319 SendSuperstructureGoal();
320}
321
322void AutonomousActor::HighCubeScore() {
323 set_arm_goal_position(
324 control_loops::superstructure::arm::ScoreFrontHighCubeIndex());
325 set_wrist_goal(0.6);
326 SendSuperstructureGoal();
327}
328
329void AutonomousActor::MidCubeScore() {
330 set_arm_goal_position(
331 control_loops::superstructure::arm::ScoreFrontMidCubeIndex());
332 set_wrist_goal(0.6);
333 SendSuperstructureGoal();
334}
335
336void AutonomousActor::PickupCube() {
337 set_arm_goal_position(
338 control_loops::superstructure::arm::GroundPickupBackCubeIndex());
339 set_wrist_goal(0.6);
340 SendSuperstructureGoal();
341}
342
343void AutonomousActor::Spit() {
344 set_roller_goal(control_loops::superstructure::RollerGoal::SPIT);
345 SendSuperstructureGoal();
346}
347
348void AutonomousActor::IntakeCube() {
349 set_roller_goal(control_loops::superstructure::RollerGoal::INTAKE_CUBE);
350 SendSuperstructureGoal();
351}
352
353[[nodiscard]] bool AutonomousActor::WaitForArmGoal() {
354 constexpr double kEpsTheta = 0.01;
355
356 ::aos::time::PhasedLoop phased_loop(frc971::controls::kLoopFrequency,
357 event_loop()->monotonic_now(),
358 ActorBase::kLoopOffset);
359
360 bool at_goal = false;
361 while (!at_goal) {
362 if (ShouldCancel()) {
363 return false;
364 }
365
366 phased_loop.SleepUntilNext();
367 superstructure_status_fetcher_.Fetch();
368 CHECK(superstructure_status_fetcher_.get() != nullptr);
369
370 // Check that the status had the right goal
371 at_goal = (std::abs(points_[arm_goal_position_](0) -
372 superstructure_status_fetcher_->arm()->theta0()) <
373 kEpsTheta &&
374 std::abs(points_[arm_goal_position_](1) -
375 superstructure_status_fetcher_->arm()->theta1()) <
376 kEpsTheta &&
377 std::abs(points_[arm_goal_position_](2) -
378 superstructure_status_fetcher_->arm()->theta2()) <
379 kEpsTheta) &&
380 (std::abs(wrist_goal_ -
381 superstructure_status_fetcher_->wrist()->position()) <
382 kEpsTheta);
383 }
384
385 set_preloaded(false);
386 SendSuperstructureGoal();
387
388 return true;
389}
390
391} // namespace autonomous
Maxwell Hendersonad312342023-01-10 12:07:47 -0800392} // namespace y2023