blob: e76d8aace398a2c08a402ed3b9b4e84deaa268d9 [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
11#include "bot3/autonomous/auto.q.h"
Austin Schuhaeb1f492015-09-27 19:29:45 +000012#include "bot3/actors/drivetrain_actor.h"
Comran Morshed0d6cf9b2015-06-17 19:29:57 +000013#include "bot3/control_loops/drivetrain/drivetrain.q.h"
Comran Morshed34f891d2015-09-15 22:04:43 +000014#include "bot3/control_loops/drivetrain/drivetrain.h"
Austin Schuhbd01a582015-09-21 00:05:31 +000015#include "bot3/control_loops/elevator/elevator.q.h"
16#include "bot3/control_loops/intake/intake.q.h"
Comran Morshed0d6cf9b2015-06-17 19:29:57 +000017
18using ::aos::time::Time;
19using ::bot3::control_loops::drivetrain_queue;
Austin Schuhbd01a582015-09-21 00:05:31 +000020using ::bot3::control_loops::intake_queue;
21using ::bot3::control_loops::elevator_queue;
Austin Schuhaeb1f492015-09-27 19:29:45 +000022using ::bot3::control_loops::kDrivetrainTurnWidth;
Comran Morshed0d6cf9b2015-06-17 19:29:57 +000023
24namespace bot3 {
25namespace autonomous {
26
27struct ProfileParams {
28 double velocity;
29 double acceleration;
30};
31
32namespace time = ::aos::time;
Austin Schuhaeb1f492015-09-27 19:29:45 +000033namespace actors = ::frc971::actors;
34
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() {
46 ::bot3::autonomous::autonomous.FetchLatest();
47 bool ans = !::bot3::autonomous::autonomous->run_auto;
48 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");
56 control_loops::drivetrain_queue.goal.MakeWithBuilder()
57 .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() {
68 control_loops::drivetrain_queue.status.FetchAnother();
69 left_initial_position =
70 control_loops::drivetrain_queue.status->filtered_left_position;
71 right_initial_position =
72 control_loops::drivetrain_queue.status->filtered_right_position;
73}
74
Austin Schuhaeb1f492015-09-27 19:29:45 +000075::std::unique_ptr< ::frc971::actors::DrivetrainAction> SetDriveGoal(
76 double distance, const ProfileParams drive_params, double theta,
77 const ProfileParams &turn_params) {
78 LOG(INFO, "Driving to %f\n", distance);
79
80 actors::DrivetrainActionParams params;
81 params.left_initial_position = left_initial_position;
82 params.right_initial_position = right_initial_position;
83 params.y_offset = distance;
84 params.theta_offset = theta;
85 params.maximum_turn_acceleration = turn_params.acceleration;
86 params.maximum_turn_velocity = turn_params.velocity;
87 params.maximum_velocity = drive_params.velocity;
88 params.maximum_acceleration = drive_params.acceleration;
89 auto drivetrain_action = actors::MakeDrivetrainAction(params);
90
91 drivetrain_action->Start();
92 left_initial_position += distance - theta * kDrivetrainTurnWidth / 2.0;
93 right_initial_position += distance + theta * kDrivetrainTurnWidth / 2.0;
94 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 }
102 while (true) {
103 // Poll the running bit and auto done bits.
104 ::aos::time::PhasedLoopXMS(5, 2500);
105 if (!action->Running() || ShouldExitAuto()) {
106 return;
107 }
108 }
109}
110
111void WaitUntilNear(double distance) {
112 while (true) {
113 if (ShouldExitAuto()) return;
114 control_loops::drivetrain_queue.status.FetchAnother();
115 double left_error = ::std::abs(
116 left_initial_position -
117 control_loops::drivetrain_queue.status->filtered_left_position);
118 double right_error = ::std::abs(
119 right_initial_position -
120 control_loops::drivetrain_queue.status->filtered_right_position);
121 const double kPositionThreshold = 0.05 + distance;
122 if (right_error < kPositionThreshold && left_error < kPositionThreshold) {
123 LOG(INFO, "At the goal\n");
124 return;
125 }
126 }
127}
128
Comran Morshed34f891d2015-09-15 22:04:43 +0000129void GrabberForTime(double voltage, double wait_time) {
130 ::aos::time::Time now = ::aos::time::Time::Now();
131 ::aos::time::Time end_time = now + time::Time::InSeconds(wait_time);
132 LOG(INFO, "Starting to grab at %f for %f seconds\n", voltage, wait_time);
133
134 while (true) {
135 autonomous::can_grabber_control.MakeWithBuilder()
Austin Schuhbd01a582015-09-21 00:05:31 +0000136 .can_grabber_voltage(voltage).can_grabbers(false).Send();
Comran Morshed34f891d2015-09-15 22:04:43 +0000137
138 // Poll the running bit and auto done bits.
139 if (ShouldExitAuto()) {
140 return;
141 }
142 if (::aos::time::Time::Now() > end_time) {
143 LOG(INFO, "Done grabbing\n");
144 return;
145 }
146 ::aos::time::PhasedLoopXMS(5, 2500);
147 }
148}
149
150// Auto methods.
151void CanGrabberAuto() {
152 ResetDrivetrain();
153
154 // Launch can grabbers.
Austin Schuhbd01a582015-09-21 00:05:31 +0000155 //GrabberForTime(12.0, 0.26);
156 GrabberForTime(6.0, 0.40);
Comran Morshed34f891d2015-09-15 22:04:43 +0000157 if (ShouldExitAuto()) return;
158 InitializeEncoders();
159 ResetDrivetrain();
160 if (ShouldExitAuto()) return;
Austin Schuhbd01a582015-09-21 00:05:31 +0000161 // Send our intake goals.
162 if (!intake_queue.goal.MakeWithBuilder().movement(0.0).claw_closed(true)
163 .Send()) {
164 LOG(ERROR, "Sending intake goal failed.\n");
165 }
166 {
167 auto new_elevator_goal = elevator_queue.goal.MakeMessage();
168 new_elevator_goal->max_velocity = 0.0;
169 new_elevator_goal->max_acceleration = 0.0;
170 new_elevator_goal->height = 0.030;
171 new_elevator_goal->velocity = 0.0;
172 new_elevator_goal->passive_support = true;
173 new_elevator_goal->can_support = false;
174
175 if (new_elevator_goal.Send()) {
176 LOG(DEBUG, "sending goals: elevator: %f\n", 0.03);
177 } else {
178 LOG(ERROR, "Sending elevator goal failed.\n");
179 }
180 }
181
182 const double kMoveBackDistance = 1.75;
183 //const double kMoveBackDistance = 0.0;
Comran Morshed34f891d2015-09-15 22:04:43 +0000184
185 // Drive backwards, and pulse the can grabbers again to tip the cans.
186 control_loops::drivetrain_queue.goal.MakeWithBuilder()
187 .control_loop_driving(true)
188 .steering(0.0)
189 .throttle(0.0)
Austin Schuhbd01a582015-09-21 00:05:31 +0000190 .left_goal(left_initial_position + kMoveBackDistance)
Comran Morshed34f891d2015-09-15 22:04:43 +0000191 .left_velocity_goal(0)
Austin Schuhbd01a582015-09-21 00:05:31 +0000192 .right_goal(right_initial_position + kMoveBackDistance)
Comran Morshed34f891d2015-09-15 22:04:43 +0000193 .right_velocity_goal(0)
194 .Send();
195 GrabberForTime(12.0, 0.02);
196 if (ShouldExitAuto()) return;
197
198 // We shouldn't need as much power at this point, so lower the can grabber
199 // voltages to avoid damaging the motors due to stalling.
200 GrabberForTime(4.0, 0.75);
201 if (ShouldExitAuto()) return;
202 GrabberForTime(-3.0, 0.25);
203 if (ShouldExitAuto()) return;
204 GrabberForTime(-12.0, 1.0);
205 if (ShouldExitAuto()) return;
206 GrabberForTime(-3.0, 12.0);
207}
208
Austin Schuhaeb1f492015-09-27 19:29:45 +0000209const ProfileParams kElevatorProfile = {1.0, 5.0};
210
211static double elevator_goal_height = 0.0;
212
213void SetElevatorHeight(double height, const ProfileParams params,
214 bool can_open = false, bool support_open = true) {
215 // Send our elevator goals, with limits set in the profile params.
216 auto new_elevator_goal = elevator_queue.goal.MakeMessage();
217 elevator_goal_height = height;
218 new_elevator_goal->max_velocity = params.velocity;
219 new_elevator_goal->max_acceleration = params.acceleration;
220 new_elevator_goal->height = elevator_goal_height;
221 new_elevator_goal->velocity = 0.0;
222 new_elevator_goal->passive_support = support_open;
223 new_elevator_goal->can_support = can_open;
224
225 if (new_elevator_goal.Send()) {
226 LOG(DEBUG, "sending goals: elevator: %f\n", elevator_goal_height);
227 } else {
228 LOG(ERROR, "Sending elevator goal failed.\n");
229 }
230}
231
232void WaitForElevator() {
233 while (true) {
234 if (ShouldExitAuto()) return;
235 control_loops::elevator_queue.status.FetchAnother();
236
237 constexpr double kProfileError = 1e-5;
238 constexpr double kEpsilon = 0.03;
239
240 if (::std::abs(control_loops::elevator_queue.status->goal_height -
241 elevator_goal_height) <
242 kProfileError &&
243 ::std::abs(control_loops::elevator_queue.status->goal_velocity) <
244 kProfileError) {
245 LOG(INFO, "Profile done.\n");
246 if (::std::abs(control_loops::elevator_queue.status->height -
247 elevator_goal_height) <
248 kEpsilon) {
249 LOG(INFO, "Near goal, done.\n");
250 return;
251 }
252 }
253 }
254}
255
256void WaitUntilElevatorBelow(double height) {
257 while (true) {
258 if (ShouldExitAuto()) return;
259 control_loops::elevator_queue.status.FetchAnother();
260
261 if (control_loops::elevator_queue.status->goal_height < height) {
262 LOG(INFO, "Profile below.\n");
263 if (control_loops::elevator_queue.status->height < height) {
264 LOG(INFO, "Elevator below goal, done.\n");
265 return;
266 }
267 }
268 }
269}
270
271void WaitUntilElevatorAbove(double height) {
272 while (true) {
273 if (ShouldExitAuto()) return;
274 control_loops::elevator_queue.status.FetchAnother();
275
276 if (control_loops::elevator_queue.status->goal_height > height) {
277 LOG(INFO, "Profile above.\n");
278 if (control_loops::elevator_queue.status->height > height) {
279 LOG(INFO, "Elevator above goal, done.\n");
280 return;
281 }
282 }
283 }
284}
285
286void LiftTote(double final_height = 0.48) {
287 // Send our intake goals.
288 if (!intake_queue.goal.MakeWithBuilder().movement(10.0).claw_closed(true)
289 .Send()) {
290 LOG(ERROR, "Sending intake goal failed.\n");
291 }
292
293 while (true) {
294 elevator_queue.status.FetchAnother();
295 if (!elevator_queue.status.get()) {
296 LOG(ERROR, "Got no elevator status packet.\n");
297 }
298 if (ShouldExitAuto()) return;
299 if (elevator_queue.status->has_tote) {
300 break;
301 }
302 }
303 if (!intake_queue.goal.MakeWithBuilder().movement(0.0).claw_closed(true)
304 .Send()) {
305 LOG(ERROR, "Sending intake goal failed.\n");
306 }
307 SetElevatorHeight(0.02, kElevatorProfile, false, false);
308 WaitUntilElevatorBelow(0.05);
309 if (ShouldExitAuto()) return;
310
311 SetElevatorHeight(final_height, kElevatorProfile, false, false);
312}
313
314void TripleCanAuto() {
315 ::aos::time::Time start_time = ::aos::time::Time::Now();
316
317 ::std::unique_ptr<::frc971::actors::DrivetrainAction> drive;
318 InitializeEncoders();
319 ResetDrivetrain();
320
321 SetElevatorHeight(0.03, kElevatorProfile, false, true);
322
323
324 LiftTote();
325 if (ShouldExitAuto()) return;
326
327 // The amount to turn out for going around the first can.
328 const double kFirstTurn = 0.5;
329
330 drive = SetDriveGoal(0.0, kFastDrive, kFirstTurn, kStackingFirstTurn);
331
332 WaitUntilDoneOrCanceled(::std::move(drive));
333 if (ShouldExitAuto()) return;
334
335 drive = SetDriveGoal(2.0, kFastDrive, -kFirstTurn * 2.0, kSlowFirstDriveTurn);
336
337 WaitUntilNear(1.5);
338 if (ShouldExitAuto()) return;
339
340 if (!intake_queue.goal.MakeWithBuilder().movement(0.0).claw_closed(false)
341 .Send()) {
342 LOG(ERROR, "Sending intake goal failed.\n");
343 }
344
345 WaitUntilDoneOrCanceled(::std::move(drive));
346 if (ShouldExitAuto()) return;
347
348 drive = SetDriveGoal(0.0, kFastDrive, kFirstTurn, kStackingFirstTurn);
349 LiftTote();
350 if (ShouldExitAuto()) return;
351 WaitUntilDoneOrCanceled(::std::move(drive));
352 if (ShouldExitAuto()) return;
353
354 // The amount to turn out for going around the second can.
355 const double kSecondTurn = 0.35;
356 const double kSecondTurnExtraOnSecond = 0.10;
357
358 drive = SetDriveGoal(0.0, kFastDrive, kSecondTurn, kStackingFirstTurn);
359 WaitUntilDoneOrCanceled(::std::move(drive));
360 if (ShouldExitAuto()) return;
361
362 drive =
363 SetDriveGoal(2.05, kFastDrive, -kSecondTurn * 2.0 - kSecondTurnExtraOnSecond, kSlowSecondDriveTurn);
364 WaitUntilNear(1.5);
365
366 if (!intake_queue.goal.MakeWithBuilder().movement(0.0).claw_closed(false)
367 .Send()) {
368 LOG(ERROR, "Sending intake goal failed.\n");
369 }
370
371 WaitUntilDoneOrCanceled(::std::move(drive));
372 if (ShouldExitAuto()) return;
373
374 drive = SetDriveGoal(0.0, kFastDrive, kSecondTurn + kSecondTurnExtraOnSecond, kStackingFirstTurn);
375
376 LiftTote(0.18);
377
378 WaitUntilDoneOrCanceled(::std::move(drive));
379 if (ShouldExitAuto()) return;
380
381 drive = SetDriveGoal(0.3, kFastDrive, -1.7, kFinalDriveTurn);
382 WaitUntilDoneOrCanceled(::std::move(drive));
383 if (ShouldExitAuto()) return;
384
385 if (!intake_queue.goal.MakeWithBuilder().movement(0.0).claw_closed(false)
386 .Send()) {
387 LOG(ERROR, "Sending intake goal failed.\n");
388 }
389
390 WaitUntilDoneOrCanceled(::std::move(drive));
391 if (ShouldExitAuto()) return;
392 drive = SetDriveGoal(2.95, kLastDrive, 0.0, kFinalDriveTurn);
393
394 WaitUntilDoneOrCanceled(::std::move(drive));
395 if (ShouldExitAuto()) return;
396
397 SetElevatorHeight(0.03, kElevatorProfile, true, true);
398 WaitForElevator();
399 if (ShouldExitAuto()) return;
400
401 drive = SetDriveGoal(-2.25, kFastDrive, 0.0, kFinalDriveTurn);
402 WaitUntilDoneOrCanceled(::std::move(drive));
403 if (ShouldExitAuto()) return;
404
405 drive = SetDriveGoal(0.0, kFastDrive, 1.80, kFinalDriveTurn);
406 WaitUntilDoneOrCanceled(::std::move(drive));
407 if (ShouldExitAuto()) return;
408
409 if (!intake_queue.goal.MakeWithBuilder().movement(10.0).claw_closed(true)
410 .Send()) {
411 LOG(ERROR, "Sending intake goal failed.\n");
412 }
413 SetElevatorHeight(0.03, kElevatorProfile, false, true);
414
415 drive = SetDriveGoal(1.0, kCanPickupDrive, 0.0, kFinalDriveTurn);
416 WaitUntilDoneOrCanceled(::std::move(drive));
417 if (ShouldExitAuto()) return;
418
419 SetElevatorHeight(0.03, kElevatorProfile, true, true);
420
421 while (true) {
422 elevator_queue.status.FetchAnother();
423 if (!elevator_queue.status.get()) {
424 LOG(ERROR, "Got no elevator status packet.\n");
425 }
426 if (ShouldExitAuto()) return;
427 if (elevator_queue.status->has_tote) {
428 LOG(INFO, "Got the tote!\n");
429 break;
430 }
431 if ((::aos::time::Time::Now() - start_time) > time::Time::InSeconds(15.0)) {
432 LOG(INFO, "Out of time\n");
433 break;
434 }
435 }
436
437 ::aos::time::Time end_time = ::aos::time::Time::Now();
438 LOG(INFO, "Ended auto with %f to spare\n",
439 (time::Time::InSeconds(15.0) - (end_time - start_time)).ToSeconds());
440 if (!intake_queue.goal.MakeWithBuilder().movement(0.0).claw_closed(true)
441 .Send()) {
442 LOG(ERROR, "Sending intake goal failed.\n");
443 }
444}
445
Comran Morshed0d6cf9b2015-06-17 19:29:57 +0000446void HandleAuto() {
447 ::aos::time::Time start_time = ::aos::time::Time::Now();
448 LOG(INFO, "Starting auto mode at %f\n", start_time.ToSeconds());
Comran Morshed0d6cf9b2015-06-17 19:29:57 +0000449
Comran Morshed34f891d2015-09-15 22:04:43 +0000450 // TODO(comran): Add various options for different autos down below.
Austin Schuhaeb1f492015-09-27 19:29:45 +0000451 //CanGrabberAuto();
452 TripleCanAuto();
Comran Morshed0d6cf9b2015-06-17 19:29:57 +0000453}
454
455} // namespace autonomous
456} // namespace bot3