blob: ca6cc89a1be6c0367d893d16f4050cdf5f7cc764 [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
180bool BaseAutonomousActor::WaitForAboveAngle(double angle) {
Yash Chainania6fe97b2021-12-15 21:01:11 -0800181 ::aos::time::PhasedLoop phased_loop(frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700182 event_loop()->monotonic_now(),
Yash Chainania6fe97b2021-12-15 21:01:11 -0800183 ActorBase::kLoopOffset);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000184 while (true) {
185 if (ShouldCancel()) {
186 return false;
187 }
188 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700189 drivetrain_status_fetcher_.Fetch();
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000190 if (IsDriveDone()) {
191 return true;
192 }
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700193 if (drivetrain_status_fetcher_.get()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700194 if (drivetrain_status_fetcher_->ground_angle() > angle) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000195 return true;
196 }
197 }
198 }
199}
200
201bool BaseAutonomousActor::WaitForBelowAngle(double angle) {
Yash Chainania6fe97b2021-12-15 21:01:11 -0800202 ::aos::time::PhasedLoop phased_loop(frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700203 event_loop()->monotonic_now(),
Yash Chainania6fe97b2021-12-15 21:01:11 -0800204 ActorBase::kLoopOffset);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000205 while (true) {
206 if (ShouldCancel()) {
207 return false;
208 }
209 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700210 drivetrain_status_fetcher_.Fetch();
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000211 if (IsDriveDone()) {
212 return true;
213 }
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700214 if (drivetrain_status_fetcher_.get()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700215 if (drivetrain_status_fetcher_->ground_angle() < angle) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000216 return true;
217 }
218 }
219 }
220}
221
222bool BaseAutonomousActor::WaitForMaxBy(double angle) {
Yash Chainania6fe97b2021-12-15 21:01:11 -0800223 ::aos::time::PhasedLoop phased_loop(frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700224 event_loop()->monotonic_now(),
Yash Chainania6fe97b2021-12-15 21:01:11 -0800225 ActorBase::kLoopOffset);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000226 double max_angle = -M_PI;
227 while (true) {
228 if (ShouldCancel()) {
229 return false;
230 }
231 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700232 drivetrain_status_fetcher_.Fetch();
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000233 if (IsDriveDone()) {
234 return true;
235 }
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700236 if (drivetrain_status_fetcher_.get()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700237 if (drivetrain_status_fetcher_->ground_angle() > max_angle) {
238 max_angle = drivetrain_status_fetcher_->ground_angle();
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000239 }
Alex Perrycb7da4b2019-08-28 19:35:56 -0700240 if (drivetrain_status_fetcher_->ground_angle() < max_angle - angle) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000241 return true;
242 }
243 }
244 }
245}
246
247bool BaseAutonomousActor::WaitForDriveNear(double distance, double angle) {
Yash Chainania6fe97b2021-12-15 21:01:11 -0800248 ::aos::time::PhasedLoop phased_loop(frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700249 event_loop()->monotonic_now(),
Yash Chainania6fe97b2021-12-15 21:01:11 -0800250 ActorBase::kLoopOffset);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000251 constexpr double kPositionTolerance = 0.02;
252 constexpr double kProfileTolerance = 0.001;
253
Austin Schuhe6af9992018-07-08 15:59:14 -0700254 bool drive_has_been_close = false;
255 bool turn_has_been_close = false;
256 bool printed_first = false;
257
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000258 while (true) {
259 if (ShouldCancel()) {
260 return false;
261 }
262 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700263 drivetrain_status_fetcher_.Fetch();
264 if (drivetrain_status_fetcher_.get()) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000265 const double left_profile_error =
266 (initial_drivetrain_.left -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700267 drivetrain_status_fetcher_->profiled_left_position_goal());
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000268 const double right_profile_error =
269 (initial_drivetrain_.right -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700270 drivetrain_status_fetcher_->profiled_right_position_goal());
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000271
272 const double left_error =
273 (initial_drivetrain_.left -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700274 drivetrain_status_fetcher_->estimated_left_position());
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000275 const double right_error =
276 (initial_drivetrain_.right -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700277 drivetrain_status_fetcher_->estimated_right_position());
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000278
279 const double profile_distance_to_go =
280 (left_profile_error + right_profile_error) / 2.0;
281 const double profile_angle_to_go =
282 (right_profile_error - left_profile_error) /
283 (dt_config_.robot_radius * 2.0);
284
285 const double distance_to_go = (left_error + right_error) / 2.0;
286 const double angle_to_go =
287 (right_error - left_error) / (dt_config_.robot_radius * 2.0);
288
Austin Schuhe6af9992018-07-08 15:59:14 -0700289 const bool drive_close =
290 ::std::abs(profile_distance_to_go) < distance + kProfileTolerance &&
291 ::std::abs(distance_to_go) < distance + kPositionTolerance;
292 const bool turn_close =
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000293 ::std::abs(profile_angle_to_go) < angle + kProfileTolerance &&
Austin Schuhe6af9992018-07-08 15:59:14 -0700294 ::std::abs(angle_to_go) < angle + kPositionTolerance;
295
296 drive_has_been_close |= drive_close;
297 turn_has_been_close |= turn_close;
298 if (drive_has_been_close && !turn_has_been_close && !printed_first) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700299 AOS_LOG(INFO, "Drive finished first\n");
Austin Schuhe6af9992018-07-08 15:59:14 -0700300 printed_first = true;
301 } else if (!drive_has_been_close && turn_has_been_close &&
302 !printed_first) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700303 AOS_LOG(INFO, "Turn finished first\n");
Austin Schuhe6af9992018-07-08 15:59:14 -0700304 printed_first = true;
305 }
306
307 if (drive_close && turn_close) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700308 AOS_LOG(INFO, "Closer than %f < %f distance, %f < %f angle\n",
309 distance_to_go, distance, angle_to_go, angle);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000310 return true;
311 }
312 }
313 }
314}
315
Austin Schuh0aae9242018-03-14 19:49:44 -0700316bool BaseAutonomousActor::WaitForDriveProfileNear(double tolerance) {
Yash Chainania6fe97b2021-12-15 21:01:11 -0800317 ::aos::time::PhasedLoop phased_loop(frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700318 event_loop()->monotonic_now(),
Yash Chainania6fe97b2021-12-15 21:01:11 -0800319 ActorBase::kLoopOffset);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000320 while (true) {
321 if (ShouldCancel()) {
322 return false;
323 }
324 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700325 drivetrain_status_fetcher_.Fetch();
Austin Schuh0aae9242018-03-14 19:49:44 -0700326
327 const Eigen::Matrix<double, 7, 1> current_error =
328 (Eigen::Matrix<double, 7, 1>()
329 << initial_drivetrain_.left -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700330 drivetrain_status_fetcher_->profiled_left_position_goal(),
Tyler Chatowbf0609c2021-07-31 16:13:27 -0700331 0.0,
332 initial_drivetrain_.right -
333 drivetrain_status_fetcher_->profiled_right_position_goal(),
Austin Schuh0aae9242018-03-14 19:49:44 -0700334 0.0, 0.0, 0.0, 0.0)
335 .finished();
336 const Eigen::Matrix<double, 2, 1> linear_error =
337 dt_config_.LeftRightToLinear(current_error);
338
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700339 if (drivetrain_status_fetcher_.get()) {
Austin Schuh0aae9242018-03-14 19:49:44 -0700340 if (::std::abs(linear_error(0)) < tolerance) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700341 AOS_LOG(INFO, "Finished drive\n");
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000342 return true;
343 }
344 }
345 }
346}
347
Austin Schuh0aae9242018-03-14 19:49:44 -0700348bool BaseAutonomousActor::WaitForDriveProfileDone() {
349 constexpr double kProfileTolerance = 0.001;
350 return WaitForDriveProfileNear(kProfileTolerance);
351}
352
353bool BaseAutonomousActor::WaitForTurnProfileNear(double tolerance) {
Yash Chainania6fe97b2021-12-15 21:01:11 -0800354 ::aos::time::PhasedLoop phased_loop(frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700355 event_loop()->monotonic_now(),
Yash Chainania6fe97b2021-12-15 21:01:11 -0800356 ActorBase::kLoopOffset);
Austin Schuh546a0382017-04-16 19:10:18 -0700357 while (true) {
358 if (ShouldCancel()) {
359 return false;
360 }
361 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700362 drivetrain_status_fetcher_.Fetch();
Austin Schuh0aae9242018-03-14 19:49:44 -0700363
364 const Eigen::Matrix<double, 7, 1> current_error =
365 (Eigen::Matrix<double, 7, 1>()
366 << initial_drivetrain_.left -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700367 drivetrain_status_fetcher_->profiled_left_position_goal(),
Tyler Chatowbf0609c2021-07-31 16:13:27 -0700368 0.0,
369 initial_drivetrain_.right -
370 drivetrain_status_fetcher_->profiled_right_position_goal(),
Austin Schuh0aae9242018-03-14 19:49:44 -0700371 0.0, 0.0, 0.0, 0.0)
372 .finished();
373 const Eigen::Matrix<double, 2, 1> angular_error =
374 dt_config_.LeftRightToAngular(current_error);
375
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700376 if (drivetrain_status_fetcher_.get()) {
Austin Schuh0aae9242018-03-14 19:49:44 -0700377 if (::std::abs(angular_error(0)) < tolerance) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700378 AOS_LOG(INFO, "Finished turn\n");
Austin Schuh546a0382017-04-16 19:10:18 -0700379 return true;
380 }
381 }
382 }
383}
384
Austin Schuh0aae9242018-03-14 19:49:44 -0700385bool BaseAutonomousActor::WaitForTurnProfileDone() {
386 constexpr double kProfileTolerance = 0.001;
387 return WaitForTurnProfileNear(kProfileTolerance);
388}
389
Austin Schuh546a0382017-04-16 19:10:18 -0700390double BaseAutonomousActor::DriveDistanceLeft() {
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700391 drivetrain_status_fetcher_.Fetch();
392 if (drivetrain_status_fetcher_.get()) {
Austin Schuh546a0382017-04-16 19:10:18 -0700393 const double left_error =
394 (initial_drivetrain_.left -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700395 drivetrain_status_fetcher_->estimated_left_position());
Austin Schuh546a0382017-04-16 19:10:18 -0700396 const double right_error =
397 (initial_drivetrain_.right -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700398 drivetrain_status_fetcher_->estimated_right_position());
Austin Schuh546a0382017-04-16 19:10:18 -0700399
400 return (left_error + right_error) / 2.0;
401 } else {
402 return 0;
403 }
404}
405
James Kuszmaul838040b2019-04-13 15:51:02 -0700406bool BaseAutonomousActor::SplineHandle::SplineDistanceRemaining(
407 double distance) {
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700408 base_autonomous_actor_->drivetrain_status_fetcher_.Fetch();
409 if (base_autonomous_actor_->drivetrain_status_fetcher_.get()) {
James Kuszmaul04e8d6c2021-03-27 18:12:13 -0700410 // Confirm that:
411 // (a) The spline has started executiong (is_executing remains true even
412 // when we reach the end of the spline).
413 // (b) The spline that we are executing is the correct one.
414 // (c) There is less than distance distance remaining.
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700415 return base_autonomous_actor_->drivetrain_status_fetcher_
Alex Perrycb7da4b2019-08-28 19:35:56 -0700416 ->trajectory_logging()
417 ->is_executing() &&
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700418 base_autonomous_actor_->drivetrain_status_fetcher_
Alex Perrycb7da4b2019-08-28 19:35:56 -0700419 ->trajectory_logging()
James Kuszmaul04e8d6c2021-03-27 18:12:13 -0700420 ->goal_spline_handle() == spline_handle_ &&
421 base_autonomous_actor_->drivetrain_status_fetcher_
422 ->trajectory_logging()
Alex Perrycb7da4b2019-08-28 19:35:56 -0700423 ->distance_remaining() < distance;
James Kuszmaul838040b2019-04-13 15:51:02 -0700424 }
425 return false;
426}
427bool BaseAutonomousActor::SplineHandle::WaitForSplineDistanceRemaining(
428 double distance) {
Austin Schuhd32b3622019-06-23 18:49:06 -0700429 ::aos::time::PhasedLoop phased_loop(
Yash Chainania6fe97b2021-12-15 21:01:11 -0800430 frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700431 base_autonomous_actor_->event_loop()->monotonic_now(),
Yash Chainania6fe97b2021-12-15 21:01:11 -0800432 ActorBase::kLoopOffset);
James Kuszmaul838040b2019-04-13 15:51:02 -0700433 while (true) {
434 if (base_autonomous_actor_->ShouldCancel()) {
435 return false;
436 }
437 phased_loop.SleepUntilNext();
438 if (SplineDistanceRemaining(distance)) {
439 return true;
440 }
441 }
442}
443
Alex Perrycb7da4b2019-08-28 19:35:56 -0700444void BaseAutonomousActor::LineFollowAtVelocity(
445 double velocity, y2019::control_loops::drivetrain::SelectionHint hint) {
446 {
447 auto builder = drivetrain_goal_sender_.MakeBuilder();
448 drivetrain::Goal::Builder goal_builder =
449 builder.MakeBuilder<drivetrain::Goal>();
450 goal_builder.add_controller_type(
Austin Schuh872723c2019-12-25 14:38:09 -0800451 drivetrain::ControllerType::SPLINE_FOLLOWER);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700452 // TODO(james): Currently the 4.0 is copied from the
453 // line_follow_drivetrain.cc, but it is somewhat year-specific, so we should
454 // factor it out in some way.
455 goal_builder.add_throttle(velocity / 4.0);
milind1f1dca32021-07-03 13:50:07 -0700456 builder.CheckOk(builder.Send(goal_builder.Finish()));
Alex Perrycb7da4b2019-08-28 19:35:56 -0700457 }
458
James Kuszmaul202e4382023-03-05 14:56:55 -0800459 if (target_selector_hint_sender_) {
460 // TODO(james): 2019? Seriously?
Alex Perrycb7da4b2019-08-28 19:35:56 -0700461 auto builder = target_selector_hint_sender_.MakeBuilder();
462 ::y2019::control_loops::drivetrain::TargetSelectorHint::Builder
463 target_hint_builder = builder.MakeBuilder<
464 ::y2019::control_loops::drivetrain::TargetSelectorHint>();
465
466 target_hint_builder.add_suggested_target(hint);
milind1f1dca32021-07-03 13:50:07 -0700467 builder.CheckOk(builder.Send(target_hint_builder.Finish()));
Alex Perrycb7da4b2019-08-28 19:35:56 -0700468 }
James Kuszmaul838040b2019-04-13 15:51:02 -0700469}
470
Austin Schuh6bcc2302019-03-23 22:28:06 -0700471BaseAutonomousActor::SplineHandle BaseAutonomousActor::PlanSpline(
Alex Perrycb7da4b2019-08-28 19:35:56 -0700472 std::function<flatbuffers::Offset<frc971::MultiSpline>(
James Kuszmaul75a18c52021-03-10 22:02:07 -0800473 aos::Sender<frc971::control_loops::drivetrain::SplineGoal>::Builder
474 *builder)> &&multispline_builder,
Alex Perrycb7da4b2019-08-28 19:35:56 -0700475 SplineDirection direction) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700476 AOS_LOG(INFO, "Planning spline\n");
Austin Schuh6bcc2302019-03-23 22:28:06 -0700477
478 int32_t spline_handle = (++spline_handle_) | ((getpid() & 0xFFFF) << 15);
479
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700480 drivetrain_goal_fetcher_.Fetch();
Austin Schuh6bcc2302019-03-23 22:28:06 -0700481
James Kuszmaul75a18c52021-03-10 22:02:07 -0800482 auto builder = spline_goal_sender_.MakeBuilder();
James Kuszmaulc864bcf2019-05-01 20:17:34 -0700483
Alex Perrycb7da4b2019-08-28 19:35:56 -0700484 flatbuffers::Offset<frc971::MultiSpline> multispline_offset =
485 multispline_builder(&builder);
486
487 drivetrain::SplineGoal::Builder spline_builder =
488 builder.MakeBuilder<drivetrain::SplineGoal>();
489 spline_builder.add_spline_idx(spline_handle);
490 spline_builder.add_drive_spline_backwards(direction ==
491 SplineDirection::kBackward);
492 spline_builder.add_spline(multispline_offset);
493
James Kuszmaul99af8b52021-03-28 10:50:15 -0700494 // Calculate the starting position and yaw.
495 Eigen::Vector3d start;
496 {
497 const frc971::MultiSpline *const spline =
498 flatbuffers::GetTemporaryPointer(*builder.fbb(), multispline_offset);
499
500 start(0) = spline->spline_x()->Get(0);
501 start(1) = spline->spline_y()->Get(0);
502
503 Eigen::Matrix<double, 2, 6> control_points;
504 for (size_t ii = 0; ii < 6; ++ii) {
505 control_points(0, ii) = spline->spline_x()->Get(ii);
506 control_points(1, ii) = spline->spline_y()->Get(ii);
507 }
508
509 frc971::control_loops::drivetrain::Spline spline_object(control_points);
510 start(2) = spline_object.Theta(0);
511 if (direction == SplineDirection::kBackward) {
512 start(2) = aos::math::NormalizeAngle(start(2) + M_PI);
513 }
514 }
515
milind1f1dca32021-07-03 13:50:07 -0700516 builder.CheckOk(builder.Send(spline_builder.Finish()));
Austin Schuh6bcc2302019-03-23 22:28:06 -0700517
James Kuszmaul99af8b52021-03-28 10:50:15 -0700518 return BaseAutonomousActor::SplineHandle(spline_handle, this, start);
Austin Schuh6bcc2302019-03-23 22:28:06 -0700519}
520
521bool BaseAutonomousActor::SplineHandle::IsPlanned() {
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700522 base_autonomous_actor_->drivetrain_status_fetcher_.Fetch();
Alex Perrycb7da4b2019-08-28 19:35:56 -0700523 VLOG(1) << aos::FlatbufferToJson(
524 base_autonomous_actor_->drivetrain_status_fetcher_.get());
525
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700526 if (base_autonomous_actor_->drivetrain_status_fetcher_.get() &&
James Kuszmaul75a18c52021-03-10 22:02:07 -0800527 base_autonomous_actor_->drivetrain_status_fetcher_.get()
528 ->has_trajectory_logging() &&
529 base_autonomous_actor_->drivetrain_status_fetcher_.get()
530 ->trajectory_logging()
531 ->has_available_splines()) {
532 const flatbuffers::Vector<int> *splines =
533 base_autonomous_actor_->drivetrain_status_fetcher_.get()
534 ->trajectory_logging()
535 ->available_splines();
536
537 return std::find(splines->begin(), splines->end(), spline_handle_) !=
538 splines->end();
Austin Schuh6bcc2302019-03-23 22:28:06 -0700539 }
540 return false;
541}
542
543bool BaseAutonomousActor::SplineHandle::WaitForPlan() {
Austin Schuhd32b3622019-06-23 18:49:06 -0700544 ::aos::time::PhasedLoop phased_loop(
Yash Chainania6fe97b2021-12-15 21:01:11 -0800545 frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700546 base_autonomous_actor_->event_loop()->monotonic_now(),
Yash Chainania6fe97b2021-12-15 21:01:11 -0800547 ActorBase::kLoopOffset);
Austin Schuh6bcc2302019-03-23 22:28:06 -0700548 while (true) {
549 if (base_autonomous_actor_->ShouldCancel()) {
550 return false;
551 }
552 phased_loop.SleepUntilNext();
553 if (IsPlanned()) {
554 return true;
555 }
556 }
557}
558
559void BaseAutonomousActor::SplineHandle::Start() {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700560 auto builder = base_autonomous_actor_->drivetrain_goal_sender_.MakeBuilder();
561 drivetrain::Goal::Builder goal_builder =
562 builder.MakeBuilder<drivetrain::Goal>();
Austin Schuh872723c2019-12-25 14:38:09 -0800563 goal_builder.add_controller_type(drivetrain::ControllerType::SPLINE_FOLLOWER);
Austin Schuh6bcc2302019-03-23 22:28:06 -0700564
Austin Schuhf257f3c2019-10-27 21:00:43 -0700565 AOS_LOG(INFO, "Starting spline\n");
Austin Schuh6bcc2302019-03-23 22:28:06 -0700566
Alex Perrycb7da4b2019-08-28 19:35:56 -0700567 goal_builder.add_spline_handle(spline_handle_);
Austin Schuh6bcc2302019-03-23 22:28:06 -0700568 base_autonomous_actor_->goal_spline_handle_ = spline_handle_;
569
milind1f1dca32021-07-03 13:50:07 -0700570 builder.CheckOk(builder.Send(goal_builder.Finish()));
Austin Schuh6bcc2302019-03-23 22:28:06 -0700571}
572
573bool BaseAutonomousActor::SplineHandle::IsDone() {
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700574 base_autonomous_actor_->drivetrain_status_fetcher_.Fetch();
Austin Schuh6bcc2302019-03-23 22:28:06 -0700575
James Kuszmaulc73bb222019-04-07 12:15:35 -0700576 // We check that the spline we are waiting on is neither currently planning
James Kuszmaul29e417d2019-04-13 10:03:35 -0700577 // nor executing (we check is_executed because it is possible to receive
578 // status messages with is_executing false before the execution has started).
579 // We check for planning so that the user can go straight from starting the
580 // planner to executing without a WaitForPlan in between.
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700581 if (base_autonomous_actor_->drivetrain_status_fetcher_.get() &&
Alex Perrycb7da4b2019-08-28 19:35:56 -0700582 ((!base_autonomous_actor_->drivetrain_status_fetcher_
583 ->trajectory_logging()
584 ->is_executed() &&
585 base_autonomous_actor_->drivetrain_status_fetcher_->trajectory_logging()
586 ->current_spline_idx() == spline_handle_) ||
James Kuszmaul75a18c52021-03-10 22:02:07 -0800587 IsPlanned())) {
Austin Schuh6bcc2302019-03-23 22:28:06 -0700588 return false;
589 }
590 return true;
591}
592
593bool BaseAutonomousActor::SplineHandle::WaitForDone() {
Austin Schuhd32b3622019-06-23 18:49:06 -0700594 ::aos::time::PhasedLoop phased_loop(
Yash Chainania6fe97b2021-12-15 21:01:11 -0800595 frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700596 base_autonomous_actor_->event_loop()->monotonic_now(),
Yash Chainania6fe97b2021-12-15 21:01:11 -0800597 ActorBase::kLoopOffset);
Austin Schuh6bcc2302019-03-23 22:28:06 -0700598 while (true) {
599 if (base_autonomous_actor_->ShouldCancel()) {
600 return false;
601 }
602 phased_loop.SleepUntilNext();
603 if (IsDone()) {
604 return true;
605 }
606 }
607}
608
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000609} // namespace autonomous
610} // namespace frc971