blob: abb91a7fb0548c9b3c6857c8a8a599e535b39c6e [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");
30 drivetrain_queue.goal.MakeWithBuilder()
31 .control_loop_driving(false)
32 .highgear(true)
Austin Schuh2b1fce02018-03-02 20:05:20 -080033 .wheel(0.0)
Philipp Schrader4bd29b12017-02-22 04:42:27 +000034 .throttle(0.0)
35 .left_goal(initial_drivetrain_.left)
36 .left_velocity_goal(0)
37 .right_goal(initial_drivetrain_.right)
38 .right_velocity_goal(0)
39 .Send();
40}
41
42void BaseAutonomousActor::InitializeEncoders() {
43 drivetrain_queue.status.FetchAnother();
44 initial_drivetrain_.left = drivetrain_queue.status->estimated_left_position;
45 initial_drivetrain_.right = drivetrain_queue.status->estimated_right_position;
46}
47
48void BaseAutonomousActor::StartDrive(double distance, double angle,
49 ProfileParameters linear,
50 ProfileParameters angular) {
51 LOG(INFO, "Driving distance %f, angle %f\n", distance, angle);
52 {
53 const double dangle = angle * dt_config_.robot_radius;
54 initial_drivetrain_.left += distance - dangle;
55 initial_drivetrain_.right += distance + dangle;
56 }
57
58 auto drivetrain_message = drivetrain_queue.goal.MakeMessage();
59 drivetrain_message->control_loop_driving = true;
60 drivetrain_message->highgear = true;
Austin Schuh2b1fce02018-03-02 20:05:20 -080061 drivetrain_message->wheel = 0.0;
Philipp Schrader4bd29b12017-02-22 04:42:27 +000062 drivetrain_message->throttle = 0.0;
63 drivetrain_message->left_goal = initial_drivetrain_.left;
64 drivetrain_message->left_velocity_goal = 0;
65 drivetrain_message->right_goal = initial_drivetrain_.right;
66 drivetrain_message->right_velocity_goal = 0;
67 drivetrain_message->linear = linear;
68 drivetrain_message->angular = angular;
69
70 LOG_STRUCT(DEBUG, "drivetrain_goal", *drivetrain_message);
71
72 drivetrain_message.Send();
73}
74
75void BaseAutonomousActor::WaitUntilDoneOrCanceled(
76 ::std::unique_ptr<aos::common::actions::Action> action) {
77 if (!action) {
78 LOG(ERROR, "No action, not waiting\n");
79 return;
80 }
81
82 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
83 ::std::chrono::milliseconds(5) / 2);
84 while (true) {
85 // Poll the running bit and see if we should cancel.
86 phased_loop.SleepUntilNext();
87 if (!action->Running() || ShouldCancel()) {
88 return;
89 }
90 }
91}
92
93bool BaseAutonomousActor::WaitForDriveDone() {
94 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
95 ::std::chrono::milliseconds(5) / 2);
96
97 while (true) {
98 if (ShouldCancel()) {
99 return false;
100 }
101 phased_loop.SleepUntilNext();
102 drivetrain_queue.status.FetchLatest();
103 if (IsDriveDone()) {
104 return true;
105 }
106 }
107}
108
109bool BaseAutonomousActor::IsDriveDone() {
Brian Silvermanf83678c2017-03-11 14:02:26 -0800110 static constexpr double kPositionTolerance = 0.02;
111 static constexpr double kVelocityTolerance = 0.10;
112 static constexpr double kProfileTolerance = 0.001;
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000113
114 if (drivetrain_queue.status.get()) {
115 if (::std::abs(drivetrain_queue.status->profiled_left_position_goal -
116 initial_drivetrain_.left) < kProfileTolerance &&
117 ::std::abs(drivetrain_queue.status->profiled_right_position_goal -
118 initial_drivetrain_.right) < kProfileTolerance &&
119 ::std::abs(drivetrain_queue.status->estimated_left_position -
120 initial_drivetrain_.left) < kPositionTolerance &&
121 ::std::abs(drivetrain_queue.status->estimated_right_position -
122 initial_drivetrain_.right) < kPositionTolerance &&
123 ::std::abs(drivetrain_queue.status->estimated_left_velocity) <
124 kVelocityTolerance &&
125 ::std::abs(drivetrain_queue.status->estimated_right_velocity) <
126 kVelocityTolerance) {
127 LOG(INFO, "Finished drive\n");
128 return true;
129 }
130 }
131 return false;
132}
133
134bool BaseAutonomousActor::WaitForAboveAngle(double angle) {
135 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
136 ::std::chrono::milliseconds(5) / 2);
137 while (true) {
138 if (ShouldCancel()) {
139 return false;
140 }
141 phased_loop.SleepUntilNext();
142 drivetrain_queue.status.FetchLatest();
143 if (IsDriveDone()) {
144 return true;
145 }
146 if (drivetrain_queue.status.get()) {
147 if (drivetrain_queue.status->ground_angle > angle) {
148 return true;
149 }
150 }
151 }
152}
153
154bool BaseAutonomousActor::WaitForBelowAngle(double angle) {
155 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
156 ::std::chrono::milliseconds(5) / 2);
157 while (true) {
158 if (ShouldCancel()) {
159 return false;
160 }
161 phased_loop.SleepUntilNext();
162 drivetrain_queue.status.FetchLatest();
163 if (IsDriveDone()) {
164 return true;
165 }
166 if (drivetrain_queue.status.get()) {
167 if (drivetrain_queue.status->ground_angle < angle) {
168 return true;
169 }
170 }
171 }
172}
173
174bool BaseAutonomousActor::WaitForMaxBy(double angle) {
175 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
176 ::std::chrono::milliseconds(5) / 2);
177 double max_angle = -M_PI;
178 while (true) {
179 if (ShouldCancel()) {
180 return false;
181 }
182 phased_loop.SleepUntilNext();
183 drivetrain_queue.status.FetchLatest();
184 if (IsDriveDone()) {
185 return true;
186 }
187 if (drivetrain_queue.status.get()) {
188 if (drivetrain_queue.status->ground_angle > max_angle) {
189 max_angle = drivetrain_queue.status->ground_angle;
190 }
191 if (drivetrain_queue.status->ground_angle < max_angle - angle) {
192 return true;
193 }
194 }
195 }
196}
197
198bool BaseAutonomousActor::WaitForDriveNear(double distance, double angle) {
199 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
200 ::std::chrono::milliseconds(5) / 2);
201 constexpr double kPositionTolerance = 0.02;
202 constexpr double kProfileTolerance = 0.001;
203
204 while (true) {
205 if (ShouldCancel()) {
206 return false;
207 }
208 phased_loop.SleepUntilNext();
209 drivetrain_queue.status.FetchLatest();
210 if (drivetrain_queue.status.get()) {
211 const double left_profile_error =
212 (initial_drivetrain_.left -
213 drivetrain_queue.status->profiled_left_position_goal);
214 const double right_profile_error =
215 (initial_drivetrain_.right -
216 drivetrain_queue.status->profiled_right_position_goal);
217
218 const double left_error =
219 (initial_drivetrain_.left -
220 drivetrain_queue.status->estimated_left_position);
221 const double right_error =
222 (initial_drivetrain_.right -
223 drivetrain_queue.status->estimated_right_position);
224
225 const double profile_distance_to_go =
226 (left_profile_error + right_profile_error) / 2.0;
227 const double profile_angle_to_go =
228 (right_profile_error - left_profile_error) /
229 (dt_config_.robot_radius * 2.0);
230
231 const double distance_to_go = (left_error + right_error) / 2.0;
232 const double angle_to_go =
233 (right_error - left_error) / (dt_config_.robot_radius * 2.0);
234
235 if (::std::abs(profile_distance_to_go) < distance + kProfileTolerance &&
236 ::std::abs(profile_angle_to_go) < angle + kProfileTolerance &&
237 ::std::abs(distance_to_go) < distance + kPositionTolerance &&
238 ::std::abs(angle_to_go) < angle + kPositionTolerance) {
239 LOG(INFO, "Closer than %f distance, %f angle\n", distance, angle);
240 return true;
241 }
242 }
243 }
244}
245
246bool BaseAutonomousActor::WaitForDriveProfileDone() {
247 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
248 ::std::chrono::milliseconds(5) / 2);
249 constexpr double kProfileTolerance = 0.001;
250
251 while (true) {
252 if (ShouldCancel()) {
253 return false;
254 }
255 phased_loop.SleepUntilNext();
256 drivetrain_queue.status.FetchLatest();
257 if (drivetrain_queue.status.get()) {
258 if (::std::abs(drivetrain_queue.status->profiled_left_position_goal -
259 initial_drivetrain_.left) < kProfileTolerance &&
260 ::std::abs(drivetrain_queue.status->profiled_right_position_goal -
261 initial_drivetrain_.right) < kProfileTolerance) {
262 LOG(INFO, "Finished drive\n");
263 return true;
264 }
265 }
266 }
267}
268
Austin Schuh546a0382017-04-16 19:10:18 -0700269bool BaseAutonomousActor::WaitForTurnProfileDone() {
270 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
271 ::std::chrono::milliseconds(5) / 2);
272 constexpr double kProfileTolerance = 0.001;
273
274 while (true) {
275 if (ShouldCancel()) {
276 return false;
277 }
278 phased_loop.SleepUntilNext();
279 drivetrain_queue.status.FetchLatest();
280 if (drivetrain_queue.status.get()) {
281 const double left_profile_error =
282 (initial_drivetrain_.left -
283 drivetrain_queue.status->profiled_left_position_goal);
284 const double right_profile_error =
285 (initial_drivetrain_.right -
286 drivetrain_queue.status->profiled_right_position_goal);
287
288 const double profile_angle_to_go =
289 (right_profile_error - left_profile_error) /
290 (dt_config_.robot_radius * 2.0);
291
292 if (::std::abs(profile_angle_to_go) < kProfileTolerance) {
293 LOG(INFO, "Finished turn profile\n");
294 return true;
295 }
296 }
297 }
298}
299
300double BaseAutonomousActor::DriveDistanceLeft() {
301 using ::frc971::control_loops::drivetrain_queue;
302 drivetrain_queue.status.FetchLatest();
303 if (drivetrain_queue.status.get()) {
304 const double left_error =
305 (initial_drivetrain_.left -
306 drivetrain_queue.status->estimated_left_position);
307 const double right_error =
308 (initial_drivetrain_.right -
309 drivetrain_queue.status->estimated_right_position);
310
311 return (left_error + right_error) / 2.0;
312 } else {
313 return 0;
314 }
315}
316
Philipp Schrader4bd29b12017-02-22 04:42:27 +0000317::std::unique_ptr<AutonomousAction> MakeAutonomousAction(
318 const AutonomousActionParams &params) {
319 return ::std::unique_ptr<AutonomousAction>(
320 new AutonomousAction(&autonomous_action, params));
321}
322
323} // namespace autonomous
324} // namespace frc971