blob: 4705f8673f8caf8cd6accadabf8e782fe36aef9d [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),
41 last_encoder_(0.0){}
42
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
64
65 void set_zeroing_state(JointZeroingState zeroing_state) {
66 zeroing_state_ = zeroing_state;
67 }
68
69
70 JointZeroingState zeroing_state() const { return zeroing_state_; }
71
72
73 // Sets the calibration offset given the absolute angle and the corrisponding
74 // encoder value.
75 void SetCalibration(double encoder_val, double known_position) {
76 offset_ = known_position - encoder_val;
77 }
78
79
Ben Fredricksonedf0e092014-02-16 10:46:50 +000080 bool SetCalibrationOnEdge(const constants::Values::ShooterLimits &shooter_values,
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000081 JointZeroingState zeroing_state) {
82 double edge_encoder;
83 double known_position;
Ben Fredricksonedf0e092014-02-16 10:46:50 +000084 if (GetPositionOfEdge(shooter_values, &edge_encoder, &known_position)) {
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000085 LOG(INFO, "Calibration edge.\n");
86 SetCalibration(edge_encoder, known_position);
87 set_zeroing_state(zeroing_state);
88 return true;
89 }
90 return false;
91 }
92
93
Ben Fredricksonedf0e092014-02-16 10:46:50 +000094 void SetPositionValues(double position) {
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000095 Eigen::Matrix<double, 1, 1> Y;
96 Y << position;
97 Correct(Y);
98 }
99
100
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000101 void SetGoalPosition(double desired_position,
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000102 double desired_velocity) {
103 // austin said something about which matrix to set, but I didn't under
104 // very much of it
105 //some_matrix = {desired_position, desired_velocity};
Ben Fredrickson7d980c22014-02-16 21:39:02 +0000106 R << desired_position, desired_velocity, 0;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000107 }
108
109 double position() const { return X_hat(0, 0); }
110 double encoder() const { return encoder_; }
111 double last_encoder() const { return last_encoder_; }
112
113 // Returns true if an edge was detected in the last cycle and then sets the
114 // edge_position to the absolute position of the edge.
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000115 bool GetPositionOfEdge(const constants::Values::ShooterLimits &shooter,
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000116 double *edge_encoder, double *known_position);
117
118#undef COUNT_SETTER_GETTER
119
120 private:
121 // The accumulated voltage to apply to the motor.
122 double voltage_;
123 double last_voltage_;
124 double uncapped_voltage_;
125 double offset_;
126
127 double previous_position_;
128
129 JointZeroingState zeroing_state_;
130 double encoder_;
131 double last_encoder_;
132};
133
134
joe93778a62014-02-15 13:22:14 -0800135class ShooterMotor
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000136 : public aos::control_loops::ControlLoop<control_loops::ShooterGroup> {
joe93778a62014-02-15 13:22:14 -0800137 public:
138 explicit ShooterMotor(
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000139 control_loops::ShooterGroup *my_shooter = &control_loops::shooter_queue_group);
joe93778a62014-02-15 13:22:14 -0800140
141 // True if the goal was moved to avoid goal windup.
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000142 //bool capped_goal() const { return shooter_.capped_goal(); }
joe93778a62014-02-15 13:22:14 -0800143
Ben Fredrickson4413f3b2014-02-16 23:25:36 +0000144 double PowerToPosition(double power) {
145 LOG(WARNING, "power to position not correctly implemented");
146 const frc971::constants::Values &values = constants::GetValues();
147 double new_pos =
148 (power > values.shooter.upper_limit) ? values.shooter.upper_limit
149 : (power < 0.0) ? 0.0 : power;
150
151 return new_pos;
152 }
153
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000154typedef enum {
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000155 STATE_INITIALIZE,
156 STATE_REQUEST_LOAD,
157 STATE_LOAD_BACKTRACK,
158 STATE_LOAD,
159 STATE_LOADING_PROBLEM,
160 STATE_PREPARE_SHOT,
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000161 STATE_READY,
162 STATE_REQUEST_FIRE,
163 STATE_PREPARE_FIRE,
164 STATE_FIRE,
165 STATE_UNLOAD,
166 STATE_UNLOAD_MOVE,
167 STATE_READY_UNLOAD
168} State;
169
joe93778a62014-02-15 13:22:14 -0800170 protected:
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000171
joe93778a62014-02-15 13:22:14 -0800172 virtual void RunIteration(
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000173 const ShooterGroup::Goal *goal,
174 const control_loops::ShooterGroup::Position *position,
175 ShooterGroup::Output *output,
176 ShooterGroup::Status *status);
joe93778a62014-02-15 13:22:14 -0800177
178 private:
179 // Friend the test classes for acces to the internal state.
180 friend class testing::ShooterTest_NoWindupPositive_Test;
181 friend class testing::ShooterTest_NoWindupNegative_Test;
182
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000183 control_loops::ShooterGroup::Position last_position_;
184
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000185 ZeroedStateFeedbackLoop shooter_;
joe93778a62014-02-15 13:22:14 -0800186
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000187 // position need to zero
188 double calibration_position_;
189
190 // state machine state
191 State state_;
192
193 // time to giving up on loading problem
194 Time loading_problem_end_time_;
195
196 // wait for brake to set
197 Time shooter_brake_set_time_;
198
199 // we are attempting to take up some of the backlash
200 // in the gears before the plunger hits
201 Time prepare_fire_end_time_;
202
203 // time that shot must have completed
204 Time shot_end_time_;
205
206 // track cycles that we are stuck to detect errors
207 int cycles_not_moved_;
208
joe93778a62014-02-15 13:22:14 -0800209 DISALLOW_COPY_AND_ASSIGN(ShooterMotor);
210};
211
212} // namespace control_loops
213} // namespace frc971
214
215#endif // FRC971_CONTROL_LOOPS_shooter_shooter_H_