blob: ade396e988f8e8bdf12f29213af1de29fc5141e6 [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"
12
Philipp Schrader4bd29b12017-02-22 04:42:27 +000013using ::frc971::control_loops::drivetrain_queue;
14using ::aos::monotonic_clock;
15namespace chrono = ::std::chrono;
16namespace this_thread = ::std::this_thread;
17
Brian Silvermanf83678c2017-03-11 14:02:26 -080018namespace frc971 {
19namespace autonomous {
Philipp Schrader4bd29b12017-02-22 04:42:27 +000020
21BaseAutonomousActor::BaseAutonomousActor(
22 AutonomousActionQueueGroup *s,
Austin Schuhbcce26a2018-03-26 23:41:24 -070023 const control_loops::drivetrain::DrivetrainConfig<double> &dt_config)
Philipp Schrader4bd29b12017-02-22 04:42:27 +000024 : aos::common::actions::ActorBase<AutonomousActionQueueGroup>(s),
25 dt_config_(dt_config),
26 initial_drivetrain_({0.0, 0.0}) {}
27
28void BaseAutonomousActor::ResetDrivetrain() {
29 LOG(INFO, "resetting the drivetrain\n");
Austin Schuh0aae9242018-03-14 19:49:44 -070030 max_drivetrain_voltage_ = 12.0;
Philipp Schrader4bd29b12017-02-22 04:42:27 +000031 drivetrain_queue.goal.MakeWithBuilder()
Austin Schuh78379ea2019-01-04 20:39:45 -080032 .controller_type(0)
Philipp Schrader4bd29b12017-02-22 04:42:27 +000033 .highgear(true)
Austin Schuh2b1fce02018-03-02 20:05:20 -080034 .wheel(0.0)
Philipp Schrader4bd29b12017-02-22 04:42:27 +000035 .throttle(0.0)
36 .left_goal(initial_drivetrain_.left)
Philipp Schrader4bd29b12017-02-22 04:42:27 +000037 .right_goal(initial_drivetrain_.right)
Austin Schuh0aae9242018-03-14 19:49:44 -070038 .max_ss_voltage(max_drivetrain_voltage_)
Philipp Schrader4bd29b12017-02-22 04:42:27 +000039 .Send();
40}
41
42void BaseAutonomousActor::InitializeEncoders() {
43 drivetrain_queue.status.FetchAnother();
44 initial_drivetrain_.left = drivetrain_queue.status->estimated_left_position;
45 initial_drivetrain_.right = drivetrain_queue.status->estimated_right_position;
46}
47
48void BaseAutonomousActor::StartDrive(double distance, double angle,
49 ProfileParameters linear,
50 ProfileParameters angular) {
51 LOG(INFO, "Driving distance %f, angle %f\n", distance, angle);
52 {
53 const double dangle = angle * dt_config_.robot_radius;
54 initial_drivetrain_.left += distance - dangle;
55 initial_drivetrain_.right += distance + dangle;
56 }
57
58 auto drivetrain_message = drivetrain_queue.goal.MakeMessage();
Austin Schuh78379ea2019-01-04 20:39:45 -080059 drivetrain_message->controller_type = 1;
Philipp Schrader4bd29b12017-02-22 04:42:27 +000060 drivetrain_message->highgear = true;
Austin Schuh2b1fce02018-03-02 20:05:20 -080061 drivetrain_message->wheel = 0.0;
Philipp Schrader4bd29b12017-02-22 04:42:27 +000062 drivetrain_message->throttle = 0.0;
63 drivetrain_message->left_goal = initial_drivetrain_.left;
Philipp Schrader4bd29b12017-02-22 04:42:27 +000064 drivetrain_message->right_goal = initial_drivetrain_.right;
Austin Schuh0aae9242018-03-14 19:49:44 -070065 drivetrain_message->max_ss_voltage = max_drivetrain_voltage_;
Philipp Schrader4bd29b12017-02-22 04:42:27 +000066 drivetrain_message->linear = linear;
67 drivetrain_message->angular = angular;
68
Austin Schuh6bcc2302019-03-23 22:28:06 -070069 LOG_STRUCT(DEBUG, "dtg", *drivetrain_message);
Philipp Schrader4bd29b12017-02-22 04:42:27 +000070
71 drivetrain_message.Send();
72}
73
74void BaseAutonomousActor::WaitUntilDoneOrCanceled(
75 ::std::unique_ptr<aos::common::actions::Action> action) {
76 if (!action) {
77 LOG(ERROR, "No action, not waiting\n");
78 return;
79 }
80
81 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
82 ::std::chrono::milliseconds(5) / 2);
83 while (true) {
84 // Poll the running bit and see if we should cancel.
85 phased_loop.SleepUntilNext();
86 if (!action->Running() || ShouldCancel()) {
87 return;
88 }
89 }
90}
91
92bool BaseAutonomousActor::WaitForDriveDone() {
93 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
94 ::std::chrono::milliseconds(5) / 2);
95
96 while (true) {
97 if (ShouldCancel()) {
98 return false;
99 }
100 phased_loop.SleepUntilNext();
101 drivetrain_queue.status.FetchLatest();
102 if (IsDriveDone()) {
103 return true;
104 }
105 }
106}
107
108bool BaseAutonomousActor::IsDriveDone() {
Brian Silvermanf83678c2017-03-11 14:02:26 -0800109 static constexpr double kPositionTolerance = 0.02;
110 static constexpr double kVelocityTolerance = 0.10;
111 static constexpr double kProfileTolerance = 0.001;
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000112
113 if (drivetrain_queue.status.get()) {
114 if (::std::abs(drivetrain_queue.status->profiled_left_position_goal -
115 initial_drivetrain_.left) < kProfileTolerance &&
116 ::std::abs(drivetrain_queue.status->profiled_right_position_goal -
117 initial_drivetrain_.right) < kProfileTolerance &&
118 ::std::abs(drivetrain_queue.status->estimated_left_position -
119 initial_drivetrain_.left) < kPositionTolerance &&
120 ::std::abs(drivetrain_queue.status->estimated_right_position -
121 initial_drivetrain_.right) < kPositionTolerance &&
122 ::std::abs(drivetrain_queue.status->estimated_left_velocity) <
123 kVelocityTolerance &&
124 ::std::abs(drivetrain_queue.status->estimated_right_velocity) <
125 kVelocityTolerance) {
126 LOG(INFO, "Finished drive\n");
127 return true;
128 }
129 }
130 return false;
131}
132
133bool BaseAutonomousActor::WaitForAboveAngle(double angle) {
134 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
135 ::std::chrono::milliseconds(5) / 2);
136 while (true) {
137 if (ShouldCancel()) {
138 return false;
139 }
140 phased_loop.SleepUntilNext();
141 drivetrain_queue.status.FetchLatest();
142 if (IsDriveDone()) {
143 return true;
144 }
145 if (drivetrain_queue.status.get()) {
146 if (drivetrain_queue.status->ground_angle > angle) {
147 return true;
148 }
149 }
150 }
151}
152
153bool BaseAutonomousActor::WaitForBelowAngle(double angle) {
154 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
155 ::std::chrono::milliseconds(5) / 2);
156 while (true) {
157 if (ShouldCancel()) {
158 return false;
159 }
160 phased_loop.SleepUntilNext();
161 drivetrain_queue.status.FetchLatest();
162 if (IsDriveDone()) {
163 return true;
164 }
165 if (drivetrain_queue.status.get()) {
166 if (drivetrain_queue.status->ground_angle < angle) {
167 return true;
168 }
169 }
170 }
171}
172
173bool BaseAutonomousActor::WaitForMaxBy(double angle) {
174 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
175 ::std::chrono::milliseconds(5) / 2);
176 double max_angle = -M_PI;
177 while (true) {
178 if (ShouldCancel()) {
179 return false;
180 }
181 phased_loop.SleepUntilNext();
182 drivetrain_queue.status.FetchLatest();
183 if (IsDriveDone()) {
184 return true;
185 }
186 if (drivetrain_queue.status.get()) {
187 if (drivetrain_queue.status->ground_angle > max_angle) {
188 max_angle = drivetrain_queue.status->ground_angle;
189 }
190 if (drivetrain_queue.status->ground_angle < max_angle - angle) {
191 return true;
192 }
193 }
194 }
195}
196
197bool BaseAutonomousActor::WaitForDriveNear(double distance, double angle) {
198 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
199 ::std::chrono::milliseconds(5) / 2);
200 constexpr double kPositionTolerance = 0.02;
201 constexpr double kProfileTolerance = 0.001;
202
Austin Schuhe6af9992018-07-08 15:59:14 -0700203 bool drive_has_been_close = false;
204 bool turn_has_been_close = false;
205 bool printed_first = false;
206
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000207 while (true) {
208 if (ShouldCancel()) {
209 return false;
210 }
211 phased_loop.SleepUntilNext();
212 drivetrain_queue.status.FetchLatest();
213 if (drivetrain_queue.status.get()) {
214 const double left_profile_error =
215 (initial_drivetrain_.left -
216 drivetrain_queue.status->profiled_left_position_goal);
217 const double right_profile_error =
218 (initial_drivetrain_.right -
219 drivetrain_queue.status->profiled_right_position_goal);
220
221 const double left_error =
222 (initial_drivetrain_.left -
223 drivetrain_queue.status->estimated_left_position);
224 const double right_error =
225 (initial_drivetrain_.right -
226 drivetrain_queue.status->estimated_right_position);
227
228 const double profile_distance_to_go =
229 (left_profile_error + right_profile_error) / 2.0;
230 const double profile_angle_to_go =
231 (right_profile_error - left_profile_error) /
232 (dt_config_.robot_radius * 2.0);
233
234 const double distance_to_go = (left_error + right_error) / 2.0;
235 const double angle_to_go =
236 (right_error - left_error) / (dt_config_.robot_radius * 2.0);
237
Austin Schuhe6af9992018-07-08 15:59:14 -0700238 const bool drive_close =
239 ::std::abs(profile_distance_to_go) < distance + kProfileTolerance &&
240 ::std::abs(distance_to_go) < distance + kPositionTolerance;
241 const bool turn_close =
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000242 ::std::abs(profile_angle_to_go) < angle + kProfileTolerance &&
Austin Schuhe6af9992018-07-08 15:59:14 -0700243 ::std::abs(angle_to_go) < angle + kPositionTolerance;
244
245 drive_has_been_close |= drive_close;
246 turn_has_been_close |= turn_close;
247 if (drive_has_been_close && !turn_has_been_close && !printed_first) {
248 LOG(INFO, "Drive finished first\n");
249 printed_first = true;
250 } else if (!drive_has_been_close && turn_has_been_close &&
251 !printed_first) {
252 LOG(INFO, "Turn finished first\n");
253 printed_first = true;
254 }
255
256 if (drive_close && turn_close) {
257 LOG(INFO, "Closer than %f < %f distance, %f < %f angle\n",
258 distance_to_go, distance, angle_to_go, angle);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000259 return true;
260 }
261 }
262 }
263}
264
Austin Schuh0aae9242018-03-14 19:49:44 -0700265bool BaseAutonomousActor::WaitForDriveProfileNear(double tolerance) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000266 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
267 ::std::chrono::milliseconds(5) / 2);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000268 while (true) {
269 if (ShouldCancel()) {
270 return false;
271 }
272 phased_loop.SleepUntilNext();
273 drivetrain_queue.status.FetchLatest();
Austin Schuh0aae9242018-03-14 19:49:44 -0700274
275 const Eigen::Matrix<double, 7, 1> current_error =
276 (Eigen::Matrix<double, 7, 1>()
277 << initial_drivetrain_.left -
278 drivetrain_queue.status->profiled_left_position_goal,
279 0.0, initial_drivetrain_.right -
280 drivetrain_queue.status->profiled_right_position_goal,
281 0.0, 0.0, 0.0, 0.0)
282 .finished();
283 const Eigen::Matrix<double, 2, 1> linear_error =
284 dt_config_.LeftRightToLinear(current_error);
285
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000286 if (drivetrain_queue.status.get()) {
Austin Schuh0aae9242018-03-14 19:49:44 -0700287 if (::std::abs(linear_error(0)) < tolerance) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000288 LOG(INFO, "Finished drive\n");
289 return true;
290 }
291 }
292 }
293}
294
Austin Schuh0aae9242018-03-14 19:49:44 -0700295bool BaseAutonomousActor::WaitForDriveProfileDone() {
296 constexpr double kProfileTolerance = 0.001;
297 return WaitForDriveProfileNear(kProfileTolerance);
298}
299
300bool BaseAutonomousActor::WaitForTurnProfileNear(double tolerance) {
Austin Schuh546a0382017-04-16 19:10:18 -0700301 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
302 ::std::chrono::milliseconds(5) / 2);
Austin Schuh546a0382017-04-16 19:10:18 -0700303 while (true) {
304 if (ShouldCancel()) {
305 return false;
306 }
307 phased_loop.SleepUntilNext();
308 drivetrain_queue.status.FetchLatest();
Austin Schuh0aae9242018-03-14 19:49:44 -0700309
310 const Eigen::Matrix<double, 7, 1> current_error =
311 (Eigen::Matrix<double, 7, 1>()
312 << initial_drivetrain_.left -
313 drivetrain_queue.status->profiled_left_position_goal,
314 0.0, initial_drivetrain_.right -
315 drivetrain_queue.status->profiled_right_position_goal,
316 0.0, 0.0, 0.0, 0.0)
317 .finished();
318 const Eigen::Matrix<double, 2, 1> angular_error =
319 dt_config_.LeftRightToAngular(current_error);
320
Austin Schuh546a0382017-04-16 19:10:18 -0700321 if (drivetrain_queue.status.get()) {
Austin Schuh0aae9242018-03-14 19:49:44 -0700322 if (::std::abs(angular_error(0)) < tolerance) {
323 LOG(INFO, "Finished turn\n");
Austin Schuh546a0382017-04-16 19:10:18 -0700324 return true;
325 }
326 }
327 }
328}
329
Austin Schuh0aae9242018-03-14 19:49:44 -0700330bool BaseAutonomousActor::WaitForTurnProfileDone() {
331 constexpr double kProfileTolerance = 0.001;
332 return WaitForTurnProfileNear(kProfileTolerance);
333}
334
Austin Schuh546a0382017-04-16 19:10:18 -0700335double BaseAutonomousActor::DriveDistanceLeft() {
336 using ::frc971::control_loops::drivetrain_queue;
337 drivetrain_queue.status.FetchLatest();
338 if (drivetrain_queue.status.get()) {
339 const double left_error =
340 (initial_drivetrain_.left -
341 drivetrain_queue.status->estimated_left_position);
342 const double right_error =
343 (initial_drivetrain_.right -
344 drivetrain_queue.status->estimated_right_position);
345
346 return (left_error + right_error) / 2.0;
347 } else {
348 return 0;
349 }
350}
351
Austin Schuh6bcc2302019-03-23 22:28:06 -0700352BaseAutonomousActor::SplineHandle BaseAutonomousActor::PlanSpline(
353 const ::frc971::MultiSpline &spline) {
354 LOG(INFO, "Planning spline\n");
355
356 int32_t spline_handle = (++spline_handle_) | ((getpid() & 0xFFFF) << 15);
357
358 drivetrain_queue.goal.FetchLatest();
359
360 auto drivetrain_message = drivetrain_queue.goal.MakeMessage();
361 drivetrain_message->controller_type = 2;
362
363 drivetrain_message->spline = spline;
364 drivetrain_message->spline.spline_idx = spline_handle;
365 drivetrain_message->spline_handle = goal_spline_handle_;
366
367 LOG_STRUCT(DEBUG, "dtg", *drivetrain_message);
368
369 drivetrain_message.Send();
370
371 return BaseAutonomousActor::SplineHandle(spline_handle, this);
372}
373
374bool BaseAutonomousActor::SplineHandle::IsPlanned() {
375 drivetrain_queue.status.FetchLatest();
376 LOG_STRUCT(INFO, "dts", *drivetrain_queue.status.get());
377 if (drivetrain_queue.status.get() &&
378 ((drivetrain_queue.status->trajectory_logging.planning_spline_idx ==
379 spline_handle_ &&
380 drivetrain_queue.status->trajectory_logging.planning_state == 3) ||
381 drivetrain_queue.status->trajectory_logging.current_spline_idx ==
382 spline_handle_)) {
383 return true;
384 }
385 return false;
386}
387
388bool BaseAutonomousActor::SplineHandle::WaitForPlan() {
389 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
390 ::std::chrono::milliseconds(5) / 2);
391 while (true) {
392 if (base_autonomous_actor_->ShouldCancel()) {
393 return false;
394 }
395 phased_loop.SleepUntilNext();
396 if (IsPlanned()) {
397 return true;
398 }
399 }
400}
401
402void BaseAutonomousActor::SplineHandle::Start() {
403 auto drivetrain_message = drivetrain_queue.goal.MakeMessage();
404 drivetrain_message->controller_type = 2;
405
406 LOG(INFO, "Starting spline\n");
407
408 drivetrain_message->spline_handle = spline_handle_;
409 base_autonomous_actor_->goal_spline_handle_ = spline_handle_;
410
411 LOG_STRUCT(DEBUG, "dtg", *drivetrain_message);
412
413 drivetrain_message.Send();
414}
415
416bool BaseAutonomousActor::SplineHandle::IsDone() {
417 drivetrain_queue.status.FetchLatest();
418 LOG_STRUCT(INFO, "dts", *drivetrain_queue.status.get());
419
420 if (drivetrain_queue.status.get() &&
421 drivetrain_queue.status->trajectory_logging.current_spline_idx ==
422 spline_handle_) {
423 return false;
424 }
425 return true;
426}
427
428bool BaseAutonomousActor::SplineHandle::WaitForDone() {
429 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
430 ::std::chrono::milliseconds(5) / 2);
431 while (true) {
432 if (base_autonomous_actor_->ShouldCancel()) {
433 return false;
434 }
435 phased_loop.SleepUntilNext();
436 if (IsDone()) {
437 return true;
438 }
439 }
440}
441
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000442::std::unique_ptr<AutonomousAction> MakeAutonomousAction(
443 const AutonomousActionParams &params) {
444 return ::std::unique_ptr<AutonomousAction>(
445 new AutonomousAction(&autonomous_action, params));
446}
447
448} // namespace autonomous
449} // namespace frc971