blob: 35ad8d204cd00b461e9b182267c7f85a40aa848b [file] [log] [blame]
Comran Morshed0d6cf9b2015-06-17 19:29:57 +00001#include <stdio.h>
2
3#include <memory>
4
5#include "aos/common/util/phased_loop.h"
6#include "aos/common/time.h"
7#include "aos/common/util/trapezoid_profile.h"
8#include "aos/common/logging/logging.h"
9#include "aos/common/logging/queue_logging.h"
10
Austin Schuh6d1ee0c2015-11-21 14:36:04 -080011#include "y2015_bot3/autonomous/auto.q.h"
12#include "y2015_bot3/actors/drivetrain_actor.h"
Austin Schuh178d5152016-11-26 14:58:40 -080013#include "frc971/control_loops/drivetrain/drivetrain.q.h"
14#include "frc971/control_loops/drivetrain/drivetrain.h"
Austin Schuh6d1ee0c2015-11-21 14:36:04 -080015#include "y2015_bot3/control_loops/elevator/elevator.q.h"
16#include "y2015_bot3/control_loops/intake/intake.q.h"
Austin Schuh178d5152016-11-26 14:58:40 -080017#include "y2015_bot3/control_loops/drivetrain/drivetrain_base.h"
Comran Morshed0d6cf9b2015-06-17 19:29:57 +000018
Austin Schuh178d5152016-11-26 14:58:40 -080019using ::frc971::control_loops::drivetrain_queue;
Austin Schuh6d1ee0c2015-11-21 14:36:04 -080020using ::y2015_bot3::control_loops::intake_queue;
21using ::y2015_bot3::control_loops::elevator_queue;
Comran Morshed0d6cf9b2015-06-17 19:29:57 +000022
Austin Schuh6d1ee0c2015-11-21 14:36:04 -080023namespace y2015_bot3 {
Comran Morshed0d6cf9b2015-06-17 19:29:57 +000024namespace autonomous {
25
26struct ProfileParams {
27 double velocity;
28 double acceleration;
29};
30
Austin Schuhf2a50ba2016-12-24 16:16:26 -080031using ::aos::monotonic_clock;
Austin Schuhaeb1f492015-09-27 19:29:45 +000032namespace actors = ::frc971::actors;
Austin Schuhf2a50ba2016-12-24 16:16:26 -080033namespace chrono = ::std::chrono;
Austin Schuhaeb1f492015-09-27 19:29:45 +000034
35const ProfileParams kFastDrive = {3.0, 3.5};
36const ProfileParams kLastDrive = {4.0, 4.0};
37const ProfileParams kStackingFirstTurn = {3.0, 7.0};
38const ProfileParams kFinalDriveTurn = {3.0, 5.0};
39const ProfileParams kSlowFirstDriveTurn = {0.75, 1.5};
40const ProfileParams kSlowSecondDriveTurn = {0.6, 1.5};
41const ProfileParams kCanPickupDrive = {1.3, 3.0};
Comran Morshed0d6cf9b2015-06-17 19:29:57 +000042
Comran Morshed34f891d2015-09-15 22:04:43 +000043static double left_initial_position, right_initial_position;
44
Comran Morshed0d6cf9b2015-06-17 19:29:57 +000045bool ShouldExitAuto() {
Austin Schuh6d1ee0c2015-11-21 14:36:04 -080046 ::y2015_bot3::autonomous::autonomous.FetchLatest();
47 bool ans = !::y2015_bot3::autonomous::autonomous->run_auto;
Comran Morshed0d6cf9b2015-06-17 19:29:57 +000048 if (ans) {
49 LOG(INFO, "Time to exit auto mode\n");
50 }
51 return ans;
52}
53
Comran Morshed34f891d2015-09-15 22:04:43 +000054void ResetDrivetrain() {
55 LOG(INFO, "resetting the drivetrain\n");
Austin Schuh178d5152016-11-26 14:58:40 -080056 drivetrain_queue.goal.MakeWithBuilder()
Comran Morshed34f891d2015-09-15 22:04:43 +000057 .control_loop_driving(false)
58 .steering(0.0)
59 .throttle(0.0)
60 .left_goal(left_initial_position)
61 .left_velocity_goal(0)
62 .right_goal(right_initial_position)
63 .right_velocity_goal(0)
64 .Send();
65}
66
67void InitializeEncoders() {
Austin Schuh178d5152016-11-26 14:58:40 -080068 drivetrain_queue.status.FetchAnother();
69 left_initial_position = drivetrain_queue.status->estimated_left_position;
70 right_initial_position = drivetrain_queue.status->estimated_right_position;
Comran Morshed34f891d2015-09-15 22:04:43 +000071}
72
Austin Schuhaeb1f492015-09-27 19:29:45 +000073::std::unique_ptr< ::frc971::actors::DrivetrainAction> SetDriveGoal(
74 double distance, const ProfileParams drive_params, double theta,
75 const ProfileParams &turn_params) {
76 LOG(INFO, "Driving to %f\n", distance);
77
78 actors::DrivetrainActionParams params;
79 params.left_initial_position = left_initial_position;
80 params.right_initial_position = right_initial_position;
81 params.y_offset = distance;
82 params.theta_offset = theta;
83 params.maximum_turn_acceleration = turn_params.acceleration;
84 params.maximum_turn_velocity = turn_params.velocity;
85 params.maximum_velocity = drive_params.velocity;
86 params.maximum_acceleration = drive_params.acceleration;
87 auto drivetrain_action = actors::MakeDrivetrainAction(params);
88
89 drivetrain_action->Start();
Austin Schuh178d5152016-11-26 14:58:40 -080090 left_initial_position +=
91 distance - theta * control_loops::drivetrain::kDrivetrainTurnWidth / 2.0;
92 right_initial_position +=
93 distance + theta * control_loops::drivetrain::kDrivetrainTurnWidth / 2.0;
Austin Schuhaeb1f492015-09-27 19:29:45 +000094 return ::std::move(drivetrain_action);
95}
96void WaitUntilDoneOrCanceled(
97 ::std::unique_ptr<aos::common::actions::Action> action) {
98 if (!action) {
99 LOG(ERROR, "No action, not waiting\n");
100 return;
101 }
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800102 ::aos::time::PhasedLoop phased_loop(chrono::milliseconds(5),
103 chrono::microseconds(2500));
Austin Schuhaeb1f492015-09-27 19:29:45 +0000104 while (true) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800105 phased_loop.SleepUntilNext();
Austin Schuhaeb1f492015-09-27 19:29:45 +0000106 // Poll the running bit and auto done bits.
Austin Schuhaeb1f492015-09-27 19:29:45 +0000107 if (!action->Running() || ShouldExitAuto()) {
108 return;
109 }
110 }
111}
112
113void WaitUntilNear(double distance) {
114 while (true) {
115 if (ShouldExitAuto()) return;
Austin Schuh178d5152016-11-26 14:58:40 -0800116 drivetrain_queue.status.FetchAnother();
117 double left_error =
118 ::std::abs(left_initial_position -
119 drivetrain_queue.status->estimated_left_position);
120 double right_error =
121 ::std::abs(right_initial_position -
122 drivetrain_queue.status->estimated_right_position);
Austin Schuhaeb1f492015-09-27 19:29:45 +0000123 const double kPositionThreshold = 0.05 + distance;
124 if (right_error < kPositionThreshold && left_error < kPositionThreshold) {
125 LOG(INFO, "At the goal\n");
126 return;
127 }
128 }
129}
130
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800131void GrabberForTime(double voltage, monotonic_clock::duration wait_time) {
132 monotonic_clock::time_point monotonic_now = monotonic_clock::now();
133 monotonic_clock::time_point end_time = monotonic_now + wait_time;
134 LOG(INFO, "Starting to grab at %f for %f seconds\n", voltage,
135 chrono::duration_cast<chrono::duration<double>>(wait_time).count());
Comran Morshed34f891d2015-09-15 22:04:43 +0000136
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800137 ::aos::time::PhasedLoop phased_loop(chrono::milliseconds(5),
138 chrono::microseconds(2500));
Comran Morshed34f891d2015-09-15 22:04:43 +0000139 while (true) {
140 autonomous::can_grabber_control.MakeWithBuilder()
Austin Schuhbd01a582015-09-21 00:05:31 +0000141 .can_grabber_voltage(voltage).can_grabbers(false).Send();
Comran Morshed34f891d2015-09-15 22:04:43 +0000142
143 // Poll the running bit and auto done bits.
144 if (ShouldExitAuto()) {
145 return;
146 }
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800147 if (monotonic_clock::now() > end_time) {
Comran Morshed34f891d2015-09-15 22:04:43 +0000148 LOG(INFO, "Done grabbing\n");
149 return;
150 }
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800151 phased_loop.SleepUntilNext();
Comran Morshed34f891d2015-09-15 22:04:43 +0000152 }
153}
154
155// Auto methods.
156void CanGrabberAuto() {
157 ResetDrivetrain();
158
159 // Launch can grabbers.
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800160 // GrabberForTime(12.0, chrono::milliseconds(260));
161 GrabberForTime(6.0, chrono::milliseconds(400));
Comran Morshed34f891d2015-09-15 22:04:43 +0000162 if (ShouldExitAuto()) return;
163 InitializeEncoders();
164 ResetDrivetrain();
165 if (ShouldExitAuto()) return;
Austin Schuhbd01a582015-09-21 00:05:31 +0000166 // Send our intake goals.
167 if (!intake_queue.goal.MakeWithBuilder().movement(0.0).claw_closed(true)
168 .Send()) {
169 LOG(ERROR, "Sending intake goal failed.\n");
170 }
171 {
172 auto new_elevator_goal = elevator_queue.goal.MakeMessage();
173 new_elevator_goal->max_velocity = 0.0;
174 new_elevator_goal->max_acceleration = 0.0;
175 new_elevator_goal->height = 0.030;
176 new_elevator_goal->velocity = 0.0;
177 new_elevator_goal->passive_support = true;
178 new_elevator_goal->can_support = false;
179
180 if (new_elevator_goal.Send()) {
181 LOG(DEBUG, "sending goals: elevator: %f\n", 0.03);
182 } else {
183 LOG(ERROR, "Sending elevator goal failed.\n");
184 }
185 }
186
187 const double kMoveBackDistance = 1.75;
188 //const double kMoveBackDistance = 0.0;
Comran Morshed34f891d2015-09-15 22:04:43 +0000189
190 // Drive backwards, and pulse the can grabbers again to tip the cans.
Austin Schuh178d5152016-11-26 14:58:40 -0800191 drivetrain_queue.goal.MakeWithBuilder()
Comran Morshed34f891d2015-09-15 22:04:43 +0000192 .control_loop_driving(true)
193 .steering(0.0)
194 .throttle(0.0)
Austin Schuhbd01a582015-09-21 00:05:31 +0000195 .left_goal(left_initial_position + kMoveBackDistance)
Comran Morshed34f891d2015-09-15 22:04:43 +0000196 .left_velocity_goal(0)
Austin Schuhbd01a582015-09-21 00:05:31 +0000197 .right_goal(right_initial_position + kMoveBackDistance)
Comran Morshed34f891d2015-09-15 22:04:43 +0000198 .right_velocity_goal(0)
199 .Send();
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800200 GrabberForTime(12.0, chrono::milliseconds(20));
Comran Morshed34f891d2015-09-15 22:04:43 +0000201 if (ShouldExitAuto()) return;
202
203 // We shouldn't need as much power at this point, so lower the can grabber
204 // voltages to avoid damaging the motors due to stalling.
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800205 GrabberForTime(4.0, chrono::milliseconds(750));
Comran Morshed34f891d2015-09-15 22:04:43 +0000206 if (ShouldExitAuto()) return;
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800207 GrabberForTime(-3.0, chrono::milliseconds(250));
Comran Morshed34f891d2015-09-15 22:04:43 +0000208 if (ShouldExitAuto()) return;
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800209 GrabberForTime(-12.0, chrono::milliseconds(1000));
Comran Morshed34f891d2015-09-15 22:04:43 +0000210 if (ShouldExitAuto()) return;
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800211 GrabberForTime(-3.0, chrono::milliseconds(12000));
Comran Morshed34f891d2015-09-15 22:04:43 +0000212}
213
Austin Schuhaeb1f492015-09-27 19:29:45 +0000214const ProfileParams kElevatorProfile = {1.0, 5.0};
215
216static double elevator_goal_height = 0.0;
217
218void SetElevatorHeight(double height, const ProfileParams params,
219 bool can_open = false, bool support_open = true) {
220 // Send our elevator goals, with limits set in the profile params.
221 auto new_elevator_goal = elevator_queue.goal.MakeMessage();
222 elevator_goal_height = height;
223 new_elevator_goal->max_velocity = params.velocity;
224 new_elevator_goal->max_acceleration = params.acceleration;
225 new_elevator_goal->height = elevator_goal_height;
226 new_elevator_goal->velocity = 0.0;
227 new_elevator_goal->passive_support = support_open;
228 new_elevator_goal->can_support = can_open;
229
230 if (new_elevator_goal.Send()) {
231 LOG(DEBUG, "sending goals: elevator: %f\n", elevator_goal_height);
232 } else {
233 LOG(ERROR, "Sending elevator goal failed.\n");
234 }
235}
236
237void WaitForElevator() {
238 while (true) {
239 if (ShouldExitAuto()) return;
240 control_loops::elevator_queue.status.FetchAnother();
241
242 constexpr double kProfileError = 1e-5;
243 constexpr double kEpsilon = 0.03;
244
245 if (::std::abs(control_loops::elevator_queue.status->goal_height -
246 elevator_goal_height) <
247 kProfileError &&
248 ::std::abs(control_loops::elevator_queue.status->goal_velocity) <
249 kProfileError) {
250 LOG(INFO, "Profile done.\n");
251 if (::std::abs(control_loops::elevator_queue.status->height -
252 elevator_goal_height) <
253 kEpsilon) {
254 LOG(INFO, "Near goal, done.\n");
255 return;
256 }
257 }
258 }
259}
260
261void WaitUntilElevatorBelow(double height) {
262 while (true) {
263 if (ShouldExitAuto()) return;
264 control_loops::elevator_queue.status.FetchAnother();
265
266 if (control_loops::elevator_queue.status->goal_height < height) {
267 LOG(INFO, "Profile below.\n");
268 if (control_loops::elevator_queue.status->height < height) {
269 LOG(INFO, "Elevator below goal, done.\n");
270 return;
271 }
272 }
273 }
274}
275
276void WaitUntilElevatorAbove(double height) {
277 while (true) {
278 if (ShouldExitAuto()) return;
279 control_loops::elevator_queue.status.FetchAnother();
280
281 if (control_loops::elevator_queue.status->goal_height > height) {
282 LOG(INFO, "Profile above.\n");
283 if (control_loops::elevator_queue.status->height > height) {
284 LOG(INFO, "Elevator above goal, done.\n");
285 return;
286 }
287 }
288 }
289}
290
291void LiftTote(double final_height = 0.48) {
292 // Send our intake goals.
293 if (!intake_queue.goal.MakeWithBuilder().movement(10.0).claw_closed(true)
294 .Send()) {
295 LOG(ERROR, "Sending intake goal failed.\n");
296 }
297
298 while (true) {
299 elevator_queue.status.FetchAnother();
300 if (!elevator_queue.status.get()) {
301 LOG(ERROR, "Got no elevator status packet.\n");
302 }
303 if (ShouldExitAuto()) return;
304 if (elevator_queue.status->has_tote) {
305 break;
306 }
307 }
308 if (!intake_queue.goal.MakeWithBuilder().movement(0.0).claw_closed(true)
309 .Send()) {
310 LOG(ERROR, "Sending intake goal failed.\n");
311 }
312 SetElevatorHeight(0.02, kElevatorProfile, false, false);
313 WaitUntilElevatorBelow(0.05);
314 if (ShouldExitAuto()) return;
315
316 SetElevatorHeight(final_height, kElevatorProfile, false, false);
317}
318
319void TripleCanAuto() {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800320 monotonic_clock::time_point start_time = monotonic_clock::now();
Austin Schuhaeb1f492015-09-27 19:29:45 +0000321
322 ::std::unique_ptr<::frc971::actors::DrivetrainAction> drive;
323 InitializeEncoders();
324 ResetDrivetrain();
325
326 SetElevatorHeight(0.03, kElevatorProfile, false, true);
327
328
329 LiftTote();
330 if (ShouldExitAuto()) return;
331
332 // The amount to turn out for going around the first can.
333 const double kFirstTurn = 0.5;
334
335 drive = SetDriveGoal(0.0, kFastDrive, kFirstTurn, kStackingFirstTurn);
336
337 WaitUntilDoneOrCanceled(::std::move(drive));
338 if (ShouldExitAuto()) return;
339
340 drive = SetDriveGoal(2.0, kFastDrive, -kFirstTurn * 2.0, kSlowFirstDriveTurn);
341
342 WaitUntilNear(1.5);
343 if (ShouldExitAuto()) return;
344
345 if (!intake_queue.goal.MakeWithBuilder().movement(0.0).claw_closed(false)
346 .Send()) {
347 LOG(ERROR, "Sending intake goal failed.\n");
348 }
349
350 WaitUntilDoneOrCanceled(::std::move(drive));
351 if (ShouldExitAuto()) return;
352
353 drive = SetDriveGoal(0.0, kFastDrive, kFirstTurn, kStackingFirstTurn);
354 LiftTote();
355 if (ShouldExitAuto()) return;
356 WaitUntilDoneOrCanceled(::std::move(drive));
357 if (ShouldExitAuto()) return;
358
359 // The amount to turn out for going around the second can.
360 const double kSecondTurn = 0.35;
361 const double kSecondTurnExtraOnSecond = 0.10;
362
363 drive = SetDriveGoal(0.0, kFastDrive, kSecondTurn, kStackingFirstTurn);
364 WaitUntilDoneOrCanceled(::std::move(drive));
365 if (ShouldExitAuto()) return;
366
367 drive =
368 SetDriveGoal(2.05, kFastDrive, -kSecondTurn * 2.0 - kSecondTurnExtraOnSecond, kSlowSecondDriveTurn);
369 WaitUntilNear(1.5);
370
371 if (!intake_queue.goal.MakeWithBuilder().movement(0.0).claw_closed(false)
372 .Send()) {
373 LOG(ERROR, "Sending intake goal failed.\n");
374 }
375
376 WaitUntilDoneOrCanceled(::std::move(drive));
377 if (ShouldExitAuto()) return;
378
379 drive = SetDriveGoal(0.0, kFastDrive, kSecondTurn + kSecondTurnExtraOnSecond, kStackingFirstTurn);
380
381 LiftTote(0.18);
382
383 WaitUntilDoneOrCanceled(::std::move(drive));
384 if (ShouldExitAuto()) return;
385
386 drive = SetDriveGoal(0.3, kFastDrive, -1.7, kFinalDriveTurn);
387 WaitUntilDoneOrCanceled(::std::move(drive));
388 if (ShouldExitAuto()) return;
389
390 if (!intake_queue.goal.MakeWithBuilder().movement(0.0).claw_closed(false)
391 .Send()) {
392 LOG(ERROR, "Sending intake goal failed.\n");
393 }
394
395 WaitUntilDoneOrCanceled(::std::move(drive));
396 if (ShouldExitAuto()) return;
397 drive = SetDriveGoal(2.95, kLastDrive, 0.0, kFinalDriveTurn);
398
399 WaitUntilDoneOrCanceled(::std::move(drive));
400 if (ShouldExitAuto()) return;
401
402 SetElevatorHeight(0.03, kElevatorProfile, true, true);
403 WaitForElevator();
404 if (ShouldExitAuto()) return;
405
406 drive = SetDriveGoal(-2.25, kFastDrive, 0.0, kFinalDriveTurn);
407 WaitUntilDoneOrCanceled(::std::move(drive));
408 if (ShouldExitAuto()) return;
409
410 drive = SetDriveGoal(0.0, kFastDrive, 1.80, kFinalDriveTurn);
411 WaitUntilDoneOrCanceled(::std::move(drive));
412 if (ShouldExitAuto()) return;
413
414 if (!intake_queue.goal.MakeWithBuilder().movement(10.0).claw_closed(true)
415 .Send()) {
416 LOG(ERROR, "Sending intake goal failed.\n");
417 }
418 SetElevatorHeight(0.03, kElevatorProfile, false, true);
419
420 drive = SetDriveGoal(1.0, kCanPickupDrive, 0.0, kFinalDriveTurn);
421 WaitUntilDoneOrCanceled(::std::move(drive));
422 if (ShouldExitAuto()) return;
423
424 SetElevatorHeight(0.03, kElevatorProfile, true, true);
425
426 while (true) {
427 elevator_queue.status.FetchAnother();
428 if (!elevator_queue.status.get()) {
429 LOG(ERROR, "Got no elevator status packet.\n");
430 }
431 if (ShouldExitAuto()) return;
432 if (elevator_queue.status->has_tote) {
433 LOG(INFO, "Got the tote!\n");
434 break;
435 }
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800436 if (monotonic_clock::now() > chrono::seconds(15) + start_time) {
Austin Schuhaeb1f492015-09-27 19:29:45 +0000437 LOG(INFO, "Out of time\n");
438 break;
439 }
440 }
441
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800442 monotonic_clock::time_point end_time = monotonic_clock::now();
Austin Schuhaeb1f492015-09-27 19:29:45 +0000443 LOG(INFO, "Ended auto with %f to spare\n",
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800444 chrono::duration_cast<chrono::duration<double>>(chrono::seconds(15) -
445 (end_time - start_time))
446 .count());
Austin Schuhaeb1f492015-09-27 19:29:45 +0000447 if (!intake_queue.goal.MakeWithBuilder().movement(0.0).claw_closed(true)
448 .Send()) {
449 LOG(ERROR, "Sending intake goal failed.\n");
450 }
451}
452
Comran Morshed0d6cf9b2015-06-17 19:29:57 +0000453void HandleAuto() {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800454 monotonic_clock::time_point start_time = monotonic_clock::now();
455 LOG(INFO, "Starting auto mode at %f\n",
456 chrono::duration_cast<chrono::duration<double>>(
457 start_time.time_since_epoch())
458 .count());
Comran Morshed0d6cf9b2015-06-17 19:29:57 +0000459
Comran Morshed34f891d2015-09-15 22:04:43 +0000460 // TODO(comran): Add various options for different autos down below.
Austin Schuhaeb1f492015-09-27 19:29:45 +0000461 //CanGrabberAuto();
462 TripleCanAuto();
Comran Morshed0d6cf9b2015-06-17 19:29:57 +0000463}
464
465} // namespace autonomous
Austin Schuh6d1ee0c2015-11-21 14:36:04 -0800466} // namespace y2015_bot3