blob: 22909bee8856973fc5ad296d616b01a476100a44 [file] [log] [blame]
Philipp Schrader4bd29b12017-02-22 04:42:27 +00001#include "frc971/autonomous/base_autonomous_actor.h"
2
Philipp Schrader4bd29b12017-02-22 04:42:27 +00003#include <chrono>
Tyler Chatowbf0609c2021-07-31 16:13:27 -07004#include <cinttypes>
Philipp Schrader4bd29b12017-02-22 04:42:27 +00005#include <cmath>
6
Tyler Chatowbf0609c2021-07-31 16:13:27 -07007#include "aos/logging/logging.h"
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"
Alex Perrycb7da4b2019-08-28 19:35:56 -070010#include "frc971/control_loops/control_loops_generated.h"
11#include "frc971/control_loops/drivetrain/drivetrain_goal_generated.h"
12#include "frc971/control_loops/drivetrain/drivetrain_status_generated.h"
James Kuszmaul99af8b52021-03-28 10:50:15 -070013#include "frc971/control_loops/drivetrain/spline.h"
Alex Perrycb7da4b2019-08-28 19:35:56 -070014#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_(
James Kuszmaul202e4382023-03-05 14:56:55 -080031 event_loop->TryMakeSender<
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
Austin Schuh9aa78b12021-11-12 11:53:33 -080045void BaseAutonomousActor::ApplyThrottle(double throttle) {
46 goal_spline_handle_ = 0;
47
48 auto builder = drivetrain_goal_sender_.MakeBuilder();
49
50 drivetrain::Goal::Builder goal_builder =
51 builder.MakeBuilder<drivetrain::Goal>();
52 goal_builder.add_controller_type(drivetrain::ControllerType::POLYDRIVE);
53 goal_builder.add_highgear(true);
54 goal_builder.add_wheel(0.0);
55 goal_builder.add_throttle(throttle);
milind1f1dca32021-07-03 13:50:07 -070056 builder.CheckOk(builder.Send(goal_builder.Finish()));
Austin Schuh9aa78b12021-11-12 11:53:33 -080057}
58
Philipp Schrader4bd29b12017-02-22 04:42:27 +000059void BaseAutonomousActor::ResetDrivetrain() {
Austin Schuhf257f3c2019-10-27 21:00:43 -070060 AOS_LOG(INFO, "resetting the drivetrain\n");
Austin Schuh0aae9242018-03-14 19:49:44 -070061 max_drivetrain_voltage_ = 12.0;
James Kuszmaulc73bb222019-04-07 12:15:35 -070062 goal_spline_handle_ = 0;
Austin Schuhbd0a40f2019-06-30 14:56:31 -070063
Alex Perrycb7da4b2019-08-28 19:35:56 -070064 auto builder = drivetrain_goal_sender_.MakeBuilder();
65
66 drivetrain::Goal::Builder goal_builder =
67 builder.MakeBuilder<drivetrain::Goal>();
Austin Schuh872723c2019-12-25 14:38:09 -080068 goal_builder.add_controller_type(drivetrain::ControllerType::POLYDRIVE);
Alex Perrycb7da4b2019-08-28 19:35:56 -070069 goal_builder.add_highgear(true);
70 goal_builder.add_wheel(0.0);
71 goal_builder.add_throttle(0.0);
72 goal_builder.add_left_goal(initial_drivetrain_.left);
73 goal_builder.add_right_goal(initial_drivetrain_.right);
74 goal_builder.add_max_ss_voltage(max_drivetrain_voltage_);
milind1f1dca32021-07-03 13:50:07 -070075 builder.CheckOk(builder.Send(goal_builder.Finish()));
Philipp Schrader4bd29b12017-02-22 04:42:27 +000076}
77
78void BaseAutonomousActor::InitializeEncoders() {
Austin Schuhbd0a40f2019-06-30 14:56:31 -070079 // Spin until we get a message.
80 WaitUntil([this]() { return drivetrain_status_fetcher_.Fetch(); });
81
82 initial_drivetrain_.left =
Alex Perrycb7da4b2019-08-28 19:35:56 -070083 drivetrain_status_fetcher_->estimated_left_position();
Austin Schuhbd0a40f2019-06-30 14:56:31 -070084 initial_drivetrain_.right =
Alex Perrycb7da4b2019-08-28 19:35:56 -070085 drivetrain_status_fetcher_->estimated_right_position();
Philipp Schrader4bd29b12017-02-22 04:42:27 +000086}
87
88void BaseAutonomousActor::StartDrive(double distance, double angle,
Alex Perrycb7da4b2019-08-28 19:35:56 -070089 ProfileParametersT linear,
90 ProfileParametersT angular) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070091 AOS_LOG(INFO, "Driving distance %f, angle %f\n", distance, angle);
Philipp Schrader4bd29b12017-02-22 04:42:27 +000092 {
93 const double dangle = angle * dt_config_.robot_radius;
94 initial_drivetrain_.left += distance - dangle;
95 initial_drivetrain_.right += distance + dangle;
96 }
97
Alex Perrycb7da4b2019-08-28 19:35:56 -070098 auto builder = drivetrain_goal_sender_.MakeBuilder();
Philipp Schrader4bd29b12017-02-22 04:42:27 +000099
Alex Perrycb7da4b2019-08-28 19:35:56 -0700100 auto linear_offset = ProfileParameters::Pack(*builder.fbb(), &linear);
101 auto angular_offset = ProfileParameters::Pack(*builder.fbb(), &angular);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000102
Alex Perrycb7da4b2019-08-28 19:35:56 -0700103 drivetrain::Goal::Builder goal_builder =
104 builder.MakeBuilder<drivetrain::Goal>();
105
Austin Schuh872723c2019-12-25 14:38:09 -0800106 goal_builder.add_controller_type(drivetrain::ControllerType::MOTION_PROFILE);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700107 goal_builder.add_highgear(true);
108 goal_builder.add_wheel(0.0);
109 goal_builder.add_throttle(0.0);
110 goal_builder.add_left_goal(initial_drivetrain_.left);
111 goal_builder.add_right_goal(initial_drivetrain_.right);
112 goal_builder.add_max_ss_voltage(max_drivetrain_voltage_);
113 goal_builder.add_linear(linear_offset);
114 goal_builder.add_angular(angular_offset);
115
milind1f1dca32021-07-03 13:50:07 -0700116 builder.CheckOk(builder.Send(goal_builder.Finish()));
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000117}
118
119void BaseAutonomousActor::WaitUntilDoneOrCanceled(
120 ::std::unique_ptr<aos::common::actions::Action> action) {
121 if (!action) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700122 AOS_LOG(ERROR, "No action, not waiting\n");
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000123 return;
124 }
125
Yash Chainania6fe97b2021-12-15 21:01:11 -0800126 ::aos::time::PhasedLoop phased_loop(frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700127 event_loop()->monotonic_now(),
Yash Chainania6fe97b2021-12-15 21:01:11 -0800128 ActorBase::kLoopOffset);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000129 while (true) {
130 // Poll the running bit and see if we should cancel.
131 phased_loop.SleepUntilNext();
132 if (!action->Running() || ShouldCancel()) {
133 return;
134 }
135 }
136}
137
138bool BaseAutonomousActor::WaitForDriveDone() {
Yash Chainania6fe97b2021-12-15 21:01:11 -0800139 ::aos::time::PhasedLoop phased_loop(frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700140 event_loop()->monotonic_now(),
Yash Chainania6fe97b2021-12-15 21:01:11 -0800141 ActorBase::kLoopOffset);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000142
143 while (true) {
144 if (ShouldCancel()) {
145 return false;
146 }
147 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700148 drivetrain_status_fetcher_.Fetch();
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000149 if (IsDriveDone()) {
150 return true;
151 }
152 }
153}
154
155bool BaseAutonomousActor::IsDriveDone() {
Brian Silvermanf83678c2017-03-11 14:02:26 -0800156 static constexpr double kPositionTolerance = 0.02;
157 static constexpr double kVelocityTolerance = 0.10;
158 static constexpr double kProfileTolerance = 0.001;
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000159
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700160 if (drivetrain_status_fetcher_.get()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700161 if (::std::abs(drivetrain_status_fetcher_->profiled_left_position_goal() -
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000162 initial_drivetrain_.left) < kProfileTolerance &&
Alex Perrycb7da4b2019-08-28 19:35:56 -0700163 ::std::abs(drivetrain_status_fetcher_->profiled_right_position_goal() -
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000164 initial_drivetrain_.right) < kProfileTolerance &&
Alex Perrycb7da4b2019-08-28 19:35:56 -0700165 ::std::abs(drivetrain_status_fetcher_->estimated_left_position() -
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000166 initial_drivetrain_.left) < kPositionTolerance &&
Alex Perrycb7da4b2019-08-28 19:35:56 -0700167 ::std::abs(drivetrain_status_fetcher_->estimated_right_position() -
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000168 initial_drivetrain_.right) < kPositionTolerance &&
Alex Perrycb7da4b2019-08-28 19:35:56 -0700169 ::std::abs(drivetrain_status_fetcher_->estimated_left_velocity()) <
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000170 kVelocityTolerance &&
Alex Perrycb7da4b2019-08-28 19:35:56 -0700171 ::std::abs(drivetrain_status_fetcher_->estimated_right_velocity()) <
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000172 kVelocityTolerance) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700173 AOS_LOG(INFO, "Finished drive\n");
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000174 return true;
175 }
176 }
177 return false;
178}
179
Austin Schuha5fefcd2023-03-22 20:23:42 -0700180double BaseAutonomousActor::X() {
181 drivetrain_status_fetcher_.Fetch();
182 CHECK(drivetrain_status_fetcher_.get());
183 return drivetrain_status_fetcher_->x();
184}
185
186double BaseAutonomousActor::Y() {
187 drivetrain_status_fetcher_.Fetch();
188 CHECK(drivetrain_status_fetcher_.get());
189 return drivetrain_status_fetcher_->y();
190}
191
192double BaseAutonomousActor::Theta() {
193 drivetrain_status_fetcher_.Fetch();
194 CHECK(drivetrain_status_fetcher_.get());
195 return drivetrain_status_fetcher_->theta();
196}
197
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000198bool BaseAutonomousActor::WaitForAboveAngle(double angle) {
Yash Chainania6fe97b2021-12-15 21:01:11 -0800199 ::aos::time::PhasedLoop phased_loop(frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700200 event_loop()->monotonic_now(),
Yash Chainania6fe97b2021-12-15 21:01:11 -0800201 ActorBase::kLoopOffset);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000202 while (true) {
203 if (ShouldCancel()) {
204 return false;
205 }
206 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700207 drivetrain_status_fetcher_.Fetch();
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000208 if (IsDriveDone()) {
209 return true;
210 }
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700211 if (drivetrain_status_fetcher_.get()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700212 if (drivetrain_status_fetcher_->ground_angle() > angle) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000213 return true;
214 }
215 }
216 }
217}
218
219bool BaseAutonomousActor::WaitForBelowAngle(double angle) {
Yash Chainania6fe97b2021-12-15 21:01:11 -0800220 ::aos::time::PhasedLoop phased_loop(frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700221 event_loop()->monotonic_now(),
Yash Chainania6fe97b2021-12-15 21:01:11 -0800222 ActorBase::kLoopOffset);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000223 while (true) {
224 if (ShouldCancel()) {
225 return false;
226 }
227 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700228 drivetrain_status_fetcher_.Fetch();
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000229 if (IsDriveDone()) {
230 return true;
231 }
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700232 if (drivetrain_status_fetcher_.get()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700233 if (drivetrain_status_fetcher_->ground_angle() < angle) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000234 return true;
235 }
236 }
237 }
238}
239
240bool BaseAutonomousActor::WaitForMaxBy(double angle) {
Yash Chainania6fe97b2021-12-15 21:01:11 -0800241 ::aos::time::PhasedLoop phased_loop(frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700242 event_loop()->monotonic_now(),
Yash Chainania6fe97b2021-12-15 21:01:11 -0800243 ActorBase::kLoopOffset);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000244 double max_angle = -M_PI;
245 while (true) {
246 if (ShouldCancel()) {
247 return false;
248 }
249 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700250 drivetrain_status_fetcher_.Fetch();
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000251 if (IsDriveDone()) {
252 return true;
253 }
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700254 if (drivetrain_status_fetcher_.get()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700255 if (drivetrain_status_fetcher_->ground_angle() > max_angle) {
256 max_angle = drivetrain_status_fetcher_->ground_angle();
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000257 }
Alex Perrycb7da4b2019-08-28 19:35:56 -0700258 if (drivetrain_status_fetcher_->ground_angle() < max_angle - angle) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000259 return true;
260 }
261 }
262 }
263}
264
265bool BaseAutonomousActor::WaitForDriveNear(double distance, double angle) {
Yash Chainania6fe97b2021-12-15 21:01:11 -0800266 ::aos::time::PhasedLoop phased_loop(frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700267 event_loop()->monotonic_now(),
Yash Chainania6fe97b2021-12-15 21:01:11 -0800268 ActorBase::kLoopOffset);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000269 constexpr double kPositionTolerance = 0.02;
270 constexpr double kProfileTolerance = 0.001;
271
Austin Schuhe6af9992018-07-08 15:59:14 -0700272 bool drive_has_been_close = false;
273 bool turn_has_been_close = false;
274 bool printed_first = false;
275
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000276 while (true) {
277 if (ShouldCancel()) {
278 return false;
279 }
280 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700281 drivetrain_status_fetcher_.Fetch();
282 if (drivetrain_status_fetcher_.get()) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000283 const double left_profile_error =
284 (initial_drivetrain_.left -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700285 drivetrain_status_fetcher_->profiled_left_position_goal());
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000286 const double right_profile_error =
287 (initial_drivetrain_.right -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700288 drivetrain_status_fetcher_->profiled_right_position_goal());
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000289
290 const double left_error =
291 (initial_drivetrain_.left -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700292 drivetrain_status_fetcher_->estimated_left_position());
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000293 const double right_error =
294 (initial_drivetrain_.right -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700295 drivetrain_status_fetcher_->estimated_right_position());
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000296
297 const double profile_distance_to_go =
298 (left_profile_error + right_profile_error) / 2.0;
299 const double profile_angle_to_go =
300 (right_profile_error - left_profile_error) /
301 (dt_config_.robot_radius * 2.0);
302
303 const double distance_to_go = (left_error + right_error) / 2.0;
304 const double angle_to_go =
305 (right_error - left_error) / (dt_config_.robot_radius * 2.0);
306
Austin Schuhe6af9992018-07-08 15:59:14 -0700307 const bool drive_close =
308 ::std::abs(profile_distance_to_go) < distance + kProfileTolerance &&
309 ::std::abs(distance_to_go) < distance + kPositionTolerance;
310 const bool turn_close =
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000311 ::std::abs(profile_angle_to_go) < angle + kProfileTolerance &&
Austin Schuhe6af9992018-07-08 15:59:14 -0700312 ::std::abs(angle_to_go) < angle + kPositionTolerance;
313
314 drive_has_been_close |= drive_close;
315 turn_has_been_close |= turn_close;
316 if (drive_has_been_close && !turn_has_been_close && !printed_first) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700317 AOS_LOG(INFO, "Drive finished first\n");
Austin Schuhe6af9992018-07-08 15:59:14 -0700318 printed_first = true;
319 } else if (!drive_has_been_close && turn_has_been_close &&
320 !printed_first) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700321 AOS_LOG(INFO, "Turn finished first\n");
Austin Schuhe6af9992018-07-08 15:59:14 -0700322 printed_first = true;
323 }
324
325 if (drive_close && turn_close) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700326 AOS_LOG(INFO, "Closer than %f < %f distance, %f < %f angle\n",
327 distance_to_go, distance, angle_to_go, angle);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000328 return true;
329 }
330 }
331 }
332}
333
Austin Schuh0aae9242018-03-14 19:49:44 -0700334bool BaseAutonomousActor::WaitForDriveProfileNear(double tolerance) {
Yash Chainania6fe97b2021-12-15 21:01:11 -0800335 ::aos::time::PhasedLoop phased_loop(frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700336 event_loop()->monotonic_now(),
Yash Chainania6fe97b2021-12-15 21:01:11 -0800337 ActorBase::kLoopOffset);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000338 while (true) {
339 if (ShouldCancel()) {
340 return false;
341 }
342 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700343 drivetrain_status_fetcher_.Fetch();
Austin Schuh0aae9242018-03-14 19:49:44 -0700344
345 const Eigen::Matrix<double, 7, 1> current_error =
346 (Eigen::Matrix<double, 7, 1>()
347 << initial_drivetrain_.left -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700348 drivetrain_status_fetcher_->profiled_left_position_goal(),
Tyler Chatowbf0609c2021-07-31 16:13:27 -0700349 0.0,
350 initial_drivetrain_.right -
351 drivetrain_status_fetcher_->profiled_right_position_goal(),
Austin Schuh0aae9242018-03-14 19:49:44 -0700352 0.0, 0.0, 0.0, 0.0)
353 .finished();
354 const Eigen::Matrix<double, 2, 1> linear_error =
355 dt_config_.LeftRightToLinear(current_error);
356
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700357 if (drivetrain_status_fetcher_.get()) {
Austin Schuh0aae9242018-03-14 19:49:44 -0700358 if (::std::abs(linear_error(0)) < tolerance) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700359 AOS_LOG(INFO, "Finished drive\n");
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000360 return true;
361 }
362 }
363 }
364}
365
Austin Schuh0aae9242018-03-14 19:49:44 -0700366bool BaseAutonomousActor::WaitForDriveProfileDone() {
367 constexpr double kProfileTolerance = 0.001;
368 return WaitForDriveProfileNear(kProfileTolerance);
369}
370
371bool BaseAutonomousActor::WaitForTurnProfileNear(double tolerance) {
Yash Chainania6fe97b2021-12-15 21:01:11 -0800372 ::aos::time::PhasedLoop phased_loop(frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700373 event_loop()->monotonic_now(),
Yash Chainania6fe97b2021-12-15 21:01:11 -0800374 ActorBase::kLoopOffset);
Austin Schuh546a0382017-04-16 19:10:18 -0700375 while (true) {
376 if (ShouldCancel()) {
377 return false;
378 }
379 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700380 drivetrain_status_fetcher_.Fetch();
Austin Schuh0aae9242018-03-14 19:49:44 -0700381
382 const Eigen::Matrix<double, 7, 1> current_error =
383 (Eigen::Matrix<double, 7, 1>()
384 << initial_drivetrain_.left -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700385 drivetrain_status_fetcher_->profiled_left_position_goal(),
Tyler Chatowbf0609c2021-07-31 16:13:27 -0700386 0.0,
387 initial_drivetrain_.right -
388 drivetrain_status_fetcher_->profiled_right_position_goal(),
Austin Schuh0aae9242018-03-14 19:49:44 -0700389 0.0, 0.0, 0.0, 0.0)
390 .finished();
391 const Eigen::Matrix<double, 2, 1> angular_error =
392 dt_config_.LeftRightToAngular(current_error);
393
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700394 if (drivetrain_status_fetcher_.get()) {
Austin Schuh0aae9242018-03-14 19:49:44 -0700395 if (::std::abs(angular_error(0)) < tolerance) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700396 AOS_LOG(INFO, "Finished turn\n");
Austin Schuh546a0382017-04-16 19:10:18 -0700397 return true;
398 }
399 }
400 }
401}
402
Austin Schuh0aae9242018-03-14 19:49:44 -0700403bool BaseAutonomousActor::WaitForTurnProfileDone() {
404 constexpr double kProfileTolerance = 0.001;
405 return WaitForTurnProfileNear(kProfileTolerance);
406}
407
Austin Schuh546a0382017-04-16 19:10:18 -0700408double BaseAutonomousActor::DriveDistanceLeft() {
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700409 drivetrain_status_fetcher_.Fetch();
410 if (drivetrain_status_fetcher_.get()) {
Austin Schuh546a0382017-04-16 19:10:18 -0700411 const double left_error =
412 (initial_drivetrain_.left -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700413 drivetrain_status_fetcher_->estimated_left_position());
Austin Schuh546a0382017-04-16 19:10:18 -0700414 const double right_error =
415 (initial_drivetrain_.right -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700416 drivetrain_status_fetcher_->estimated_right_position());
Austin Schuh546a0382017-04-16 19:10:18 -0700417
418 return (left_error + right_error) / 2.0;
419 } else {
420 return 0;
421 }
422}
423
James Kuszmaul838040b2019-04-13 15:51:02 -0700424bool BaseAutonomousActor::SplineHandle::SplineDistanceRemaining(
425 double distance) {
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700426 base_autonomous_actor_->drivetrain_status_fetcher_.Fetch();
427 if (base_autonomous_actor_->drivetrain_status_fetcher_.get()) {
James Kuszmaul04e8d6c2021-03-27 18:12:13 -0700428 // Confirm that:
429 // (a) The spline has started executiong (is_executing remains true even
430 // when we reach the end of the spline).
431 // (b) The spline that we are executing is the correct one.
432 // (c) There is less than distance distance remaining.
Austin Schuh034c34e2023-03-22 20:24:06 -0700433 if (base_autonomous_actor_->drivetrain_status_fetcher_->trajectory_logging()
434 ->goal_spline_handle() != spline_handle_) {
435 // Never done if we aren't the active spline.
436 return false;
437 }
438
439 if (base_autonomous_actor_->drivetrain_status_fetcher_->trajectory_logging()
440 ->is_executed()) {
441 return true;
442 }
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700443 return base_autonomous_actor_->drivetrain_status_fetcher_
Alex Perrycb7da4b2019-08-28 19:35:56 -0700444 ->trajectory_logging()
445 ->is_executing() &&
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700446 base_autonomous_actor_->drivetrain_status_fetcher_
Alex Perrycb7da4b2019-08-28 19:35:56 -0700447 ->trajectory_logging()
448 ->distance_remaining() < distance;
James Kuszmaul838040b2019-04-13 15:51:02 -0700449 }
450 return false;
451}
Austin Schuh034c34e2023-03-22 20:24:06 -0700452
Austin Schuh1a843772023-04-09 22:18:05 -0700453bool BaseAutonomousActor::SplineHandle::SplineDistanceTraveled(
454 double distance) {
455 base_autonomous_actor_->drivetrain_status_fetcher_.Fetch();
456 if (base_autonomous_actor_->drivetrain_status_fetcher_.get()) {
457 // Confirm that:
458 // (a) The spline has started executiong (is_executing remains true even
459 // when we reach the end of the spline).
460 // (b) The spline that we are executing is the correct one.
461 // (c) There is less than distance distance remaining.
462 if (base_autonomous_actor_->drivetrain_status_fetcher_->trajectory_logging()
463 ->goal_spline_handle() != spline_handle_) {
464 // Never done if we aren't the active spline.
465 return false;
466 }
467
468 if (base_autonomous_actor_->drivetrain_status_fetcher_->trajectory_logging()
469 ->is_executed()) {
470 return true;
471 }
472 return base_autonomous_actor_->drivetrain_status_fetcher_
473 ->trajectory_logging()
474 ->is_executing() &&
475 base_autonomous_actor_->drivetrain_status_fetcher_
476 ->trajectory_logging()
477 ->distance_traveled() > distance;
478 }
479 return false;
480}
481
James Kuszmaul838040b2019-04-13 15:51:02 -0700482bool BaseAutonomousActor::SplineHandle::WaitForSplineDistanceRemaining(
483 double distance) {
Austin Schuhd32b3622019-06-23 18:49:06 -0700484 ::aos::time::PhasedLoop phased_loop(
Yash Chainania6fe97b2021-12-15 21:01:11 -0800485 frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700486 base_autonomous_actor_->event_loop()->monotonic_now(),
Yash Chainania6fe97b2021-12-15 21:01:11 -0800487 ActorBase::kLoopOffset);
James Kuszmaul838040b2019-04-13 15:51:02 -0700488 while (true) {
489 if (base_autonomous_actor_->ShouldCancel()) {
490 return false;
491 }
492 phased_loop.SleepUntilNext();
493 if (SplineDistanceRemaining(distance)) {
494 return true;
495 }
496 }
497}
498
Austin Schuh1a843772023-04-09 22:18:05 -0700499bool BaseAutonomousActor::SplineHandle::WaitForSplineDistanceTraveled(
500 double distance) {
501 ::aos::time::PhasedLoop phased_loop(
502 frc971::controls::kLoopFrequency,
503 base_autonomous_actor_->event_loop()->monotonic_now(),
504 ActorBase::kLoopOffset);
505 while (true) {
506 if (base_autonomous_actor_->ShouldCancel()) {
507 return false;
508 }
509 phased_loop.SleepUntilNext();
510 if (SplineDistanceTraveled(distance)) {
511 return true;
512 }
513 }
514}
515
Alex Perrycb7da4b2019-08-28 19:35:56 -0700516void BaseAutonomousActor::LineFollowAtVelocity(
517 double velocity, y2019::control_loops::drivetrain::SelectionHint hint) {
518 {
519 auto builder = drivetrain_goal_sender_.MakeBuilder();
520 drivetrain::Goal::Builder goal_builder =
521 builder.MakeBuilder<drivetrain::Goal>();
522 goal_builder.add_controller_type(
Austin Schuh872723c2019-12-25 14:38:09 -0800523 drivetrain::ControllerType::SPLINE_FOLLOWER);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700524 // TODO(james): Currently the 4.0 is copied from the
525 // line_follow_drivetrain.cc, but it is somewhat year-specific, so we should
526 // factor it out in some way.
527 goal_builder.add_throttle(velocity / 4.0);
milind1f1dca32021-07-03 13:50:07 -0700528 builder.CheckOk(builder.Send(goal_builder.Finish()));
Alex Perrycb7da4b2019-08-28 19:35:56 -0700529 }
530
James Kuszmaul202e4382023-03-05 14:56:55 -0800531 if (target_selector_hint_sender_) {
532 // TODO(james): 2019? Seriously?
Alex Perrycb7da4b2019-08-28 19:35:56 -0700533 auto builder = target_selector_hint_sender_.MakeBuilder();
534 ::y2019::control_loops::drivetrain::TargetSelectorHint::Builder
535 target_hint_builder = builder.MakeBuilder<
536 ::y2019::control_loops::drivetrain::TargetSelectorHint>();
537
538 target_hint_builder.add_suggested_target(hint);
milind1f1dca32021-07-03 13:50:07 -0700539 builder.CheckOk(builder.Send(target_hint_builder.Finish()));
Alex Perrycb7da4b2019-08-28 19:35:56 -0700540 }
James Kuszmaul838040b2019-04-13 15:51:02 -0700541}
542
Austin Schuh6bcc2302019-03-23 22:28:06 -0700543BaseAutonomousActor::SplineHandle BaseAutonomousActor::PlanSpline(
Alex Perrycb7da4b2019-08-28 19:35:56 -0700544 std::function<flatbuffers::Offset<frc971::MultiSpline>(
James Kuszmaul75a18c52021-03-10 22:02:07 -0800545 aos::Sender<frc971::control_loops::drivetrain::SplineGoal>::Builder
546 *builder)> &&multispline_builder,
Alex Perrycb7da4b2019-08-28 19:35:56 -0700547 SplineDirection direction) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700548 AOS_LOG(INFO, "Planning spline\n");
Austin Schuh6bcc2302019-03-23 22:28:06 -0700549
550 int32_t spline_handle = (++spline_handle_) | ((getpid() & 0xFFFF) << 15);
551
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700552 drivetrain_goal_fetcher_.Fetch();
Austin Schuh6bcc2302019-03-23 22:28:06 -0700553
James Kuszmaul75a18c52021-03-10 22:02:07 -0800554 auto builder = spline_goal_sender_.MakeBuilder();
James Kuszmaulc864bcf2019-05-01 20:17:34 -0700555
Alex Perrycb7da4b2019-08-28 19:35:56 -0700556 flatbuffers::Offset<frc971::MultiSpline> multispline_offset =
557 multispline_builder(&builder);
558
559 drivetrain::SplineGoal::Builder spline_builder =
560 builder.MakeBuilder<drivetrain::SplineGoal>();
561 spline_builder.add_spline_idx(spline_handle);
562 spline_builder.add_drive_spline_backwards(direction ==
563 SplineDirection::kBackward);
564 spline_builder.add_spline(multispline_offset);
565
James Kuszmaul99af8b52021-03-28 10:50:15 -0700566 // Calculate the starting position and yaw.
567 Eigen::Vector3d start;
568 {
569 const frc971::MultiSpline *const spline =
570 flatbuffers::GetTemporaryPointer(*builder.fbb(), multispline_offset);
571
572 start(0) = spline->spline_x()->Get(0);
573 start(1) = spline->spline_y()->Get(0);
574
575 Eigen::Matrix<double, 2, 6> control_points;
576 for (size_t ii = 0; ii < 6; ++ii) {
577 control_points(0, ii) = spline->spline_x()->Get(ii);
578 control_points(1, ii) = spline->spline_y()->Get(ii);
579 }
580
581 frc971::control_loops::drivetrain::Spline spline_object(control_points);
582 start(2) = spline_object.Theta(0);
583 if (direction == SplineDirection::kBackward) {
584 start(2) = aos::math::NormalizeAngle(start(2) + M_PI);
585 }
586 }
587
milind1f1dca32021-07-03 13:50:07 -0700588 builder.CheckOk(builder.Send(spline_builder.Finish()));
Austin Schuh6bcc2302019-03-23 22:28:06 -0700589
James Kuszmaul99af8b52021-03-28 10:50:15 -0700590 return BaseAutonomousActor::SplineHandle(spline_handle, this, start);
Austin Schuh6bcc2302019-03-23 22:28:06 -0700591}
592
593bool BaseAutonomousActor::SplineHandle::IsPlanned() {
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700594 base_autonomous_actor_->drivetrain_status_fetcher_.Fetch();
Alex Perrycb7da4b2019-08-28 19:35:56 -0700595 VLOG(1) << aos::FlatbufferToJson(
596 base_autonomous_actor_->drivetrain_status_fetcher_.get());
597
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700598 if (base_autonomous_actor_->drivetrain_status_fetcher_.get() &&
James Kuszmaul75a18c52021-03-10 22:02:07 -0800599 base_autonomous_actor_->drivetrain_status_fetcher_.get()
600 ->has_trajectory_logging() &&
601 base_autonomous_actor_->drivetrain_status_fetcher_.get()
602 ->trajectory_logging()
603 ->has_available_splines()) {
604 const flatbuffers::Vector<int> *splines =
605 base_autonomous_actor_->drivetrain_status_fetcher_.get()
606 ->trajectory_logging()
607 ->available_splines();
608
609 return std::find(splines->begin(), splines->end(), spline_handle_) !=
610 splines->end();
Austin Schuh6bcc2302019-03-23 22:28:06 -0700611 }
612 return false;
613}
614
615bool BaseAutonomousActor::SplineHandle::WaitForPlan() {
Austin Schuhd32b3622019-06-23 18:49:06 -0700616 ::aos::time::PhasedLoop phased_loop(
Yash Chainania6fe97b2021-12-15 21:01:11 -0800617 frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700618 base_autonomous_actor_->event_loop()->monotonic_now(),
Yash Chainania6fe97b2021-12-15 21:01:11 -0800619 ActorBase::kLoopOffset);
Austin Schuh6bcc2302019-03-23 22:28:06 -0700620 while (true) {
621 if (base_autonomous_actor_->ShouldCancel()) {
622 return false;
623 }
624 phased_loop.SleepUntilNext();
625 if (IsPlanned()) {
626 return true;
627 }
628 }
629}
630
631void BaseAutonomousActor::SplineHandle::Start() {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700632 auto builder = base_autonomous_actor_->drivetrain_goal_sender_.MakeBuilder();
633 drivetrain::Goal::Builder goal_builder =
634 builder.MakeBuilder<drivetrain::Goal>();
Austin Schuh872723c2019-12-25 14:38:09 -0800635 goal_builder.add_controller_type(drivetrain::ControllerType::SPLINE_FOLLOWER);
Austin Schuh6bcc2302019-03-23 22:28:06 -0700636
Austin Schuhf257f3c2019-10-27 21:00:43 -0700637 AOS_LOG(INFO, "Starting spline\n");
Austin Schuh6bcc2302019-03-23 22:28:06 -0700638
Alex Perrycb7da4b2019-08-28 19:35:56 -0700639 goal_builder.add_spline_handle(spline_handle_);
Austin Schuh6bcc2302019-03-23 22:28:06 -0700640 base_autonomous_actor_->goal_spline_handle_ = spline_handle_;
641
milind1f1dca32021-07-03 13:50:07 -0700642 builder.CheckOk(builder.Send(goal_builder.Finish()));
Austin Schuh6bcc2302019-03-23 22:28:06 -0700643}
644
645bool BaseAutonomousActor::SplineHandle::IsDone() {
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700646 base_autonomous_actor_->drivetrain_status_fetcher_.Fetch();
Austin Schuh6bcc2302019-03-23 22:28:06 -0700647
James Kuszmaulc73bb222019-04-07 12:15:35 -0700648 // We check that the spline we are waiting on is neither currently planning
James Kuszmaul29e417d2019-04-13 10:03:35 -0700649 // nor executing (we check is_executed because it is possible to receive
650 // status messages with is_executing false before the execution has started).
651 // We check for planning so that the user can go straight from starting the
652 // planner to executing without a WaitForPlan in between.
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700653 if (base_autonomous_actor_->drivetrain_status_fetcher_.get() &&
Alex Perrycb7da4b2019-08-28 19:35:56 -0700654 ((!base_autonomous_actor_->drivetrain_status_fetcher_
655 ->trajectory_logging()
656 ->is_executed() &&
657 base_autonomous_actor_->drivetrain_status_fetcher_->trajectory_logging()
658 ->current_spline_idx() == spline_handle_) ||
James Kuszmaul75a18c52021-03-10 22:02:07 -0800659 IsPlanned())) {
Austin Schuh6bcc2302019-03-23 22:28:06 -0700660 return false;
661 }
662 return true;
663}
664
665bool BaseAutonomousActor::SplineHandle::WaitForDone() {
Austin Schuhd32b3622019-06-23 18:49:06 -0700666 ::aos::time::PhasedLoop phased_loop(
Yash Chainania6fe97b2021-12-15 21:01:11 -0800667 frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700668 base_autonomous_actor_->event_loop()->monotonic_now(),
Yash Chainania6fe97b2021-12-15 21:01:11 -0800669 ActorBase::kLoopOffset);
Austin Schuh6bcc2302019-03-23 22:28:06 -0700670 while (true) {
671 if (base_autonomous_actor_->ShouldCancel()) {
672 return false;
673 }
674 phased_loop.SleepUntilNext();
675 if (IsDone()) {
676 return true;
677 }
678 }
679}
680
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000681} // namespace autonomous
682} // namespace frc971