blob: e691d0325a8912b7c2b982c125d1cefafcbe9133 [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
James Kuszmaul99af8b52021-03-28 10:50:15 -07008#include "aos/util/math.h"
John Park33858a32018-09-28 23:05:48 -07009#include "aos/util/phased_loop.h"
10#include "aos/logging/logging.h"
Philipp Schrader4bd29b12017-02-22 04:42:27 +000011
Alex Perrycb7da4b2019-08-28 19:35:56 -070012#include "frc971/control_loops/control_loops_generated.h"
13#include "frc971/control_loops/drivetrain/drivetrain_goal_generated.h"
14#include "frc971/control_loops/drivetrain/drivetrain_status_generated.h"
James Kuszmaul99af8b52021-03-28 10:50:15 -070015#include "frc971/control_loops/drivetrain/spline.h"
Alex Perrycb7da4b2019-08-28 19:35:56 -070016#include "y2019/control_loops/drivetrain/target_selector_generated.h"
Philipp Schrader4bd29b12017-02-22 04:42:27 +000017
Philipp Schrader4bd29b12017-02-22 04:42:27 +000018using ::aos::monotonic_clock;
19namespace chrono = ::std::chrono;
20namespace this_thread = ::std::this_thread;
Alex Perrycb7da4b2019-08-28 19:35:56 -070021namespace drivetrain = frc971::control_loops::drivetrain;
Philipp Schrader4bd29b12017-02-22 04:42:27 +000022
Brian Silvermanf83678c2017-03-11 14:02:26 -080023namespace frc971 {
24namespace autonomous {
Philipp Schrader4bd29b12017-02-22 04:42:27 +000025
26BaseAutonomousActor::BaseAutonomousActor(
Austin Schuh1bf8a212019-05-26 22:13:14 -070027 ::aos::EventLoop *event_loop,
Austin Schuhbcce26a2018-03-26 23:41:24 -070028 const control_loops::drivetrain::DrivetrainConfig<double> &dt_config)
Alex Perrycb7da4b2019-08-28 19:35:56 -070029 : aos::common::actions::ActorBase<Goal>(event_loop, "/autonomous"),
Philipp Schrader4bd29b12017-02-22 04:42:27 +000030 dt_config_(dt_config),
Austin Schuhc087b102019-05-12 15:33:12 -070031 initial_drivetrain_({0.0, 0.0}),
32 target_selector_hint_sender_(
Austin Schuheb99d072019-05-12 21:03:38 -070033 event_loop->MakeSender<
Austin Schuhc087b102019-05-12 15:33:12 -070034 ::y2019::control_loops::drivetrain::TargetSelectorHint>(
Alex Perrycb7da4b2019-08-28 19:35:56 -070035 "/drivetrain")),
Austin Schuhbd0a40f2019-06-30 14:56:31 -070036 drivetrain_goal_sender_(
Alex Perrycb7da4b2019-08-28 19:35:56 -070037 event_loop->MakeSender<drivetrain::Goal>("/drivetrain")),
James Kuszmaul75a18c52021-03-10 22:02:07 -080038 spline_goal_sender_(
39 event_loop->MakeSender<drivetrain::SplineGoal>("/drivetrain")),
Austin Schuhbd0a40f2019-06-30 14:56:31 -070040 drivetrain_status_fetcher_(
Alex Perrycb7da4b2019-08-28 19:35:56 -070041 event_loop->MakeFetcher<drivetrain::Status>("/drivetrain")),
Austin Schuhbd0a40f2019-06-30 14:56:31 -070042 drivetrain_goal_fetcher_(
Austin Schuh094d09b2020-11-20 23:26:52 -080043 event_loop->MakeFetcher<drivetrain::Goal>("/drivetrain")) {
44 event_loop->SetRuntimeRealtimePriority(29);
45}
Philipp Schrader4bd29b12017-02-22 04:42:27 +000046
47void BaseAutonomousActor::ResetDrivetrain() {
Austin Schuhf257f3c2019-10-27 21:00:43 -070048 AOS_LOG(INFO, "resetting the drivetrain\n");
Austin Schuh0aae9242018-03-14 19:49:44 -070049 max_drivetrain_voltage_ = 12.0;
James Kuszmaulc73bb222019-04-07 12:15:35 -070050 goal_spline_handle_ = 0;
Austin Schuhbd0a40f2019-06-30 14:56:31 -070051
Alex Perrycb7da4b2019-08-28 19:35:56 -070052 auto builder = drivetrain_goal_sender_.MakeBuilder();
53
54 drivetrain::Goal::Builder goal_builder =
55 builder.MakeBuilder<drivetrain::Goal>();
Austin Schuh872723c2019-12-25 14:38:09 -080056 goal_builder.add_controller_type(drivetrain::ControllerType::POLYDRIVE);
Alex Perrycb7da4b2019-08-28 19:35:56 -070057 goal_builder.add_highgear(true);
58 goal_builder.add_wheel(0.0);
59 goal_builder.add_throttle(0.0);
60 goal_builder.add_left_goal(initial_drivetrain_.left);
61 goal_builder.add_right_goal(initial_drivetrain_.right);
62 goal_builder.add_max_ss_voltage(max_drivetrain_voltage_);
63 builder.Send(goal_builder.Finish());
Philipp Schrader4bd29b12017-02-22 04:42:27 +000064}
65
66void BaseAutonomousActor::InitializeEncoders() {
Austin Schuhbd0a40f2019-06-30 14:56:31 -070067 // Spin until we get a message.
68 WaitUntil([this]() { return drivetrain_status_fetcher_.Fetch(); });
69
70 initial_drivetrain_.left =
Alex Perrycb7da4b2019-08-28 19:35:56 -070071 drivetrain_status_fetcher_->estimated_left_position();
Austin Schuhbd0a40f2019-06-30 14:56:31 -070072 initial_drivetrain_.right =
Alex Perrycb7da4b2019-08-28 19:35:56 -070073 drivetrain_status_fetcher_->estimated_right_position();
Philipp Schrader4bd29b12017-02-22 04:42:27 +000074}
75
76void BaseAutonomousActor::StartDrive(double distance, double angle,
Alex Perrycb7da4b2019-08-28 19:35:56 -070077 ProfileParametersT linear,
78 ProfileParametersT angular) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070079 AOS_LOG(INFO, "Driving distance %f, angle %f\n", distance, angle);
Philipp Schrader4bd29b12017-02-22 04:42:27 +000080 {
81 const double dangle = angle * dt_config_.robot_radius;
82 initial_drivetrain_.left += distance - dangle;
83 initial_drivetrain_.right += distance + dangle;
84 }
85
Alex Perrycb7da4b2019-08-28 19:35:56 -070086 auto builder = drivetrain_goal_sender_.MakeBuilder();
Philipp Schrader4bd29b12017-02-22 04:42:27 +000087
Alex Perrycb7da4b2019-08-28 19:35:56 -070088 auto linear_offset = ProfileParameters::Pack(*builder.fbb(), &linear);
89 auto angular_offset = ProfileParameters::Pack(*builder.fbb(), &angular);
Philipp Schrader4bd29b12017-02-22 04:42:27 +000090
Alex Perrycb7da4b2019-08-28 19:35:56 -070091 drivetrain::Goal::Builder goal_builder =
92 builder.MakeBuilder<drivetrain::Goal>();
93
Austin Schuh872723c2019-12-25 14:38:09 -080094 goal_builder.add_controller_type(drivetrain::ControllerType::MOTION_PROFILE);
Alex Perrycb7da4b2019-08-28 19:35:56 -070095 goal_builder.add_highgear(true);
96 goal_builder.add_wheel(0.0);
97 goal_builder.add_throttle(0.0);
98 goal_builder.add_left_goal(initial_drivetrain_.left);
99 goal_builder.add_right_goal(initial_drivetrain_.right);
100 goal_builder.add_max_ss_voltage(max_drivetrain_voltage_);
101 goal_builder.add_linear(linear_offset);
102 goal_builder.add_angular(angular_offset);
103
104 builder.Send(goal_builder.Finish());
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000105}
106
107void BaseAutonomousActor::WaitUntilDoneOrCanceled(
108 ::std::unique_ptr<aos::common::actions::Action> action) {
109 if (!action) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700110 AOS_LOG(ERROR, "No action, not waiting\n");
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000111 return;
112 }
113
114 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
Austin Schuhd32b3622019-06-23 18:49:06 -0700115 event_loop()->monotonic_now(),
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000116 ::std::chrono::milliseconds(5) / 2);
117 while (true) {
118 // Poll the running bit and see if we should cancel.
119 phased_loop.SleepUntilNext();
120 if (!action->Running() || ShouldCancel()) {
121 return;
122 }
123 }
124}
125
126bool BaseAutonomousActor::WaitForDriveDone() {
127 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
Austin Schuhd32b3622019-06-23 18:49:06 -0700128 event_loop()->monotonic_now(),
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000129 ::std::chrono::milliseconds(5) / 2);
130
131 while (true) {
132 if (ShouldCancel()) {
133 return false;
134 }
135 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700136 drivetrain_status_fetcher_.Fetch();
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000137 if (IsDriveDone()) {
138 return true;
139 }
140 }
141}
142
143bool BaseAutonomousActor::IsDriveDone() {
Brian Silvermanf83678c2017-03-11 14:02:26 -0800144 static constexpr double kPositionTolerance = 0.02;
145 static constexpr double kVelocityTolerance = 0.10;
146 static constexpr double kProfileTolerance = 0.001;
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000147
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700148 if (drivetrain_status_fetcher_.get()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700149 if (::std::abs(drivetrain_status_fetcher_->profiled_left_position_goal() -
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000150 initial_drivetrain_.left) < kProfileTolerance &&
Alex Perrycb7da4b2019-08-28 19:35:56 -0700151 ::std::abs(drivetrain_status_fetcher_->profiled_right_position_goal() -
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000152 initial_drivetrain_.right) < kProfileTolerance &&
Alex Perrycb7da4b2019-08-28 19:35:56 -0700153 ::std::abs(drivetrain_status_fetcher_->estimated_left_position() -
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000154 initial_drivetrain_.left) < kPositionTolerance &&
Alex Perrycb7da4b2019-08-28 19:35:56 -0700155 ::std::abs(drivetrain_status_fetcher_->estimated_right_position() -
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000156 initial_drivetrain_.right) < kPositionTolerance &&
Alex Perrycb7da4b2019-08-28 19:35:56 -0700157 ::std::abs(drivetrain_status_fetcher_->estimated_left_velocity()) <
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000158 kVelocityTolerance &&
Alex Perrycb7da4b2019-08-28 19:35:56 -0700159 ::std::abs(drivetrain_status_fetcher_->estimated_right_velocity()) <
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000160 kVelocityTolerance) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700161 AOS_LOG(INFO, "Finished drive\n");
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000162 return true;
163 }
164 }
165 return false;
166}
167
168bool BaseAutonomousActor::WaitForAboveAngle(double angle) {
169 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
Austin Schuhd32b3622019-06-23 18:49:06 -0700170 event_loop()->monotonic_now(),
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000171 ::std::chrono::milliseconds(5) / 2);
172 while (true) {
173 if (ShouldCancel()) {
174 return false;
175 }
176 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700177 drivetrain_status_fetcher_.Fetch();
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000178 if (IsDriveDone()) {
179 return true;
180 }
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700181 if (drivetrain_status_fetcher_.get()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700182 if (drivetrain_status_fetcher_->ground_angle() > angle) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000183 return true;
184 }
185 }
186 }
187}
188
189bool BaseAutonomousActor::WaitForBelowAngle(double angle) {
190 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
Austin Schuhd32b3622019-06-23 18:49:06 -0700191 event_loop()->monotonic_now(),
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000192 ::std::chrono::milliseconds(5) / 2);
193 while (true) {
194 if (ShouldCancel()) {
195 return false;
196 }
197 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700198 drivetrain_status_fetcher_.Fetch();
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000199 if (IsDriveDone()) {
200 return true;
201 }
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700202 if (drivetrain_status_fetcher_.get()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700203 if (drivetrain_status_fetcher_->ground_angle() < angle) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000204 return true;
205 }
206 }
207 }
208}
209
210bool BaseAutonomousActor::WaitForMaxBy(double angle) {
211 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
Austin Schuhd32b3622019-06-23 18:49:06 -0700212 event_loop()->monotonic_now(),
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000213 ::std::chrono::milliseconds(5) / 2);
214 double max_angle = -M_PI;
215 while (true) {
216 if (ShouldCancel()) {
217 return false;
218 }
219 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700220 drivetrain_status_fetcher_.Fetch();
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000221 if (IsDriveDone()) {
222 return true;
223 }
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700224 if (drivetrain_status_fetcher_.get()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700225 if (drivetrain_status_fetcher_->ground_angle() > max_angle) {
226 max_angle = drivetrain_status_fetcher_->ground_angle();
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000227 }
Alex Perrycb7da4b2019-08-28 19:35:56 -0700228 if (drivetrain_status_fetcher_->ground_angle() < max_angle - angle) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000229 return true;
230 }
231 }
232 }
233}
234
235bool BaseAutonomousActor::WaitForDriveNear(double distance, double angle) {
236 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
Austin Schuhd32b3622019-06-23 18:49:06 -0700237 event_loop()->monotonic_now(),
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000238 ::std::chrono::milliseconds(5) / 2);
239 constexpr double kPositionTolerance = 0.02;
240 constexpr double kProfileTolerance = 0.001;
241
Austin Schuhe6af9992018-07-08 15:59:14 -0700242 bool drive_has_been_close = false;
243 bool turn_has_been_close = false;
244 bool printed_first = false;
245
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000246 while (true) {
247 if (ShouldCancel()) {
248 return false;
249 }
250 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700251 drivetrain_status_fetcher_.Fetch();
252 if (drivetrain_status_fetcher_.get()) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000253 const double left_profile_error =
254 (initial_drivetrain_.left -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700255 drivetrain_status_fetcher_->profiled_left_position_goal());
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000256 const double right_profile_error =
257 (initial_drivetrain_.right -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700258 drivetrain_status_fetcher_->profiled_right_position_goal());
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000259
260 const double left_error =
261 (initial_drivetrain_.left -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700262 drivetrain_status_fetcher_->estimated_left_position());
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000263 const double right_error =
264 (initial_drivetrain_.right -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700265 drivetrain_status_fetcher_->estimated_right_position());
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000266
267 const double profile_distance_to_go =
268 (left_profile_error + right_profile_error) / 2.0;
269 const double profile_angle_to_go =
270 (right_profile_error - left_profile_error) /
271 (dt_config_.robot_radius * 2.0);
272
273 const double distance_to_go = (left_error + right_error) / 2.0;
274 const double angle_to_go =
275 (right_error - left_error) / (dt_config_.robot_radius * 2.0);
276
Austin Schuhe6af9992018-07-08 15:59:14 -0700277 const bool drive_close =
278 ::std::abs(profile_distance_to_go) < distance + kProfileTolerance &&
279 ::std::abs(distance_to_go) < distance + kPositionTolerance;
280 const bool turn_close =
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000281 ::std::abs(profile_angle_to_go) < angle + kProfileTolerance &&
Austin Schuhe6af9992018-07-08 15:59:14 -0700282 ::std::abs(angle_to_go) < angle + kPositionTolerance;
283
284 drive_has_been_close |= drive_close;
285 turn_has_been_close |= turn_close;
286 if (drive_has_been_close && !turn_has_been_close && !printed_first) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700287 AOS_LOG(INFO, "Drive finished first\n");
Austin Schuhe6af9992018-07-08 15:59:14 -0700288 printed_first = true;
289 } else if (!drive_has_been_close && turn_has_been_close &&
290 !printed_first) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700291 AOS_LOG(INFO, "Turn finished first\n");
Austin Schuhe6af9992018-07-08 15:59:14 -0700292 printed_first = true;
293 }
294
295 if (drive_close && turn_close) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700296 AOS_LOG(INFO, "Closer than %f < %f distance, %f < %f angle\n",
297 distance_to_go, distance, angle_to_go, angle);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000298 return true;
299 }
300 }
301 }
302}
303
Austin Schuh0aae9242018-03-14 19:49:44 -0700304bool BaseAutonomousActor::WaitForDriveProfileNear(double tolerance) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000305 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
Austin Schuhd32b3622019-06-23 18:49:06 -0700306 event_loop()->monotonic_now(),
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000307 ::std::chrono::milliseconds(5) / 2);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000308 while (true) {
309 if (ShouldCancel()) {
310 return false;
311 }
312 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700313 drivetrain_status_fetcher_.Fetch();
Austin Schuh0aae9242018-03-14 19:49:44 -0700314
315 const Eigen::Matrix<double, 7, 1> current_error =
316 (Eigen::Matrix<double, 7, 1>()
317 << initial_drivetrain_.left -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700318 drivetrain_status_fetcher_->profiled_left_position_goal(),
Austin Schuh0aae9242018-03-14 19:49:44 -0700319 0.0, initial_drivetrain_.right -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700320 drivetrain_status_fetcher_->profiled_right_position_goal(),
Austin Schuh0aae9242018-03-14 19:49:44 -0700321 0.0, 0.0, 0.0, 0.0)
322 .finished();
323 const Eigen::Matrix<double, 2, 1> linear_error =
324 dt_config_.LeftRightToLinear(current_error);
325
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700326 if (drivetrain_status_fetcher_.get()) {
Austin Schuh0aae9242018-03-14 19:49:44 -0700327 if (::std::abs(linear_error(0)) < tolerance) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700328 AOS_LOG(INFO, "Finished drive\n");
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000329 return true;
330 }
331 }
332 }
333}
334
Austin Schuh0aae9242018-03-14 19:49:44 -0700335bool BaseAutonomousActor::WaitForDriveProfileDone() {
336 constexpr double kProfileTolerance = 0.001;
337 return WaitForDriveProfileNear(kProfileTolerance);
338}
339
340bool BaseAutonomousActor::WaitForTurnProfileNear(double tolerance) {
Austin Schuh546a0382017-04-16 19:10:18 -0700341 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
Austin Schuhd32b3622019-06-23 18:49:06 -0700342 event_loop()->monotonic_now(),
Austin Schuh546a0382017-04-16 19:10:18 -0700343 ::std::chrono::milliseconds(5) / 2);
Austin Schuh546a0382017-04-16 19:10:18 -0700344 while (true) {
345 if (ShouldCancel()) {
346 return false;
347 }
348 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700349 drivetrain_status_fetcher_.Fetch();
Austin Schuh0aae9242018-03-14 19:49:44 -0700350
351 const Eigen::Matrix<double, 7, 1> current_error =
352 (Eigen::Matrix<double, 7, 1>()
353 << initial_drivetrain_.left -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700354 drivetrain_status_fetcher_->profiled_left_position_goal(),
Austin Schuh0aae9242018-03-14 19:49:44 -0700355 0.0, initial_drivetrain_.right -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700356 drivetrain_status_fetcher_->profiled_right_position_goal(),
Austin Schuh0aae9242018-03-14 19:49:44 -0700357 0.0, 0.0, 0.0, 0.0)
358 .finished();
359 const Eigen::Matrix<double, 2, 1> angular_error =
360 dt_config_.LeftRightToAngular(current_error);
361
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700362 if (drivetrain_status_fetcher_.get()) {
Austin Schuh0aae9242018-03-14 19:49:44 -0700363 if (::std::abs(angular_error(0)) < tolerance) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700364 AOS_LOG(INFO, "Finished turn\n");
Austin Schuh546a0382017-04-16 19:10:18 -0700365 return true;
366 }
367 }
368 }
369}
370
Austin Schuh0aae9242018-03-14 19:49:44 -0700371bool BaseAutonomousActor::WaitForTurnProfileDone() {
372 constexpr double kProfileTolerance = 0.001;
373 return WaitForTurnProfileNear(kProfileTolerance);
374}
375
Austin Schuh546a0382017-04-16 19:10:18 -0700376double BaseAutonomousActor::DriveDistanceLeft() {
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700377 drivetrain_status_fetcher_.Fetch();
378 if (drivetrain_status_fetcher_.get()) {
Austin Schuh546a0382017-04-16 19:10:18 -0700379 const double left_error =
380 (initial_drivetrain_.left -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700381 drivetrain_status_fetcher_->estimated_left_position());
Austin Schuh546a0382017-04-16 19:10:18 -0700382 const double right_error =
383 (initial_drivetrain_.right -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700384 drivetrain_status_fetcher_->estimated_right_position());
Austin Schuh546a0382017-04-16 19:10:18 -0700385
386 return (left_error + right_error) / 2.0;
387 } else {
388 return 0;
389 }
390}
391
James Kuszmaul838040b2019-04-13 15:51:02 -0700392bool BaseAutonomousActor::SplineHandle::SplineDistanceRemaining(
393 double distance) {
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700394 base_autonomous_actor_->drivetrain_status_fetcher_.Fetch();
395 if (base_autonomous_actor_->drivetrain_status_fetcher_.get()) {
James Kuszmaul04e8d6c2021-03-27 18:12:13 -0700396 // Confirm that:
397 // (a) The spline has started executiong (is_executing remains true even
398 // when we reach the end of the spline).
399 // (b) The spline that we are executing is the correct one.
400 // (c) There is less than distance distance remaining.
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700401 return base_autonomous_actor_->drivetrain_status_fetcher_
Alex Perrycb7da4b2019-08-28 19:35:56 -0700402 ->trajectory_logging()
403 ->is_executing() &&
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700404 base_autonomous_actor_->drivetrain_status_fetcher_
Alex Perrycb7da4b2019-08-28 19:35:56 -0700405 ->trajectory_logging()
James Kuszmaul04e8d6c2021-03-27 18:12:13 -0700406 ->goal_spline_handle() == spline_handle_ &&
407 base_autonomous_actor_->drivetrain_status_fetcher_
408 ->trajectory_logging()
Alex Perrycb7da4b2019-08-28 19:35:56 -0700409 ->distance_remaining() < distance;
James Kuszmaul838040b2019-04-13 15:51:02 -0700410 }
411 return false;
412}
413bool BaseAutonomousActor::SplineHandle::WaitForSplineDistanceRemaining(
414 double distance) {
Austin Schuhd32b3622019-06-23 18:49:06 -0700415 ::aos::time::PhasedLoop phased_loop(
416 ::std::chrono::milliseconds(5),
417 base_autonomous_actor_->event_loop()->monotonic_now(),
418 ::std::chrono::milliseconds(5) / 2);
James Kuszmaul838040b2019-04-13 15:51:02 -0700419 while (true) {
420 if (base_autonomous_actor_->ShouldCancel()) {
421 return false;
422 }
423 phased_loop.SleepUntilNext();
424 if (SplineDistanceRemaining(distance)) {
425 return true;
426 }
427 }
428}
429
Alex Perrycb7da4b2019-08-28 19:35:56 -0700430void BaseAutonomousActor::LineFollowAtVelocity(
431 double velocity, y2019::control_loops::drivetrain::SelectionHint hint) {
432 {
433 auto builder = drivetrain_goal_sender_.MakeBuilder();
434 drivetrain::Goal::Builder goal_builder =
435 builder.MakeBuilder<drivetrain::Goal>();
436 goal_builder.add_controller_type(
Austin Schuh872723c2019-12-25 14:38:09 -0800437 drivetrain::ControllerType::SPLINE_FOLLOWER);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700438 // TODO(james): Currently the 4.0 is copied from the
439 // line_follow_drivetrain.cc, but it is somewhat year-specific, so we should
440 // factor it out in some way.
441 goal_builder.add_throttle(velocity / 4.0);
442 builder.Send(goal_builder.Finish());
443 }
444
445 {
446 auto builder = target_selector_hint_sender_.MakeBuilder();
447 ::y2019::control_loops::drivetrain::TargetSelectorHint::Builder
448 target_hint_builder = builder.MakeBuilder<
449 ::y2019::control_loops::drivetrain::TargetSelectorHint>();
450
451 target_hint_builder.add_suggested_target(hint);
452 builder.Send(target_hint_builder.Finish());
453 }
James Kuszmaul838040b2019-04-13 15:51:02 -0700454}
455
Austin Schuh6bcc2302019-03-23 22:28:06 -0700456BaseAutonomousActor::SplineHandle BaseAutonomousActor::PlanSpline(
Alex Perrycb7da4b2019-08-28 19:35:56 -0700457 std::function<flatbuffers::Offset<frc971::MultiSpline>(
James Kuszmaul75a18c52021-03-10 22:02:07 -0800458 aos::Sender<frc971::control_loops::drivetrain::SplineGoal>::Builder
459 *builder)> &&multispline_builder,
Alex Perrycb7da4b2019-08-28 19:35:56 -0700460 SplineDirection direction) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700461 AOS_LOG(INFO, "Planning spline\n");
Austin Schuh6bcc2302019-03-23 22:28:06 -0700462
463 int32_t spline_handle = (++spline_handle_) | ((getpid() & 0xFFFF) << 15);
464
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700465 drivetrain_goal_fetcher_.Fetch();
Austin Schuh6bcc2302019-03-23 22:28:06 -0700466
James Kuszmaul75a18c52021-03-10 22:02:07 -0800467 auto builder = spline_goal_sender_.MakeBuilder();
James Kuszmaulc864bcf2019-05-01 20:17:34 -0700468
Alex Perrycb7da4b2019-08-28 19:35:56 -0700469 flatbuffers::Offset<frc971::MultiSpline> multispline_offset =
470 multispline_builder(&builder);
471
472 drivetrain::SplineGoal::Builder spline_builder =
473 builder.MakeBuilder<drivetrain::SplineGoal>();
474 spline_builder.add_spline_idx(spline_handle);
475 spline_builder.add_drive_spline_backwards(direction ==
476 SplineDirection::kBackward);
477 spline_builder.add_spline(multispline_offset);
478
James Kuszmaul99af8b52021-03-28 10:50:15 -0700479 // Calculate the starting position and yaw.
480 Eigen::Vector3d start;
481 {
482 const frc971::MultiSpline *const spline =
483 flatbuffers::GetTemporaryPointer(*builder.fbb(), multispline_offset);
484
485 start(0) = spline->spline_x()->Get(0);
486 start(1) = spline->spline_y()->Get(0);
487
488 Eigen::Matrix<double, 2, 6> control_points;
489 for (size_t ii = 0; ii < 6; ++ii) {
490 control_points(0, ii) = spline->spline_x()->Get(ii);
491 control_points(1, ii) = spline->spline_y()->Get(ii);
492 }
493
494 frc971::control_loops::drivetrain::Spline spline_object(control_points);
495 start(2) = spline_object.Theta(0);
496 if (direction == SplineDirection::kBackward) {
497 start(2) = aos::math::NormalizeAngle(start(2) + M_PI);
498 }
499 }
500
James Kuszmaul75a18c52021-03-10 22:02:07 -0800501 builder.Send(spline_builder.Finish());
Austin Schuh6bcc2302019-03-23 22:28:06 -0700502
James Kuszmaul99af8b52021-03-28 10:50:15 -0700503 return BaseAutonomousActor::SplineHandle(spline_handle, this, start);
Austin Schuh6bcc2302019-03-23 22:28:06 -0700504}
505
506bool BaseAutonomousActor::SplineHandle::IsPlanned() {
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700507 base_autonomous_actor_->drivetrain_status_fetcher_.Fetch();
Alex Perrycb7da4b2019-08-28 19:35:56 -0700508 VLOG(1) << aos::FlatbufferToJson(
509 base_autonomous_actor_->drivetrain_status_fetcher_.get());
510
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700511 if (base_autonomous_actor_->drivetrain_status_fetcher_.get() &&
James Kuszmaul75a18c52021-03-10 22:02:07 -0800512 base_autonomous_actor_->drivetrain_status_fetcher_.get()
513 ->has_trajectory_logging() &&
514 base_autonomous_actor_->drivetrain_status_fetcher_.get()
515 ->trajectory_logging()
516 ->has_available_splines()) {
517 const flatbuffers::Vector<int> *splines =
518 base_autonomous_actor_->drivetrain_status_fetcher_.get()
519 ->trajectory_logging()
520 ->available_splines();
521
522 return std::find(splines->begin(), splines->end(), spline_handle_) !=
523 splines->end();
Austin Schuh6bcc2302019-03-23 22:28:06 -0700524 }
525 return false;
526}
527
528bool BaseAutonomousActor::SplineHandle::WaitForPlan() {
Austin Schuhd32b3622019-06-23 18:49:06 -0700529 ::aos::time::PhasedLoop phased_loop(
530 ::std::chrono::milliseconds(5),
531 base_autonomous_actor_->event_loop()->monotonic_now(),
532 ::std::chrono::milliseconds(5) / 2);
Austin Schuh6bcc2302019-03-23 22:28:06 -0700533 while (true) {
534 if (base_autonomous_actor_->ShouldCancel()) {
535 return false;
536 }
537 phased_loop.SleepUntilNext();
538 if (IsPlanned()) {
539 return true;
540 }
541 }
542}
543
544void BaseAutonomousActor::SplineHandle::Start() {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700545 auto builder = base_autonomous_actor_->drivetrain_goal_sender_.MakeBuilder();
546 drivetrain::Goal::Builder goal_builder =
547 builder.MakeBuilder<drivetrain::Goal>();
Austin Schuh872723c2019-12-25 14:38:09 -0800548 goal_builder.add_controller_type(drivetrain::ControllerType::SPLINE_FOLLOWER);
Austin Schuh6bcc2302019-03-23 22:28:06 -0700549
Austin Schuhf257f3c2019-10-27 21:00:43 -0700550 AOS_LOG(INFO, "Starting spline\n");
Austin Schuh6bcc2302019-03-23 22:28:06 -0700551
Alex Perrycb7da4b2019-08-28 19:35:56 -0700552 goal_builder.add_spline_handle(spline_handle_);
Austin Schuh6bcc2302019-03-23 22:28:06 -0700553 base_autonomous_actor_->goal_spline_handle_ = spline_handle_;
554
Alex Perrycb7da4b2019-08-28 19:35:56 -0700555 builder.Send(goal_builder.Finish());
Austin Schuh6bcc2302019-03-23 22:28:06 -0700556}
557
558bool BaseAutonomousActor::SplineHandle::IsDone() {
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700559 base_autonomous_actor_->drivetrain_status_fetcher_.Fetch();
Austin Schuh6bcc2302019-03-23 22:28:06 -0700560
James Kuszmaulc73bb222019-04-07 12:15:35 -0700561 // We check that the spline we are waiting on is neither currently planning
James Kuszmaul29e417d2019-04-13 10:03:35 -0700562 // nor executing (we check is_executed because it is possible to receive
563 // status messages with is_executing false before the execution has started).
564 // We check for planning so that the user can go straight from starting the
565 // planner to executing without a WaitForPlan in between.
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700566 if (base_autonomous_actor_->drivetrain_status_fetcher_.get() &&
Alex Perrycb7da4b2019-08-28 19:35:56 -0700567 ((!base_autonomous_actor_->drivetrain_status_fetcher_
568 ->trajectory_logging()
569 ->is_executed() &&
570 base_autonomous_actor_->drivetrain_status_fetcher_->trajectory_logging()
571 ->current_spline_idx() == spline_handle_) ||
James Kuszmaul75a18c52021-03-10 22:02:07 -0800572 IsPlanned())) {
Austin Schuh6bcc2302019-03-23 22:28:06 -0700573 return false;
574 }
575 return true;
576}
577
578bool BaseAutonomousActor::SplineHandle::WaitForDone() {
Austin Schuhd32b3622019-06-23 18:49:06 -0700579 ::aos::time::PhasedLoop phased_loop(
580 ::std::chrono::milliseconds(5),
581 base_autonomous_actor_->event_loop()->monotonic_now(),
582 ::std::chrono::milliseconds(5) / 2);
Austin Schuh6bcc2302019-03-23 22:28:06 -0700583 while (true) {
584 if (base_autonomous_actor_->ShouldCancel()) {
585 return false;
586 }
587 phased_loop.SleepUntilNext();
588 if (IsDone()) {
589 return true;
590 }
591 }
592}
593
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000594} // namespace autonomous
595} // namespace frc971