blob: f951e06ed523c2e0d59431e171fb56cc8e4b9755 [file] [log] [blame]
joe93778a62014-02-15 13:22:14 -08001#include "frc971/control_loops/shooter/shooter.h"
joe2d92e852014-01-25 14:31:24 -08002
3#include <stdio.h>
4
5#include <algorithm>
6
7#include "aos/common/control_loop/control_loops.q.h"
Ben Fredricksonedf0e092014-02-16 10:46:50 +00008#include "aos/common/control_loop/control_loops.q.h"
joe2d92e852014-01-25 14:31:24 -08009#include "aos/common/logging/logging.h"
10
11#include "frc971/constants.h"
joe93778a62014-02-15 13:22:14 -080012#include "frc971/control_loops/shooter/shooter_motor_plant.h"
joe2d92e852014-01-25 14:31:24 -080013
14namespace frc971 {
15namespace control_loops {
16
Ben Fredricksonedf0e092014-02-16 10:46:50 +000017using ::aos::time::Time;
Ben Fredrickson22c93322014-02-17 05:56:33 +000018
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000019void ZeroedStateFeedbackLoop::CapU() {
20 const double old_voltage = voltage_;
21 voltage_ += U(0, 0);
22
23 uncapped_voltage_ = voltage_;
24
Ben Fredrickson22c93322014-02-17 05:56:33 +000025 // TODO(ben): Limit the voltage if we are ever not certain that things are
26 // working.
27 double limit = 12.0;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000028
29 // Make sure that reality and the observer can't get too far off. There is a
30 // delay by one cycle between the applied voltage and X_hat(2, 0), so compare
31 // against last cycle's voltage.
32 if (X_hat(2, 0) > last_voltage_ + 2.0) {
33 voltage_ -= X_hat(2, 0) - (last_voltage_ + 2.0);
Ben Fredrickson22c93322014-02-17 05:56:33 +000034 //LOG(DEBUG, "X_hat(2, 0) = %f\n", X_hat(2, 0));
35 } else if (X_hat(2, 0) < last_voltage_ - 2.0) {
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000036 voltage_ += X_hat(2, 0) - (last_voltage_ - 2.0);
Ben Fredrickson22c93322014-02-17 05:56:33 +000037 //LOG(DEBUG, "X_hat(2, 0) = %f\n", X_hat(2, 0));
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000038 }
39
40 voltage_ = std::min(limit, voltage_);
41 voltage_ = std::max(-limit, voltage_);
42 U(0, 0) = voltage_ - old_voltage;
Ben Fredrickson22c93322014-02-17 05:56:33 +000043 //LOG(DEBUG, "abc %f\n", X_hat(2, 0) - voltage_);
44 //LOG(DEBUG, "error %f\n", X_hat(0, 0) - R(0, 0));
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000045
46 last_voltage_ = voltage_;
47}
48
Ben Fredricksonedf0e092014-02-16 10:46:50 +000049ShooterMotor::ShooterMotor(control_loops::ShooterGroup *my_shooter)
50 : aos::control_loops::ControlLoop<control_loops::ShooterGroup>(my_shooter),
51 shooter_(MakeShooterLoop()),
Ben Fredrickson22c93322014-02-17 05:56:33 +000052 calibration_position_(0.0),
53 state_(STATE_INITIALIZE),
54 loading_problem_end_time_(0, 0),
55 shooter_brake_set_time_(0, 0),
56 prepare_fire_end_time_(0, 0),
57 shot_end_time_(0, 0),
58 cycles_not_moved_(0),
59 initial_loop_(true) {}
Ben Fredrickson1e512ff2014-02-15 21:36:52 +000060
61// Positive is out, and positive power is out.
joe2d92e852014-01-25 14:31:24 -080062void ShooterMotor::RunIteration(
Ben Fredricksonedf0e092014-02-16 10:46:50 +000063 const control_loops::ShooterGroup::Goal *goal,
64 const control_loops::ShooterGroup::Position *position,
65 control_loops::ShooterGroup::Output *output,
Ben Fredrickson22c93322014-02-17 05:56:33 +000066 control_loops::ShooterGroup::Status *status) {
Ben Fredrickson1e512ff2014-02-15 21:36:52 +000067 constexpr double dt = 0.01;
68
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000069 // we must always have these or we have issues.
70 if (goal == NULL || status == NULL) {
Ben Fredrickson22c93322014-02-17 05:56:33 +000071 if (output) output->voltage = 0;
72 LOG(ERROR, "Thought I would just check for null and die.\n");
73 return;
74 }
75
76 if (initial_loop_) {
77 initial_loop_ = false;
78 shooter_.SetPositionDirectly(position->position);
79 } else {
80 shooter_.SetPositionValues(position->position);
Ben Fredrickson1e512ff2014-02-15 21:36:52 +000081 }
joe2d92e852014-01-25 14:31:24 -080082
83 // Disable the motors now so that all early returns will return with the
84 // motors disabled.
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000085 if (output) output->voltage = 0;
joe2d92e852014-01-25 14:31:24 -080086
Ben Fredrickson1e512ff2014-02-15 21:36:52 +000087 const frc971::constants::Values &values = constants::GetValues();
88
Ben Fredrickson22c93322014-02-17 05:56:33 +000089 double real_position = shooter_.position();
90 double adjusted_position = shooter_.position() - calibration_position_;
91
92 if (position) {
93 last_position_ = *position;
94 LOG(DEBUG,
95 "pos > real: %.2f adjusted: %.2f raw: %.2f calib: %.2f state= %d\n",
96 real_position, adjusted_position, position->position,
97 calibration_position_, state_);
98 }
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000099
Ben Fredrickson7d980c22014-02-16 21:39:02 +0000100 // don't even let the control loops run
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000101 bool shooter_loop_disable = false;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000102
Ben Fredrickson7d980c22014-02-16 21:39:02 +0000103 // adds voltage to take up slack in gears before shot
104 bool apply_some_voltage = false;
105
Ben Fredrickson1e512ff2014-02-15 21:36:52 +0000106 switch (state_) {
Ben Fredrickson22c93322014-02-17 05:56:33 +0000107 case STATE_INITIALIZE:
108 // start off with the assumption that we are at the value
109 // futhest back given our sensors
110 if (position && position->pusher_distal_hall_effect) {
111 //TODO_ben: use posedge
112 calibration_position_ =
113 position->position - values.shooter.pusher_distal.lower_limit;
114 } else if (position && position->pusher_proximal_hall_effect) {
115 //TODO_ben: use posedge
116 calibration_position_ =
117 position->position - values.shooter.pusher_proximal.lower_limit;
118 }
Ben Fredrickson1e512ff2014-02-15 21:36:52 +0000119
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000120 state_ = STATE_REQUEST_LOAD;
Ben Fredrickson1e512ff2014-02-15 21:36:52 +0000121
Ben Fredrickson22c93322014-02-17 05:56:33 +0000122 // zero out initial goal
123 shooter_.SetGoalPosition(real_position, 0.0);
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000124 if (position) {
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000125 output->latch_piston = position->plunger_back_hall_effect;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000126 } else {
Ben Fredrickson22c93322014-02-17 05:56:33 +0000127 // we don't know what is going on so just close the latch to be safe
128 output->latch_piston = true;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000129 }
130 output->brake_piston = false;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000131 break;
132 case STATE_REQUEST_LOAD:
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000133 if (position->plunger_back_hall_effect && position->latch_hall_effect) {
Ben Fredrickson22c93322014-02-17 05:56:33 +0000134 // already latched
135 state_ = STATE_PREPARE_SHOT;
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000136 } else if (position->pusher_distal_hall_effect ||
Ben Fredrickson22c93322014-02-17 05:56:33 +0000137 (adjusted_position) < 0) {
138 state_ = STATE_LOAD_BACKTRACK;
139 //TODO_ben: double check that rezero is the right thing to do here
140 if (position) {
141 calibration_position_ = position->position;
142 }
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000143 } else {
Ben Fredrickson22c93322014-02-17 05:56:33 +0000144 state_ = STATE_LOAD;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000145 }
146
Ben Fredrickson22c93322014-02-17 05:56:33 +0000147 shooter_.SetGoalPosition(0.0, 0.0);
148 if (position && output)
149 output->latch_piston = position->plunger_back_hall_effect;
150 if (output) output->brake_piston = false;
151 break;
152 case STATE_LOAD_BACKTRACK:
153 if (adjusted_position > values.shooter.pusher_distal.upper_limit + 0.01) {
154 shooter_.SetGoalPosition(
155 real_position - values.shooter_zeroing_speed * dt,
156 values.shooter_zeroing_speed);
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000157 } else {
Ben Fredrickson22c93322014-02-17 05:56:33 +0000158 state_ = STATE_LOAD;
159 }
160
161 if (output) output->latch_piston = false;
162 if (output) output->brake_piston = true;
163 break;
164 case STATE_LOAD:
165 if (position && position->pusher_proximal_hall_effect &&
166 !last_position_.pusher_proximal_hall_effect) {
167 //TODO_ben: use posedge
168 calibration_position_ =
169 position->position - values.shooter.pusher_proximal.upper_limit;
170 }
171 if (position && position->pusher_distal_hall_effect &&
172 !last_position_.pusher_distal_hall_effect) {
173 //TODO_ben: use posedge
174 calibration_position_ =
175 position->position - values.shooter.pusher_distal.lower_limit;
176 }
177
178 shooter_.SetGoalPosition(calibration_position_, 0.0);
179 if (position && output) {
180 output->latch_piston = position->plunger_back_hall_effect;
181 }
182
183 if (position->plunger_back_hall_effect && position->latch_hall_effect) {
184 state_ = STATE_PREPARE_SHOT;
185 } else if (position->plunger_back_hall_effect &&
186 abs(adjusted_position - PowerToPosition(goal->shot_power)) <
187 0.05) {
188 state_ = STATE_LOADING_PROBLEM;
189 loading_problem_end_time_ =
190 Time::Now(Time::kDefaultClock) + Time::InSeconds(3.0);
191 }
192 if (output) output->brake_piston = false;
193 break;
194 case STATE_LOADING_PROBLEM:
195 if (Time::Now() > loading_problem_end_time_) {
196 state_ = STATE_UNLOAD;
197 } else if (position->plunger_back_hall_effect &&
198 position->latch_hall_effect) {
199 state_ = STATE_PREPARE_SHOT;
200 }
201 shooter_.SetGoalPosition(calibration_position_, 0.0);
202 LOG(DEBUG, "Waiting on latch: plunger %d, latch: %d\n",
203 position->plunger_back_hall_effect, position->latch_hall_effect);
204
205 if (output) output->latch_piston = true;
206 if (output) output->brake_piston = false;
207 break;
208 case STATE_PREPARE_SHOT:
209 shooter_.SetGoalPosition(PowerToPosition(goal->shot_power), 0.0);
210 if (abs(adjusted_position - PowerToPosition(goal->shot_power)) < 0.05) {
211 state_ = STATE_READY;
212 output->latch_piston = true;
213 output->brake_piston = true;
214 shooter_brake_set_time_ =
215 Time::Now(Time::kDefaultClock) + Time::InSeconds(3.0);
216 } else {
217 output->latch_piston = true;
218 output->brake_piston = false;
219 }
220 break;
221 case STATE_READY:
222 if (Time::Now() > shooter_brake_set_time_) {
223 shooter_loop_disable = true;
224 if (goal->unload_requested) {
225 state_ = STATE_UNLOAD;
226 } else if (abs(adjusted_position - PowerToPosition(goal->shot_power)) >
227 0.05) {
228 state_ = STATE_PREPARE_SHOT;
229 } else if (goal->shot_requested) {
230 state_ = STATE_REQUEST_FIRE;
231 }
232
233 }
234 output->latch_piston = true;
235 output->brake_piston = true;
236 break;
237 case STATE_REQUEST_FIRE:
238 shooter_loop_disable = true;
239 if (position->plunger_back_hall_effect) {
240 prepare_fire_end_time_ =
241 Time::Now(Time::kDefaultClock) + Time::InMS(40.0);
242 apply_some_voltage = true;
243 state_ = STATE_PREPARE_FIRE;
244 } else {
245 state_ = STATE_REQUEST_LOAD;
246 }
247 break;
248 case STATE_PREPARE_FIRE:
249 shooter_loop_disable = true;
250 if (Time::Now(Time::kDefaultClock) < prepare_fire_end_time_) {
251 apply_some_voltage = true;
252 } else {
253 state_ = STATE_FIRE;
254 cycles_not_moved_ = 0;
255 shot_end_time_ = Time::Now(Time::kDefaultClock) + Time::InMS(500);
256 }
257
258 output->latch_piston = true;
259 output->brake_piston = true;
260
261 break;
262 case STATE_FIRE:
263 shooter_loop_disable = true;
264 //TODO_ben: need approamately equal
265 if (abs(last_position_.position - adjusted_position) < 0.07) {
266 cycles_not_moved_++;
267 } else {
268 cycles_not_moved_ = 0;
269 }
270 if ((adjusted_position < 0.10 && cycles_not_moved_ > 5) ||
271 Time::Now(Time::kDefaultClock) > shot_end_time_) {
272 state_ = STATE_REQUEST_LOAD;
273 }
274 output->latch_piston = true;
275 output->brake_piston = true;
276 break;
277 case STATE_UNLOAD:
278 if (position->plunger_back_hall_effect && position->latch_hall_effect) {
279 shooter_.SetGoalPosition(0.02, 0.0);
280 if (adjusted_position < 0.04) {
281 output->latch_piston = false;
282 }
283 } else {
284 output->latch_piston = false;
285 state_ = STATE_UNLOAD_MOVE;
286 }
287
288 output->brake_piston = false;
289 break;
290 case STATE_UNLOAD_MOVE:
291 if (adjusted_position > values.shooter_total_length - 0.03) {
292 shooter_.SetGoalPosition(real_position, 0.0);
293 state_ = STATE_READY_UNLOAD;
294 } else {
295 shooter_.SetGoalPosition(
296 real_position + values.shooter_zeroing_speed * dt,
297 values.shooter_zeroing_speed);
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000298 }
299
300 output->latch_piston = false;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000301 output->brake_piston = false;
302 break;
303 case STATE_READY_UNLOAD:
304 if (!goal->unload_requested) {
305 state_ = STATE_REQUEST_LOAD;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000306 }
307
Ben Fredrickson22c93322014-02-17 05:56:33 +0000308 output->latch_piston = false;
309 output->brake_piston = false;
310 break;
joe2d92e852014-01-25 14:31:24 -0800311 }
312
Ben Fredrickson7d980c22014-02-16 21:39:02 +0000313 if (apply_some_voltage) {
Ben Fredrickson22c93322014-02-17 05:56:33 +0000314 shooter_.Update(true);
315 if (output) output->voltage = 2.0;
Ben Fredrickson7d980c22014-02-16 21:39:02 +0000316 } else if (!shooter_loop_disable) {
Ben Fredrickson22c93322014-02-17 05:56:33 +0000317 LOG(DEBUG, "Running the loop, goal is %f\n", shooter_.R(0, 0));
318 shooter_.Update(output == NULL);
319 if (output) output->voltage = shooter_.voltage();
Ben Fredrickson7d980c22014-02-16 21:39:02 +0000320 } else {
Ben Fredrickson22c93322014-02-17 05:56:33 +0000321 shooter_.Update(true);
322 if (output) output->voltage = 0.0;
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000323 }
Ben Fredrickson7d980c22014-02-16 21:39:02 +0000324
Ben Fredrickson22c93322014-02-17 05:56:33 +0000325 status->done =
326 ::std::abs(adjusted_position - PowerToPosition(goal->shot_power)) < 0.004;
joe2d92e852014-01-25 14:31:24 -0800327}
328
329} // namespace control_loops
330} // namespace frc971