blob: a8858ea304ce6c4f6618cd0a8a76a5560d4135db [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
Stephan Pleinesf63bde82024-01-13 15:59:33 -080021namespace frc971::autonomous {
Philipp Schrader4bd29b12017-02-22 04:42:27 +000022
23BaseAutonomousActor::BaseAutonomousActor(
Austin Schuh1bf8a212019-05-26 22:13:14 -070024 ::aos::EventLoop *event_loop,
Austin Schuhbcce26a2018-03-26 23:41:24 -070025 const control_loops::drivetrain::DrivetrainConfig<double> &dt_config)
Alex Perrycb7da4b2019-08-28 19:35:56 -070026 : aos::common::actions::ActorBase<Goal>(event_loop, "/autonomous"),
Philipp Schrader4bd29b12017-02-22 04:42:27 +000027 dt_config_(dt_config),
Austin Schuhc087b102019-05-12 15:33:12 -070028 initial_drivetrain_({0.0, 0.0}),
29 target_selector_hint_sender_(
James Kuszmaul202e4382023-03-05 14:56:55 -080030 event_loop->TryMakeSender<
Austin Schuhc087b102019-05-12 15:33:12 -070031 ::y2019::control_loops::drivetrain::TargetSelectorHint>(
Alex Perrycb7da4b2019-08-28 19:35:56 -070032 "/drivetrain")),
Austin Schuhbd0a40f2019-06-30 14:56:31 -070033 drivetrain_goal_sender_(
Alex Perrycb7da4b2019-08-28 19:35:56 -070034 event_loop->MakeSender<drivetrain::Goal>("/drivetrain")),
James Kuszmaul75a18c52021-03-10 22:02:07 -080035 spline_goal_sender_(
36 event_loop->MakeSender<drivetrain::SplineGoal>("/drivetrain")),
Austin Schuhbd0a40f2019-06-30 14:56:31 -070037 drivetrain_status_fetcher_(
Alex Perrycb7da4b2019-08-28 19:35:56 -070038 event_loop->MakeFetcher<drivetrain::Status>("/drivetrain")),
Austin Schuhbd0a40f2019-06-30 14:56:31 -070039 drivetrain_goal_fetcher_(
Austin Schuh094d09b2020-11-20 23:26:52 -080040 event_loop->MakeFetcher<drivetrain::Goal>("/drivetrain")) {
41 event_loop->SetRuntimeRealtimePriority(29);
42}
Philipp Schrader4bd29b12017-02-22 04:42:27 +000043
Austin Schuh9aa78b12021-11-12 11:53:33 -080044void BaseAutonomousActor::ApplyThrottle(double throttle) {
45 goal_spline_handle_ = 0;
46
47 auto builder = drivetrain_goal_sender_.MakeBuilder();
48
49 drivetrain::Goal::Builder goal_builder =
50 builder.MakeBuilder<drivetrain::Goal>();
51 goal_builder.add_controller_type(drivetrain::ControllerType::POLYDRIVE);
52 goal_builder.add_highgear(true);
53 goal_builder.add_wheel(0.0);
54 goal_builder.add_throttle(throttle);
milind1f1dca32021-07-03 13:50:07 -070055 builder.CheckOk(builder.Send(goal_builder.Finish()));
Austin Schuh9aa78b12021-11-12 11:53:33 -080056}
57
Philipp Schrader4bd29b12017-02-22 04:42:27 +000058void BaseAutonomousActor::ResetDrivetrain() {
Austin Schuhf257f3c2019-10-27 21:00:43 -070059 AOS_LOG(INFO, "resetting the drivetrain\n");
Austin Schuh0aae9242018-03-14 19:49:44 -070060 max_drivetrain_voltage_ = 12.0;
James Kuszmaulc73bb222019-04-07 12:15:35 -070061 goal_spline_handle_ = 0;
Austin Schuhbd0a40f2019-06-30 14:56:31 -070062
Alex Perrycb7da4b2019-08-28 19:35:56 -070063 auto builder = drivetrain_goal_sender_.MakeBuilder();
64
65 drivetrain::Goal::Builder goal_builder =
66 builder.MakeBuilder<drivetrain::Goal>();
Austin Schuh872723c2019-12-25 14:38:09 -080067 goal_builder.add_controller_type(drivetrain::ControllerType::POLYDRIVE);
Alex Perrycb7da4b2019-08-28 19:35:56 -070068 goal_builder.add_highgear(true);
69 goal_builder.add_wheel(0.0);
70 goal_builder.add_throttle(0.0);
71 goal_builder.add_left_goal(initial_drivetrain_.left);
72 goal_builder.add_right_goal(initial_drivetrain_.right);
73 goal_builder.add_max_ss_voltage(max_drivetrain_voltage_);
milind1f1dca32021-07-03 13:50:07 -070074 builder.CheckOk(builder.Send(goal_builder.Finish()));
Philipp Schrader4bd29b12017-02-22 04:42:27 +000075}
76
77void BaseAutonomousActor::InitializeEncoders() {
Austin Schuhbd0a40f2019-06-30 14:56:31 -070078 // Spin until we get a message.
79 WaitUntil([this]() { return drivetrain_status_fetcher_.Fetch(); });
80
81 initial_drivetrain_.left =
Alex Perrycb7da4b2019-08-28 19:35:56 -070082 drivetrain_status_fetcher_->estimated_left_position();
Austin Schuhbd0a40f2019-06-30 14:56:31 -070083 initial_drivetrain_.right =
Alex Perrycb7da4b2019-08-28 19:35:56 -070084 drivetrain_status_fetcher_->estimated_right_position();
Philipp Schrader4bd29b12017-02-22 04:42:27 +000085}
86
87void BaseAutonomousActor::StartDrive(double distance, double angle,
Alex Perrycb7da4b2019-08-28 19:35:56 -070088 ProfileParametersT linear,
89 ProfileParametersT angular) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070090 AOS_LOG(INFO, "Driving distance %f, angle %f\n", distance, angle);
Philipp Schrader4bd29b12017-02-22 04:42:27 +000091 {
92 const double dangle = angle * dt_config_.robot_radius;
93 initial_drivetrain_.left += distance - dangle;
94 initial_drivetrain_.right += distance + dangle;
95 }
96
Alex Perrycb7da4b2019-08-28 19:35:56 -070097 auto builder = drivetrain_goal_sender_.MakeBuilder();
Philipp Schrader4bd29b12017-02-22 04:42:27 +000098
Alex Perrycb7da4b2019-08-28 19:35:56 -070099 auto linear_offset = ProfileParameters::Pack(*builder.fbb(), &linear);
100 auto angular_offset = ProfileParameters::Pack(*builder.fbb(), &angular);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000101
Alex Perrycb7da4b2019-08-28 19:35:56 -0700102 drivetrain::Goal::Builder goal_builder =
103 builder.MakeBuilder<drivetrain::Goal>();
104
Austin Schuh872723c2019-12-25 14:38:09 -0800105 goal_builder.add_controller_type(drivetrain::ControllerType::MOTION_PROFILE);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700106 goal_builder.add_highgear(true);
107 goal_builder.add_wheel(0.0);
108 goal_builder.add_throttle(0.0);
109 goal_builder.add_left_goal(initial_drivetrain_.left);
110 goal_builder.add_right_goal(initial_drivetrain_.right);
111 goal_builder.add_max_ss_voltage(max_drivetrain_voltage_);
112 goal_builder.add_linear(linear_offset);
113 goal_builder.add_angular(angular_offset);
114
milind1f1dca32021-07-03 13:50:07 -0700115 builder.CheckOk(builder.Send(goal_builder.Finish()));
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000116}
117
118void BaseAutonomousActor::WaitUntilDoneOrCanceled(
119 ::std::unique_ptr<aos::common::actions::Action> action) {
120 if (!action) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700121 AOS_LOG(ERROR, "No action, not waiting\n");
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000122 return;
123 }
124
Yash Chainania6fe97b2021-12-15 21:01:11 -0800125 ::aos::time::PhasedLoop phased_loop(frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700126 event_loop()->monotonic_now(),
Stephan Pleines743f83a2024-02-02 18:32:09 -0800127 aos::common::actions::kLoopOffset);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000128 while (true) {
129 // Poll the running bit and see if we should cancel.
130 phased_loop.SleepUntilNext();
131 if (!action->Running() || ShouldCancel()) {
132 return;
133 }
134 }
135}
136
137bool BaseAutonomousActor::WaitForDriveDone() {
Yash Chainania6fe97b2021-12-15 21:01:11 -0800138 ::aos::time::PhasedLoop phased_loop(frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700139 event_loop()->monotonic_now(),
Stephan Pleines743f83a2024-02-02 18:32:09 -0800140 aos::common::actions::kLoopOffset);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000141
142 while (true) {
143 if (ShouldCancel()) {
144 return false;
145 }
146 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700147 drivetrain_status_fetcher_.Fetch();
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000148 if (IsDriveDone()) {
149 return true;
150 }
151 }
152}
153
154bool BaseAutonomousActor::IsDriveDone() {
Brian Silvermanf83678c2017-03-11 14:02:26 -0800155 static constexpr double kPositionTolerance = 0.02;
156 static constexpr double kVelocityTolerance = 0.10;
157 static constexpr double kProfileTolerance = 0.001;
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000158
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700159 if (drivetrain_status_fetcher_.get()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700160 if (::std::abs(drivetrain_status_fetcher_->profiled_left_position_goal() -
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000161 initial_drivetrain_.left) < kProfileTolerance &&
Alex Perrycb7da4b2019-08-28 19:35:56 -0700162 ::std::abs(drivetrain_status_fetcher_->profiled_right_position_goal() -
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000163 initial_drivetrain_.right) < kProfileTolerance &&
Alex Perrycb7da4b2019-08-28 19:35:56 -0700164 ::std::abs(drivetrain_status_fetcher_->estimated_left_position() -
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000165 initial_drivetrain_.left) < kPositionTolerance &&
Alex Perrycb7da4b2019-08-28 19:35:56 -0700166 ::std::abs(drivetrain_status_fetcher_->estimated_right_position() -
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000167 initial_drivetrain_.right) < kPositionTolerance &&
Alex Perrycb7da4b2019-08-28 19:35:56 -0700168 ::std::abs(drivetrain_status_fetcher_->estimated_left_velocity()) <
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000169 kVelocityTolerance &&
Alex Perrycb7da4b2019-08-28 19:35:56 -0700170 ::std::abs(drivetrain_status_fetcher_->estimated_right_velocity()) <
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000171 kVelocityTolerance) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700172 AOS_LOG(INFO, "Finished drive\n");
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000173 return true;
174 }
175 }
176 return false;
177}
178
Austin Schuha5fefcd2023-03-22 20:23:42 -0700179double BaseAutonomousActor::X() {
180 drivetrain_status_fetcher_.Fetch();
181 CHECK(drivetrain_status_fetcher_.get());
182 return drivetrain_status_fetcher_->x();
183}
184
185double BaseAutonomousActor::Y() {
186 drivetrain_status_fetcher_.Fetch();
187 CHECK(drivetrain_status_fetcher_.get());
188 return drivetrain_status_fetcher_->y();
189}
190
191double BaseAutonomousActor::Theta() {
192 drivetrain_status_fetcher_.Fetch();
193 CHECK(drivetrain_status_fetcher_.get());
194 return drivetrain_status_fetcher_->theta();
195}
196
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000197bool BaseAutonomousActor::WaitForAboveAngle(double angle) {
Yash Chainania6fe97b2021-12-15 21:01:11 -0800198 ::aos::time::PhasedLoop phased_loop(frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700199 event_loop()->monotonic_now(),
Stephan Pleines743f83a2024-02-02 18:32:09 -0800200 aos::common::actions::kLoopOffset);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000201 while (true) {
202 if (ShouldCancel()) {
203 return false;
204 }
205 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700206 drivetrain_status_fetcher_.Fetch();
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000207 if (IsDriveDone()) {
208 return true;
209 }
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700210 if (drivetrain_status_fetcher_.get()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700211 if (drivetrain_status_fetcher_->ground_angle() > angle) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000212 return true;
213 }
214 }
215 }
216}
217
218bool BaseAutonomousActor::WaitForBelowAngle(double angle) {
Yash Chainania6fe97b2021-12-15 21:01:11 -0800219 ::aos::time::PhasedLoop phased_loop(frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700220 event_loop()->monotonic_now(),
Stephan Pleines743f83a2024-02-02 18:32:09 -0800221 aos::common::actions::kLoopOffset);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000222 while (true) {
223 if (ShouldCancel()) {
224 return false;
225 }
226 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700227 drivetrain_status_fetcher_.Fetch();
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000228 if (IsDriveDone()) {
229 return true;
230 }
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700231 if (drivetrain_status_fetcher_.get()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700232 if (drivetrain_status_fetcher_->ground_angle() < angle) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000233 return true;
234 }
235 }
236 }
237}
238
239bool BaseAutonomousActor::WaitForMaxBy(double angle) {
Yash Chainania6fe97b2021-12-15 21:01:11 -0800240 ::aos::time::PhasedLoop phased_loop(frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700241 event_loop()->monotonic_now(),
Stephan Pleines743f83a2024-02-02 18:32:09 -0800242 aos::common::actions::kLoopOffset);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000243 double max_angle = -M_PI;
244 while (true) {
245 if (ShouldCancel()) {
246 return false;
247 }
248 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700249 drivetrain_status_fetcher_.Fetch();
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000250 if (IsDriveDone()) {
251 return true;
252 }
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700253 if (drivetrain_status_fetcher_.get()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700254 if (drivetrain_status_fetcher_->ground_angle() > max_angle) {
255 max_angle = drivetrain_status_fetcher_->ground_angle();
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000256 }
Alex Perrycb7da4b2019-08-28 19:35:56 -0700257 if (drivetrain_status_fetcher_->ground_angle() < max_angle - angle) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000258 return true;
259 }
260 }
261 }
262}
263
264bool BaseAutonomousActor::WaitForDriveNear(double distance, double angle) {
Yash Chainania6fe97b2021-12-15 21:01:11 -0800265 ::aos::time::PhasedLoop phased_loop(frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700266 event_loop()->monotonic_now(),
Stephan Pleines743f83a2024-02-02 18:32:09 -0800267 aos::common::actions::kLoopOffset);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000268 constexpr double kPositionTolerance = 0.02;
269 constexpr double kProfileTolerance = 0.001;
270
Austin Schuhe6af9992018-07-08 15:59:14 -0700271 bool drive_has_been_close = false;
272 bool turn_has_been_close = false;
273 bool printed_first = false;
274
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000275 while (true) {
276 if (ShouldCancel()) {
277 return false;
278 }
279 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700280 drivetrain_status_fetcher_.Fetch();
281 if (drivetrain_status_fetcher_.get()) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000282 const double left_profile_error =
283 (initial_drivetrain_.left -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700284 drivetrain_status_fetcher_->profiled_left_position_goal());
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000285 const double right_profile_error =
286 (initial_drivetrain_.right -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700287 drivetrain_status_fetcher_->profiled_right_position_goal());
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000288
289 const double left_error =
290 (initial_drivetrain_.left -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700291 drivetrain_status_fetcher_->estimated_left_position());
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000292 const double right_error =
293 (initial_drivetrain_.right -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700294 drivetrain_status_fetcher_->estimated_right_position());
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000295
296 const double profile_distance_to_go =
297 (left_profile_error + right_profile_error) / 2.0;
298 const double profile_angle_to_go =
299 (right_profile_error - left_profile_error) /
300 (dt_config_.robot_radius * 2.0);
301
302 const double distance_to_go = (left_error + right_error) / 2.0;
303 const double angle_to_go =
304 (right_error - left_error) / (dt_config_.robot_radius * 2.0);
305
Austin Schuhe6af9992018-07-08 15:59:14 -0700306 const bool drive_close =
307 ::std::abs(profile_distance_to_go) < distance + kProfileTolerance &&
308 ::std::abs(distance_to_go) < distance + kPositionTolerance;
309 const bool turn_close =
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000310 ::std::abs(profile_angle_to_go) < angle + kProfileTolerance &&
Austin Schuhe6af9992018-07-08 15:59:14 -0700311 ::std::abs(angle_to_go) < angle + kPositionTolerance;
312
313 drive_has_been_close |= drive_close;
314 turn_has_been_close |= turn_close;
315 if (drive_has_been_close && !turn_has_been_close && !printed_first) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700316 AOS_LOG(INFO, "Drive finished first\n");
Austin Schuhe6af9992018-07-08 15:59:14 -0700317 printed_first = true;
318 } else if (!drive_has_been_close && turn_has_been_close &&
319 !printed_first) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700320 AOS_LOG(INFO, "Turn finished first\n");
Austin Schuhe6af9992018-07-08 15:59:14 -0700321 printed_first = true;
322 }
323
324 if (drive_close && turn_close) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700325 AOS_LOG(INFO, "Closer than %f < %f distance, %f < %f angle\n",
326 distance_to_go, distance, angle_to_go, angle);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000327 return true;
328 }
329 }
330 }
331}
332
Austin Schuh0aae9242018-03-14 19:49:44 -0700333bool BaseAutonomousActor::WaitForDriveProfileNear(double tolerance) {
Yash Chainania6fe97b2021-12-15 21:01:11 -0800334 ::aos::time::PhasedLoop phased_loop(frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700335 event_loop()->monotonic_now(),
Stephan Pleines743f83a2024-02-02 18:32:09 -0800336 aos::common::actions::kLoopOffset);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000337 while (true) {
338 if (ShouldCancel()) {
339 return false;
340 }
341 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700342 drivetrain_status_fetcher_.Fetch();
Austin Schuh0aae9242018-03-14 19:49:44 -0700343
344 const Eigen::Matrix<double, 7, 1> current_error =
345 (Eigen::Matrix<double, 7, 1>()
346 << initial_drivetrain_.left -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700347 drivetrain_status_fetcher_->profiled_left_position_goal(),
Tyler Chatowbf0609c2021-07-31 16:13:27 -0700348 0.0,
349 initial_drivetrain_.right -
350 drivetrain_status_fetcher_->profiled_right_position_goal(),
Austin Schuh0aae9242018-03-14 19:49:44 -0700351 0.0, 0.0, 0.0, 0.0)
352 .finished();
353 const Eigen::Matrix<double, 2, 1> linear_error =
354 dt_config_.LeftRightToLinear(current_error);
355
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700356 if (drivetrain_status_fetcher_.get()) {
Austin Schuh0aae9242018-03-14 19:49:44 -0700357 if (::std::abs(linear_error(0)) < tolerance) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700358 AOS_LOG(INFO, "Finished drive\n");
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000359 return true;
360 }
361 }
362 }
363}
364
Austin Schuh0aae9242018-03-14 19:49:44 -0700365bool BaseAutonomousActor::WaitForDriveProfileDone() {
366 constexpr double kProfileTolerance = 0.001;
367 return WaitForDriveProfileNear(kProfileTolerance);
368}
369
370bool BaseAutonomousActor::WaitForTurnProfileNear(double tolerance) {
Yash Chainania6fe97b2021-12-15 21:01:11 -0800371 ::aos::time::PhasedLoop phased_loop(frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700372 event_loop()->monotonic_now(),
Stephan Pleines743f83a2024-02-02 18:32:09 -0800373 aos::common::actions::kLoopOffset);
Austin Schuh546a0382017-04-16 19:10:18 -0700374 while (true) {
375 if (ShouldCancel()) {
376 return false;
377 }
378 phased_loop.SleepUntilNext();
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700379 drivetrain_status_fetcher_.Fetch();
Austin Schuh0aae9242018-03-14 19:49:44 -0700380
381 const Eigen::Matrix<double, 7, 1> current_error =
382 (Eigen::Matrix<double, 7, 1>()
383 << initial_drivetrain_.left -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700384 drivetrain_status_fetcher_->profiled_left_position_goal(),
Tyler Chatowbf0609c2021-07-31 16:13:27 -0700385 0.0,
386 initial_drivetrain_.right -
387 drivetrain_status_fetcher_->profiled_right_position_goal(),
Austin Schuh0aae9242018-03-14 19:49:44 -0700388 0.0, 0.0, 0.0, 0.0)
389 .finished();
390 const Eigen::Matrix<double, 2, 1> angular_error =
391 dt_config_.LeftRightToAngular(current_error);
392
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700393 if (drivetrain_status_fetcher_.get()) {
Austin Schuh0aae9242018-03-14 19:49:44 -0700394 if (::std::abs(angular_error(0)) < tolerance) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700395 AOS_LOG(INFO, "Finished turn\n");
Austin Schuh546a0382017-04-16 19:10:18 -0700396 return true;
397 }
398 }
399 }
400}
401
Austin Schuh0aae9242018-03-14 19:49:44 -0700402bool BaseAutonomousActor::WaitForTurnProfileDone() {
403 constexpr double kProfileTolerance = 0.001;
404 return WaitForTurnProfileNear(kProfileTolerance);
405}
406
Austin Schuh546a0382017-04-16 19:10:18 -0700407double BaseAutonomousActor::DriveDistanceLeft() {
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700408 drivetrain_status_fetcher_.Fetch();
409 if (drivetrain_status_fetcher_.get()) {
Austin Schuh546a0382017-04-16 19:10:18 -0700410 const double left_error =
411 (initial_drivetrain_.left -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700412 drivetrain_status_fetcher_->estimated_left_position());
Austin Schuh546a0382017-04-16 19:10:18 -0700413 const double right_error =
414 (initial_drivetrain_.right -
Alex Perrycb7da4b2019-08-28 19:35:56 -0700415 drivetrain_status_fetcher_->estimated_right_position());
Austin Schuh546a0382017-04-16 19:10:18 -0700416
417 return (left_error + right_error) / 2.0;
418 } else {
419 return 0;
420 }
421}
422
James Kuszmaul838040b2019-04-13 15:51:02 -0700423bool BaseAutonomousActor::SplineHandle::SplineDistanceRemaining(
424 double distance) {
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700425 base_autonomous_actor_->drivetrain_status_fetcher_.Fetch();
426 if (base_autonomous_actor_->drivetrain_status_fetcher_.get()) {
James Kuszmaul04e8d6c2021-03-27 18:12:13 -0700427 // Confirm that:
428 // (a) The spline has started executiong (is_executing remains true even
429 // when we reach the end of the spline).
430 // (b) The spline that we are executing is the correct one.
431 // (c) There is less than distance distance remaining.
Austin Schuh034c34e2023-03-22 20:24:06 -0700432 if (base_autonomous_actor_->drivetrain_status_fetcher_->trajectory_logging()
433 ->goal_spline_handle() != spline_handle_) {
434 // Never done if we aren't the active spline.
435 return false;
436 }
437
438 if (base_autonomous_actor_->drivetrain_status_fetcher_->trajectory_logging()
439 ->is_executed()) {
440 return true;
441 }
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700442 return base_autonomous_actor_->drivetrain_status_fetcher_
Alex Perrycb7da4b2019-08-28 19:35:56 -0700443 ->trajectory_logging()
444 ->is_executing() &&
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700445 base_autonomous_actor_->drivetrain_status_fetcher_
Alex Perrycb7da4b2019-08-28 19:35:56 -0700446 ->trajectory_logging()
447 ->distance_remaining() < distance;
James Kuszmaul838040b2019-04-13 15:51:02 -0700448 }
449 return false;
450}
Austin Schuh034c34e2023-03-22 20:24:06 -0700451
Austin Schuh1a843772023-04-09 22:18:05 -0700452bool BaseAutonomousActor::SplineHandle::SplineDistanceTraveled(
453 double distance) {
454 base_autonomous_actor_->drivetrain_status_fetcher_.Fetch();
455 if (base_autonomous_actor_->drivetrain_status_fetcher_.get()) {
456 // Confirm that:
457 // (a) The spline has started executiong (is_executing remains true even
458 // when we reach the end of the spline).
459 // (b) The spline that we are executing is the correct one.
460 // (c) There is less than distance distance remaining.
461 if (base_autonomous_actor_->drivetrain_status_fetcher_->trajectory_logging()
462 ->goal_spline_handle() != spline_handle_) {
463 // Never done if we aren't the active spline.
464 return false;
465 }
466
467 if (base_autonomous_actor_->drivetrain_status_fetcher_->trajectory_logging()
468 ->is_executed()) {
469 return true;
470 }
471 return base_autonomous_actor_->drivetrain_status_fetcher_
472 ->trajectory_logging()
473 ->is_executing() &&
474 base_autonomous_actor_->drivetrain_status_fetcher_
475 ->trajectory_logging()
476 ->distance_traveled() > distance;
477 }
478 return false;
479}
480
James Kuszmaul838040b2019-04-13 15:51:02 -0700481bool BaseAutonomousActor::SplineHandle::WaitForSplineDistanceRemaining(
482 double distance) {
Austin Schuhd32b3622019-06-23 18:49:06 -0700483 ::aos::time::PhasedLoop phased_loop(
Yash Chainania6fe97b2021-12-15 21:01:11 -0800484 frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700485 base_autonomous_actor_->event_loop()->monotonic_now(),
Stephan Pleines743f83a2024-02-02 18:32:09 -0800486 aos::common::actions::kLoopOffset);
James Kuszmaul838040b2019-04-13 15:51:02 -0700487 while (true) {
488 if (base_autonomous_actor_->ShouldCancel()) {
489 return false;
490 }
491 phased_loop.SleepUntilNext();
492 if (SplineDistanceRemaining(distance)) {
493 return true;
494 }
495 }
496}
497
Austin Schuh1a843772023-04-09 22:18:05 -0700498bool BaseAutonomousActor::SplineHandle::WaitForSplineDistanceTraveled(
499 double distance) {
500 ::aos::time::PhasedLoop phased_loop(
501 frc971::controls::kLoopFrequency,
502 base_autonomous_actor_->event_loop()->monotonic_now(),
Stephan Pleines743f83a2024-02-02 18:32:09 -0800503 aos::common::actions::kLoopOffset);
Austin Schuh1a843772023-04-09 22:18:05 -0700504 while (true) {
505 if (base_autonomous_actor_->ShouldCancel()) {
506 return false;
507 }
508 phased_loop.SleepUntilNext();
509 if (SplineDistanceTraveled(distance)) {
510 return true;
511 }
512 }
513}
514
Alex Perrycb7da4b2019-08-28 19:35:56 -0700515void BaseAutonomousActor::LineFollowAtVelocity(
516 double velocity, y2019::control_loops::drivetrain::SelectionHint hint) {
517 {
518 auto builder = drivetrain_goal_sender_.MakeBuilder();
519 drivetrain::Goal::Builder goal_builder =
520 builder.MakeBuilder<drivetrain::Goal>();
521 goal_builder.add_controller_type(
Austin Schuh872723c2019-12-25 14:38:09 -0800522 drivetrain::ControllerType::SPLINE_FOLLOWER);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700523 // TODO(james): Currently the 4.0 is copied from the
524 // line_follow_drivetrain.cc, but it is somewhat year-specific, so we should
525 // factor it out in some way.
526 goal_builder.add_throttle(velocity / 4.0);
milind1f1dca32021-07-03 13:50:07 -0700527 builder.CheckOk(builder.Send(goal_builder.Finish()));
Alex Perrycb7da4b2019-08-28 19:35:56 -0700528 }
529
James Kuszmaul202e4382023-03-05 14:56:55 -0800530 if (target_selector_hint_sender_) {
531 // TODO(james): 2019? Seriously?
Alex Perrycb7da4b2019-08-28 19:35:56 -0700532 auto builder = target_selector_hint_sender_.MakeBuilder();
533 ::y2019::control_loops::drivetrain::TargetSelectorHint::Builder
534 target_hint_builder = builder.MakeBuilder<
535 ::y2019::control_loops::drivetrain::TargetSelectorHint>();
536
537 target_hint_builder.add_suggested_target(hint);
milind1f1dca32021-07-03 13:50:07 -0700538 builder.CheckOk(builder.Send(target_hint_builder.Finish()));
Alex Perrycb7da4b2019-08-28 19:35:56 -0700539 }
James Kuszmaul838040b2019-04-13 15:51:02 -0700540}
541
Austin Schuh6bcc2302019-03-23 22:28:06 -0700542BaseAutonomousActor::SplineHandle BaseAutonomousActor::PlanSpline(
Alex Perrycb7da4b2019-08-28 19:35:56 -0700543 std::function<flatbuffers::Offset<frc971::MultiSpline>(
James Kuszmaul75a18c52021-03-10 22:02:07 -0800544 aos::Sender<frc971::control_loops::drivetrain::SplineGoal>::Builder
545 *builder)> &&multispline_builder,
Alex Perrycb7da4b2019-08-28 19:35:56 -0700546 SplineDirection direction) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700547 AOS_LOG(INFO, "Planning spline\n");
Austin Schuh6bcc2302019-03-23 22:28:06 -0700548
549 int32_t spline_handle = (++spline_handle_) | ((getpid() & 0xFFFF) << 15);
550
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700551 drivetrain_goal_fetcher_.Fetch();
Austin Schuh6bcc2302019-03-23 22:28:06 -0700552
James Kuszmaul75a18c52021-03-10 22:02:07 -0800553 auto builder = spline_goal_sender_.MakeBuilder();
James Kuszmaulc864bcf2019-05-01 20:17:34 -0700554
Alex Perrycb7da4b2019-08-28 19:35:56 -0700555 flatbuffers::Offset<frc971::MultiSpline> multispline_offset =
556 multispline_builder(&builder);
557
558 drivetrain::SplineGoal::Builder spline_builder =
559 builder.MakeBuilder<drivetrain::SplineGoal>();
560 spline_builder.add_spline_idx(spline_handle);
561 spline_builder.add_drive_spline_backwards(direction ==
562 SplineDirection::kBackward);
563 spline_builder.add_spline(multispline_offset);
564
James Kuszmaul99af8b52021-03-28 10:50:15 -0700565 // Calculate the starting position and yaw.
566 Eigen::Vector3d start;
567 {
568 const frc971::MultiSpline *const spline =
569 flatbuffers::GetTemporaryPointer(*builder.fbb(), multispline_offset);
570
571 start(0) = spline->spline_x()->Get(0);
572 start(1) = spline->spline_y()->Get(0);
573
574 Eigen::Matrix<double, 2, 6> control_points;
575 for (size_t ii = 0; ii < 6; ++ii) {
576 control_points(0, ii) = spline->spline_x()->Get(ii);
577 control_points(1, ii) = spline->spline_y()->Get(ii);
578 }
579
580 frc971::control_loops::drivetrain::Spline spline_object(control_points);
581 start(2) = spline_object.Theta(0);
582 if (direction == SplineDirection::kBackward) {
583 start(2) = aos::math::NormalizeAngle(start(2) + M_PI);
584 }
585 }
586
milind1f1dca32021-07-03 13:50:07 -0700587 builder.CheckOk(builder.Send(spline_builder.Finish()));
Austin Schuh6bcc2302019-03-23 22:28:06 -0700588
James Kuszmaul99af8b52021-03-28 10:50:15 -0700589 return BaseAutonomousActor::SplineHandle(spline_handle, this, start);
Austin Schuh6bcc2302019-03-23 22:28:06 -0700590}
591
592bool BaseAutonomousActor::SplineHandle::IsPlanned() {
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700593 base_autonomous_actor_->drivetrain_status_fetcher_.Fetch();
Alex Perrycb7da4b2019-08-28 19:35:56 -0700594 VLOG(1) << aos::FlatbufferToJson(
595 base_autonomous_actor_->drivetrain_status_fetcher_.get());
596
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700597 if (base_autonomous_actor_->drivetrain_status_fetcher_.get() &&
James Kuszmaul75a18c52021-03-10 22:02:07 -0800598 base_autonomous_actor_->drivetrain_status_fetcher_.get()
599 ->has_trajectory_logging() &&
600 base_autonomous_actor_->drivetrain_status_fetcher_.get()
601 ->trajectory_logging()
602 ->has_available_splines()) {
603 const flatbuffers::Vector<int> *splines =
604 base_autonomous_actor_->drivetrain_status_fetcher_.get()
605 ->trajectory_logging()
606 ->available_splines();
607
608 return std::find(splines->begin(), splines->end(), spline_handle_) !=
609 splines->end();
Austin Schuh6bcc2302019-03-23 22:28:06 -0700610 }
611 return false;
612}
613
614bool BaseAutonomousActor::SplineHandle::WaitForPlan() {
Austin Schuhd32b3622019-06-23 18:49:06 -0700615 ::aos::time::PhasedLoop phased_loop(
Yash Chainania6fe97b2021-12-15 21:01:11 -0800616 frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700617 base_autonomous_actor_->event_loop()->monotonic_now(),
Stephan Pleines743f83a2024-02-02 18:32:09 -0800618 aos::common::actions::kLoopOffset);
Austin Schuh6bcc2302019-03-23 22:28:06 -0700619 while (true) {
620 if (base_autonomous_actor_->ShouldCancel()) {
621 return false;
622 }
623 phased_loop.SleepUntilNext();
624 if (IsPlanned()) {
625 return true;
626 }
627 }
628}
629
630void BaseAutonomousActor::SplineHandle::Start() {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700631 auto builder = base_autonomous_actor_->drivetrain_goal_sender_.MakeBuilder();
632 drivetrain::Goal::Builder goal_builder =
633 builder.MakeBuilder<drivetrain::Goal>();
Austin Schuh872723c2019-12-25 14:38:09 -0800634 goal_builder.add_controller_type(drivetrain::ControllerType::SPLINE_FOLLOWER);
Austin Schuh6bcc2302019-03-23 22:28:06 -0700635
Austin Schuhf257f3c2019-10-27 21:00:43 -0700636 AOS_LOG(INFO, "Starting spline\n");
Austin Schuh6bcc2302019-03-23 22:28:06 -0700637
Alex Perrycb7da4b2019-08-28 19:35:56 -0700638 goal_builder.add_spline_handle(spline_handle_);
Austin Schuh6bcc2302019-03-23 22:28:06 -0700639 base_autonomous_actor_->goal_spline_handle_ = spline_handle_;
640
milind1f1dca32021-07-03 13:50:07 -0700641 builder.CheckOk(builder.Send(goal_builder.Finish()));
Austin Schuh6bcc2302019-03-23 22:28:06 -0700642}
643
644bool BaseAutonomousActor::SplineHandle::IsDone() {
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700645 base_autonomous_actor_->drivetrain_status_fetcher_.Fetch();
Austin Schuh6bcc2302019-03-23 22:28:06 -0700646
James Kuszmaulc73bb222019-04-07 12:15:35 -0700647 // We check that the spline we are waiting on is neither currently planning
James Kuszmaul29e417d2019-04-13 10:03:35 -0700648 // nor executing (we check is_executed because it is possible to receive
649 // status messages with is_executing false before the execution has started).
650 // We check for planning so that the user can go straight from starting the
651 // planner to executing without a WaitForPlan in between.
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700652 if (base_autonomous_actor_->drivetrain_status_fetcher_.get() &&
Alex Perrycb7da4b2019-08-28 19:35:56 -0700653 ((!base_autonomous_actor_->drivetrain_status_fetcher_
654 ->trajectory_logging()
655 ->is_executed() &&
656 base_autonomous_actor_->drivetrain_status_fetcher_->trajectory_logging()
657 ->current_spline_idx() == spline_handle_) ||
James Kuszmaul75a18c52021-03-10 22:02:07 -0800658 IsPlanned())) {
Austin Schuh6bcc2302019-03-23 22:28:06 -0700659 return false;
660 }
661 return true;
662}
663
664bool BaseAutonomousActor::SplineHandle::WaitForDone() {
Austin Schuhd32b3622019-06-23 18:49:06 -0700665 ::aos::time::PhasedLoop phased_loop(
Yash Chainania6fe97b2021-12-15 21:01:11 -0800666 frc971::controls::kLoopFrequency,
Austin Schuhd32b3622019-06-23 18:49:06 -0700667 base_autonomous_actor_->event_loop()->monotonic_now(),
Stephan Pleines743f83a2024-02-02 18:32:09 -0800668 aos::common::actions::kLoopOffset);
Austin Schuh6bcc2302019-03-23 22:28:06 -0700669 while (true) {
670 if (base_autonomous_actor_->ShouldCancel()) {
671 return false;
672 }
673 phased_loop.SleepUntilNext();
674 if (IsDone()) {
675 return true;
676 }
677 }
678}
679
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800680} // namespace frc971::autonomous