blob: 097196de61cfbe316640bb34c6e9be8c4d783f9c [file] [log] [blame]
Philipp Schrader4bd29b12017-02-22 04:42:27 +00001#include "frc971/autonomous/base_autonomous_actor.h"
2
3#include <inttypes.h>
4
5#include <chrono>
6#include <cmath>
7
John Park33858a32018-09-28 23:05:48 -07008#include "aos/util/phased_loop.h"
9#include "aos/logging/logging.h"
Philipp Schrader4bd29b12017-02-22 04:42:27 +000010
11#include "frc971/control_loops/drivetrain/drivetrain.q.h"
James Kuszmaul8bb5df22019-05-01 21:40:08 -050012#include "frc971/control_loops/drivetrain/localizer.q.h"
13#include "y2019/control_loops/drivetrain/target_selector.q.h"
Philipp Schrader4bd29b12017-02-22 04:42:27 +000014
Philipp Schrader4bd29b12017-02-22 04:42:27 +000015using ::frc971::control_loops::drivetrain_queue;
16using ::aos::monotonic_clock;
James Kuszmaul8bb5df22019-05-01 21:40:08 -050017using ::y2019::control_loops::drivetrain::target_selector_hint;
Philipp Schrader4bd29b12017-02-22 04:42:27 +000018namespace chrono = ::std::chrono;
19namespace this_thread = ::std::this_thread;
20
Brian Silvermanf83678c2017-03-11 14:02:26 -080021namespace frc971 {
22namespace autonomous {
Philipp Schrader4bd29b12017-02-22 04:42:27 +000023
24BaseAutonomousActor::BaseAutonomousActor(
25 AutonomousActionQueueGroup *s,
Austin Schuhbcce26a2018-03-26 23:41:24 -070026 const control_loops::drivetrain::DrivetrainConfig<double> &dt_config)
Philipp Schrader4bd29b12017-02-22 04:42:27 +000027 : aos::common::actions::ActorBase<AutonomousActionQueueGroup>(s),
28 dt_config_(dt_config),
29 initial_drivetrain_({0.0, 0.0}) {}
30
31void BaseAutonomousActor::ResetDrivetrain() {
32 LOG(INFO, "resetting the drivetrain\n");
Austin Schuh0aae9242018-03-14 19:49:44 -070033 max_drivetrain_voltage_ = 12.0;
James Kuszmaulc73bb222019-04-07 12:15:35 -070034 goal_spline_handle_ = 0;
Philipp Schrader4bd29b12017-02-22 04:42:27 +000035 drivetrain_queue.goal.MakeWithBuilder()
Austin Schuh78379ea2019-01-04 20:39:45 -080036 .controller_type(0)
Philipp Schrader4bd29b12017-02-22 04:42:27 +000037 .highgear(true)
Austin Schuh2b1fce02018-03-02 20:05:20 -080038 .wheel(0.0)
Philipp Schrader4bd29b12017-02-22 04:42:27 +000039 .throttle(0.0)
40 .left_goal(initial_drivetrain_.left)
Philipp Schrader4bd29b12017-02-22 04:42:27 +000041 .right_goal(initial_drivetrain_.right)
Austin Schuh0aae9242018-03-14 19:49:44 -070042 .max_ss_voltage(max_drivetrain_voltage_)
Philipp Schrader4bd29b12017-02-22 04:42:27 +000043 .Send();
44}
45
46void BaseAutonomousActor::InitializeEncoders() {
47 drivetrain_queue.status.FetchAnother();
48 initial_drivetrain_.left = drivetrain_queue.status->estimated_left_position;
49 initial_drivetrain_.right = drivetrain_queue.status->estimated_right_position;
50}
51
52void BaseAutonomousActor::StartDrive(double distance, double angle,
53 ProfileParameters linear,
54 ProfileParameters angular) {
55 LOG(INFO, "Driving distance %f, angle %f\n", distance, angle);
56 {
57 const double dangle = angle * dt_config_.robot_radius;
58 initial_drivetrain_.left += distance - dangle;
59 initial_drivetrain_.right += distance + dangle;
60 }
61
62 auto drivetrain_message = drivetrain_queue.goal.MakeMessage();
Austin Schuh78379ea2019-01-04 20:39:45 -080063 drivetrain_message->controller_type = 1;
Philipp Schrader4bd29b12017-02-22 04:42:27 +000064 drivetrain_message->highgear = true;
Austin Schuh2b1fce02018-03-02 20:05:20 -080065 drivetrain_message->wheel = 0.0;
Philipp Schrader4bd29b12017-02-22 04:42:27 +000066 drivetrain_message->throttle = 0.0;
67 drivetrain_message->left_goal = initial_drivetrain_.left;
Philipp Schrader4bd29b12017-02-22 04:42:27 +000068 drivetrain_message->right_goal = initial_drivetrain_.right;
Austin Schuh0aae9242018-03-14 19:49:44 -070069 drivetrain_message->max_ss_voltage = max_drivetrain_voltage_;
Philipp Schrader4bd29b12017-02-22 04:42:27 +000070 drivetrain_message->linear = linear;
71 drivetrain_message->angular = angular;
72
Austin Schuh6bcc2302019-03-23 22:28:06 -070073 LOG_STRUCT(DEBUG, "dtg", *drivetrain_message);
Philipp Schrader4bd29b12017-02-22 04:42:27 +000074
75 drivetrain_message.Send();
76}
77
78void BaseAutonomousActor::WaitUntilDoneOrCanceled(
79 ::std::unique_ptr<aos::common::actions::Action> action) {
80 if (!action) {
81 LOG(ERROR, "No action, not waiting\n");
82 return;
83 }
84
85 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
86 ::std::chrono::milliseconds(5) / 2);
87 while (true) {
88 // Poll the running bit and see if we should cancel.
89 phased_loop.SleepUntilNext();
90 if (!action->Running() || ShouldCancel()) {
91 return;
92 }
93 }
94}
95
96bool BaseAutonomousActor::WaitForDriveDone() {
97 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
98 ::std::chrono::milliseconds(5) / 2);
99
100 while (true) {
101 if (ShouldCancel()) {
102 return false;
103 }
104 phased_loop.SleepUntilNext();
105 drivetrain_queue.status.FetchLatest();
106 if (IsDriveDone()) {
107 return true;
108 }
109 }
110}
111
112bool BaseAutonomousActor::IsDriveDone() {
Brian Silvermanf83678c2017-03-11 14:02:26 -0800113 static constexpr double kPositionTolerance = 0.02;
114 static constexpr double kVelocityTolerance = 0.10;
115 static constexpr double kProfileTolerance = 0.001;
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000116
117 if (drivetrain_queue.status.get()) {
118 if (::std::abs(drivetrain_queue.status->profiled_left_position_goal -
119 initial_drivetrain_.left) < kProfileTolerance &&
120 ::std::abs(drivetrain_queue.status->profiled_right_position_goal -
121 initial_drivetrain_.right) < kProfileTolerance &&
122 ::std::abs(drivetrain_queue.status->estimated_left_position -
123 initial_drivetrain_.left) < kPositionTolerance &&
124 ::std::abs(drivetrain_queue.status->estimated_right_position -
125 initial_drivetrain_.right) < kPositionTolerance &&
126 ::std::abs(drivetrain_queue.status->estimated_left_velocity) <
127 kVelocityTolerance &&
128 ::std::abs(drivetrain_queue.status->estimated_right_velocity) <
129 kVelocityTolerance) {
130 LOG(INFO, "Finished drive\n");
131 return true;
132 }
133 }
134 return false;
135}
136
137bool BaseAutonomousActor::WaitForAboveAngle(double angle) {
138 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
139 ::std::chrono::milliseconds(5) / 2);
140 while (true) {
141 if (ShouldCancel()) {
142 return false;
143 }
144 phased_loop.SleepUntilNext();
145 drivetrain_queue.status.FetchLatest();
146 if (IsDriveDone()) {
147 return true;
148 }
149 if (drivetrain_queue.status.get()) {
150 if (drivetrain_queue.status->ground_angle > angle) {
151 return true;
152 }
153 }
154 }
155}
156
157bool BaseAutonomousActor::WaitForBelowAngle(double angle) {
158 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
159 ::std::chrono::milliseconds(5) / 2);
160 while (true) {
161 if (ShouldCancel()) {
162 return false;
163 }
164 phased_loop.SleepUntilNext();
165 drivetrain_queue.status.FetchLatest();
166 if (IsDriveDone()) {
167 return true;
168 }
169 if (drivetrain_queue.status.get()) {
170 if (drivetrain_queue.status->ground_angle < angle) {
171 return true;
172 }
173 }
174 }
175}
176
177bool BaseAutonomousActor::WaitForMaxBy(double angle) {
178 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
179 ::std::chrono::milliseconds(5) / 2);
180 double max_angle = -M_PI;
181 while (true) {
182 if (ShouldCancel()) {
183 return false;
184 }
185 phased_loop.SleepUntilNext();
186 drivetrain_queue.status.FetchLatest();
187 if (IsDriveDone()) {
188 return true;
189 }
190 if (drivetrain_queue.status.get()) {
191 if (drivetrain_queue.status->ground_angle > max_angle) {
192 max_angle = drivetrain_queue.status->ground_angle;
193 }
194 if (drivetrain_queue.status->ground_angle < max_angle - angle) {
195 return true;
196 }
197 }
198 }
199}
200
201bool BaseAutonomousActor::WaitForDriveNear(double distance, double angle) {
202 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
203 ::std::chrono::milliseconds(5) / 2);
204 constexpr double kPositionTolerance = 0.02;
205 constexpr double kProfileTolerance = 0.001;
206
Austin Schuhe6af9992018-07-08 15:59:14 -0700207 bool drive_has_been_close = false;
208 bool turn_has_been_close = false;
209 bool printed_first = false;
210
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000211 while (true) {
212 if (ShouldCancel()) {
213 return false;
214 }
215 phased_loop.SleepUntilNext();
216 drivetrain_queue.status.FetchLatest();
217 if (drivetrain_queue.status.get()) {
218 const double left_profile_error =
219 (initial_drivetrain_.left -
220 drivetrain_queue.status->profiled_left_position_goal);
221 const double right_profile_error =
222 (initial_drivetrain_.right -
223 drivetrain_queue.status->profiled_right_position_goal);
224
225 const double left_error =
226 (initial_drivetrain_.left -
227 drivetrain_queue.status->estimated_left_position);
228 const double right_error =
229 (initial_drivetrain_.right -
230 drivetrain_queue.status->estimated_right_position);
231
232 const double profile_distance_to_go =
233 (left_profile_error + right_profile_error) / 2.0;
234 const double profile_angle_to_go =
235 (right_profile_error - left_profile_error) /
236 (dt_config_.robot_radius * 2.0);
237
238 const double distance_to_go = (left_error + right_error) / 2.0;
239 const double angle_to_go =
240 (right_error - left_error) / (dt_config_.robot_radius * 2.0);
241
Austin Schuhe6af9992018-07-08 15:59:14 -0700242 const bool drive_close =
243 ::std::abs(profile_distance_to_go) < distance + kProfileTolerance &&
244 ::std::abs(distance_to_go) < distance + kPositionTolerance;
245 const bool turn_close =
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000246 ::std::abs(profile_angle_to_go) < angle + kProfileTolerance &&
Austin Schuhe6af9992018-07-08 15:59:14 -0700247 ::std::abs(angle_to_go) < angle + kPositionTolerance;
248
249 drive_has_been_close |= drive_close;
250 turn_has_been_close |= turn_close;
251 if (drive_has_been_close && !turn_has_been_close && !printed_first) {
252 LOG(INFO, "Drive finished first\n");
253 printed_first = true;
254 } else if (!drive_has_been_close && turn_has_been_close &&
255 !printed_first) {
256 LOG(INFO, "Turn finished first\n");
257 printed_first = true;
258 }
259
260 if (drive_close && turn_close) {
261 LOG(INFO, "Closer than %f < %f distance, %f < %f angle\n",
262 distance_to_go, distance, angle_to_go, angle);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000263 return true;
264 }
265 }
266 }
267}
268
Austin Schuh0aae9242018-03-14 19:49:44 -0700269bool BaseAutonomousActor::WaitForDriveProfileNear(double tolerance) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000270 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
271 ::std::chrono::milliseconds(5) / 2);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000272 while (true) {
273 if (ShouldCancel()) {
274 return false;
275 }
276 phased_loop.SleepUntilNext();
277 drivetrain_queue.status.FetchLatest();
Austin Schuh0aae9242018-03-14 19:49:44 -0700278
279 const Eigen::Matrix<double, 7, 1> current_error =
280 (Eigen::Matrix<double, 7, 1>()
281 << initial_drivetrain_.left -
282 drivetrain_queue.status->profiled_left_position_goal,
283 0.0, initial_drivetrain_.right -
284 drivetrain_queue.status->profiled_right_position_goal,
285 0.0, 0.0, 0.0, 0.0)
286 .finished();
287 const Eigen::Matrix<double, 2, 1> linear_error =
288 dt_config_.LeftRightToLinear(current_error);
289
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000290 if (drivetrain_queue.status.get()) {
Austin Schuh0aae9242018-03-14 19:49:44 -0700291 if (::std::abs(linear_error(0)) < tolerance) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000292 LOG(INFO, "Finished drive\n");
293 return true;
294 }
295 }
296 }
297}
298
Austin Schuh0aae9242018-03-14 19:49:44 -0700299bool BaseAutonomousActor::WaitForDriveProfileDone() {
300 constexpr double kProfileTolerance = 0.001;
301 return WaitForDriveProfileNear(kProfileTolerance);
302}
303
304bool BaseAutonomousActor::WaitForTurnProfileNear(double tolerance) {
Austin Schuh546a0382017-04-16 19:10:18 -0700305 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
306 ::std::chrono::milliseconds(5) / 2);
Austin Schuh546a0382017-04-16 19:10:18 -0700307 while (true) {
308 if (ShouldCancel()) {
309 return false;
310 }
311 phased_loop.SleepUntilNext();
312 drivetrain_queue.status.FetchLatest();
Austin Schuh0aae9242018-03-14 19:49:44 -0700313
314 const Eigen::Matrix<double, 7, 1> current_error =
315 (Eigen::Matrix<double, 7, 1>()
316 << initial_drivetrain_.left -
317 drivetrain_queue.status->profiled_left_position_goal,
318 0.0, initial_drivetrain_.right -
319 drivetrain_queue.status->profiled_right_position_goal,
320 0.0, 0.0, 0.0, 0.0)
321 .finished();
322 const Eigen::Matrix<double, 2, 1> angular_error =
323 dt_config_.LeftRightToAngular(current_error);
324
Austin Schuh546a0382017-04-16 19:10:18 -0700325 if (drivetrain_queue.status.get()) {
Austin Schuh0aae9242018-03-14 19:49:44 -0700326 if (::std::abs(angular_error(0)) < tolerance) {
327 LOG(INFO, "Finished turn\n");
Austin Schuh546a0382017-04-16 19:10:18 -0700328 return true;
329 }
330 }
331 }
332}
333
Austin Schuh0aae9242018-03-14 19:49:44 -0700334bool BaseAutonomousActor::WaitForTurnProfileDone() {
335 constexpr double kProfileTolerance = 0.001;
336 return WaitForTurnProfileNear(kProfileTolerance);
337}
338
Austin Schuh546a0382017-04-16 19:10:18 -0700339double BaseAutonomousActor::DriveDistanceLeft() {
340 using ::frc971::control_loops::drivetrain_queue;
341 drivetrain_queue.status.FetchLatest();
342 if (drivetrain_queue.status.get()) {
343 const double left_error =
344 (initial_drivetrain_.left -
345 drivetrain_queue.status->estimated_left_position);
346 const double right_error =
347 (initial_drivetrain_.right -
348 drivetrain_queue.status->estimated_right_position);
349
350 return (left_error + right_error) / 2.0;
351 } else {
352 return 0;
353 }
354}
355
James Kuszmaul838040b2019-04-13 15:51:02 -0700356bool BaseAutonomousActor::SplineHandle::SplineDistanceRemaining(
357 double distance) {
358 drivetrain_queue.status.FetchLatest();
359 if (drivetrain_queue.status.get()) {
360 return drivetrain_queue.status->trajectory_logging.is_executing &&
361 drivetrain_queue.status->trajectory_logging.distance_remaining <
362 distance;
363 }
364 return false;
365}
366bool BaseAutonomousActor::SplineHandle::WaitForSplineDistanceRemaining(
367 double distance) {
368 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
369 ::std::chrono::milliseconds(5) / 2);
370 while (true) {
371 if (base_autonomous_actor_->ShouldCancel()) {
372 return false;
373 }
374 phased_loop.SleepUntilNext();
375 if (SplineDistanceRemaining(distance)) {
376 return true;
377 }
378 }
379}
380
James Kuszmaul8bb5df22019-05-01 21:40:08 -0500381void BaseAutonomousActor::LineFollowAtVelocity(double velocity, int hint) {
James Kuszmaul838040b2019-04-13 15:51:02 -0700382 auto drivetrain_message = drivetrain_queue.goal.MakeMessage();
383 drivetrain_message->controller_type = 3;
384 // TODO(james): Currently the 4.0 is copied from the
385 // line_follow_drivetrain.cc, but it is somewhat year-specific, so we should
386 // factor it out in some way.
387 drivetrain_message->throttle = velocity / 4.0;
388 drivetrain_message.Send();
James Kuszmaul8bb5df22019-05-01 21:40:08 -0500389 auto target_hint = target_selector_hint.MakeMessage();
390 target_hint->suggested_target = hint;
391 target_hint.Send();
James Kuszmaul838040b2019-04-13 15:51:02 -0700392}
393
Austin Schuh6bcc2302019-03-23 22:28:06 -0700394BaseAutonomousActor::SplineHandle BaseAutonomousActor::PlanSpline(
James Kuszmaulc73bb222019-04-07 12:15:35 -0700395 const ::frc971::MultiSpline &spline, SplineDirection direction) {
Austin Schuh6bcc2302019-03-23 22:28:06 -0700396 LOG(INFO, "Planning spline\n");
397
398 int32_t spline_handle = (++spline_handle_) | ((getpid() & 0xFFFF) << 15);
399
400 drivetrain_queue.goal.FetchLatest();
401
402 auto drivetrain_message = drivetrain_queue.goal.MakeMessage();
James Kuszmaulc864bcf2019-05-01 20:17:34 -0700403
404 int controller_type = 2;
405 if (drivetrain_queue.goal.get()) {
406 controller_type = drivetrain_queue.goal->controller_type;
407 drivetrain_message->throttle = drivetrain_queue.goal->throttle;
408 }
409 drivetrain_message->controller_type = controller_type;
Austin Schuh6bcc2302019-03-23 22:28:06 -0700410
411 drivetrain_message->spline = spline;
412 drivetrain_message->spline.spline_idx = spline_handle;
413 drivetrain_message->spline_handle = goal_spline_handle_;
James Kuszmaul29e417d2019-04-13 10:03:35 -0700414 drivetrain_message->spline.drive_spline_backwards =
James Kuszmaulc73bb222019-04-07 12:15:35 -0700415 direction == SplineDirection::kBackward;
Austin Schuh6bcc2302019-03-23 22:28:06 -0700416
417 LOG_STRUCT(DEBUG, "dtg", *drivetrain_message);
418
419 drivetrain_message.Send();
420
421 return BaseAutonomousActor::SplineHandle(spline_handle, this);
422}
423
424bool BaseAutonomousActor::SplineHandle::IsPlanned() {
425 drivetrain_queue.status.FetchLatest();
426 LOG_STRUCT(INFO, "dts", *drivetrain_queue.status.get());
427 if (drivetrain_queue.status.get() &&
428 ((drivetrain_queue.status->trajectory_logging.planning_spline_idx ==
429 spline_handle_ &&
430 drivetrain_queue.status->trajectory_logging.planning_state == 3) ||
431 drivetrain_queue.status->trajectory_logging.current_spline_idx ==
432 spline_handle_)) {
433 return true;
434 }
435 return false;
436}
437
438bool BaseAutonomousActor::SplineHandle::WaitForPlan() {
439 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
440 ::std::chrono::milliseconds(5) / 2);
441 while (true) {
442 if (base_autonomous_actor_->ShouldCancel()) {
443 return false;
444 }
445 phased_loop.SleepUntilNext();
446 if (IsPlanned()) {
447 return true;
448 }
449 }
450}
451
452void BaseAutonomousActor::SplineHandle::Start() {
453 auto drivetrain_message = drivetrain_queue.goal.MakeMessage();
454 drivetrain_message->controller_type = 2;
455
456 LOG(INFO, "Starting spline\n");
457
458 drivetrain_message->spline_handle = spline_handle_;
459 base_autonomous_actor_->goal_spline_handle_ = spline_handle_;
460
461 LOG_STRUCT(DEBUG, "dtg", *drivetrain_message);
462
463 drivetrain_message.Send();
464}
465
466bool BaseAutonomousActor::SplineHandle::IsDone() {
467 drivetrain_queue.status.FetchLatest();
468 LOG_STRUCT(INFO, "dts", *drivetrain_queue.status.get());
469
James Kuszmaulc73bb222019-04-07 12:15:35 -0700470 // We check that the spline we are waiting on is neither currently planning
James Kuszmaul29e417d2019-04-13 10:03:35 -0700471 // nor executing (we check is_executed because it is possible to receive
472 // status messages with is_executing false before the execution has started).
473 // We check for planning so that the user can go straight from starting the
474 // planner to executing without a WaitForPlan in between.
Austin Schuh6bcc2302019-03-23 22:28:06 -0700475 if (drivetrain_queue.status.get() &&
James Kuszmaul29e417d2019-04-13 10:03:35 -0700476 ((!drivetrain_queue.status->trajectory_logging.is_executed &&
477 drivetrain_queue.status->trajectory_logging.current_spline_idx ==
478 spline_handle_) ||
James Kuszmaulc73bb222019-04-07 12:15:35 -0700479 drivetrain_queue.status->trajectory_logging.planning_spline_idx ==
480 spline_handle_)) {
Austin Schuh6bcc2302019-03-23 22:28:06 -0700481 return false;
482 }
483 return true;
484}
485
486bool BaseAutonomousActor::SplineHandle::WaitForDone() {
487 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
488 ::std::chrono::milliseconds(5) / 2);
489 while (true) {
490 if (base_autonomous_actor_->ShouldCancel()) {
491 return false;
492 }
493 phased_loop.SleepUntilNext();
494 if (IsDone()) {
495 return true;
496 }
497 }
498}
499
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000500::std::unique_ptr<AutonomousAction> MakeAutonomousAction(
501 const AutonomousActionParams &params) {
502 return ::std::unique_ptr<AutonomousAction>(
503 new AutonomousAction(&autonomous_action, params));
504}
505
506} // namespace autonomous
507} // namespace frc971