blob: 86991e8c846324d5f371685f6e4790a3c7a5aef6 [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 Fredrickson1f633ef2014-02-16 05:35:45 +000018
19void ZeroedStateFeedbackLoop::CapU() {
20 const double old_voltage = voltage_;
21 voltage_ += U(0, 0);
22
23 uncapped_voltage_ = voltage_;
24
25 double limit = zeroing_state() != UNKNOWN_POSITION ? 12.0 : kZeroingMaxVoltage;
26
27 // Make sure that reality and the observer can't get too far off. There is a
28 // delay by one cycle between the applied voltage and X_hat(2, 0), so compare
29 // against last cycle's voltage.
30 if (X_hat(2, 0) > last_voltage_ + 2.0) {
31 voltage_ -= X_hat(2, 0) - (last_voltage_ + 2.0);
32 LOG(DEBUG, "X_hat(2, 0) = %f\n", X_hat(2, 0));
33 } else if (X_hat(2, 0) < last_voltage_ -2.0) {
34 voltage_ += X_hat(2, 0) - (last_voltage_ - 2.0);
35 LOG(DEBUG, "X_hat(2, 0) = %f\n", X_hat(2, 0));
36 }
37
38 voltage_ = std::min(limit, voltage_);
39 voltage_ = std::max(-limit, voltage_);
40 U(0, 0) = voltage_ - old_voltage;
41 LOG(DEBUG, "abc %f\n", X_hat(2, 0) - voltage_);
42 LOG(DEBUG, "error %f\n", X_hat(0, 0) - R(0, 0));
43
44 last_voltage_ = voltage_;
45}
46
Ben Fredricksonedf0e092014-02-16 10:46:50 +000047ShooterMotor::ShooterMotor(control_loops::ShooterGroup *my_shooter)
48 : aos::control_loops::ControlLoop<control_loops::ShooterGroup>(my_shooter),
49 shooter_(MakeShooterLoop()),
50 calibration_position_(0.0),
51 state_(STATE_INITIALIZE),
52 loading_problem_end_time_(0,0),
53 shooter_brake_set_time_(0,0),
54 prepare_fire_end_time_(0,0),
55 shot_end_time_(0,0),
56 cycles_not_moved_(0) { }
joe2d92e852014-01-25 14:31:24 -080057
Ben Fredrickson1e512ff2014-02-15 21:36:52 +000058
59// Positive is out, and positive power is out.
joe2d92e852014-01-25 14:31:24 -080060void ShooterMotor::RunIteration(
Ben Fredricksonedf0e092014-02-16 10:46:50 +000061 const control_loops::ShooterGroup::Goal *goal,
62 const control_loops::ShooterGroup::Position *position,
63 control_loops::ShooterGroup::Output *output,
64 control_loops::ShooterGroup::Status * status) {
Ben Fredrickson1e512ff2014-02-15 21:36:52 +000065 constexpr double dt = 0.01;
66
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000067 // we must always have these or we have issues.
68 if (goal == NULL || status == NULL) {
Ben Fredrickson1e512ff2014-02-15 21:36:52 +000069 if (output) output->voltage = 0;
70 LOG(ERROR, "Thought I would just check for null and die.\n");
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000071 return;
Ben Fredrickson1e512ff2014-02-15 21:36:52 +000072 }
joe2d92e852014-01-25 14:31:24 -080073
74 // Disable the motors now so that all early returns will return with the
75 // motors disabled.
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000076 if (output) output->voltage = 0;
joe2d92e852014-01-25 14:31:24 -080077
Ben Fredrickson1e512ff2014-02-15 21:36:52 +000078 const frc971::constants::Values &values = constants::GetValues();
79
Ben Fredricksonedf0e092014-02-16 10:46:50 +000080 double real_position = position->position - calibration_position_;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000081
Ben Fredrickson7d980c22014-02-16 21:39:02 +000082 // don't even let the control loops run
Ben Fredricksonedf0e092014-02-16 10:46:50 +000083 bool shooter_loop_disable = false;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000084
Ben Fredrickson7d980c22014-02-16 21:39:02 +000085 // adds voltage to take up slack in gears before shot
86 bool apply_some_voltage = false;
87
Ben Fredrickson1e512ff2014-02-15 21:36:52 +000088 switch (state_) {
89 case STATE_INITIALIZE:
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000090 // start off with the assumption that we are at the value
91 // futhest back given our sensors
92 if (position && position->pusher_distal_hall_effect){
Ben Fredrickson1e512ff2014-02-15 21:36:52 +000093 calibration_position_ = position->position -
Ben Fredricksonedf0e092014-02-16 10:46:50 +000094 values.shooter.pusher_distal.lower_limit;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000095 } else if (position && position->pusher_proximal_hall_effect) {
96 calibration_position_ = position->position -
Ben Fredricksonedf0e092014-02-16 10:46:50 +000097 values.shooter.pusher_proximal.lower_limit;
Ben Fredrickson1e512ff2014-02-15 21:36:52 +000098 } else {
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000099 calibration_position_ = values.shooter_total_length;
Ben Fredrickson1e512ff2014-02-15 21:36:52 +0000100 }
101
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000102 state_ = STATE_REQUEST_LOAD;
Ben Fredrickson1e512ff2014-02-15 21:36:52 +0000103
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000104 // zero out initial goal
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000105 shooter_.SetGoalPosition(0.0, 0.0);
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000106 if (position) {
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000107 output->latch_piston = position->plunger_back_hall_effect;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000108 } else {
109 // we don't know what is going on so just close the latch to be safe
110 output->latch_piston = true;
111 }
112 output->brake_piston = false;
113 break;
Ben Fredrickson1e512ff2014-02-15 21:36:52 +0000114 case STATE_REQUEST_LOAD:
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000115 if (position->plunger_back_hall_effect && position->latch_hall_effect) {
116 // already latched
117 state_ = STATE_PREPARE_SHOT;
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000118 } else if (position->pusher_distal_hall_effect ||
119 (real_position) < 0) {
120 state_ = STATE_LOAD_BACKTRACK;
121 if (position) {
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000122 calibration_position_ = position->position;
123 }
124 } else {
125 state_ = STATE_LOAD;
126 }
127
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000128 shooter_.SetGoalPosition(0.0, 0.0);
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000129 if (position && output) output->latch_piston = position->plunger_back_hall_effect;
130 output->brake_piston = false;
131 break;
Ben Fredrickson1e512ff2014-02-15 21:36:52 +0000132 case STATE_LOAD_BACKTRACK:
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000133 if (real_position < values.shooter.pusher_distal.upper_limit + 0.01) {
134 shooter_.SetGoalPosition(position->position + values.shooter_zeroing_speed*dt,
135 values.shooter_zeroing_speed);
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000136 } else {
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000137 state_ = STATE_LOAD;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000138 }
139
140 output->latch_piston = false;
141 output->brake_piston = true;
Ben Fredrickson1e512ff2014-02-15 21:36:52 +0000142 break;
143 case STATE_LOAD:
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000144 if (position->pusher_proximal_hall_effect &&
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000145 !last_position_.pusher_proximal_hall_effect) {
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000146 calibration_position_ = position->position -
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000147 values.shooter.pusher_proximal.upper_limit;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000148 }
149 if (position->pusher_distal_hall_effect &&
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000150 !last_position_.pusher_distal_hall_effect) {
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000151 calibration_position_ = position->position -
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000152 values.shooter.pusher_distal.lower_limit;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000153 }
154
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000155 shooter_.SetGoalPosition(calibration_position_, 0.0);
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000156 if (position && output) output->latch_piston = position->plunger_back_hall_effect;
157 if(output) output->brake_piston = false;
158
159 if (position->plunger_back_hall_effect && position->latch_hall_effect) {
160 state_ = STATE_PREPARE_SHOT;
161 } else if (position->plunger_back_hall_effect &&
162 position->position == PowerToPosition(goal->shot_power)) {
163 //TODO_ben: I'm worried it will bounce states if the position is drifting slightly
164 state_ = STATE_LOADING_PROBLEM;
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000165 loading_problem_end_time_ = Time::Now(Time::kDefaultClock) + Time::InSeconds(3.0);
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000166 }
Ben Fredrickson1e512ff2014-02-15 21:36:52 +0000167 break;
168 case STATE_LOADING_PROBLEM:
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000169 if (position->plunger_back_hall_effect && position->latch_hall_effect) {
170 state_ = STATE_PREPARE_SHOT;
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000171 } else if (real_position < -0.02 || Time::Now() > loading_problem_end_time_) {
172 state_ = STATE_UNLOAD;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000173 }
174
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000175 shooter_.SetGoalPosition(position->position - values.shooter_zeroing_speed*dt,
176 values.shooter_zeroing_speed);
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000177 if (output) output->latch_piston = true;
178 if (output) output->brake_piston = false;
Ben Fredrickson1e512ff2014-02-15 21:36:52 +0000179 break;
180 case STATE_PREPARE_SHOT:
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000181 shooter_.SetGoalPosition(
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000182 PowerToPosition(goal->shot_power), 0.0);
183 //TODO_ben: I'm worried it will bounce states if the position is drifting slightly
184 if (position->position == PowerToPosition(goal->shot_power)) {
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000185 state_ = STATE_READY;
186 output->latch_piston = true;
187 output->brake_piston = true;
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000188 shooter_brake_set_time_ = Time::Now(Time::kDefaultClock) + Time::InSeconds(3.0);
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000189 } else {
190 output->latch_piston =true;
191 output->brake_piston = false;
192 }
Ben Fredrickson1e512ff2014-02-15 21:36:52 +0000193 break;
194 case STATE_READY:
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000195 if (Time::Now() > shooter_brake_set_time_) {
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000196 shooter_loop_disable = true;
197 if (goal->unload_requested) {
198 state_ = STATE_UNLOAD;
199 } else if (PowerToPosition(goal->shot_power)
200 != position->position) {
201 //TODO_ben: I'm worried it will bounce states if the position is drifting slightly
202 state_ = STATE_PREPARE_SHOT;
203 }else if (goal->shot_requested) {
204 state_ = STATE_REQUEST_FIRE;
205 }
206
207 }
208 output->latch_piston = true;
209 output->brake_piston = true;
Ben Fredrickson1e512ff2014-02-15 21:36:52 +0000210 break;
211 case STATE_REQUEST_FIRE:
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000212 shooter_loop_disable = true;
213 if (position->plunger_back_hall_effect) {
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000214 prepare_fire_end_time_ = Time::Now(Time::kDefaultClock)
215 + Time::InMS(40.0);
Ben Fredrickson7d980c22014-02-16 21:39:02 +0000216 apply_some_voltage = true;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000217 state_ = STATE_PREPARE_FIRE;
218 } else {
219 state_ = STATE_REQUEST_LOAD;
220 }
Ben Fredrickson1e512ff2014-02-15 21:36:52 +0000221 break;
222 case STATE_PREPARE_FIRE:
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000223 shooter_loop_disable = true;
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000224 if (Time::Now(Time::kDefaultClock) < prepare_fire_end_time_) {
Ben Fredrickson7d980c22014-02-16 21:39:02 +0000225 apply_some_voltage = true;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000226 } else {
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000227 state_ = STATE_FIRE;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000228 cycles_not_moved_ = 0;
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000229 shot_end_time_ = Time::Now(Time::kDefaultClock) +
230 Time::InMS(500);
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000231 }
232
233 output->latch_piston = true;
234 output->brake_piston = true;
235
Ben Fredrickson1e512ff2014-02-15 21:36:52 +0000236 break;
237 case STATE_FIRE:
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000238 shooter_loop_disable = true;
239 //TODO_ben: need approamately equal
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000240 if (last_position_.position - position->position < 7) {
241 cycles_not_moved_++;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000242 } else {
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000243 cycles_not_moved_ = 0;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000244 }
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000245 if ((real_position < 10.0 && cycles_not_moved_ > 5) ||
246 Time::Now(Time::kDefaultClock) > shot_end_time_) {
247 state_ = STATE_REQUEST_LOAD;
248 }
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000249 output->latch_piston = true;
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000250 output->brake_piston = true;
Ben Fredrickson1e512ff2014-02-15 21:36:52 +0000251 break;
252 case STATE_UNLOAD:
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000253 if (position->plunger_back_hall_effect && position->latch_hall_effect) {
254 shooter_.SetGoalPosition(0.02, 0.0);
255 if (real_position == 0.02) {
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000256 output->latch_piston = false;
257 }
258 } else {
259 output->latch_piston = false;
260 state_ = STATE_UNLOAD_MOVE;
261 }
262
263 output->brake_piston = false;
Ben Fredrickson1e512ff2014-02-15 21:36:52 +0000264 break;
265 case STATE_UNLOAD_MOVE:
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000266 if (position->position > values.shooter_total_length - 0.03) {
267 shooter_.SetGoalPosition(position->position, 0.0);
268 state_ = STATE_READY_UNLOAD;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000269 } else {
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000270 shooter_.SetGoalPosition(
271 position->position + values.shooter_zeroing_speed*dt,
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000272 values.shooter_zeroing_speed);
273 }
274
275 output->latch_piston = false;
276 output->brake_piston = false;
Ben Fredrickson1e512ff2014-02-15 21:36:52 +0000277 break;
278 case STATE_READY_UNLOAD:
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000279 if (!goal->unload_requested) {
280 state_ = STATE_REQUEST_LOAD;
281 }
282
283 output->latch_piston = false;
284 output->brake_piston = false;
Ben Fredrickson1e512ff2014-02-15 21:36:52 +0000285 break;
286 }
287
joe2d92e852014-01-25 14:31:24 -0800288 if (position) {
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000289 last_position_ = *position;
290 LOG(DEBUG, "pos: hall: real: %.2f absolute: %.2f\n",
291 real_position, position->position);
joe2d92e852014-01-25 14:31:24 -0800292 }
293
Ben Fredrickson7d980c22014-02-16 21:39:02 +0000294 if (apply_some_voltage) {
295 output->voltage = 2.0;
296 } else if (!shooter_loop_disable) {
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000297 output->voltage = shooter_.voltage();
Ben Fredrickson7d980c22014-02-16 21:39:02 +0000298 } else {
299 output->voltage = 0.0;
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000300 }
Ben Fredrickson7d980c22014-02-16 21:39:02 +0000301
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000302 status->done = ::std::abs(position->position - PowerToPosition(goal->shot_power)) < 0.004;
joe2d92e852014-01-25 14:31:24 -0800303}
304
305} // namespace control_loops
306} // namespace frc971