blob: 4448b33d19821d9f35835aa2f080cc91abc3cdff [file] [log] [blame]
Austin Schuh4fae0fc2018-03-27 23:51:42 -07001#include "motors/seems_reasonable/spring.h"
2
3#include "frc971/zeroing/wrap.h"
4
5#include <cmath>
6
7namespace motors {
8namespace seems_reasonable {
9namespace {
10
11constexpr float kTwoPi = 2.0 * M_PI;
12
13} // namespace
14
15float NextGoal(float current_goal, float goal) {
16 float remainder = remainderf(current_goal - goal, kTwoPi);
17 if (remainder >= 0.0f) {
18 remainder -= kTwoPi;
19 }
20 return -remainder + current_goal;
21}
22
23float PreviousGoal(float current_goal, float goal) {
24 float remainder = remainderf(current_goal - goal, kTwoPi);
25 if (remainder <= 0.0f) {
26 remainder += kTwoPi;
27 }
28 return -remainder + current_goal;
29}
30
31void Spring::Iterate(bool unload, bool prime, bool fire, bool force_reset,
Austin Schuhe666dc62018-08-08 21:09:12 -070032 bool force_move, bool encoder_valid, float angle) {
Austin Schuh4fae0fc2018-03-27 23:51:42 -070033 // Angle is +- M_PI. So, we need to find the nearest angle to the previous
34 // one, and that's our new angle.
35 angle_ = ::frc971::zeroing::Wrap(angle_, angle, kTwoPi);
36
37 switch (state_) {
38 case State::UNINITIALIZED:
39 // Go to the previous unload from where we are.
40 goal_ = angle_;
41 goal_ = PreviousGoal(kUnloadGoal);
Austin Schuhe666dc62018-08-08 21:09:12 -070042 if (force_move) {
43 ForceMove();
44 } else if (prime && fire) {
Austin Schuh4fae0fc2018-03-27 23:51:42 -070045 Unload();
46 }
47 break;
Austin Schuhe666dc62018-08-08 21:09:12 -070048 case State::FORCE_MOVE:
49 if (!force_move) {
50 state_ = State::UNINITIALIZED;
51 }
52 break;
Austin Schuh4fae0fc2018-03-27 23:51:42 -070053 case State::UNLOAD:
Austin Schuhe666dc62018-08-08 21:09:12 -070054 if (force_move) {
55 ForceMove();
56 } else if (!encoder_valid) {
Austin Schuh4fae0fc2018-03-27 23:51:42 -070057 state_ = State::STUCK_UNLOAD;
58 } else if (!unload && prime && fire) {
59 // Go to the next goal from the current location. This handles if we
60 // fired or didn't on the previous cycle.
61 goal_ = angle_;
62 goal_ = NextGoal(kLoadGoal);
63 Load();
64 }
Brian Silverman1eea1132018-09-02 16:29:53 -070065 // TODO(Austin): This should be a break, right?
66 // fallthrough
Austin Schuh4fae0fc2018-03-27 23:51:42 -070067 case State::STUCK_UNLOAD:
Austin Schuhe666dc62018-08-08 21:09:12 -070068 if (force_move) {
69 ForceMove();
70 } else if (force_reset && encoder_valid &&
71 state_ == State::STUCK_UNLOAD) {
Austin Schuh4fae0fc2018-03-27 23:51:42 -070072 state_ = State::UNINITIALIZED;
73 } else if (timeout_ > 0) {
74 --timeout_;
75 }
76 break;
77 case State::LOAD:
Austin Schuhe666dc62018-08-08 21:09:12 -070078 if (force_move) {
79 ForceMove();
80 } else if (!encoder_valid) {
Austin Schuh4fae0fc2018-03-27 23:51:42 -070081 goal_ = PreviousGoal(kUnloadGoal);
82 StuckUnload();
83 } else if (unload) {
84 goal_ = PreviousGoal(kUnloadGoal);
85 Unload();
86 } else if (!Near()) {
87 if (timeout_ > 0) {
88 --timeout_;
89 } else {
90 StuckUnload();
91 }
92 } else if (prime) {
93 goal_ = NextGoal(kPrimeGoal);
94 Prime();
95 }
96 break;
97 case State::PRIME:
Austin Schuhe666dc62018-08-08 21:09:12 -070098 if (force_move) {
99 ForceMove();
100 } else if (!encoder_valid) {
Austin Schuh4fae0fc2018-03-27 23:51:42 -0700101 goal_ = PreviousGoal(kUnloadGoal);
102 StuckUnload();
103 } else if (unload) {
104 goal_ = PreviousGoal(kUnloadGoal);
105 Unload();
106 } else if (!prime) {
107 goal_ = PreviousGoal(kLoadGoal);
108 Load();
109 } else if (!Near()) {
110 if (timeout_ > 0) {
111 --timeout_;
112 } else {
113 StuckUnload();
114 }
115 } else if (fire) {
116 goal_ = NextGoal(kFireGoal);
117 Fire();
118 }
119 break;
120
121 case State::FIRE:
Austin Schuhe666dc62018-08-08 21:09:12 -0700122 if (force_move) {
123 ForceMove();
124 } else if (!encoder_valid) {
Austin Schuh4fae0fc2018-03-27 23:51:42 -0700125 goal_ = PreviousGoal(kUnloadGoal);
126 StuckUnload();
127 } else if (!Near()) {
128 if (timeout_ > 0) {
129 --timeout_;
130 } else {
131 StuckUnload();
132 }
133 } else {
134 // TODO(austin): Maybe have a different timeout for success.
135 if (timeout_ > 0) {
136 timeout_--;
Austin Schuh72656c42018-04-01 16:37:52 -0700137 } else if (!prime) {
138 state_ = State::WAIT_FOR_LOAD;
Austin Schuh4fae0fc2018-03-27 23:51:42 -0700139 }
140 }
141 break;
Austin Schuh72656c42018-04-01 16:37:52 -0700142 case State::WAIT_FOR_LOAD:
Austin Schuhe666dc62018-08-08 21:09:12 -0700143 if (force_move) {
144 ForceMove();
145 } else if (!encoder_valid) {
Austin Schuh72656c42018-04-01 16:37:52 -0700146 StuckUnload();
147 } else if (unload) {
148 // Goal is as good as it is going to get since unload is the fire
149 // position.
150 Unload();
151 } else if (prime) {
152 state_ = State::WAIT_FOR_LOAD_RELEASE;
153 }
154 break;
155 case State::WAIT_FOR_LOAD_RELEASE:
Austin Schuhe666dc62018-08-08 21:09:12 -0700156 if (force_move) {
157 ForceMove();
158 } else if (!encoder_valid) {
Austin Schuh72656c42018-04-01 16:37:52 -0700159 StuckUnload();
160 } else if (unload) {
161 // Goal is as good as it is going to get since unload is the fire
162 // position.
163 Unload();
164 } else if (!prime) {
165 Load();
166 goal_ = NextGoal(kLoadGoal);
167 }
168 break;
Austin Schuh4fae0fc2018-03-27 23:51:42 -0700169 }
170 const float error = goal_ - angle_;
171 const float derror = (error - last_error_) * 200.0f;
172
173 switch (state_) {
174 case State::UNINITIALIZED:
175 output_ = 0.0f;
176 break;
177 case State::STUCK_UNLOAD:
178 case State::UNLOAD:
179 if (timeout_ > 0) {
180 output_ = -0.1f;
181 } else {
182 output_ = 0.0f;
183 }
184 break;
185
Austin Schuhe666dc62018-08-08 21:09:12 -0700186 case State::FORCE_MOVE:
187 output_ = 1.0f;
188 break;
189
Austin Schuh4fae0fc2018-03-27 23:51:42 -0700190 case State::LOAD:
191 case State::PRIME:
Austin Schuh72656c42018-04-01 16:37:52 -0700192 case State::FIRE:
193 case State::WAIT_FOR_LOAD:
194 case State::WAIT_FOR_LOAD_RELEASE: {
Austin Schuh4fae0fc2018-03-27 23:51:42 -0700195 constexpr float kP = 3.00f;
196 constexpr float kD = 0.00f;
197 output_ = kP * error + kD * derror;
198 } break;
199 }
200 last_error_ = error;
201}
202
203} // namespace seems_reasonable
204} // namespace motors