blob: 7cf80c14152c8678c2aa91dfe7540239d66dd6bf [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,
32 bool encoder_valid, float angle) {
33 // 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);
42 if (prime && fire) {
43 Unload();
44 }
45 break;
46 case State::UNLOAD:
47 if (!encoder_valid) {
48 state_ = State::STUCK_UNLOAD;
49 } else if (!unload && prime && fire) {
50 // Go to the next goal from the current location. This handles if we
51 // fired or didn't on the previous cycle.
52 goal_ = angle_;
53 goal_ = NextGoal(kLoadGoal);
54 Load();
55 }
56 case State::STUCK_UNLOAD:
57 if (force_reset && encoder_valid && state_ == State::STUCK_UNLOAD) {
58 state_ = State::UNINITIALIZED;
59 } else if (timeout_ > 0) {
60 --timeout_;
61 }
62 break;
63 case State::LOAD:
64 if (!encoder_valid) {
65 goal_ = PreviousGoal(kUnloadGoal);
66 StuckUnload();
67 } else if (unload) {
68 goal_ = PreviousGoal(kUnloadGoal);
69 Unload();
70 } else if (!Near()) {
71 if (timeout_ > 0) {
72 --timeout_;
73 } else {
74 StuckUnload();
75 }
76 } else if (prime) {
77 goal_ = NextGoal(kPrimeGoal);
78 Prime();
79 }
80 break;
81 case State::PRIME:
82 if (!encoder_valid) {
83 goal_ = PreviousGoal(kUnloadGoal);
84 StuckUnload();
85 } else if (unload) {
86 goal_ = PreviousGoal(kUnloadGoal);
87 Unload();
88 } else if (!prime) {
89 goal_ = PreviousGoal(kLoadGoal);
90 Load();
91 } else if (!Near()) {
92 if (timeout_ > 0) {
93 --timeout_;
94 } else {
95 StuckUnload();
96 }
97 } else if (fire) {
98 goal_ = NextGoal(kFireGoal);
99 Fire();
100 }
101 break;
102
103 case State::FIRE:
104 if (!encoder_valid) {
105 goal_ = PreviousGoal(kUnloadGoal);
106 StuckUnload();
107 } else if (!Near()) {
108 if (timeout_ > 0) {
109 --timeout_;
110 } else {
111 StuckUnload();
112 }
113 } else {
114 // TODO(austin): Maybe have a different timeout for success.
115 if (timeout_ > 0) {
116 timeout_--;
Austin Schuh72656c42018-04-01 16:37:52 -0700117 } else if (!prime) {
118 state_ = State::WAIT_FOR_LOAD;
Austin Schuh4fae0fc2018-03-27 23:51:42 -0700119 }
120 }
121 break;
Austin Schuh72656c42018-04-01 16:37:52 -0700122 case State::WAIT_FOR_LOAD:
123 if (!encoder_valid) {
124 StuckUnload();
125 } else if (unload) {
126 // Goal is as good as it is going to get since unload is the fire
127 // position.
128 Unload();
129 } else if (prime) {
130 state_ = State::WAIT_FOR_LOAD_RELEASE;
131 }
132 break;
133 case State::WAIT_FOR_LOAD_RELEASE:
134 if (!encoder_valid) {
135 StuckUnload();
136 } else if (unload) {
137 // Goal is as good as it is going to get since unload is the fire
138 // position.
139 Unload();
140 } else if (!prime) {
141 Load();
142 goal_ = NextGoal(kLoadGoal);
143 }
144 break;
Austin Schuh4fae0fc2018-03-27 23:51:42 -0700145 }
146 const float error = goal_ - angle_;
147 const float derror = (error - last_error_) * 200.0f;
148
149 switch (state_) {
150 case State::UNINITIALIZED:
151 output_ = 0.0f;
152 break;
153 case State::STUCK_UNLOAD:
154 case State::UNLOAD:
155 if (timeout_ > 0) {
156 output_ = -0.1f;
157 } else {
158 output_ = 0.0f;
159 }
160 break;
161
162 case State::LOAD:
163 case State::PRIME:
Austin Schuh72656c42018-04-01 16:37:52 -0700164 case State::FIRE:
165 case State::WAIT_FOR_LOAD:
166 case State::WAIT_FOR_LOAD_RELEASE: {
Austin Schuh4fae0fc2018-03-27 23:51:42 -0700167 constexpr float kP = 3.00f;
168 constexpr float kD = 0.00f;
169 output_ = kP * error + kD * derror;
170 } break;
171 }
172 last_error_ = error;
173}
174
175} // namespace seems_reasonable
176} // namespace motors