blob: 2e0dcc2412aec7388f062eab3cba0e5cbf809849 [file] [log] [blame]
Austin Schuh6e242ac2015-03-07 17:08:21 -08001#ifndef FRC971_ACTORS_FRIDGE_PROFILE_LIB_H_
2#define FRC971_ACTORS_FRIDGE_PROFILE_LIB_H_
3
4#include <cmath>
5
6#include "aos/common/actions/actor.h"
Austin Schuh813b9af2015-03-08 18:46:58 -07007#include "aos/common/util/phased_loop.h"
Austin Schuh6e242ac2015-03-07 17:08:21 -08008#include "frc971/control_loops/fridge/fridge.q.h"
9
10namespace frc971 {
11namespace actors {
12
13struct ProfileParams {
14 double velocity;
15 double acceleration;
16};
17
18// Base class to provide helper utilities to all Actors who want to control the
19// fridge.
20template <typename T>
21class FridgeActorBase : public aos::common::actions::ActorBase<T> {
22 public:
23 FridgeActorBase(T *queues) : aos::common::actions::ActorBase<T>(queues) {}
24
25 protected:
26 void DoFridgeProfile(double height, double angle,
27 ProfileParams elevator_parameters,
28 ProfileParams arm_parameters, bool grabbers) {
29 DoFridgeProfile(height, angle, elevator_parameters, arm_parameters,
30 grabbers, grabbers, grabbers);
31 }
32
Austin Schuhfa65bfd2015-03-14 21:10:44 -070033 bool StartFridgeProfile(double height, double angle,
34 ProfileParams elevator_parameters,
35 ProfileParams arm_parameters, bool top_grabbers,
36 bool front_grabbers, bool back_grabbers) {
Austin Schuh6e242ac2015-03-07 17:08:21 -080037 auto new_fridge_goal = control_loops::fridge_queue.goal.MakeMessage();
Austin Schuh1d44bd42015-03-15 16:40:45 -070038 new_fridge_goal->profiling_type = 0;
Austin Schuh6e242ac2015-03-07 17:08:21 -080039 new_fridge_goal->max_velocity = elevator_parameters.velocity;
40 new_fridge_goal->max_acceleration = elevator_parameters.acceleration;
41 new_fridge_goal->height = height;
42 new_fridge_goal->velocity = 0.0;
43 new_fridge_goal->max_angular_velocity = arm_parameters.velocity;
44 new_fridge_goal->max_angular_acceleration = arm_parameters.acceleration;
45 new_fridge_goal->angle = angle;
46 new_fridge_goal->angular_velocity = 0.0;
47 new_fridge_goal->grabbers.top_front = top_grabbers;
48 new_fridge_goal->grabbers.top_back = top_grabbers;
49 new_fridge_goal->grabbers.bottom_front = front_grabbers;
50 new_fridge_goal->grabbers.bottom_back = back_grabbers;
Austin Schuhfa65bfd2015-03-14 21:10:44 -070051 LOG(INFO, "Starting profile to %f, %f\n", height, angle);
Austin Schuh6e242ac2015-03-07 17:08:21 -080052
53 if (!new_fridge_goal.Send()) {
54 LOG(ERROR, "Failed to send fridge goal\n");
Austin Schuhfa65bfd2015-03-14 21:10:44 -070055 return false;
56 }
57 return true;
58 }
59
Brian Silvermaned86fc12015-03-19 23:37:35 -070060 enum ProfileStatus { RUNNING, DONE, CANCELED };
Austin Schuhfa65bfd2015-03-14 21:10:44 -070061
62 ProfileStatus IterateProfile(double height, double angle,
63 ProfileParams elevator_parameters,
64 ProfileParams arm_parameters, bool top_grabbers,
65 bool front_grabbers, bool back_grabbers) {
Austin Schuhfa65bfd2015-03-14 21:10:44 -070066 if (this->ShouldCancel()) {
Austin Schuhfa65bfd2015-03-14 21:10:44 -070067 LOG(INFO, "Canceling fridge movement\n");
Brian Silvermanf1c5e7d2015-03-28 18:25:25 -040068 if (!control_loops::fridge_queue.status.get()) {
69 LOG(WARNING, "no fridge status so can't really cancel\n");
70 return CANCELED;
71 }
72
Austin Schuhfa65bfd2015-03-14 21:10:44 -070073 auto new_fridge_goal = control_loops::fridge_queue.goal.MakeMessage();
Austin Schuh1d44bd42015-03-15 16:40:45 -070074 new_fridge_goal->profiling_type = 0;
Austin Schuhfa65bfd2015-03-14 21:10:44 -070075 new_fridge_goal->max_velocity = elevator_parameters.velocity;
76 new_fridge_goal->max_acceleration = elevator_parameters.acceleration;
77 new_fridge_goal->height =
78 control_loops::fridge_queue.status->height +
79 (control_loops::fridge_queue.status->goal_velocity *
80 ::std::abs(control_loops::fridge_queue.status->goal_velocity)) /
81 (2.0 * new_fridge_goal->max_acceleration);
Austin Schuh511e8652015-03-15 17:53:31 -070082 height = new_fridge_goal->height;
Austin Schuhfa65bfd2015-03-14 21:10:44 -070083 new_fridge_goal->velocity = 0.0;
84 new_fridge_goal->max_angular_velocity = arm_parameters.velocity;
85 new_fridge_goal->max_angular_acceleration = arm_parameters.acceleration;
86 new_fridge_goal->angle =
87 control_loops::fridge_queue.status->angle +
88 (control_loops::fridge_queue.status->goal_angular_velocity *
89 ::std::abs(
90 control_loops::fridge_queue.status->goal_angular_velocity)) /
91 (2.0 * new_fridge_goal->max_angular_acceleration);
Austin Schuh511e8652015-03-15 17:53:31 -070092 angle = new_fridge_goal->angle;
Austin Schuhfa65bfd2015-03-14 21:10:44 -070093 new_fridge_goal->angular_velocity = 0.0;
94 new_fridge_goal->grabbers.top_front = top_grabbers;
95 new_fridge_goal->grabbers.top_back = top_grabbers;
96 new_fridge_goal->grabbers.bottom_front = front_grabbers;
97 new_fridge_goal->grabbers.bottom_back = back_grabbers;
98
99 if (!new_fridge_goal.Send()) {
100 LOG(ERROR, "Failed to send fridge goal\n");
Austin Schuhfa65bfd2015-03-14 21:10:44 -0700101 }
Brian Silvermaned86fc12015-03-19 23:37:35 -0700102 return CANCELED;
Austin Schuhfa65bfd2015-03-14 21:10:44 -0700103 }
104 control_loops::fridge_queue.status.FetchAnother();
105
106 constexpr double kProfileError = 1e-5;
107 constexpr double kAngleEpsilon = 0.02, kHeightEpsilon = 0.015;
108
109 if (control_loops::fridge_queue.status->state != 4) {
110 LOG(ERROR, "Fridge no longer running, aborting action\n");
111 return CANCELED;
112 }
113
114 if (::std::abs(control_loops::fridge_queue.status->goal_angle - angle) <
115 kProfileError &&
116 ::std::abs(control_loops::fridge_queue.status->goal_height - height) <
117 kProfileError &&
118 ::std::abs(control_loops::fridge_queue.status->goal_angular_velocity) <
119 kProfileError &&
120 ::std::abs(control_loops::fridge_queue.status->goal_velocity) <
121 kProfileError) {
122 LOG(INFO, "Profile done.\n");
Brian Silvermaned86fc12015-03-19 23:37:35 -0700123 if (::std::abs(control_loops::fridge_queue.status->angle - angle) <
Austin Schuhfa65bfd2015-03-14 21:10:44 -0700124 kAngleEpsilon &&
125 ::std::abs(control_loops::fridge_queue.status->height -
126 height) < kHeightEpsilon) {
127 LOG(INFO, "Near goal, done.\n");
128 return DONE;
129 }
130 }
131
Brian Silvermaned86fc12015-03-19 23:37:35 -0700132 return RUNNING;
Austin Schuhfa65bfd2015-03-14 21:10:44 -0700133 }
134
135 void DoFridgeProfile(double height, double angle,
136 ProfileParams elevator_parameters,
137 ProfileParams arm_parameters, bool top_grabbers,
138 bool front_grabbers, bool back_grabbers) {
139 if (!StartFridgeProfile(height, angle, elevator_parameters, arm_parameters,
140 top_grabbers, front_grabbers, back_grabbers)) {
Austin Schuh6e242ac2015-03-07 17:08:21 -0800141 return;
142 }
143
144 while (true) {
Austin Schuhfa65bfd2015-03-14 21:10:44 -0700145 ProfileStatus status =
146 IterateProfile(height, angle, elevator_parameters, arm_parameters,
147 top_grabbers, front_grabbers, back_grabbers);
148 if (status == DONE || status == CANCELED) {
Austin Schuh6e242ac2015-03-07 17:08:21 -0800149 return;
150 }
Austin Schuh6e242ac2015-03-07 17:08:21 -0800151 }
152 }
Austin Schuh4c52fb02015-03-29 13:40:08 -0700153
154 void DoFridgeXYProfile(double x, double y, ProfileParams x_parameters,
155 ProfileParams y_parameters, bool grabbers) {
156 DoFridgeXYProfile(x, y, x_parameters, y_parameters, grabbers, grabbers,
157 grabbers);
158 }
159
160 void DoFridgeXYProfile(double x, double y, ProfileParams x_parameters,
161 ProfileParams y_parameters, bool top_grabbers,
162 bool front_grabbers, bool back_grabbers) {
163 if (!StartFridgeXYProfile(x, y, x_parameters, y_parameters, top_grabbers,
164 front_grabbers, back_grabbers)) {
165 return;
166 }
167
168 while (true) {
169 ProfileStatus status =
170 IterateXYProfile(x, y, x_parameters, y_parameters, top_grabbers,
171 front_grabbers, back_grabbers);
172 if (status == DONE || status == CANCELED) {
173 return;
174 }
175 }
176 }
177
178 void CancelXYMotion(ProfileParams x_parameters, ProfileParams y_parameters,
179 bool top_grabbers, bool front_grabbers,
180 bool back_grabbers) {
181 LOG(INFO, "Canceling fridge movement\n");
182 if (!control_loops::fridge_queue.status.get()) {
183 LOG(WARNING, "no fridge status so can't really cancel\n");
184 return;
185 }
186
187 auto new_fridge_goal = control_loops::fridge_queue.goal.MakeMessage();
188 new_fridge_goal->profiling_type = 1;
189 new_fridge_goal->max_x_velocity = x_parameters.velocity;
190 new_fridge_goal->max_x_acceleration = x_parameters.acceleration;
191 new_fridge_goal->x =
192 control_loops::fridge_queue.status->x +
193 (control_loops::fridge_queue.status->goal_x_velocity *
194 ::std::abs(control_loops::fridge_queue.status->goal_x_velocity)) /
195 (2.0 * new_fridge_goal->max_x_acceleration);
196 new_fridge_goal->x_velocity = 0.0;
197
198 new_fridge_goal->max_y_velocity = y_parameters.velocity;
199 new_fridge_goal->max_y_acceleration = y_parameters.acceleration;
200 new_fridge_goal->y =
201 control_loops::fridge_queue.status->y +
202 (control_loops::fridge_queue.status->goal_y_velocity *
203 ::std::abs(control_loops::fridge_queue.status->goal_y_velocity)) /
204 (2.0 * new_fridge_goal->max_y_acceleration);
205 new_fridge_goal->y_velocity = 0.0;
206
207 new_fridge_goal->grabbers.top_front = top_grabbers;
208 new_fridge_goal->grabbers.top_back = top_grabbers;
209 new_fridge_goal->grabbers.bottom_front = front_grabbers;
210 new_fridge_goal->grabbers.bottom_back = back_grabbers;
211
212 if (!new_fridge_goal.Send()) {
213 LOG(ERROR, "Failed to send fridge goal\n");
214 }
215 }
216
217 ProfileStatus IterateXYProfile(double x, double y, ProfileParams x_parameters,
218 ProfileParams y_parameters, bool top_grabbers,
219 bool front_grabbers, bool back_grabbers) {
220 if (this->ShouldCancel()) {
221 CancelXYMotion(x_parameters, y_parameters, top_grabbers, front_grabbers,
222 back_grabbers);
223 return CANCELED;
224 }
225 control_loops::fridge_queue.status.FetchAnother();
226
227 constexpr double kProfileError = 1e-5;
228 constexpr double kXEpsilon = 0.02, kYEpsilon = 0.02;
229
230 if (control_loops::fridge_queue.status->state != 4) {
231 LOG(ERROR, "Fridge no longer running, aborting action\n");
232 return CANCELED;
233 }
234
235 if (::std::abs(control_loops::fridge_queue.status->goal_x - x) <
236 kProfileError &&
237 ::std::abs(control_loops::fridge_queue.status->goal_y - y) <
238 kProfileError &&
239 ::std::abs(control_loops::fridge_queue.status->goal_x_velocity) <
240 kProfileError &&
241 ::std::abs(control_loops::fridge_queue.status->goal_y_velocity) <
242 kProfileError) {
243 LOG(INFO, "Profile done.\n");
244 if (::std::abs(control_loops::fridge_queue.status->x - x) < kXEpsilon &&
245 ::std::abs(control_loops::fridge_queue.status->y - y) < kYEpsilon) {
246 LOG(INFO, "Near goal, done.\n");
247 return DONE;
248 }
249 }
250
251 return RUNNING;
252 }
253
254 bool StartFridgeXYProfile(double x, double y, ProfileParams x_parameters,
255 ProfileParams y_parameters, bool top_grabbers,
256 bool front_grabbers, bool back_grabbers) {
257 auto new_fridge_goal = control_loops::fridge_queue.goal.MakeMessage();
258 new_fridge_goal->profiling_type = 1;
259 new_fridge_goal->max_x_velocity = x_parameters.velocity;
260 new_fridge_goal->max_x_acceleration = x_parameters.acceleration;
261 new_fridge_goal->x = x;
262 new_fridge_goal->x_velocity = 0.0;
263
264 new_fridge_goal->max_y_velocity = y_parameters.velocity;
265 new_fridge_goal->max_y_acceleration = y_parameters.acceleration;
266 new_fridge_goal->y = y;
267 new_fridge_goal->y_velocity = 0.0;
268 new_fridge_goal->grabbers.top_front = top_grabbers;
269 new_fridge_goal->grabbers.top_back = top_grabbers;
270 new_fridge_goal->grabbers.bottom_front = front_grabbers;
271 new_fridge_goal->grabbers.bottom_back = back_grabbers;
272 LOG(INFO, "Starting xy profile to %f, %f\n", x, y);
273
274 if (!new_fridge_goal.Send()) {
275 LOG(ERROR, "Failed to send fridge goal\n");
276 return false;
277 }
278 return true;
279 }
Austin Schuh6e242ac2015-03-07 17:08:21 -0800280};
281
282} // namespace actors
283} // namespace frc971
284
285#endif // FRC971_ACTORS_FRIDGE_PROFILE_LIB_H_