blob: 953bb27ee1e6c0e13b7e2640128b51f1d964e8e7 [file] [log] [blame]
joe93778a62014-02-15 13:22:14 -08001#ifndef FRC971_CONTROL_LOOPS_shooter_shooter_H_
2#define FRC971_CONTROL_LOOPS_shooter_shooter_H_
3
4#include <memory>
5
6#include "aos/common/control_loop/ControlLoop.h"
7#include "frc971/control_loops/state_feedback_loop.h"
Ben Fredricksonedf0e092014-02-16 10:46:50 +00008#include "aos/common/time.h"
joe93778a62014-02-15 13:22:14 -08009
Ben Fredricksonedf0e092014-02-16 10:46:50 +000010#include "frc971/constants.h"
joe93778a62014-02-15 13:22:14 -080011#include "frc971/control_loops/shooter/shooter_motor_plant.h"
12#include "frc971/control_loops/shooter/shooter.q.h"
13
joe93778a62014-02-15 13:22:14 -080014namespace frc971 {
15namespace control_loops {
16namespace testing {
17class ShooterTest_NoWindupPositive_Test;
18class ShooterTest_NoWindupNegative_Test;
19};
20
Ben Fredricksonedf0e092014-02-16 10:46:50 +000021using ::aos::time::Time;
22
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000023// Note: Everything in this file assumes that there is a 1 cycle delay between
24// power being requested and it showing up at the motor. It assumes that
25// X_hat(2, 1) is the voltage being applied as well. It will go unstable if
26// that isn't true.
27
28// This class implements the CapU function correctly given all the extra
29// information that we know about from the wrist motor.
30// It does not have any zeroing logic in it, only logic to deal with a delta U
31// controller.
32class ZeroedStateFeedbackLoop : public StateFeedbackLoop<3, 1, 1> {
33 public:
34 ZeroedStateFeedbackLoop(StateFeedbackLoop<3, 1, 1> loop)
35 : StateFeedbackLoop<3, 1, 1>(loop),
36 voltage_(0.0),
37 last_voltage_(0.0),
38 uncapped_voltage_(0.0),
39 offset_(0.0),
40 encoder_(0.0),
Ben Fredrickson22c93322014-02-17 05:56:33 +000041 last_encoder_(0.0) {}
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000042
43 const static int kZeroingMaxVoltage = 5;
44
45 // Caps U, but this time respects the state of the wrist as well.
46 virtual void CapU();
47
48 // Returns the accumulated voltage.
49 double voltage() const { return voltage_; }
50
51 // Returns the uncapped voltage.
52 double uncapped_voltage() const { return uncapped_voltage_; }
53
54 // Zeros the accumulator.
55 void ZeroPower() { voltage_ = 0.0; }
56
57 enum JointZeroingState {
58 // We don't know where the joint is at all.
59 UNKNOWN_POSITION,
60 // Ready for use during teleop.
61 CALIBRATED
62 };
63
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000064 void set_zeroing_state(JointZeroingState zeroing_state) {
65 zeroing_state_ = zeroing_state;
66 }
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000067
68 JointZeroingState zeroing_state() const { return zeroing_state_; }
69
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000070 // Sets the calibration offset given the absolute angle and the corrisponding
71 // encoder value.
72 void SetCalibration(double encoder_val, double known_position) {
73 offset_ = known_position - encoder_val;
74 }
75
Ben Fredrickson22c93322014-02-17 05:56:33 +000076 bool SetCalibrationOnEdge(
77 const constants::Values::ShooterLimits &shooter_values,
78 JointZeroingState zeroing_state) {
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000079 double edge_encoder;
80 double known_position;
Ben Fredricksonedf0e092014-02-16 10:46:50 +000081 if (GetPositionOfEdge(shooter_values, &edge_encoder, &known_position)) {
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000082 LOG(INFO, "Calibration edge.\n");
83 SetCalibration(edge_encoder, known_position);
84 set_zeroing_state(zeroing_state);
85 return true;
86 }
87 return false;
88 }
89
Ben Fredrickson22c93322014-02-17 05:56:33 +000090 void SetPositionDirectly(double position) { X_hat(0, 0) = position; }
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000091
Ben Fredricksonedf0e092014-02-16 10:46:50 +000092 void SetPositionValues(double position) {
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000093 Eigen::Matrix<double, 1, 1> Y;
94 Y << position;
Ben Fredrickson22c93322014-02-17 05:56:33 +000095 LOG(INFO, "Setting position to %f\n", position);
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000096 Correct(Y);
97 }
98
Ben Fredrickson22c93322014-02-17 05:56:33 +000099 void SetGoalPosition(double desired_position, double desired_velocity) {
100 // austin said something about which matrix to set, but I didn't under
101 // very much of it
102 //some_matrix = {desired_position, desired_velocity};
103 LOG(INFO, "ZSFL> dp: %.2f dz: %.2f\n", desired_position, desired_velocity);
104 R << desired_position, desired_velocity, 0;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000105 }
106
107 double position() const { return X_hat(0, 0); }
108 double encoder() const { return encoder_; }
109 double last_encoder() const { return last_encoder_; }
110
111 // Returns true if an edge was detected in the last cycle and then sets the
112 // edge_position to the absolute position of the edge.
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000113 bool GetPositionOfEdge(const constants::Values::ShooterLimits &shooter,
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000114 double *edge_encoder, double *known_position);
115
116#undef COUNT_SETTER_GETTER
117
118 private:
119 // The accumulated voltage to apply to the motor.
120 double voltage_;
121 double last_voltage_;
122 double uncapped_voltage_;
123 double offset_;
124
125 double previous_position_;
126
127 JointZeroingState zeroing_state_;
128 double encoder_;
129 double last_encoder_;
130};
131
joe93778a62014-02-15 13:22:14 -0800132class ShooterMotor
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000133 : public aos::control_loops::ControlLoop<control_loops::ShooterGroup> {
joe93778a62014-02-15 13:22:14 -0800134 public:
Ben Fredrickson22c93322014-02-17 05:56:33 +0000135 explicit ShooterMotor(control_loops::ShooterGroup *my_shooter =
136 &control_loops::shooter_queue_group);
joe93778a62014-02-15 13:22:14 -0800137
138 // True if the goal was moved to avoid goal windup.
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000139 //bool capped_goal() const { return shooter_.capped_goal(); }
joe93778a62014-02-15 13:22:14 -0800140
Ben Fredrickson4413f3b2014-02-16 23:25:36 +0000141 double PowerToPosition(double power) {
Ben Fredrickson22c93322014-02-17 05:56:33 +0000142 //LOG(WARNING, "power to position not correctly implemented\n");
Ben Fredrickson4413f3b2014-02-16 23:25:36 +0000143 const frc971::constants::Values &values = constants::GetValues();
144 double new_pos =
145 (power > values.shooter.upper_limit) ? values.shooter.upper_limit
Ben Fredrickson22c93322014-02-17 05:56:33 +0000146 : (power < 0.0)
147 ? 0.0
148 : power;
Ben Fredrickson4413f3b2014-02-16 23:25:36 +0000149
150 return new_pos;
151 }
152
Ben Fredrickson22c93322014-02-17 05:56:33 +0000153 typedef enum {
154 STATE_INITIALIZE = 0,
155 STATE_REQUEST_LOAD = 1,
156 STATE_LOAD_BACKTRACK = 2,
157 STATE_LOAD = 3,
158 STATE_LOADING_PROBLEM = 4,
159 STATE_PREPARE_SHOT = 5,
160 STATE_READY = 6,
161 STATE_REQUEST_FIRE = 7,
162 STATE_PREPARE_FIRE = 8,
163 STATE_FIRE = 9,
164 STATE_UNLOAD = 10,
165 STATE_UNLOAD_MOVE = 11,
166 STATE_READY_UNLOAD = 12
167 } State;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000168
joe93778a62014-02-15 13:22:14 -0800169 protected:
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000170
joe93778a62014-02-15 13:22:14 -0800171 virtual void RunIteration(
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000172 const ShooterGroup::Goal *goal,
173 const control_loops::ShooterGroup::Position *position,
Ben Fredrickson22c93322014-02-17 05:56:33 +0000174 ShooterGroup::Output *output, ShooterGroup::Status *status);
joe93778a62014-02-15 13:22:14 -0800175
176 private:
177 // Friend the test classes for acces to the internal state.
178 friend class testing::ShooterTest_NoWindupPositive_Test;
179 friend class testing::ShooterTest_NoWindupNegative_Test;
180
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000181 control_loops::ShooterGroup::Position last_position_;
182
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000183 ZeroedStateFeedbackLoop shooter_;
joe93778a62014-02-15 13:22:14 -0800184
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000185 // position need to zero
186 double calibration_position_;
187
188 // state machine state
189 State state_;
190
191 // time to giving up on loading problem
192 Time loading_problem_end_time_;
193
194 // wait for brake to set
195 Time shooter_brake_set_time_;
196
197 // we are attempting to take up some of the backlash
198 // in the gears before the plunger hits
199 Time prepare_fire_end_time_;
200
201 // time that shot must have completed
202 Time shot_end_time_;
203
204 // track cycles that we are stuck to detect errors
205 int cycles_not_moved_;
206
Ben Fredrickson22c93322014-02-17 05:56:33 +0000207 // setup on the intial loop may involve shortcuts
208 bool initial_loop_;
209
joe93778a62014-02-15 13:22:14 -0800210 DISALLOW_COPY_AND_ASSIGN(ShooterMotor);
211};
212
213} // namespace control_loops
214} // namespace frc971
215
216#endif // FRC971_CONTROL_LOOPS_shooter_shooter_H_