blob: 04ee33412a6df5e9b45801ac1200fdd3420b79e0 [file] [log] [blame]
Philipp Schrader4bd29b12017-02-22 04:42:27 +00001#include "frc971/autonomous/base_autonomous_actor.h"
2
3#include <inttypes.h>
4
5#include <chrono>
6#include <cmath>
7
John Park33858a32018-09-28 23:05:48 -07008#include "aos/util/phased_loop.h"
9#include "aos/logging/logging.h"
Philipp Schrader4bd29b12017-02-22 04:42:27 +000010
11#include "frc971/control_loops/drivetrain/drivetrain.q.h"
12
Philipp Schrader4bd29b12017-02-22 04:42:27 +000013using ::frc971::control_loops::drivetrain_queue;
14using ::aos::monotonic_clock;
15namespace chrono = ::std::chrono;
16namespace this_thread = ::std::this_thread;
17
Brian Silvermanf83678c2017-03-11 14:02:26 -080018namespace frc971 {
19namespace autonomous {
Philipp Schrader4bd29b12017-02-22 04:42:27 +000020
21BaseAutonomousActor::BaseAutonomousActor(
22 AutonomousActionQueueGroup *s,
Austin Schuhbcce26a2018-03-26 23:41:24 -070023 const control_loops::drivetrain::DrivetrainConfig<double> &dt_config)
Philipp Schrader4bd29b12017-02-22 04:42:27 +000024 : aos::common::actions::ActorBase<AutonomousActionQueueGroup>(s),
25 dt_config_(dt_config),
26 initial_drivetrain_({0.0, 0.0}) {}
27
28void BaseAutonomousActor::ResetDrivetrain() {
29 LOG(INFO, "resetting the drivetrain\n");
Austin Schuh0aae9242018-03-14 19:49:44 -070030 max_drivetrain_voltage_ = 12.0;
Philipp Schrader4bd29b12017-02-22 04:42:27 +000031 drivetrain_queue.goal.MakeWithBuilder()
Austin Schuh78379ea2019-01-04 20:39:45 -080032 .controller_type(0)
Philipp Schrader4bd29b12017-02-22 04:42:27 +000033 .highgear(true)
Austin Schuh2b1fce02018-03-02 20:05:20 -080034 .wheel(0.0)
Philipp Schrader4bd29b12017-02-22 04:42:27 +000035 .throttle(0.0)
36 .left_goal(initial_drivetrain_.left)
37 .left_velocity_goal(0)
38 .right_goal(initial_drivetrain_.right)
39 .right_velocity_goal(0)
Austin Schuh0aae9242018-03-14 19:49:44 -070040 .max_ss_voltage(max_drivetrain_voltage_)
Philipp Schrader4bd29b12017-02-22 04:42:27 +000041 .Send();
42}
43
44void BaseAutonomousActor::InitializeEncoders() {
45 drivetrain_queue.status.FetchAnother();
46 initial_drivetrain_.left = drivetrain_queue.status->estimated_left_position;
47 initial_drivetrain_.right = drivetrain_queue.status->estimated_right_position;
48}
49
50void BaseAutonomousActor::StartDrive(double distance, double angle,
51 ProfileParameters linear,
52 ProfileParameters angular) {
53 LOG(INFO, "Driving distance %f, angle %f\n", distance, angle);
54 {
55 const double dangle = angle * dt_config_.robot_radius;
56 initial_drivetrain_.left += distance - dangle;
57 initial_drivetrain_.right += distance + dangle;
58 }
59
60 auto drivetrain_message = drivetrain_queue.goal.MakeMessage();
Austin Schuh78379ea2019-01-04 20:39:45 -080061 drivetrain_message->controller_type = 1;
Philipp Schrader4bd29b12017-02-22 04:42:27 +000062 drivetrain_message->highgear = true;
Austin Schuh2b1fce02018-03-02 20:05:20 -080063 drivetrain_message->wheel = 0.0;
Philipp Schrader4bd29b12017-02-22 04:42:27 +000064 drivetrain_message->throttle = 0.0;
65 drivetrain_message->left_goal = initial_drivetrain_.left;
66 drivetrain_message->left_velocity_goal = 0;
67 drivetrain_message->right_goal = initial_drivetrain_.right;
68 drivetrain_message->right_velocity_goal = 0;
Austin Schuh0aae9242018-03-14 19:49:44 -070069 drivetrain_message->max_ss_voltage = max_drivetrain_voltage_;
Philipp Schrader4bd29b12017-02-22 04:42:27 +000070 drivetrain_message->linear = linear;
71 drivetrain_message->angular = angular;
72
73 LOG_STRUCT(DEBUG, "drivetrain_goal", *drivetrain_message);
74
75 drivetrain_message.Send();
76}
77
78void BaseAutonomousActor::WaitUntilDoneOrCanceled(
79 ::std::unique_ptr<aos::common::actions::Action> action) {
80 if (!action) {
81 LOG(ERROR, "No action, not waiting\n");
82 return;
83 }
84
85 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
86 ::std::chrono::milliseconds(5) / 2);
87 while (true) {
88 // Poll the running bit and see if we should cancel.
89 phased_loop.SleepUntilNext();
90 if (!action->Running() || ShouldCancel()) {
91 return;
92 }
93 }
94}
95
96bool BaseAutonomousActor::WaitForDriveDone() {
97 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
98 ::std::chrono::milliseconds(5) / 2);
99
100 while (true) {
101 if (ShouldCancel()) {
102 return false;
103 }
104 phased_loop.SleepUntilNext();
105 drivetrain_queue.status.FetchLatest();
106 if (IsDriveDone()) {
107 return true;
108 }
109 }
110}
111
112bool BaseAutonomousActor::IsDriveDone() {
Brian Silvermanf83678c2017-03-11 14:02:26 -0800113 static constexpr double kPositionTolerance = 0.02;
114 static constexpr double kVelocityTolerance = 0.10;
115 static constexpr double kProfileTolerance = 0.001;
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000116
117 if (drivetrain_queue.status.get()) {
118 if (::std::abs(drivetrain_queue.status->profiled_left_position_goal -
119 initial_drivetrain_.left) < kProfileTolerance &&
120 ::std::abs(drivetrain_queue.status->profiled_right_position_goal -
121 initial_drivetrain_.right) < kProfileTolerance &&
122 ::std::abs(drivetrain_queue.status->estimated_left_position -
123 initial_drivetrain_.left) < kPositionTolerance &&
124 ::std::abs(drivetrain_queue.status->estimated_right_position -
125 initial_drivetrain_.right) < kPositionTolerance &&
126 ::std::abs(drivetrain_queue.status->estimated_left_velocity) <
127 kVelocityTolerance &&
128 ::std::abs(drivetrain_queue.status->estimated_right_velocity) <
129 kVelocityTolerance) {
130 LOG(INFO, "Finished drive\n");
131 return true;
132 }
133 }
134 return false;
135}
136
137bool BaseAutonomousActor::WaitForAboveAngle(double angle) {
138 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
139 ::std::chrono::milliseconds(5) / 2);
140 while (true) {
141 if (ShouldCancel()) {
142 return false;
143 }
144 phased_loop.SleepUntilNext();
145 drivetrain_queue.status.FetchLatest();
146 if (IsDriveDone()) {
147 return true;
148 }
149 if (drivetrain_queue.status.get()) {
150 if (drivetrain_queue.status->ground_angle > angle) {
151 return true;
152 }
153 }
154 }
155}
156
157bool BaseAutonomousActor::WaitForBelowAngle(double angle) {
158 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
159 ::std::chrono::milliseconds(5) / 2);
160 while (true) {
161 if (ShouldCancel()) {
162 return false;
163 }
164 phased_loop.SleepUntilNext();
165 drivetrain_queue.status.FetchLatest();
166 if (IsDriveDone()) {
167 return true;
168 }
169 if (drivetrain_queue.status.get()) {
170 if (drivetrain_queue.status->ground_angle < angle) {
171 return true;
172 }
173 }
174 }
175}
176
177bool BaseAutonomousActor::WaitForMaxBy(double angle) {
178 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
179 ::std::chrono::milliseconds(5) / 2);
180 double max_angle = -M_PI;
181 while (true) {
182 if (ShouldCancel()) {
183 return false;
184 }
185 phased_loop.SleepUntilNext();
186 drivetrain_queue.status.FetchLatest();
187 if (IsDriveDone()) {
188 return true;
189 }
190 if (drivetrain_queue.status.get()) {
191 if (drivetrain_queue.status->ground_angle > max_angle) {
192 max_angle = drivetrain_queue.status->ground_angle;
193 }
194 if (drivetrain_queue.status->ground_angle < max_angle - angle) {
195 return true;
196 }
197 }
198 }
199}
200
201bool BaseAutonomousActor::WaitForDriveNear(double distance, double angle) {
202 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
203 ::std::chrono::milliseconds(5) / 2);
204 constexpr double kPositionTolerance = 0.02;
205 constexpr double kProfileTolerance = 0.001;
206
Austin Schuhe6af9992018-07-08 15:59:14 -0700207 bool drive_has_been_close = false;
208 bool turn_has_been_close = false;
209 bool printed_first = false;
210
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000211 while (true) {
212 if (ShouldCancel()) {
213 return false;
214 }
215 phased_loop.SleepUntilNext();
216 drivetrain_queue.status.FetchLatest();
217 if (drivetrain_queue.status.get()) {
218 const double left_profile_error =
219 (initial_drivetrain_.left -
220 drivetrain_queue.status->profiled_left_position_goal);
221 const double right_profile_error =
222 (initial_drivetrain_.right -
223 drivetrain_queue.status->profiled_right_position_goal);
224
225 const double left_error =
226 (initial_drivetrain_.left -
227 drivetrain_queue.status->estimated_left_position);
228 const double right_error =
229 (initial_drivetrain_.right -
230 drivetrain_queue.status->estimated_right_position);
231
232 const double profile_distance_to_go =
233 (left_profile_error + right_profile_error) / 2.0;
234 const double profile_angle_to_go =
235 (right_profile_error - left_profile_error) /
236 (dt_config_.robot_radius * 2.0);
237
238 const double distance_to_go = (left_error + right_error) / 2.0;
239 const double angle_to_go =
240 (right_error - left_error) / (dt_config_.robot_radius * 2.0);
241
Austin Schuhe6af9992018-07-08 15:59:14 -0700242 const bool drive_close =
243 ::std::abs(profile_distance_to_go) < distance + kProfileTolerance &&
244 ::std::abs(distance_to_go) < distance + kPositionTolerance;
245 const bool turn_close =
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000246 ::std::abs(profile_angle_to_go) < angle + kProfileTolerance &&
Austin Schuhe6af9992018-07-08 15:59:14 -0700247 ::std::abs(angle_to_go) < angle + kPositionTolerance;
248
249 drive_has_been_close |= drive_close;
250 turn_has_been_close |= turn_close;
251 if (drive_has_been_close && !turn_has_been_close && !printed_first) {
252 LOG(INFO, "Drive finished first\n");
253 printed_first = true;
254 } else if (!drive_has_been_close && turn_has_been_close &&
255 !printed_first) {
256 LOG(INFO, "Turn finished first\n");
257 printed_first = true;
258 }
259
260 if (drive_close && turn_close) {
261 LOG(INFO, "Closer than %f < %f distance, %f < %f angle\n",
262 distance_to_go, distance, angle_to_go, angle);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000263 return true;
264 }
265 }
266 }
267}
268
Austin Schuh0aae9242018-03-14 19:49:44 -0700269bool BaseAutonomousActor::WaitForDriveProfileNear(double tolerance) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000270 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
271 ::std::chrono::milliseconds(5) / 2);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000272 while (true) {
273 if (ShouldCancel()) {
274 return false;
275 }
276 phased_loop.SleepUntilNext();
277 drivetrain_queue.status.FetchLatest();
Austin Schuh0aae9242018-03-14 19:49:44 -0700278
279 const Eigen::Matrix<double, 7, 1> current_error =
280 (Eigen::Matrix<double, 7, 1>()
281 << initial_drivetrain_.left -
282 drivetrain_queue.status->profiled_left_position_goal,
283 0.0, initial_drivetrain_.right -
284 drivetrain_queue.status->profiled_right_position_goal,
285 0.0, 0.0, 0.0, 0.0)
286 .finished();
287 const Eigen::Matrix<double, 2, 1> linear_error =
288 dt_config_.LeftRightToLinear(current_error);
289
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000290 if (drivetrain_queue.status.get()) {
Austin Schuh0aae9242018-03-14 19:49:44 -0700291 if (::std::abs(linear_error(0)) < tolerance) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000292 LOG(INFO, "Finished drive\n");
293 return true;
294 }
295 }
296 }
297}
298
Austin Schuh0aae9242018-03-14 19:49:44 -0700299bool BaseAutonomousActor::WaitForDriveProfileDone() {
300 constexpr double kProfileTolerance = 0.001;
301 return WaitForDriveProfileNear(kProfileTolerance);
302}
303
304bool BaseAutonomousActor::WaitForTurnProfileNear(double tolerance) {
Austin Schuh546a0382017-04-16 19:10:18 -0700305 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
306 ::std::chrono::milliseconds(5) / 2);
Austin Schuh546a0382017-04-16 19:10:18 -0700307 while (true) {
308 if (ShouldCancel()) {
309 return false;
310 }
311 phased_loop.SleepUntilNext();
312 drivetrain_queue.status.FetchLatest();
Austin Schuh0aae9242018-03-14 19:49:44 -0700313
314 const Eigen::Matrix<double, 7, 1> current_error =
315 (Eigen::Matrix<double, 7, 1>()
316 << initial_drivetrain_.left -
317 drivetrain_queue.status->profiled_left_position_goal,
318 0.0, initial_drivetrain_.right -
319 drivetrain_queue.status->profiled_right_position_goal,
320 0.0, 0.0, 0.0, 0.0)
321 .finished();
322 const Eigen::Matrix<double, 2, 1> angular_error =
323 dt_config_.LeftRightToAngular(current_error);
324
Austin Schuh546a0382017-04-16 19:10:18 -0700325 if (drivetrain_queue.status.get()) {
Austin Schuh0aae9242018-03-14 19:49:44 -0700326 if (::std::abs(angular_error(0)) < tolerance) {
327 LOG(INFO, "Finished turn\n");
Austin Schuh546a0382017-04-16 19:10:18 -0700328 return true;
329 }
330 }
331 }
332}
333
Austin Schuh0aae9242018-03-14 19:49:44 -0700334bool BaseAutonomousActor::WaitForTurnProfileDone() {
335 constexpr double kProfileTolerance = 0.001;
336 return WaitForTurnProfileNear(kProfileTolerance);
337}
338
Austin Schuh546a0382017-04-16 19:10:18 -0700339double BaseAutonomousActor::DriveDistanceLeft() {
340 using ::frc971::control_loops::drivetrain_queue;
341 drivetrain_queue.status.FetchLatest();
342 if (drivetrain_queue.status.get()) {
343 const double left_error =
344 (initial_drivetrain_.left -
345 drivetrain_queue.status->estimated_left_position);
346 const double right_error =
347 (initial_drivetrain_.right -
348 drivetrain_queue.status->estimated_right_position);
349
350 return (left_error + right_error) / 2.0;
351 } else {
352 return 0;
353 }
354}
355
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000356::std::unique_ptr<AutonomousAction> MakeAutonomousAction(
357 const AutonomousActionParams &params) {
358 return ::std::unique_ptr<AutonomousAction>(
359 new AutonomousAction(&autonomous_action, params));
360}
361
362} // namespace autonomous
363} // namespace frc971