blob: 36ea16bbca97bfc9d57995c628702c958d0e3699 [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
Austin Schuh813b9af2015-03-08 18:46:58 -07006#include "aos/common/controls/control_loop.h"
Austin Schuh6e242ac2015-03-07 17:08:21 -08007#include "aos/common/actions/actor.h"
Austin Schuh813b9af2015-03-08 18:46:58 -07008#include "aos/common/util/phased_loop.h"
Austin Schuh6e242ac2015-03-07 17:08:21 -08009#include "frc971/control_loops/fridge/fridge.q.h"
10
11namespace frc971 {
12namespace actors {
13
14struct ProfileParams {
15 double velocity;
16 double acceleration;
17};
18
19// Base class to provide helper utilities to all Actors who want to control the
20// fridge.
21template <typename T>
22class FridgeActorBase : public aos::common::actions::ActorBase<T> {
23 public:
24 FridgeActorBase(T *queues) : aos::common::actions::ActorBase<T>(queues) {}
25
26 protected:
27 void DoFridgeProfile(double height, double angle,
28 ProfileParams elevator_parameters,
29 ProfileParams arm_parameters, bool grabbers) {
30 DoFridgeProfile(height, angle, elevator_parameters, arm_parameters,
31 grabbers, grabbers, grabbers);
32 }
33
Austin Schuhfa65bfd2015-03-14 21:10:44 -070034 bool StartFridgeProfile(double height, double angle,
35 ProfileParams elevator_parameters,
36 ProfileParams arm_parameters, bool top_grabbers,
37 bool front_grabbers, bool back_grabbers) {
Austin Schuh6e242ac2015-03-07 17:08:21 -080038 auto new_fridge_goal = control_loops::fridge_queue.goal.MakeMessage();
Austin Schuh1d44bd42015-03-15 16:40:45 -070039 new_fridge_goal->profiling_type = 0;
Austin Schuh6e242ac2015-03-07 17:08:21 -080040 new_fridge_goal->max_velocity = elevator_parameters.velocity;
41 new_fridge_goal->max_acceleration = elevator_parameters.acceleration;
42 new_fridge_goal->height = height;
43 new_fridge_goal->velocity = 0.0;
44 new_fridge_goal->max_angular_velocity = arm_parameters.velocity;
45 new_fridge_goal->max_angular_acceleration = arm_parameters.acceleration;
46 new_fridge_goal->angle = angle;
47 new_fridge_goal->angular_velocity = 0.0;
48 new_fridge_goal->grabbers.top_front = top_grabbers;
49 new_fridge_goal->grabbers.top_back = top_grabbers;
50 new_fridge_goal->grabbers.bottom_front = front_grabbers;
51 new_fridge_goal->grabbers.bottom_back = back_grabbers;
Austin Schuhfa65bfd2015-03-14 21:10:44 -070052 LOG(INFO, "Starting profile to %f, %f\n", height, angle);
Austin Schuh6e242ac2015-03-07 17:08:21 -080053
54 if (!new_fridge_goal.Send()) {
55 LOG(ERROR, "Failed to send fridge goal\n");
Austin Schuhfa65bfd2015-03-14 21:10:44 -070056 return false;
57 }
58 return true;
59 }
60
Brian Silvermaned86fc12015-03-19 23:37:35 -070061 enum ProfileStatus { RUNNING, DONE, CANCELED };
Austin Schuhfa65bfd2015-03-14 21:10:44 -070062
63 ProfileStatus IterateProfile(double height, double angle,
64 ProfileParams elevator_parameters,
65 ProfileParams arm_parameters, bool top_grabbers,
66 bool front_grabbers, bool back_grabbers) {
Austin Schuhfa65bfd2015-03-14 21:10:44 -070067 if (this->ShouldCancel()) {
Austin Schuhfa65bfd2015-03-14 21:10:44 -070068 LOG(INFO, "Canceling fridge movement\n");
69 auto new_fridge_goal = control_loops::fridge_queue.goal.MakeMessage();
Austin Schuh1d44bd42015-03-15 16:40:45 -070070 new_fridge_goal->profiling_type = 0;
Austin Schuhfa65bfd2015-03-14 21:10:44 -070071 new_fridge_goal->max_velocity = elevator_parameters.velocity;
72 new_fridge_goal->max_acceleration = elevator_parameters.acceleration;
73 new_fridge_goal->height =
74 control_loops::fridge_queue.status->height +
75 (control_loops::fridge_queue.status->goal_velocity *
76 ::std::abs(control_loops::fridge_queue.status->goal_velocity)) /
77 (2.0 * new_fridge_goal->max_acceleration);
Austin Schuh511e8652015-03-15 17:53:31 -070078 height = new_fridge_goal->height;
Austin Schuhfa65bfd2015-03-14 21:10:44 -070079 new_fridge_goal->velocity = 0.0;
80 new_fridge_goal->max_angular_velocity = arm_parameters.velocity;
81 new_fridge_goal->max_angular_acceleration = arm_parameters.acceleration;
82 new_fridge_goal->angle =
83 control_loops::fridge_queue.status->angle +
84 (control_loops::fridge_queue.status->goal_angular_velocity *
85 ::std::abs(
86 control_loops::fridge_queue.status->goal_angular_velocity)) /
87 (2.0 * new_fridge_goal->max_angular_acceleration);
Austin Schuh511e8652015-03-15 17:53:31 -070088 angle = new_fridge_goal->angle;
Austin Schuhfa65bfd2015-03-14 21:10:44 -070089 new_fridge_goal->angular_velocity = 0.0;
90 new_fridge_goal->grabbers.top_front = top_grabbers;
91 new_fridge_goal->grabbers.top_back = top_grabbers;
92 new_fridge_goal->grabbers.bottom_front = front_grabbers;
93 new_fridge_goal->grabbers.bottom_back = back_grabbers;
94
95 if (!new_fridge_goal.Send()) {
96 LOG(ERROR, "Failed to send fridge goal\n");
Austin Schuhfa65bfd2015-03-14 21:10:44 -070097 }
Brian Silvermaned86fc12015-03-19 23:37:35 -070098 return CANCELED;
Austin Schuhfa65bfd2015-03-14 21:10:44 -070099 }
100 control_loops::fridge_queue.status.FetchAnother();
101
102 constexpr double kProfileError = 1e-5;
103 constexpr double kAngleEpsilon = 0.02, kHeightEpsilon = 0.015;
104
105 if (control_loops::fridge_queue.status->state != 4) {
106 LOG(ERROR, "Fridge no longer running, aborting action\n");
107 return CANCELED;
108 }
109
110 if (::std::abs(control_loops::fridge_queue.status->goal_angle - angle) <
111 kProfileError &&
112 ::std::abs(control_loops::fridge_queue.status->goal_height - height) <
113 kProfileError &&
114 ::std::abs(control_loops::fridge_queue.status->goal_angular_velocity) <
115 kProfileError &&
116 ::std::abs(control_loops::fridge_queue.status->goal_velocity) <
117 kProfileError) {
118 LOG(INFO, "Profile done.\n");
Brian Silvermaned86fc12015-03-19 23:37:35 -0700119 if (::std::abs(control_loops::fridge_queue.status->angle - angle) <
Austin Schuhfa65bfd2015-03-14 21:10:44 -0700120 kAngleEpsilon &&
121 ::std::abs(control_loops::fridge_queue.status->height -
122 height) < kHeightEpsilon) {
123 LOG(INFO, "Near goal, done.\n");
124 return DONE;
125 }
126 }
127
Brian Silvermaned86fc12015-03-19 23:37:35 -0700128 return RUNNING;
Austin Schuhfa65bfd2015-03-14 21:10:44 -0700129 }
130
131 void DoFridgeProfile(double height, double angle,
132 ProfileParams elevator_parameters,
133 ProfileParams arm_parameters, bool top_grabbers,
134 bool front_grabbers, bool back_grabbers) {
135 if (!StartFridgeProfile(height, angle, elevator_parameters, arm_parameters,
136 top_grabbers, front_grabbers, back_grabbers)) {
Austin Schuh6e242ac2015-03-07 17:08:21 -0800137 return;
138 }
139
140 while (true) {
Austin Schuhfa65bfd2015-03-14 21:10:44 -0700141 ProfileStatus status =
142 IterateProfile(height, angle, elevator_parameters, arm_parameters,
143 top_grabbers, front_grabbers, back_grabbers);
144 if (status == DONE || status == CANCELED) {
Austin Schuh6e242ac2015-03-07 17:08:21 -0800145 return;
146 }
Austin Schuh6e242ac2015-03-07 17:08:21 -0800147 }
148 }
Austin Schuh813b9af2015-03-08 18:46:58 -0700149
150 bool WaitOrCancel(::aos::time::Time duration) {
151 ::aos::time::Time end_time = ::aos::time::Time::Now() + duration;
152 while (::aos::time::Time::Now() <= end_time) {
153 ::aos::time::PhasedLoopXMS(::aos::controls::kLoopFrequency.ToMSec(),
154 2500);
155 if (this->ShouldCancel()) return false;
156 }
157 return true;
158 }
Austin Schuh6e242ac2015-03-07 17:08:21 -0800159};
160
161} // namespace actors
162} // namespace frc971
163
164#endif // FRC971_ACTORS_FRIDGE_PROFILE_LIB_H_