blob: bb488d8828a9fffa18ee3cc7594369b642b2094e [file] [log] [blame]
milind-u086d7262022-01-19 20:44:18 -08001#include "y2022/actors/autonomous_actor.h"
2
3#include <chrono>
4#include <cinttypes>
5#include <cmath>
6
7#include "aos/logging/logging.h"
Ravago Jones81e50632022-03-11 16:23:51 -08008#include "aos/network/team_number.h"
9#include "aos/util/math.h"
milind-u086d7262022-01-19 20:44:18 -080010#include "frc971/control_loops/drivetrain/localizer_generated.h"
Ravago Jones81e50632022-03-11 16:23:51 -080011#include "y2022/actors/auto_splines.h"
12#include "y2022/constants.h"
milind-u086d7262022-01-19 20:44:18 -080013#include "y2022/control_loops/drivetrain/drivetrain_base.h"
14
Ravago Jones81e50632022-03-11 16:23:51 -080015DEFINE_bool(spline_auto, false, "If true, define a spline autonomous mode");
Milind Upadhyaya7793962022-03-11 19:39:36 -080016DEFINE_bool(rapid_react, false,
17 "If true, run the main rapid react autonomous mode");
Ravago Jones81e50632022-03-11 16:23:51 -080018
milind-u086d7262022-01-19 20:44:18 -080019namespace y2022 {
20namespace actors {
Ravago Jones81e50632022-03-11 16:23:51 -080021namespace {
Austin Schuhe1264372022-03-13 20:22:36 -070022constexpr double kExtendIntakeGoal = -0.02;
Ravago Jones81e50632022-03-11 16:23:51 -080023constexpr double kRetractIntakeGoal = 1.47;
Austin Schuhe1264372022-03-13 20:22:36 -070024constexpr double kIntakeRollerVoltage = 8.0;
Ravago Jones81e50632022-03-11 16:23:51 -080025constexpr double kRollerVoltage = 12.0;
26constexpr double kCatapultReturnPosition = -0.908;
27} // namespace
milind-u086d7262022-01-19 20:44:18 -080028
29using ::aos::monotonic_clock;
Ravago Jones81e50632022-03-11 16:23:51 -080030using frc971::CreateProfileParameters;
milind-u086d7262022-01-19 20:44:18 -080031using ::frc971::ProfileParametersT;
Ravago Jones81e50632022-03-11 16:23:51 -080032using frc971::control_loops::CreateStaticZeroingSingleDOFProfiledSubsystemGoal;
33using frc971::control_loops::StaticZeroingSingleDOFProfiledSubsystemGoal;
milind-u086d7262022-01-19 20:44:18 -080034using frc971::control_loops::drivetrain::LocalizerControl;
Ravago Jones81e50632022-03-11 16:23:51 -080035
milind-u086d7262022-01-19 20:44:18 -080036namespace chrono = ::std::chrono;
37
38AutonomousActor::AutonomousActor(::aos::EventLoop *event_loop)
39 : frc971::autonomous::BaseAutonomousActor(
Ravago Jones81e50632022-03-11 16:23:51 -080040 event_loop, control_loops::drivetrain::GetDrivetrainConfig()),
41 localizer_control_sender_(
42 event_loop->MakeSender<
43 ::frc971::control_loops::drivetrain::LocalizerControl>(
44 "/drivetrain")),
45 superstructure_goal_sender_(
46 event_loop->MakeSender<control_loops::superstructure::Goal>(
47 "/superstructure")),
48 superstructure_status_fetcher_(
49 event_loop->MakeFetcher<control_loops::superstructure::Status>(
50 "/superstructure")),
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 set_max_drivetrain_voltage(12.0);
56 replan_timer_ = event_loop->AddTimer([this]() { Replan(); });
57 event_loop->OnRun([this, event_loop]() {
58 replan_timer_->Setup(event_loop->monotonic_now());
59 button_poll_->Setup(event_loop->monotonic_now(), chrono::milliseconds(50));
60 });
61
62 button_poll_ = event_loop->AddTimer([this]() {
63 const aos::monotonic_clock::time_point now =
64 this->event_loop()->context().monotonic_event_time;
65 if (robot_state_fetcher_.Fetch()) {
66 if (robot_state_fetcher_->user_button()) {
67 user_indicated_safe_to_reset_ = true;
68 MaybeSendStartingPosition();
69 }
70 }
71 if (joystick_state_fetcher_.Fetch()) {
72 if (joystick_state_fetcher_->has_alliance() &&
73 (joystick_state_fetcher_->alliance() != alliance_)) {
74 alliance_ = joystick_state_fetcher_->alliance();
75 is_planned_ = false;
76 // Only kick the planning out by 2 seconds. If we end up enabled in that
77 // second, then we will kick it out further based on the code below.
78 replan_timer_->Setup(now + std::chrono::seconds(2));
79 }
80 if (joystick_state_fetcher_->enabled()) {
81 if (!is_planned_) {
82 // Only replan once we've been disabled for 5 seconds.
83 replan_timer_->Setup(now + std::chrono::seconds(5));
84 }
85 }
86 }
87 });
88}
89
90void AutonomousActor::Replan() {
91 LOG(INFO) << "Alliance " << static_cast<int>(alliance_);
92 if (alliance_ == aos::Alliance::kInvalid) {
93 return;
94 }
95 sent_starting_position_ = false;
96 if (FLAGS_spline_auto) {
97 test_spline_ =
98 PlanSpline(std::bind(&AutonomousSplines::TestSpline, &auto_splines_,
99 std::placeholders::_1, alliance_),
100 SplineDirection::kForward);
101
102 starting_position_ = test_spline_->starting_position();
Milind Upadhyaya7793962022-03-11 19:39:36 -0800103 } else if (FLAGS_rapid_react) {
104 rapid_react_splines_ = {
105 PlanSpline(std::bind(&AutonomousSplines::Spline1, &auto_splines_,
106 std::placeholders::_1, alliance_),
107 SplineDirection::kForward),
108 PlanSpline(std::bind(&AutonomousSplines::Spline2, &auto_splines_,
109 std::placeholders::_1, alliance_),
110 SplineDirection::kForward),
111 PlanSpline(std::bind(&AutonomousSplines::Spline3, &auto_splines_,
112 std::placeholders::_1, alliance_),
113 SplineDirection::kForward),
114 PlanSpline(std::bind(&AutonomousSplines::Spline4, &auto_splines_,
115 std::placeholders::_1, alliance_),
116 SplineDirection::kBackward),
117 PlanSpline(std::bind(&AutonomousSplines::Spline5, &auto_splines_,
118 std::placeholders::_1, alliance_),
119 SplineDirection::kBackward)};
120 starting_position_ = rapid_react_splines_.value()[0].starting_position();
121 CHECK(starting_position_);
Ravago Jones81e50632022-03-11 16:23:51 -0800122 }
123
124 is_planned_ = true;
125
126 MaybeSendStartingPosition();
127}
128
129void AutonomousActor::MaybeSendStartingPosition() {
130 if (is_planned_ && user_indicated_safe_to_reset_ &&
131 !sent_starting_position_) {
132 CHECK(starting_position_);
133 SendStartingPosition(starting_position_.value());
134 }
135}
milind-u086d7262022-01-19 20:44:18 -0800136
137void AutonomousActor::Reset() {
138 InitializeEncoders();
139 ResetDrivetrain();
Ravago Jones81e50632022-03-11 16:23:51 -0800140 RetractFrontIntake();
141 RetractBackIntake();
142
143 joystick_state_fetcher_.Fetch();
144 CHECK(joystick_state_fetcher_.get() != nullptr)
145 << "Expect at least one JoystickState message before running auto...";
146 alliance_ = joystick_state_fetcher_->alliance();
milind-u086d7262022-01-19 20:44:18 -0800147}
148
149bool AutonomousActor::RunAction(
150 const ::frc971::autonomous::AutonomousActionParams *params) {
151 Reset();
Ravago Jones81e50632022-03-11 16:23:51 -0800152 if (!user_indicated_safe_to_reset_) {
153 AOS_LOG(WARNING, "Didn't send starting position prior to starting auto.");
154 CHECK(starting_position_);
155 SendStartingPosition(starting_position_.value());
156 }
157 // Clear this so that we don't accidentally resend things as soon as we replan
158 // later.
159 user_indicated_safe_to_reset_ = false;
160 is_planned_ = false;
161 starting_position_.reset();
milind-u086d7262022-01-19 20:44:18 -0800162
163 AOS_LOG(INFO, "Params are %d\n", params->mode());
Ravago Jones81e50632022-03-11 16:23:51 -0800164 if (alliance_ == aos::Alliance::kInvalid) {
165 AOS_LOG(INFO, "Aborting autonomous due to invalid alliance selection.");
166 return false;
167 }
168 if (FLAGS_spline_auto) {
169 SplineAuto();
Milind Upadhyaya7793962022-03-11 19:39:36 -0800170 } else if (FLAGS_rapid_react) {
171 RapidReact();
Ravago Jones81e50632022-03-11 16:23:51 -0800172 }
173
milind-u086d7262022-01-19 20:44:18 -0800174 return true;
175}
176
Ravago Jones81e50632022-03-11 16:23:51 -0800177void AutonomousActor::SendStartingPosition(const Eigen::Vector3d &start) {
178 // Set up the starting position for the blue alliance.
179
180 // TODO(james): Resetting the localizer breaks the left/right statespace
181 // controller. That is a bug, but we can fix that later by not resetting.
182 auto builder = localizer_control_sender_.MakeBuilder();
183
184 LocalizerControl::Builder localizer_control_builder =
185 builder.MakeBuilder<LocalizerControl>();
186 localizer_control_builder.add_x(start(0));
187 localizer_control_builder.add_y(start(1));
188 localizer_control_builder.add_theta(start(2));
189 localizer_control_builder.add_theta_uncertainty(0.00001);
190 LOG(INFO) << "User button pressed, x: " << start(0) << " y: " << start(1)
191 << " theta: " << start(2);
192 if (builder.Send(localizer_control_builder.Finish()) !=
193 aos::RawSender::Error::kOk) {
194 AOS_LOG(ERROR, "Failed to reset localizer.\n");
195 }
196}
197
198void AutonomousActor::SplineAuto() {
199 CHECK(test_spline_);
200
201 if (!test_spline_->WaitForPlan()) return;
202 test_spline_->Start();
203
204 if (!test_spline_->WaitForSplineDistanceRemaining(0.02)) return;
205}
206
Milind Upadhyaya7793962022-03-11 19:39:36 -0800207void AutonomousActor::RapidReact() {
208 aos::monotonic_clock::time_point start_time = aos::monotonic_clock::now();
209
210 CHECK(rapid_react_splines_);
211
212 auto &splines = *rapid_react_splines_;
213
214 // Tell the superstructure a ball was preloaded
215
216 if (!WaitForPreloaded()) return;
217 // Drive and intake the 2nd ball
218 ExtendFrontIntake();
219 if (!splines[0].WaitForPlan()) return;
220 splines[0].Start();
221 if (!splines[0].WaitForSplineDistanceRemaining(0.02)) return;
222
223 // Fire the two balls once we stopped
224 set_fire_at_will(true);
225 SendSuperstructureGoal();
226 if (!WaitForBallsShot(2)) return;
227 set_fire_at_will(false);
228
229 // Drive and intake the 3rd ball
230 if (!splines[1].WaitForPlan()) return;
231 splines[1].Start();
232 if (!splines[1].WaitForSplineDistanceRemaining(0.02)) return;
233
234 // Fire the 3rd once we stopped.
235 set_fire_at_will(true);
236 SendSuperstructureGoal();
237 if (!WaitForBallsShot(1)) return;
238 set_fire_at_will(false);
239
240 // Drive to the human player station while intaking two balls.
241 // Once is already placed down,
242 // and one will be rolled to the robot by the human player
243 if (!splines[2].WaitForPlan()) return;
244 splines[2].Start();
245 if (!splines[2].WaitForSplineDistanceRemaining(0.02)) return;
246
247 // Drive to the shooting position
248 if (!splines[3].WaitForPlan()) return;
249 splines[3].Start();
250 if (!splines[3].WaitForSplineDistanceRemaining(0.02)) return;
251
252 // Fire the two balls once we stopped
253 set_fire_at_will(true);
254 SendSuperstructureGoal();
255 if (!WaitForBallsShot(2)) return;
256 set_fire_at_will(false);
257
258 // Done intaking
259 RetractFrontIntake();
260
261 // Drive to the middle of the field to get ready for teleop
262 if (!splines[4].WaitForPlan()) return;
263 splines[4].Start();
264 if (!splines[4].WaitForSplineDistanceRemaining(0.02)) return;
265
266 LOG(INFO) << "Took "
267 << chrono::duration<double>(aos::monotonic_clock::now() -
268 start_time)
269 .count()
270 << 's';
271}
272
273[[nodiscard]] bool AutonomousActor::WaitForPreloaded() {
Milind Upadhyay803bbf02022-03-11 17:56:26 -0800274 set_preloaded(true);
275 SendSuperstructureGoal();
276
277 ::aos::time::PhasedLoop phased_loop(frc971::controls::kLoopFrequency,
278 event_loop()->monotonic_now(),
279 ActorBase::kLoopOffset);
280
281 bool loaded = false;
282 while (!loaded) {
283 if (ShouldCancel()) {
284 return false;
285 }
286
287 phased_loop.SleepUntilNext();
288 superstructure_status_fetcher_.Fetch();
289 CHECK(superstructure_status_fetcher_.get() != nullptr);
290
291 loaded = (superstructure_status_fetcher_->state() ==
292 control_loops::superstructure::SuperstructureState::LOADED);
293 }
294
295 set_preloaded(false);
296 SendSuperstructureGoal();
297
298 return true;
299}
300
Ravago Jones81e50632022-03-11 16:23:51 -0800301void AutonomousActor::SendSuperstructureGoal() {
302 auto builder = superstructure_goal_sender_.MakeBuilder();
303
304 flatbuffers::Offset<StaticZeroingSingleDOFProfiledSubsystemGoal>
305 intake_front_offset = CreateStaticZeroingSingleDOFProfiledSubsystemGoal(
306 *builder.fbb(), intake_front_goal_,
307 CreateProfileParameters(*builder.fbb(), 20.0, 60.0));
308
309 flatbuffers::Offset<StaticZeroingSingleDOFProfiledSubsystemGoal>
310 intake_back_offset = CreateStaticZeroingSingleDOFProfiledSubsystemGoal(
311 *builder.fbb(), intake_back_goal_,
312 CreateProfileParameters(*builder.fbb(), 20.0, 60.0));
313
314 flatbuffers::Offset<StaticZeroingSingleDOFProfiledSubsystemGoal>
315 catapult_return_position_offset =
316 CreateStaticZeroingSingleDOFProfiledSubsystemGoal(
317 *builder.fbb(), kCatapultReturnPosition,
318 CreateProfileParameters(*builder.fbb(), 9.0, 50.0));
319
320 superstructure::CatapultGoal::Builder catapult_goal_builder(*builder.fbb());
321 catapult_goal_builder.add_shot_position(0.03);
322 catapult_goal_builder.add_shot_velocity(18.0);
323 catapult_goal_builder.add_return_position(catapult_return_position_offset);
324 flatbuffers::Offset<superstructure::CatapultGoal> catapult_goal_offset =
325 catapult_goal_builder.Finish();
326
327 superstructure::Goal::Builder superstructure_builder =
328 builder.MakeBuilder<superstructure::Goal>();
329
330 superstructure_builder.add_intake_front(intake_front_offset);
331 superstructure_builder.add_intake_back(intake_back_offset);
332 superstructure_builder.add_roller_speed_compensation(1.5);
333 superstructure_builder.add_roller_speed_front(roller_front_voltage_);
334 superstructure_builder.add_roller_speed_back(roller_back_voltage_);
Milind Upadhyayb1a74ea2022-03-09 20:34:35 -0800335 superstructure_builder.add_transfer_roller_speed_front(
336 transfer_roller_front_voltage_);
337 superstructure_builder.add_transfer_roller_speed_back(
338 transfer_roller_back_voltage_);
Ravago Jones81e50632022-03-11 16:23:51 -0800339 superstructure_builder.add_catapult(catapult_goal_offset);
340 superstructure_builder.add_fire(fire_);
Milind Upadhyay803bbf02022-03-11 17:56:26 -0800341 superstructure_builder.add_preloaded(preloaded_);
Ravago Jones81e50632022-03-11 16:23:51 -0800342 superstructure_builder.add_auto_aim(true);
343
344 if (builder.Send(superstructure_builder.Finish()) !=
345 aos::RawSender::Error::kOk) {
346 AOS_LOG(ERROR, "Sending superstructure goal failed.\n");
347 }
348}
349
350void AutonomousActor::ExtendFrontIntake() {
351 set_intake_front_goal(kExtendIntakeGoal);
Austin Schuhe1264372022-03-13 20:22:36 -0700352 set_roller_front_voltage(kIntakeRollerVoltage);
Milind Upadhyayb1a74ea2022-03-09 20:34:35 -0800353 set_transfer_roller_front_voltage(kRollerVoltage);
354 set_transfer_roller_back_voltage(-kRollerVoltage);
Ravago Jones81e50632022-03-11 16:23:51 -0800355 SendSuperstructureGoal();
356}
357
358void AutonomousActor::RetractFrontIntake() {
359 set_intake_front_goal(kRetractIntakeGoal);
Austin Schuhe1264372022-03-13 20:22:36 -0700360 set_roller_front_voltage(0.0);
Milind Upadhyayb1a74ea2022-03-09 20:34:35 -0800361 set_transfer_roller_front_voltage(0.0);
362 set_transfer_roller_back_voltage(0.0);
Ravago Jones81e50632022-03-11 16:23:51 -0800363 SendSuperstructureGoal();
364}
365
366void AutonomousActor::ExtendBackIntake() {
367 set_intake_back_goal(kExtendIntakeGoal);
Austin Schuhe1264372022-03-13 20:22:36 -0700368 set_roller_back_voltage(kIntakeRollerVoltage);
Milind Upadhyayb1a74ea2022-03-09 20:34:35 -0800369 set_transfer_roller_back_voltage(kRollerVoltage);
370 set_transfer_roller_front_voltage(-kRollerVoltage);
Ravago Jones81e50632022-03-11 16:23:51 -0800371 SendSuperstructureGoal();
372}
373
374void AutonomousActor::RetractBackIntake() {
375 set_intake_back_goal(kRetractIntakeGoal);
Austin Schuhe1264372022-03-13 20:22:36 -0700376 set_roller_back_voltage(0.0);
Milind Upadhyayb1a74ea2022-03-09 20:34:35 -0800377 set_transfer_roller_front_voltage(0.0);
378 set_transfer_roller_back_voltage(0.0);
Ravago Jones81e50632022-03-11 16:23:51 -0800379 SendSuperstructureGoal();
380}
381
Milind Upadhyaya7793962022-03-11 19:39:36 -0800382[[nodiscard]] bool AutonomousActor::WaitForBallsShot(int num_wanted) {
Ravago Jonesf699d1c2022-03-11 18:39:56 -0800383 ::aos::time::PhasedLoop phased_loop(frc971::controls::kLoopFrequency,
384 event_loop()->monotonic_now(),
385 ActorBase::kLoopOffset);
386 superstructure_status_fetcher_.Fetch();
387 CHECK(superstructure_status_fetcher_.get() != nullptr);
388 int initial_balls = superstructure_status_fetcher_->shot_count();
389 LOG(INFO) << "Waiting for balls, started with " << initial_balls;
390 while (true) {
391 if (ShouldCancel()) {
392 return false;
393 }
394 phased_loop.SleepUntilNext();
395 superstructure_status_fetcher_.Fetch();
396 CHECK(superstructure_status_fetcher_.get() != nullptr);
397 if (superstructure_status_fetcher_->shot_count() - initial_balls >=
398 num_wanted) {
399 return true;
400 }
401 }
402}
403
milind-u086d7262022-01-19 20:44:18 -0800404} // namespace actors
405} // namespace y2022