blob: 1b1ce368e9ba3c3ed698c396a893b4c4368b17e1 [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
Alex Perrycb7da4b2019-08-28 19:35:56 -070011#include "frc971/control_loops/control_loops_generated.h"
12#include "frc971/control_loops/drivetrain/drivetrain_goal_generated.h"
13#include "frc971/control_loops/drivetrain/drivetrain_status_generated.h"
14#include "y2019/control_loops/drivetrain/target_selector_generated.h"
Philipp Schrader4bd29b12017-02-22 04:42:27 +000015
Philipp Schrader4bd29b12017-02-22 04:42:27 +000016using ::aos::monotonic_clock;
17namespace chrono = ::std::chrono;
18namespace this_thread = ::std::this_thread;
Alex Perrycb7da4b2019-08-28 19:35:56 -070019namespace drivetrain = frc971::control_loops::drivetrain;
Philipp Schrader4bd29b12017-02-22 04:42:27 +000020
Brian Silvermanf83678c2017-03-11 14:02:26 -080021namespace frc971 {
22namespace autonomous {
Philipp Schrader4bd29b12017-02-22 04:42:27 +000023
24BaseAutonomousActor::BaseAutonomousActor(
Austin Schuh1bf8a212019-05-26 22:13:14 -070025 ::aos::EventLoop *event_loop,
Austin Schuhbcce26a2018-03-26 23:41:24 -070026 const control_loops::drivetrain::DrivetrainConfig<double> &dt_config)
Alex Perrycb7da4b2019-08-28 19:35:56 -070027 : aos::common::actions::ActorBase<Goal>(event_loop, "/autonomous"),
Philipp Schrader4bd29b12017-02-22 04:42:27 +000028 dt_config_(dt_config),
Austin Schuhc087b102019-05-12 15:33:12 -070029 initial_drivetrain_({0.0, 0.0}),
30 target_selector_hint_sender_(
Austin Schuheb99d072019-05-12 21:03:38 -070031 event_loop->MakeSender<
Austin Schuhc087b102019-05-12 15:33:12 -070032 ::y2019::control_loops::drivetrain::TargetSelectorHint>(
Alex Perrycb7da4b2019-08-28 19:35:56 -070033 "/drivetrain")),
Austin Schuhbd0a40f2019-06-30 14:56:31 -070034 drivetrain_goal_sender_(
Alex Perrycb7da4b2019-08-28 19:35:56 -070035 event_loop->MakeSender<drivetrain::Goal>("/drivetrain")),
James Kuszmaul75a18c52021-03-10 22:02:07 -080036 spline_goal_sender_(
37 event_loop->MakeSender<drivetrain::SplineGoal>("/drivetrain")),
Austin Schuhbd0a40f2019-06-30 14:56:31 -070038 drivetrain_status_fetcher_(
Alex Perrycb7da4b2019-08-28 19:35:56 -070039 event_loop->MakeFetcher<drivetrain::Status>("/drivetrain")),
Austin Schuhbd0a40f2019-06-30 14:56:31 -070040 drivetrain_goal_fetcher_(
Austin Schuh094d09b2020-11-20 23:26:52 -080041 event_loop->MakeFetcher<drivetrain::Goal>("/drivetrain")) {
42 event_loop->SetRuntimeRealtimePriority(29);
43}
Philipp Schrader4bd29b12017-02-22 04:42:27 +000044
45void BaseAutonomousActor::ResetDrivetrain() {
Austin Schuhf257f3c2019-10-27 21:00:43 -070046 AOS_LOG(INFO, "resetting the drivetrain\n");
Austin Schuh0aae9242018-03-14 19:49:44 -070047 max_drivetrain_voltage_ = 12.0;
James Kuszmaulc73bb222019-04-07 12:15:35 -070048 goal_spline_handle_ = 0;
Austin Schuhbd0a40f2019-06-30 14:56:31 -070049
Alex Perrycb7da4b2019-08-28 19:35:56 -070050 auto builder = drivetrain_goal_sender_.MakeBuilder();
51
52 drivetrain::Goal::Builder goal_builder =
53 builder.MakeBuilder<drivetrain::Goal>();
Austin Schuh872723c2019-12-25 14:38:09 -080054 goal_builder.add_controller_type(drivetrain::ControllerType::POLYDRIVE);
Alex Perrycb7da4b2019-08-28 19:35:56 -070055 goal_builder.add_highgear(true);
56 goal_builder.add_wheel(0.0);
57 goal_builder.add_throttle(0.0);
58 goal_builder.add_left_goal(initial_drivetrain_.left);
59 goal_builder.add_right_goal(initial_drivetrain_.right);
60 goal_builder.add_max_ss_voltage(max_drivetrain_voltage_);
61 builder.Send(goal_builder.Finish());
Philipp Schrader4bd29b12017-02-22 04:42:27 +000062}
63
64void BaseAutonomousActor::InitializeEncoders() {
Austin Schuhbd0a40f2019-06-30 14:56:31 -070065 // Spin until we get a message.
66 WaitUntil([this]() { return drivetrain_status_fetcher_.Fetch(); });
67
68 initial_drivetrain_.left =
Alex Perrycb7da4b2019-08-28 19:35:56 -070069 drivetrain_status_fetcher_->estimated_left_position();
Austin Schuhbd0a40f2019-06-30 14:56:31 -070070 initial_drivetrain_.right =
Alex Perrycb7da4b2019-08-28 19:35:56 -070071 drivetrain_status_fetcher_->estimated_right_position();
Philipp Schrader4bd29b12017-02-22 04:42:27 +000072}
73
74void BaseAutonomousActor::StartDrive(double distance, double angle,
Alex Perrycb7da4b2019-08-28 19:35:56 -070075 ProfileParametersT linear,
76 ProfileParametersT angular) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070077 AOS_LOG(INFO, "Driving distance %f, angle %f\n", distance, angle);
Philipp Schrader4bd29b12017-02-22 04:42:27 +000078 {
79 const double dangle = angle * dt_config_.robot_radius;
80 initial_drivetrain_.left += distance - dangle;
81 initial_drivetrain_.right += distance + dangle;
82 }
83
Alex Perrycb7da4b2019-08-28 19:35:56 -070084 auto builder = drivetrain_goal_sender_.MakeBuilder();
Philipp Schrader4bd29b12017-02-22 04:42:27 +000085
Alex Perrycb7da4b2019-08-28 19:35:56 -070086 auto linear_offset = ProfileParameters::Pack(*builder.fbb(), &linear);
87 auto angular_offset = ProfileParameters::Pack(*builder.fbb(), &angular);
Philipp Schrader4bd29b12017-02-22 04:42:27 +000088
Alex Perrycb7da4b2019-08-28 19:35:56 -070089 drivetrain::Goal::Builder goal_builder =
90 builder.MakeBuilder<drivetrain::Goal>();
91
Austin Schuh872723c2019-12-25 14:38:09 -080092 goal_builder.add_controller_type(drivetrain::ControllerType::MOTION_PROFILE);
Alex Perrycb7da4b2019-08-28 19:35:56 -070093 goal_builder.add_highgear(true);
94 goal_builder.add_wheel(0.0);
95 goal_builder.add_throttle(0.0);
96 goal_builder.add_left_goal(initial_drivetrain_.left);
97 goal_builder.add_right_goal(initial_drivetrain_.right);
98 goal_builder.add_max_ss_voltage(max_drivetrain_voltage_);
99 goal_builder.add_linear(linear_offset);
100 goal_builder.add_angular(angular_offset);
101
102 builder.Send(goal_builder.Finish());
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000103}
104
105void BaseAutonomousActor::WaitUntilDoneOrCanceled(
106 ::std::unique_ptr<aos::common::actions::Action> action) {
107 if (!action) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700108 AOS_LOG(ERROR, "No action, not waiting\n");
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000109 return;
110 }
111
112 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
Austin Schuhd32b3622019-06-23 18:49:06 -0700113 event_loop()->monotonic_now(),
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000114 ::std::chrono::milliseconds(5) / 2);
115 while (true) {
116 // Poll the running bit and see if we should cancel.
117 phased_loop.SleepUntilNext();
118 if (!action->Running() || ShouldCancel()) {
119 return;
120 }
121 }
122}
123
124bool BaseAutonomousActor::WaitForDriveDone() {
125 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
Austin Schuhd32b3622019-06-23 18:49:06 -0700126 event_loop()->monotonic_now(),
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000127 ::std::chrono::milliseconds(5) / 2);
128
129 while (true) {
130 if (ShouldCancel()) {
131 return false;
132 }
133 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700134 drivetrain_status_fetcher_.Fetch();
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000135 if (IsDriveDone()) {
136 return true;
137 }
138 }
139}
140
141bool BaseAutonomousActor::IsDriveDone() {
Brian Silvermanf83678c2017-03-11 14:02:26 -0800142 static constexpr double kPositionTolerance = 0.02;
143 static constexpr double kVelocityTolerance = 0.10;
144 static constexpr double kProfileTolerance = 0.001;
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000145
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700146 if (drivetrain_status_fetcher_.get()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700147 if (::std::abs(drivetrain_status_fetcher_->profiled_left_position_goal() -
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000148 initial_drivetrain_.left) < kProfileTolerance &&
Alex Perrycb7da4b2019-08-28 19:35:56 -0700149 ::std::abs(drivetrain_status_fetcher_->profiled_right_position_goal() -
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000150 initial_drivetrain_.right) < kProfileTolerance &&
Alex Perrycb7da4b2019-08-28 19:35:56 -0700151 ::std::abs(drivetrain_status_fetcher_->estimated_left_position() -
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000152 initial_drivetrain_.left) < kPositionTolerance &&
Alex Perrycb7da4b2019-08-28 19:35:56 -0700153 ::std::abs(drivetrain_status_fetcher_->estimated_right_position() -
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000154 initial_drivetrain_.right) < kPositionTolerance &&
Alex Perrycb7da4b2019-08-28 19:35:56 -0700155 ::std::abs(drivetrain_status_fetcher_->estimated_left_velocity()) <
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000156 kVelocityTolerance &&
Alex Perrycb7da4b2019-08-28 19:35:56 -0700157 ::std::abs(drivetrain_status_fetcher_->estimated_right_velocity()) <
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000158 kVelocityTolerance) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700159 AOS_LOG(INFO, "Finished drive\n");
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000160 return true;
161 }
162 }
163 return false;
164}
165
166bool BaseAutonomousActor::WaitForAboveAngle(double angle) {
167 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
Austin Schuhd32b3622019-06-23 18:49:06 -0700168 event_loop()->monotonic_now(),
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000169 ::std::chrono::milliseconds(5) / 2);
170 while (true) {
171 if (ShouldCancel()) {
172 return false;
173 }
174 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700175 drivetrain_status_fetcher_.Fetch();
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000176 if (IsDriveDone()) {
177 return true;
178 }
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700179 if (drivetrain_status_fetcher_.get()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700180 if (drivetrain_status_fetcher_->ground_angle() > angle) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000181 return true;
182 }
183 }
184 }
185}
186
187bool BaseAutonomousActor::WaitForBelowAngle(double angle) {
188 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
Austin Schuhd32b3622019-06-23 18:49:06 -0700189 event_loop()->monotonic_now(),
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000190 ::std::chrono::milliseconds(5) / 2);
191 while (true) {
192 if (ShouldCancel()) {
193 return false;
194 }
195 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700196 drivetrain_status_fetcher_.Fetch();
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000197 if (IsDriveDone()) {
198 return true;
199 }
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700200 if (drivetrain_status_fetcher_.get()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700201 if (drivetrain_status_fetcher_->ground_angle() < angle) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000202 return true;
203 }
204 }
205 }
206}
207
208bool BaseAutonomousActor::WaitForMaxBy(double angle) {
209 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
Austin Schuhd32b3622019-06-23 18:49:06 -0700210 event_loop()->monotonic_now(),
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000211 ::std::chrono::milliseconds(5) / 2);
212 double max_angle = -M_PI;
213 while (true) {
214 if (ShouldCancel()) {
215 return false;
216 }
217 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700218 drivetrain_status_fetcher_.Fetch();
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000219 if (IsDriveDone()) {
220 return true;
221 }
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700222 if (drivetrain_status_fetcher_.get()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700223 if (drivetrain_status_fetcher_->ground_angle() > max_angle) {
224 max_angle = drivetrain_status_fetcher_->ground_angle();
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000225 }
Alex Perrycb7da4b2019-08-28 19:35:56 -0700226 if (drivetrain_status_fetcher_->ground_angle() < max_angle - angle) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000227 return true;
228 }
229 }
230 }
231}
232
233bool BaseAutonomousActor::WaitForDriveNear(double distance, double angle) {
234 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
Austin Schuhd32b3622019-06-23 18:49:06 -0700235 event_loop()->monotonic_now(),
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000236 ::std::chrono::milliseconds(5) / 2);
237 constexpr double kPositionTolerance = 0.02;
238 constexpr double kProfileTolerance = 0.001;
239
Austin Schuhe6af9992018-07-08 15:59:14 -0700240 bool drive_has_been_close = false;
241 bool turn_has_been_close = false;
242 bool printed_first = false;
243
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000244 while (true) {
245 if (ShouldCancel()) {
246 return false;
247 }
248 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700249 drivetrain_status_fetcher_.Fetch();
250 if (drivetrain_status_fetcher_.get()) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000251 const double left_profile_error =
252 (initial_drivetrain_.left -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700253 drivetrain_status_fetcher_->profiled_left_position_goal());
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000254 const double right_profile_error =
255 (initial_drivetrain_.right -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700256 drivetrain_status_fetcher_->profiled_right_position_goal());
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000257
258 const double left_error =
259 (initial_drivetrain_.left -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700260 drivetrain_status_fetcher_->estimated_left_position());
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000261 const double right_error =
262 (initial_drivetrain_.right -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700263 drivetrain_status_fetcher_->estimated_right_position());
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000264
265 const double profile_distance_to_go =
266 (left_profile_error + right_profile_error) / 2.0;
267 const double profile_angle_to_go =
268 (right_profile_error - left_profile_error) /
269 (dt_config_.robot_radius * 2.0);
270
271 const double distance_to_go = (left_error + right_error) / 2.0;
272 const double angle_to_go =
273 (right_error - left_error) / (dt_config_.robot_radius * 2.0);
274
Austin Schuhe6af9992018-07-08 15:59:14 -0700275 const bool drive_close =
276 ::std::abs(profile_distance_to_go) < distance + kProfileTolerance &&
277 ::std::abs(distance_to_go) < distance + kPositionTolerance;
278 const bool turn_close =
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000279 ::std::abs(profile_angle_to_go) < angle + kProfileTolerance &&
Austin Schuhe6af9992018-07-08 15:59:14 -0700280 ::std::abs(angle_to_go) < angle + kPositionTolerance;
281
282 drive_has_been_close |= drive_close;
283 turn_has_been_close |= turn_close;
284 if (drive_has_been_close && !turn_has_been_close && !printed_first) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700285 AOS_LOG(INFO, "Drive finished first\n");
Austin Schuhe6af9992018-07-08 15:59:14 -0700286 printed_first = true;
287 } else if (!drive_has_been_close && turn_has_been_close &&
288 !printed_first) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700289 AOS_LOG(INFO, "Turn finished first\n");
Austin Schuhe6af9992018-07-08 15:59:14 -0700290 printed_first = true;
291 }
292
293 if (drive_close && turn_close) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700294 AOS_LOG(INFO, "Closer than %f < %f distance, %f < %f angle\n",
295 distance_to_go, distance, angle_to_go, angle);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000296 return true;
297 }
298 }
299 }
300}
301
Austin Schuh0aae9242018-03-14 19:49:44 -0700302bool BaseAutonomousActor::WaitForDriveProfileNear(double tolerance) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000303 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
Austin Schuhd32b3622019-06-23 18:49:06 -0700304 event_loop()->monotonic_now(),
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000305 ::std::chrono::milliseconds(5) / 2);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000306 while (true) {
307 if (ShouldCancel()) {
308 return false;
309 }
310 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700311 drivetrain_status_fetcher_.Fetch();
Austin Schuh0aae9242018-03-14 19:49:44 -0700312
313 const Eigen::Matrix<double, 7, 1> current_error =
314 (Eigen::Matrix<double, 7, 1>()
315 << initial_drivetrain_.left -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700316 drivetrain_status_fetcher_->profiled_left_position_goal(),
Austin Schuh0aae9242018-03-14 19:49:44 -0700317 0.0, initial_drivetrain_.right -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700318 drivetrain_status_fetcher_->profiled_right_position_goal(),
Austin Schuh0aae9242018-03-14 19:49:44 -0700319 0.0, 0.0, 0.0, 0.0)
320 .finished();
321 const Eigen::Matrix<double, 2, 1> linear_error =
322 dt_config_.LeftRightToLinear(current_error);
323
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700324 if (drivetrain_status_fetcher_.get()) {
Austin Schuh0aae9242018-03-14 19:49:44 -0700325 if (::std::abs(linear_error(0)) < tolerance) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700326 AOS_LOG(INFO, "Finished drive\n");
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000327 return true;
328 }
329 }
330 }
331}
332
Austin Schuh0aae9242018-03-14 19:49:44 -0700333bool BaseAutonomousActor::WaitForDriveProfileDone() {
334 constexpr double kProfileTolerance = 0.001;
335 return WaitForDriveProfileNear(kProfileTolerance);
336}
337
338bool BaseAutonomousActor::WaitForTurnProfileNear(double tolerance) {
Austin Schuh546a0382017-04-16 19:10:18 -0700339 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
Austin Schuhd32b3622019-06-23 18:49:06 -0700340 event_loop()->monotonic_now(),
Austin Schuh546a0382017-04-16 19:10:18 -0700341 ::std::chrono::milliseconds(5) / 2);
Austin Schuh546a0382017-04-16 19:10:18 -0700342 while (true) {
343 if (ShouldCancel()) {
344 return false;
345 }
346 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700347 drivetrain_status_fetcher_.Fetch();
Austin Schuh0aae9242018-03-14 19:49:44 -0700348
349 const Eigen::Matrix<double, 7, 1> current_error =
350 (Eigen::Matrix<double, 7, 1>()
351 << initial_drivetrain_.left -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700352 drivetrain_status_fetcher_->profiled_left_position_goal(),
Austin Schuh0aae9242018-03-14 19:49:44 -0700353 0.0, initial_drivetrain_.right -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700354 drivetrain_status_fetcher_->profiled_right_position_goal(),
Austin Schuh0aae9242018-03-14 19:49:44 -0700355 0.0, 0.0, 0.0, 0.0)
356 .finished();
357 const Eigen::Matrix<double, 2, 1> angular_error =
358 dt_config_.LeftRightToAngular(current_error);
359
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700360 if (drivetrain_status_fetcher_.get()) {
Austin Schuh0aae9242018-03-14 19:49:44 -0700361 if (::std::abs(angular_error(0)) < tolerance) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700362 AOS_LOG(INFO, "Finished turn\n");
Austin Schuh546a0382017-04-16 19:10:18 -0700363 return true;
364 }
365 }
366 }
367}
368
Austin Schuh0aae9242018-03-14 19:49:44 -0700369bool BaseAutonomousActor::WaitForTurnProfileDone() {
370 constexpr double kProfileTolerance = 0.001;
371 return WaitForTurnProfileNear(kProfileTolerance);
372}
373
Austin Schuh546a0382017-04-16 19:10:18 -0700374double BaseAutonomousActor::DriveDistanceLeft() {
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700375 drivetrain_status_fetcher_.Fetch();
376 if (drivetrain_status_fetcher_.get()) {
Austin Schuh546a0382017-04-16 19:10:18 -0700377 const double left_error =
378 (initial_drivetrain_.left -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700379 drivetrain_status_fetcher_->estimated_left_position());
Austin Schuh546a0382017-04-16 19:10:18 -0700380 const double right_error =
381 (initial_drivetrain_.right -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700382 drivetrain_status_fetcher_->estimated_right_position());
Austin Schuh546a0382017-04-16 19:10:18 -0700383
384 return (left_error + right_error) / 2.0;
385 } else {
386 return 0;
387 }
388}
389
James Kuszmaul838040b2019-04-13 15:51:02 -0700390bool BaseAutonomousActor::SplineHandle::SplineDistanceRemaining(
391 double distance) {
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700392 base_autonomous_actor_->drivetrain_status_fetcher_.Fetch();
393 if (base_autonomous_actor_->drivetrain_status_fetcher_.get()) {
James Kuszmaul04e8d6c2021-03-27 18:12:13 -0700394 // Confirm that:
395 // (a) The spline has started executiong (is_executing remains true even
396 // when we reach the end of the spline).
397 // (b) The spline that we are executing is the correct one.
398 // (c) There is less than distance distance remaining.
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700399 return base_autonomous_actor_->drivetrain_status_fetcher_
Alex Perrycb7da4b2019-08-28 19:35:56 -0700400 ->trajectory_logging()
401 ->is_executing() &&
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700402 base_autonomous_actor_->drivetrain_status_fetcher_
Alex Perrycb7da4b2019-08-28 19:35:56 -0700403 ->trajectory_logging()
James Kuszmaul04e8d6c2021-03-27 18:12:13 -0700404 ->goal_spline_handle() == spline_handle_ &&
405 base_autonomous_actor_->drivetrain_status_fetcher_
406 ->trajectory_logging()
Alex Perrycb7da4b2019-08-28 19:35:56 -0700407 ->distance_remaining() < distance;
James Kuszmaul838040b2019-04-13 15:51:02 -0700408 }
409 return false;
410}
411bool BaseAutonomousActor::SplineHandle::WaitForSplineDistanceRemaining(
412 double distance) {
Austin Schuhd32b3622019-06-23 18:49:06 -0700413 ::aos::time::PhasedLoop phased_loop(
414 ::std::chrono::milliseconds(5),
415 base_autonomous_actor_->event_loop()->monotonic_now(),
416 ::std::chrono::milliseconds(5) / 2);
James Kuszmaul838040b2019-04-13 15:51:02 -0700417 while (true) {
418 if (base_autonomous_actor_->ShouldCancel()) {
419 return false;
420 }
421 phased_loop.SleepUntilNext();
422 if (SplineDistanceRemaining(distance)) {
423 return true;
424 }
425 }
426}
427
Alex Perrycb7da4b2019-08-28 19:35:56 -0700428void BaseAutonomousActor::LineFollowAtVelocity(
429 double velocity, y2019::control_loops::drivetrain::SelectionHint hint) {
430 {
431 auto builder = drivetrain_goal_sender_.MakeBuilder();
432 drivetrain::Goal::Builder goal_builder =
433 builder.MakeBuilder<drivetrain::Goal>();
434 goal_builder.add_controller_type(
Austin Schuh872723c2019-12-25 14:38:09 -0800435 drivetrain::ControllerType::SPLINE_FOLLOWER);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700436 // TODO(james): Currently the 4.0 is copied from the
437 // line_follow_drivetrain.cc, but it is somewhat year-specific, so we should
438 // factor it out in some way.
439 goal_builder.add_throttle(velocity / 4.0);
440 builder.Send(goal_builder.Finish());
441 }
442
443 {
444 auto builder = target_selector_hint_sender_.MakeBuilder();
445 ::y2019::control_loops::drivetrain::TargetSelectorHint::Builder
446 target_hint_builder = builder.MakeBuilder<
447 ::y2019::control_loops::drivetrain::TargetSelectorHint>();
448
449 target_hint_builder.add_suggested_target(hint);
450 builder.Send(target_hint_builder.Finish());
451 }
James Kuszmaul838040b2019-04-13 15:51:02 -0700452}
453
Austin Schuh6bcc2302019-03-23 22:28:06 -0700454BaseAutonomousActor::SplineHandle BaseAutonomousActor::PlanSpline(
Alex Perrycb7da4b2019-08-28 19:35:56 -0700455 std::function<flatbuffers::Offset<frc971::MultiSpline>(
James Kuszmaul75a18c52021-03-10 22:02:07 -0800456 aos::Sender<frc971::control_loops::drivetrain::SplineGoal>::Builder
457 *builder)> &&multispline_builder,
Alex Perrycb7da4b2019-08-28 19:35:56 -0700458 SplineDirection direction) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700459 AOS_LOG(INFO, "Planning spline\n");
Austin Schuh6bcc2302019-03-23 22:28:06 -0700460
461 int32_t spline_handle = (++spline_handle_) | ((getpid() & 0xFFFF) << 15);
462
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700463 drivetrain_goal_fetcher_.Fetch();
Austin Schuh6bcc2302019-03-23 22:28:06 -0700464
James Kuszmaul75a18c52021-03-10 22:02:07 -0800465 auto builder = spline_goal_sender_.MakeBuilder();
James Kuszmaulc864bcf2019-05-01 20:17:34 -0700466
Alex Perrycb7da4b2019-08-28 19:35:56 -0700467 flatbuffers::Offset<frc971::MultiSpline> multispline_offset =
468 multispline_builder(&builder);
469
470 drivetrain::SplineGoal::Builder spline_builder =
471 builder.MakeBuilder<drivetrain::SplineGoal>();
472 spline_builder.add_spline_idx(spline_handle);
473 spline_builder.add_drive_spline_backwards(direction ==
474 SplineDirection::kBackward);
475 spline_builder.add_spline(multispline_offset);
476
James Kuszmaul75a18c52021-03-10 22:02:07 -0800477 builder.Send(spline_builder.Finish());
Austin Schuh6bcc2302019-03-23 22:28:06 -0700478
479 return BaseAutonomousActor::SplineHandle(spline_handle, this);
480}
481
482bool BaseAutonomousActor::SplineHandle::IsPlanned() {
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700483 base_autonomous_actor_->drivetrain_status_fetcher_.Fetch();
Alex Perrycb7da4b2019-08-28 19:35:56 -0700484 VLOG(1) << aos::FlatbufferToJson(
485 base_autonomous_actor_->drivetrain_status_fetcher_.get());
486
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700487 if (base_autonomous_actor_->drivetrain_status_fetcher_.get() &&
James Kuszmaul75a18c52021-03-10 22:02:07 -0800488 base_autonomous_actor_->drivetrain_status_fetcher_.get()
489 ->has_trajectory_logging() &&
490 base_autonomous_actor_->drivetrain_status_fetcher_.get()
491 ->trajectory_logging()
492 ->has_available_splines()) {
493 const flatbuffers::Vector<int> *splines =
494 base_autonomous_actor_->drivetrain_status_fetcher_.get()
495 ->trajectory_logging()
496 ->available_splines();
497
498 return std::find(splines->begin(), splines->end(), spline_handle_) !=
499 splines->end();
Austin Schuh6bcc2302019-03-23 22:28:06 -0700500 }
501 return false;
502}
503
504bool BaseAutonomousActor::SplineHandle::WaitForPlan() {
Austin Schuhd32b3622019-06-23 18:49:06 -0700505 ::aos::time::PhasedLoop phased_loop(
506 ::std::chrono::milliseconds(5),
507 base_autonomous_actor_->event_loop()->monotonic_now(),
508 ::std::chrono::milliseconds(5) / 2);
Austin Schuh6bcc2302019-03-23 22:28:06 -0700509 while (true) {
510 if (base_autonomous_actor_->ShouldCancel()) {
511 return false;
512 }
513 phased_loop.SleepUntilNext();
514 if (IsPlanned()) {
515 return true;
516 }
517 }
518}
519
520void BaseAutonomousActor::SplineHandle::Start() {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700521 auto builder = base_autonomous_actor_->drivetrain_goal_sender_.MakeBuilder();
522 drivetrain::Goal::Builder goal_builder =
523 builder.MakeBuilder<drivetrain::Goal>();
Austin Schuh872723c2019-12-25 14:38:09 -0800524 goal_builder.add_controller_type(drivetrain::ControllerType::SPLINE_FOLLOWER);
Austin Schuh6bcc2302019-03-23 22:28:06 -0700525
Austin Schuhf257f3c2019-10-27 21:00:43 -0700526 AOS_LOG(INFO, "Starting spline\n");
Austin Schuh6bcc2302019-03-23 22:28:06 -0700527
Alex Perrycb7da4b2019-08-28 19:35:56 -0700528 goal_builder.add_spline_handle(spline_handle_);
Austin Schuh6bcc2302019-03-23 22:28:06 -0700529 base_autonomous_actor_->goal_spline_handle_ = spline_handle_;
530
Alex Perrycb7da4b2019-08-28 19:35:56 -0700531 builder.Send(goal_builder.Finish());
Austin Schuh6bcc2302019-03-23 22:28:06 -0700532}
533
534bool BaseAutonomousActor::SplineHandle::IsDone() {
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700535 base_autonomous_actor_->drivetrain_status_fetcher_.Fetch();
Austin Schuh6bcc2302019-03-23 22:28:06 -0700536
James Kuszmaulc73bb222019-04-07 12:15:35 -0700537 // We check that the spline we are waiting on is neither currently planning
James Kuszmaul29e417d2019-04-13 10:03:35 -0700538 // nor executing (we check is_executed because it is possible to receive
539 // status messages with is_executing false before the execution has started).
540 // We check for planning so that the user can go straight from starting the
541 // planner to executing without a WaitForPlan in between.
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700542 if (base_autonomous_actor_->drivetrain_status_fetcher_.get() &&
Alex Perrycb7da4b2019-08-28 19:35:56 -0700543 ((!base_autonomous_actor_->drivetrain_status_fetcher_
544 ->trajectory_logging()
545 ->is_executed() &&
546 base_autonomous_actor_->drivetrain_status_fetcher_->trajectory_logging()
547 ->current_spline_idx() == spline_handle_) ||
James Kuszmaul75a18c52021-03-10 22:02:07 -0800548 IsPlanned())) {
Austin Schuh6bcc2302019-03-23 22:28:06 -0700549 return false;
550 }
551 return true;
552}
553
554bool BaseAutonomousActor::SplineHandle::WaitForDone() {
Austin Schuhd32b3622019-06-23 18:49:06 -0700555 ::aos::time::PhasedLoop phased_loop(
556 ::std::chrono::milliseconds(5),
557 base_autonomous_actor_->event_loop()->monotonic_now(),
558 ::std::chrono::milliseconds(5) / 2);
Austin Schuh6bcc2302019-03-23 22:28:06 -0700559 while (true) {
560 if (base_autonomous_actor_->ShouldCancel()) {
561 return false;
562 }
563 phased_loop.SleepUntilNext();
564 if (IsDone()) {
565 return true;
566 }
567 }
568}
569
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000570} // namespace autonomous
571} // namespace frc971