blob: 4493e3cfbb9d52f8d299af86f7ee0d04205980e5 [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
8#include "aos/common/util/phased_loop.h"
9#include "aos/common/logging/logging.h"
10
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,
23 const control_loops::drivetrain::DrivetrainConfig dt_config)
24 : 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()
32 .control_loop_driving(false)
33 .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();
61 drivetrain_message->control_loop_driving = true;
62 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
207 while (true) {
208 if (ShouldCancel()) {
209 return false;
210 }
211 phased_loop.SleepUntilNext();
212 drivetrain_queue.status.FetchLatest();
213 if (drivetrain_queue.status.get()) {
214 const double left_profile_error =
215 (initial_drivetrain_.left -
216 drivetrain_queue.status->profiled_left_position_goal);
217 const double right_profile_error =
218 (initial_drivetrain_.right -
219 drivetrain_queue.status->profiled_right_position_goal);
220
221 const double left_error =
222 (initial_drivetrain_.left -
223 drivetrain_queue.status->estimated_left_position);
224 const double right_error =
225 (initial_drivetrain_.right -
226 drivetrain_queue.status->estimated_right_position);
227
228 const double profile_distance_to_go =
229 (left_profile_error + right_profile_error) / 2.0;
230 const double profile_angle_to_go =
231 (right_profile_error - left_profile_error) /
232 (dt_config_.robot_radius * 2.0);
233
234 const double distance_to_go = (left_error + right_error) / 2.0;
235 const double angle_to_go =
236 (right_error - left_error) / (dt_config_.robot_radius * 2.0);
237
238 if (::std::abs(profile_distance_to_go) < distance + kProfileTolerance &&
239 ::std::abs(profile_angle_to_go) < angle + kProfileTolerance &&
240 ::std::abs(distance_to_go) < distance + kPositionTolerance &&
241 ::std::abs(angle_to_go) < angle + kPositionTolerance) {
242 LOG(INFO, "Closer than %f distance, %f angle\n", distance, angle);
243 return true;
244 }
245 }
246 }
247}
248
Austin Schuh0aae9242018-03-14 19:49:44 -0700249bool BaseAutonomousActor::WaitForDriveProfileNear(double tolerance) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000250 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
251 ::std::chrono::milliseconds(5) / 2);
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000252 while (true) {
253 if (ShouldCancel()) {
254 return false;
255 }
256 phased_loop.SleepUntilNext();
257 drivetrain_queue.status.FetchLatest();
Austin Schuh0aae9242018-03-14 19:49:44 -0700258
259 const Eigen::Matrix<double, 7, 1> current_error =
260 (Eigen::Matrix<double, 7, 1>()
261 << initial_drivetrain_.left -
262 drivetrain_queue.status->profiled_left_position_goal,
263 0.0, initial_drivetrain_.right -
264 drivetrain_queue.status->profiled_right_position_goal,
265 0.0, 0.0, 0.0, 0.0)
266 .finished();
267 const Eigen::Matrix<double, 2, 1> linear_error =
268 dt_config_.LeftRightToLinear(current_error);
269
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000270 if (drivetrain_queue.status.get()) {
Austin Schuh0aae9242018-03-14 19:49:44 -0700271 if (::std::abs(linear_error(0)) < tolerance) {
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000272 LOG(INFO, "Finished drive\n");
273 return true;
274 }
275 }
276 }
277}
278
Austin Schuh0aae9242018-03-14 19:49:44 -0700279bool BaseAutonomousActor::WaitForDriveProfileDone() {
280 constexpr double kProfileTolerance = 0.001;
281 return WaitForDriveProfileNear(kProfileTolerance);
282}
283
284bool BaseAutonomousActor::WaitForTurnProfileNear(double tolerance) {
Austin Schuh546a0382017-04-16 19:10:18 -0700285 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
286 ::std::chrono::milliseconds(5) / 2);
Austin Schuh546a0382017-04-16 19:10:18 -0700287 while (true) {
288 if (ShouldCancel()) {
289 return false;
290 }
291 phased_loop.SleepUntilNext();
292 drivetrain_queue.status.FetchLatest();
Austin Schuh0aae9242018-03-14 19:49:44 -0700293
294 const Eigen::Matrix<double, 7, 1> current_error =
295 (Eigen::Matrix<double, 7, 1>()
296 << initial_drivetrain_.left -
297 drivetrain_queue.status->profiled_left_position_goal,
298 0.0, initial_drivetrain_.right -
299 drivetrain_queue.status->profiled_right_position_goal,
300 0.0, 0.0, 0.0, 0.0)
301 .finished();
302 const Eigen::Matrix<double, 2, 1> angular_error =
303 dt_config_.LeftRightToAngular(current_error);
304
Austin Schuh546a0382017-04-16 19:10:18 -0700305 if (drivetrain_queue.status.get()) {
Austin Schuh0aae9242018-03-14 19:49:44 -0700306 if (::std::abs(angular_error(0)) < tolerance) {
307 LOG(INFO, "Finished turn\n");
Austin Schuh546a0382017-04-16 19:10:18 -0700308 return true;
309 }
310 }
311 }
312}
313
Austin Schuh0aae9242018-03-14 19:49:44 -0700314bool BaseAutonomousActor::WaitForTurnProfileDone() {
315 constexpr double kProfileTolerance = 0.001;
316 return WaitForTurnProfileNear(kProfileTolerance);
317}
318
Austin Schuh546a0382017-04-16 19:10:18 -0700319double BaseAutonomousActor::DriveDistanceLeft() {
320 using ::frc971::control_loops::drivetrain_queue;
321 drivetrain_queue.status.FetchLatest();
322 if (drivetrain_queue.status.get()) {
323 const double left_error =
324 (initial_drivetrain_.left -
325 drivetrain_queue.status->estimated_left_position);
326 const double right_error =
327 (initial_drivetrain_.right -
328 drivetrain_queue.status->estimated_right_position);
329
330 return (left_error + right_error) / 2.0;
331 } else {
332 return 0;
333 }
334}
335
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000336::std::unique_ptr<AutonomousAction> MakeAutonomousAction(
337 const AutonomousActionParams &params) {
338 return ::std::unique_ptr<AutonomousAction>(
339 new AutonomousAction(&autonomous_action, params));
340}
341
342} // namespace autonomous
343} // namespace frc971