blob: 73102ec607ba98bb933523b96a1c1129ee1a0ccc [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
13namespace frc971 {
14namespace autonomous {
15
16using ::frc971::control_loops::drivetrain_queue;
17using ::aos::monotonic_clock;
18namespace chrono = ::std::chrono;
19namespace this_thread = ::std::this_thread;
20
21namespace {} // namespace
22
23BaseAutonomousActor::BaseAutonomousActor(
24 AutonomousActionQueueGroup *s,
25 const control_loops::drivetrain::DrivetrainConfig dt_config)
26 : aos::common::actions::ActorBase<AutonomousActionQueueGroup>(s),
27 dt_config_(dt_config),
28 initial_drivetrain_({0.0, 0.0}) {}
29
30void BaseAutonomousActor::ResetDrivetrain() {
31 LOG(INFO, "resetting the drivetrain\n");
32 drivetrain_queue.goal.MakeWithBuilder()
33 .control_loop_driving(false)
34 .highgear(true)
35 .steering(0.0)
36 .throttle(0.0)
37 .left_goal(initial_drivetrain_.left)
38 .left_velocity_goal(0)
39 .right_goal(initial_drivetrain_.right)
40 .right_velocity_goal(0)
41 .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;
63 drivetrain_message->steering = 0.0;
64 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;
69 drivetrain_message->linear = linear;
70 drivetrain_message->angular = angular;
71
72 LOG_STRUCT(DEBUG, "drivetrain_goal", *drivetrain_message);
73
74 drivetrain_message.Send();
75}
76
77void BaseAutonomousActor::WaitUntilDoneOrCanceled(
78 ::std::unique_ptr<aos::common::actions::Action> action) {
79 if (!action) {
80 LOG(ERROR, "No action, not waiting\n");
81 return;
82 }
83
84 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
85 ::std::chrono::milliseconds(5) / 2);
86 while (true) {
87 // Poll the running bit and see if we should cancel.
88 phased_loop.SleepUntilNext();
89 if (!action->Running() || ShouldCancel()) {
90 return;
91 }
92 }
93}
94
95bool BaseAutonomousActor::WaitForDriveDone() {
96 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
97 ::std::chrono::milliseconds(5) / 2);
98
99 while (true) {
100 if (ShouldCancel()) {
101 return false;
102 }
103 phased_loop.SleepUntilNext();
104 drivetrain_queue.status.FetchLatest();
105 if (IsDriveDone()) {
106 return true;
107 }
108 }
109}
110
111bool BaseAutonomousActor::IsDriveDone() {
112 constexpr double kPositionTolerance = 0.02;
113 constexpr double kVelocityTolerance = 0.10;
114 constexpr double kProfileTolerance = 0.001;
115
116 if (drivetrain_queue.status.get()) {
117 if (::std::abs(drivetrain_queue.status->profiled_left_position_goal -
118 initial_drivetrain_.left) < kProfileTolerance &&
119 ::std::abs(drivetrain_queue.status->profiled_right_position_goal -
120 initial_drivetrain_.right) < kProfileTolerance &&
121 ::std::abs(drivetrain_queue.status->estimated_left_position -
122 initial_drivetrain_.left) < kPositionTolerance &&
123 ::std::abs(drivetrain_queue.status->estimated_right_position -
124 initial_drivetrain_.right) < kPositionTolerance &&
125 ::std::abs(drivetrain_queue.status->estimated_left_velocity) <
126 kVelocityTolerance &&
127 ::std::abs(drivetrain_queue.status->estimated_right_velocity) <
128 kVelocityTolerance) {
129 LOG(INFO, "Finished drive\n");
130 return true;
131 }
132 }
133 return false;
134}
135
136bool BaseAutonomousActor::WaitForAboveAngle(double angle) {
137 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
138 ::std::chrono::milliseconds(5) / 2);
139 while (true) {
140 if (ShouldCancel()) {
141 return false;
142 }
143 phased_loop.SleepUntilNext();
144 drivetrain_queue.status.FetchLatest();
145 if (IsDriveDone()) {
146 return true;
147 }
148 if (drivetrain_queue.status.get()) {
149 if (drivetrain_queue.status->ground_angle > angle) {
150 return true;
151 }
152 }
153 }
154}
155
156bool BaseAutonomousActor::WaitForBelowAngle(double angle) {
157 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
158 ::std::chrono::milliseconds(5) / 2);
159 while (true) {
160 if (ShouldCancel()) {
161 return false;
162 }
163 phased_loop.SleepUntilNext();
164 drivetrain_queue.status.FetchLatest();
165 if (IsDriveDone()) {
166 return true;
167 }
168 if (drivetrain_queue.status.get()) {
169 if (drivetrain_queue.status->ground_angle < angle) {
170 return true;
171 }
172 }
173 }
174}
175
176bool BaseAutonomousActor::WaitForMaxBy(double angle) {
177 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
178 ::std::chrono::milliseconds(5) / 2);
179 double max_angle = -M_PI;
180 while (true) {
181 if (ShouldCancel()) {
182 return false;
183 }
184 phased_loop.SleepUntilNext();
185 drivetrain_queue.status.FetchLatest();
186 if (IsDriveDone()) {
187 return true;
188 }
189 if (drivetrain_queue.status.get()) {
190 if (drivetrain_queue.status->ground_angle > max_angle) {
191 max_angle = drivetrain_queue.status->ground_angle;
192 }
193 if (drivetrain_queue.status->ground_angle < max_angle - angle) {
194 return true;
195 }
196 }
197 }
198}
199
200bool BaseAutonomousActor::WaitForDriveNear(double distance, double angle) {
201 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
202 ::std::chrono::milliseconds(5) / 2);
203 constexpr double kPositionTolerance = 0.02;
204 constexpr double kProfileTolerance = 0.001;
205
206 while (true) {
207 if (ShouldCancel()) {
208 return false;
209 }
210 phased_loop.SleepUntilNext();
211 drivetrain_queue.status.FetchLatest();
212 if (drivetrain_queue.status.get()) {
213 const double left_profile_error =
214 (initial_drivetrain_.left -
215 drivetrain_queue.status->profiled_left_position_goal);
216 const double right_profile_error =
217 (initial_drivetrain_.right -
218 drivetrain_queue.status->profiled_right_position_goal);
219
220 const double left_error =
221 (initial_drivetrain_.left -
222 drivetrain_queue.status->estimated_left_position);
223 const double right_error =
224 (initial_drivetrain_.right -
225 drivetrain_queue.status->estimated_right_position);
226
227 const double profile_distance_to_go =
228 (left_profile_error + right_profile_error) / 2.0;
229 const double profile_angle_to_go =
230 (right_profile_error - left_profile_error) /
231 (dt_config_.robot_radius * 2.0);
232
233 const double distance_to_go = (left_error + right_error) / 2.0;
234 const double angle_to_go =
235 (right_error - left_error) / (dt_config_.robot_radius * 2.0);
236
237 if (::std::abs(profile_distance_to_go) < distance + kProfileTolerance &&
238 ::std::abs(profile_angle_to_go) < angle + kProfileTolerance &&
239 ::std::abs(distance_to_go) < distance + kPositionTolerance &&
240 ::std::abs(angle_to_go) < angle + kPositionTolerance) {
241 LOG(INFO, "Closer than %f distance, %f angle\n", distance, angle);
242 return true;
243 }
244 }
245 }
246}
247
248bool BaseAutonomousActor::WaitForDriveProfileDone() {
249 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
250 ::std::chrono::milliseconds(5) / 2);
251 constexpr double kProfileTolerance = 0.001;
252
253 while (true) {
254 if (ShouldCancel()) {
255 return false;
256 }
257 phased_loop.SleepUntilNext();
258 drivetrain_queue.status.FetchLatest();
259 if (drivetrain_queue.status.get()) {
260 if (::std::abs(drivetrain_queue.status->profiled_left_position_goal -
261 initial_drivetrain_.left) < kProfileTolerance &&
262 ::std::abs(drivetrain_queue.status->profiled_right_position_goal -
263 initial_drivetrain_.right) < kProfileTolerance) {
264 LOG(INFO, "Finished drive\n");
265 return true;
266 }
267 }
268 }
269}
270
271::std::unique_ptr<AutonomousAction> MakeAutonomousAction(
272 const AutonomousActionParams &params) {
273 return ::std::unique_ptr<AutonomousAction>(
274 new AutonomousAction(&autonomous_action, params));
275}
276
277} // namespace autonomous
278} // namespace frc971