blob: 492302f142e78d5bda5b909add2929526b1f1dda [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 Schuhbd0a40f2019-06-30 14:56:31 -0700433 return base_autonomous_actor_->drivetrain_status_fetcher_
Alex Perrycb7da4b2019-08-28 19:35:56 -0700434 ->trajectory_logging()
435 ->is_executing() &&
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700436 base_autonomous_actor_->drivetrain_status_fetcher_
Alex Perrycb7da4b2019-08-28 19:35:56 -0700437 ->trajectory_logging()
James Kuszmaul04e8d6c2021-03-27 18:12:13 -0700438 ->goal_spline_handle() == spline_handle_ &&
439 base_autonomous_actor_->drivetrain_status_fetcher_
440 ->trajectory_logging()
Alex Perrycb7da4b2019-08-28 19:35:56 -0700441 ->distance_remaining() < distance;
James Kuszmaul838040b2019-04-13 15:51:02 -0700442 }
443 return false;
444}
445bool BaseAutonomousActor::SplineHandle::WaitForSplineDistanceRemaining(
446 double distance) {
Austin Schuhd32b3622019-06-23 18:49:06 -0700447 ::aos::time::PhasedLoop phased_loop(
Yash Chainania6fe97b2021-12-15 21:01:11 -0800448 frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700449 base_autonomous_actor_->event_loop()->monotonic_now(),
Yash Chainania6fe97b2021-12-15 21:01:11 -0800450 ActorBase::kLoopOffset);
James Kuszmaul838040b2019-04-13 15:51:02 -0700451 while (true) {
452 if (base_autonomous_actor_->ShouldCancel()) {
453 return false;
454 }
455 phased_loop.SleepUntilNext();
456 if (SplineDistanceRemaining(distance)) {
457 return true;
458 }
459 }
460}
461
Alex Perrycb7da4b2019-08-28 19:35:56 -0700462void BaseAutonomousActor::LineFollowAtVelocity(
463 double velocity, y2019::control_loops::drivetrain::SelectionHint hint) {
464 {
465 auto builder = drivetrain_goal_sender_.MakeBuilder();
466 drivetrain::Goal::Builder goal_builder =
467 builder.MakeBuilder<drivetrain::Goal>();
468 goal_builder.add_controller_type(
Austin Schuh872723c2019-12-25 14:38:09 -0800469 drivetrain::ControllerType::SPLINE_FOLLOWER);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700470 // TODO(james): Currently the 4.0 is copied from the
471 // line_follow_drivetrain.cc, but it is somewhat year-specific, so we should
472 // factor it out in some way.
473 goal_builder.add_throttle(velocity / 4.0);
milind1f1dca32021-07-03 13:50:07 -0700474 builder.CheckOk(builder.Send(goal_builder.Finish()));
Alex Perrycb7da4b2019-08-28 19:35:56 -0700475 }
476
James Kuszmaul202e4382023-03-05 14:56:55 -0800477 if (target_selector_hint_sender_) {
478 // TODO(james): 2019? Seriously?
Alex Perrycb7da4b2019-08-28 19:35:56 -0700479 auto builder = target_selector_hint_sender_.MakeBuilder();
480 ::y2019::control_loops::drivetrain::TargetSelectorHint::Builder
481 target_hint_builder = builder.MakeBuilder<
482 ::y2019::control_loops::drivetrain::TargetSelectorHint>();
483
484 target_hint_builder.add_suggested_target(hint);
milind1f1dca32021-07-03 13:50:07 -0700485 builder.CheckOk(builder.Send(target_hint_builder.Finish()));
Alex Perrycb7da4b2019-08-28 19:35:56 -0700486 }
James Kuszmaul838040b2019-04-13 15:51:02 -0700487}
488
Austin Schuh6bcc2302019-03-23 22:28:06 -0700489BaseAutonomousActor::SplineHandle BaseAutonomousActor::PlanSpline(
Alex Perrycb7da4b2019-08-28 19:35:56 -0700490 std::function<flatbuffers::Offset<frc971::MultiSpline>(
James Kuszmaul75a18c52021-03-10 22:02:07 -0800491 aos::Sender<frc971::control_loops::drivetrain::SplineGoal>::Builder
492 *builder)> &&multispline_builder,
Alex Perrycb7da4b2019-08-28 19:35:56 -0700493 SplineDirection direction) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700494 AOS_LOG(INFO, "Planning spline\n");
Austin Schuh6bcc2302019-03-23 22:28:06 -0700495
496 int32_t spline_handle = (++spline_handle_) | ((getpid() & 0xFFFF) << 15);
497
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700498 drivetrain_goal_fetcher_.Fetch();
Austin Schuh6bcc2302019-03-23 22:28:06 -0700499
James Kuszmaul75a18c52021-03-10 22:02:07 -0800500 auto builder = spline_goal_sender_.MakeBuilder();
James Kuszmaulc864bcf2019-05-01 20:17:34 -0700501
Alex Perrycb7da4b2019-08-28 19:35:56 -0700502 flatbuffers::Offset<frc971::MultiSpline> multispline_offset =
503 multispline_builder(&builder);
504
505 drivetrain::SplineGoal::Builder spline_builder =
506 builder.MakeBuilder<drivetrain::SplineGoal>();
507 spline_builder.add_spline_idx(spline_handle);
508 spline_builder.add_drive_spline_backwards(direction ==
509 SplineDirection::kBackward);
510 spline_builder.add_spline(multispline_offset);
511
James Kuszmaul99af8b52021-03-28 10:50:15 -0700512 // Calculate the starting position and yaw.
513 Eigen::Vector3d start;
514 {
515 const frc971::MultiSpline *const spline =
516 flatbuffers::GetTemporaryPointer(*builder.fbb(), multispline_offset);
517
518 start(0) = spline->spline_x()->Get(0);
519 start(1) = spline->spline_y()->Get(0);
520
521 Eigen::Matrix<double, 2, 6> control_points;
522 for (size_t ii = 0; ii < 6; ++ii) {
523 control_points(0, ii) = spline->spline_x()->Get(ii);
524 control_points(1, ii) = spline->spline_y()->Get(ii);
525 }
526
527 frc971::control_loops::drivetrain::Spline spline_object(control_points);
528 start(2) = spline_object.Theta(0);
529 if (direction == SplineDirection::kBackward) {
530 start(2) = aos::math::NormalizeAngle(start(2) + M_PI);
531 }
532 }
533
milind1f1dca32021-07-03 13:50:07 -0700534 builder.CheckOk(builder.Send(spline_builder.Finish()));
Austin Schuh6bcc2302019-03-23 22:28:06 -0700535
James Kuszmaul99af8b52021-03-28 10:50:15 -0700536 return BaseAutonomousActor::SplineHandle(spline_handle, this, start);
Austin Schuh6bcc2302019-03-23 22:28:06 -0700537}
538
539bool BaseAutonomousActor::SplineHandle::IsPlanned() {
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700540 base_autonomous_actor_->drivetrain_status_fetcher_.Fetch();
Alex Perrycb7da4b2019-08-28 19:35:56 -0700541 VLOG(1) << aos::FlatbufferToJson(
542 base_autonomous_actor_->drivetrain_status_fetcher_.get());
543
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700544 if (base_autonomous_actor_->drivetrain_status_fetcher_.get() &&
James Kuszmaul75a18c52021-03-10 22:02:07 -0800545 base_autonomous_actor_->drivetrain_status_fetcher_.get()
546 ->has_trajectory_logging() &&
547 base_autonomous_actor_->drivetrain_status_fetcher_.get()
548 ->trajectory_logging()
549 ->has_available_splines()) {
550 const flatbuffers::Vector<int> *splines =
551 base_autonomous_actor_->drivetrain_status_fetcher_.get()
552 ->trajectory_logging()
553 ->available_splines();
554
555 return std::find(splines->begin(), splines->end(), spline_handle_) !=
556 splines->end();
Austin Schuh6bcc2302019-03-23 22:28:06 -0700557 }
558 return false;
559}
560
561bool BaseAutonomousActor::SplineHandle::WaitForPlan() {
Austin Schuhd32b3622019-06-23 18:49:06 -0700562 ::aos::time::PhasedLoop phased_loop(
Yash Chainania6fe97b2021-12-15 21:01:11 -0800563 frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700564 base_autonomous_actor_->event_loop()->monotonic_now(),
Yash Chainania6fe97b2021-12-15 21:01:11 -0800565 ActorBase::kLoopOffset);
Austin Schuh6bcc2302019-03-23 22:28:06 -0700566 while (true) {
567 if (base_autonomous_actor_->ShouldCancel()) {
568 return false;
569 }
570 phased_loop.SleepUntilNext();
571 if (IsPlanned()) {
572 return true;
573 }
574 }
575}
576
577void BaseAutonomousActor::SplineHandle::Start() {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700578 auto builder = base_autonomous_actor_->drivetrain_goal_sender_.MakeBuilder();
579 drivetrain::Goal::Builder goal_builder =
580 builder.MakeBuilder<drivetrain::Goal>();
Austin Schuh872723c2019-12-25 14:38:09 -0800581 goal_builder.add_controller_type(drivetrain::ControllerType::SPLINE_FOLLOWER);
Austin Schuh6bcc2302019-03-23 22:28:06 -0700582
Austin Schuhf257f3c2019-10-27 21:00:43 -0700583 AOS_LOG(INFO, "Starting spline\n");
Austin Schuh6bcc2302019-03-23 22:28:06 -0700584
Alex Perrycb7da4b2019-08-28 19:35:56 -0700585 goal_builder.add_spline_handle(spline_handle_);
Austin Schuh6bcc2302019-03-23 22:28:06 -0700586 base_autonomous_actor_->goal_spline_handle_ = spline_handle_;
587
milind1f1dca32021-07-03 13:50:07 -0700588 builder.CheckOk(builder.Send(goal_builder.Finish()));
Austin Schuh6bcc2302019-03-23 22:28:06 -0700589}
590
591bool BaseAutonomousActor::SplineHandle::IsDone() {
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700592 base_autonomous_actor_->drivetrain_status_fetcher_.Fetch();
Austin Schuh6bcc2302019-03-23 22:28:06 -0700593
James Kuszmaulc73bb222019-04-07 12:15:35 -0700594 // We check that the spline we are waiting on is neither currently planning
James Kuszmaul29e417d2019-04-13 10:03:35 -0700595 // nor executing (we check is_executed because it is possible to receive
596 // status messages with is_executing false before the execution has started).
597 // We check for planning so that the user can go straight from starting the
598 // planner to executing without a WaitForPlan in between.
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700599 if (base_autonomous_actor_->drivetrain_status_fetcher_.get() &&
Alex Perrycb7da4b2019-08-28 19:35:56 -0700600 ((!base_autonomous_actor_->drivetrain_status_fetcher_
601 ->trajectory_logging()
602 ->is_executed() &&
603 base_autonomous_actor_->drivetrain_status_fetcher_->trajectory_logging()
604 ->current_spline_idx() == spline_handle_) ||
James Kuszmaul75a18c52021-03-10 22:02:07 -0800605 IsPlanned())) {
Austin Schuh6bcc2302019-03-23 22:28:06 -0700606 return false;
607 }
608 return true;
609}
610
611bool BaseAutonomousActor::SplineHandle::WaitForDone() {
Austin Schuhd32b3622019-06-23 18:49:06 -0700612 ::aos::time::PhasedLoop phased_loop(
Yash Chainania6fe97b2021-12-15 21:01:11 -0800613 frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700614 base_autonomous_actor_->event_loop()->monotonic_now(),
Yash Chainania6fe97b2021-12-15 21:01:11 -0800615 ActorBase::kLoopOffset);
Austin Schuh6bcc2302019-03-23 22:28:06 -0700616 while (true) {
617 if (base_autonomous_actor_->ShouldCancel()) {
618 return false;
619 }
620 phased_loop.SleepUntilNext();
621 if (IsDone()) {
622 return true;
623 }
624 }
625}
626
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000627} // namespace autonomous
628} // namespace frc971