blob: 1127aa95d31f3112f059a436b1a4d51626977d94 [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 }
65 case State::STUCK_UNLOAD:
Austin Schuhe666dc62018-08-08 21:09:12 -070066 if (force_move) {
67 ForceMove();
68 } else if (force_reset && encoder_valid &&
69 state_ == State::STUCK_UNLOAD) {
Austin Schuh4fae0fc2018-03-27 23:51:42 -070070 state_ = State::UNINITIALIZED;
71 } else if (timeout_ > 0) {
72 --timeout_;
73 }
74 break;
75 case State::LOAD:
Austin Schuhe666dc62018-08-08 21:09:12 -070076 if (force_move) {
77 ForceMove();
78 } else if (!encoder_valid) {
Austin Schuh4fae0fc2018-03-27 23:51:42 -070079 goal_ = PreviousGoal(kUnloadGoal);
80 StuckUnload();
81 } else if (unload) {
82 goal_ = PreviousGoal(kUnloadGoal);
83 Unload();
84 } else if (!Near()) {
85 if (timeout_ > 0) {
86 --timeout_;
87 } else {
88 StuckUnload();
89 }
90 } else if (prime) {
91 goal_ = NextGoal(kPrimeGoal);
92 Prime();
93 }
94 break;
95 case State::PRIME:
Austin Schuhe666dc62018-08-08 21:09:12 -070096 if (force_move) {
97 ForceMove();
98 } else if (!encoder_valid) {
Austin Schuh4fae0fc2018-03-27 23:51:42 -070099 goal_ = PreviousGoal(kUnloadGoal);
100 StuckUnload();
101 } else if (unload) {
102 goal_ = PreviousGoal(kUnloadGoal);
103 Unload();
104 } else if (!prime) {
105 goal_ = PreviousGoal(kLoadGoal);
106 Load();
107 } else if (!Near()) {
108 if (timeout_ > 0) {
109 --timeout_;
110 } else {
111 StuckUnload();
112 }
113 } else if (fire) {
114 goal_ = NextGoal(kFireGoal);
115 Fire();
116 }
117 break;
118
119 case State::FIRE:
Austin Schuhe666dc62018-08-08 21:09:12 -0700120 if (force_move) {
121 ForceMove();
122 } else if (!encoder_valid) {
Austin Schuh4fae0fc2018-03-27 23:51:42 -0700123 goal_ = PreviousGoal(kUnloadGoal);
124 StuckUnload();
125 } else if (!Near()) {
126 if (timeout_ > 0) {
127 --timeout_;
128 } else {
129 StuckUnload();
130 }
131 } else {
132 // TODO(austin): Maybe have a different timeout for success.
133 if (timeout_ > 0) {
134 timeout_--;
Austin Schuh72656c42018-04-01 16:37:52 -0700135 } else if (!prime) {
136 state_ = State::WAIT_FOR_LOAD;
Austin Schuh4fae0fc2018-03-27 23:51:42 -0700137 }
138 }
139 break;
Austin Schuh72656c42018-04-01 16:37:52 -0700140 case State::WAIT_FOR_LOAD:
Austin Schuhe666dc62018-08-08 21:09:12 -0700141 if (force_move) {
142 ForceMove();
143 } else if (!encoder_valid) {
Austin Schuh72656c42018-04-01 16:37:52 -0700144 StuckUnload();
145 } else if (unload) {
146 // Goal is as good as it is going to get since unload is the fire
147 // position.
148 Unload();
149 } else if (prime) {
150 state_ = State::WAIT_FOR_LOAD_RELEASE;
151 }
152 break;
153 case State::WAIT_FOR_LOAD_RELEASE:
Austin Schuhe666dc62018-08-08 21:09:12 -0700154 if (force_move) {
155 ForceMove();
156 } else if (!encoder_valid) {
Austin Schuh72656c42018-04-01 16:37:52 -0700157 StuckUnload();
158 } else if (unload) {
159 // Goal is as good as it is going to get since unload is the fire
160 // position.
161 Unload();
162 } else if (!prime) {
163 Load();
164 goal_ = NextGoal(kLoadGoal);
165 }
166 break;
Austin Schuh4fae0fc2018-03-27 23:51:42 -0700167 }
168 const float error = goal_ - angle_;
169 const float derror = (error - last_error_) * 200.0f;
170
171 switch (state_) {
172 case State::UNINITIALIZED:
173 output_ = 0.0f;
174 break;
175 case State::STUCK_UNLOAD:
176 case State::UNLOAD:
177 if (timeout_ > 0) {
178 output_ = -0.1f;
179 } else {
180 output_ = 0.0f;
181 }
182 break;
183
Austin Schuhe666dc62018-08-08 21:09:12 -0700184 case State::FORCE_MOVE:
185 output_ = 1.0f;
186 break;
187
Austin Schuh4fae0fc2018-03-27 23:51:42 -0700188 case State::LOAD:
189 case State::PRIME:
Austin Schuh72656c42018-04-01 16:37:52 -0700190 case State::FIRE:
191 case State::WAIT_FOR_LOAD:
192 case State::WAIT_FOR_LOAD_RELEASE: {
Austin Schuh4fae0fc2018-03-27 23:51:42 -0700193 constexpr float kP = 3.00f;
194 constexpr float kD = 0.00f;
195 output_ = kP * error + kD * derror;
196 } break;
197 }
198 last_error_ = error;
199}
200
201} // namespace seems_reasonable
202} // namespace motors