blob: 2cb688f7221f4e2824d5fea2394e0e53bb261d89 [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
Briana6553ed2014-04-02 21:26:46 -07006#include "aos/common/controls/control_loop.h"
joe93778a62014-02-15 13:22:14 -08007#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 {
Austin Schuhd34569d2014-02-18 20:26:38 -080017class ShooterTest_UnloadWindupPositive_Test;
18class ShooterTest_UnloadWindupNegative_Test;
Brian Silverman07202632014-08-09 21:53:07 -070019class ShooterTest_RezeroWhileUnloading_Test;
joe93778a62014-02-15 13:22:14 -080020};
21
Ben Fredricksonedf0e092014-02-16 10:46:50 +000022using ::aos::time::Time;
23
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000024// Note: Everything in this file assumes that there is a 1 cycle delay between
25// power being requested and it showing up at the motor. It assumes that
26// X_hat(2, 1) is the voltage being applied as well. It will go unstable if
27// that isn't true.
28
29// This class implements the CapU function correctly given all the extra
Brian Silverman0a151c92014-05-02 15:28:44 -070030// information that we know about.
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000031// It does not have any zeroing logic in it, only logic to deal with a delta U
32// controller.
33class ZeroedStateFeedbackLoop : public StateFeedbackLoop<3, 1, 1> {
34 public:
Brian Silverman0a151c92014-05-02 15:28:44 -070035 ZeroedStateFeedbackLoop(StateFeedbackLoop<3, 1, 1> &&loop)
36 : StateFeedbackLoop<3, 1, 1>(::std::move(loop)),
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000037 voltage_(0.0),
38 last_voltage_(0.0),
39 uncapped_voltage_(0.0),
Austin Schuhd34569d2014-02-18 20:26:38 -080040 offset_(0.0),
41 max_voltage_(12.0),
42 capped_goal_(false) {}
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000043
44 const static int kZeroingMaxVoltage = 5;
45
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000046 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
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000057 // Sets the calibration offset given the absolute angle and the corrisponding
58 // encoder value.
Austin Schuh30537882014-02-18 01:07:23 -080059 void SetCalibration(double encoder_val, double known_position);
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000060
Austin Schuh30537882014-02-18 01:07:23 -080061 double offset() const { return offset_; }
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000062
Brian Silvermana21c3a22014-06-12 21:49:15 -070063 double absolute_position() const { return X_hat(0, 0) + kPositionOffset; }
64 double absolute_velocity() const { return X_hat(1, 0); }
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000065
Austin Schuh30537882014-02-18 01:07:23 -080066 void CorrectPosition(double position) {
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000067 Eigen::Matrix<double, 1, 1> Y;
Austin Schuh30537882014-02-18 01:07:23 -080068 Y << position + offset_ - kPositionOffset;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000069 Correct(Y);
70 }
71
Austin Schuhd34569d2014-02-18 20:26:38 -080072 // Recomputes the power goal for the current controller and position/velocity.
73 void RecalculatePowerGoal();
74
Brian Silvermana21c3a22014-06-12 21:49:15 -070075 double goal_position() const { return R(0, 0) + kPositionOffset; }
76 double goal_velocity() const { return R(1, 0); }
Austin Schuh30537882014-02-18 01:07:23 -080077 void InitializeState(double position) {
Brian Silvermana21c3a22014-06-12 21:49:15 -070078 mutable_X_hat(0, 0) = position - kPositionOffset;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000079 }
80
Austin Schuh30537882014-02-18 01:07:23 -080081 void SetGoalPosition(double desired_position, double desired_velocity) {
Brian Silverman273d8a32014-05-10 22:19:09 -070082 LOG(DEBUG, "Goal position: %f Goal velocity: %f\n", desired_position,
83 desired_velocity);
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000084
Brian Silverman0ca790b2014-06-12 21:33:08 -070085 mutable_R() << desired_position - kPositionOffset, desired_velocity,
Austin Schuhbe1401f2014-02-18 03:18:41 -080086 (-A(1, 0) / A(1, 2) * (desired_position - kPositionOffset) -
87 A(1, 1) / A(1, 2) * desired_velocity);
Austin Schuh30537882014-02-18 01:07:23 -080088 }
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000089
Brian Silvermana21c3a22014-06-12 21:49:15 -070090 double position() const { return X_hat(0, 0) - offset_ + kPositionOffset; }
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000091
Brian Silverman273d8a32014-05-10 22:19:09 -070092 void set_max_voltage(double max_voltage) { max_voltage_ = max_voltage; }
Austin Schuhd34569d2014-02-18 20:26:38 -080093 bool capped_goal() const { return capped_goal_; }
94
95 void CapGoal();
96
Brian Silverman07202632014-08-09 21:53:07 -070097 // Friend the test classes for acces to the internal state.
98 friend class testing::ShooterTest_RezeroWhileUnloading_Test;
99
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000100 private:
Austin Schuh30537882014-02-18 01:07:23 -0800101 // The offset between what is '0' (0 rate on the spring) and the 0 (all the
102 // way cocked).
Austin Schuh25933852014-02-23 02:04:13 -0800103 constexpr static double kPositionOffset = kMaxExtension;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000104 // The accumulated voltage to apply to the motor.
105 double voltage_;
106 double last_voltage_;
107 double uncapped_voltage_;
108 double offset_;
Austin Schuhd34569d2014-02-18 20:26:38 -0800109 double max_voltage_;
110 bool capped_goal_;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000111};
112
Austin Schuh06cbbf12014-02-22 02:07:31 -0800113const Time kUnloadTimeout = Time::InSeconds(10);
Austin Schuh492331a2014-03-02 21:13:17 -0800114const Time kLoadTimeout = Time::InSeconds(2);
Austin Schuh1a08bd82014-03-09 00:47:11 -0800115const Time kLoadProblemEndTimeout = Time::InSeconds(1.0);
Austin Schuh06cbbf12014-02-22 02:07:31 -0800116const Time kShooterBrakeSetTime = Time::InSeconds(0.05);
Austin Schuhecdb0252014-02-23 04:12:35 -0800117// Time to wait after releasing the latch piston before winching back again.
118const Time kShotEndTimeout = Time::InSeconds(0.2);
Austin Schuh06cbbf12014-02-22 02:07:31 -0800119const Time kPrepareFireEndTime = Time::InMS(40);
120
joe93778a62014-02-15 13:22:14 -0800121class ShooterMotor
Brian Silverman38111502014-04-10 12:36:26 -0700122 : public aos::controls::ControlLoop<control_loops::ShooterGroup> {
joe93778a62014-02-15 13:22:14 -0800123 public:
Ben Fredrickson22c93322014-02-17 05:56:33 +0000124 explicit ShooterMotor(control_loops::ShooterGroup *my_shooter =
125 &control_loops::shooter_queue_group);
joe93778a62014-02-15 13:22:14 -0800126
127 // True if the goal was moved to avoid goal windup.
Austin Schuhd34569d2014-02-18 20:26:38 -0800128 bool capped_goal() const { return shooter_.capped_goal(); }
joe93778a62014-02-15 13:22:14 -0800129
Austin Schuh30537882014-02-18 01:07:23 -0800130 double PowerToPosition(double power);
James Kuszmauld29689f2014-03-02 13:06:54 -0800131 double PositionToPower(double position);
Brian Silverman07202632014-08-09 21:53:07 -0700132 void CheckCalibrations(const control_loops::ShooterGroup::Position *position);
Ben Fredrickson4413f3b2014-02-16 23:25:36 +0000133
Ben Fredrickson22c93322014-02-17 05:56:33 +0000134 typedef enum {
135 STATE_INITIALIZE = 0,
136 STATE_REQUEST_LOAD = 1,
137 STATE_LOAD_BACKTRACK = 2,
138 STATE_LOAD = 3,
139 STATE_LOADING_PROBLEM = 4,
140 STATE_PREPARE_SHOT = 5,
141 STATE_READY = 6,
Austin Schuh30537882014-02-18 01:07:23 -0800142 STATE_FIRE = 8,
143 STATE_UNLOAD = 9,
144 STATE_UNLOAD_MOVE = 10,
145 STATE_READY_UNLOAD = 11,
146 STATE_ESTOP = 12
Ben Fredrickson22c93322014-02-17 05:56:33 +0000147 } State;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000148
Austin Schuh30537882014-02-18 01:07:23 -0800149 State state() { return state_; }
Ben Fredricksona6d77542014-02-17 07:54:43 +0000150
joe93778a62014-02-15 13:22:14 -0800151 protected:
152 virtual void RunIteration(
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000153 const ShooterGroup::Goal *goal,
154 const control_loops::ShooterGroup::Position *position,
Ben Fredrickson22c93322014-02-17 05:56:33 +0000155 ShooterGroup::Output *output, ShooterGroup::Status *status);
joe93778a62014-02-15 13:22:14 -0800156
157 private:
Brian Silvermand1e65b92014-03-08 17:07:14 -0800158 // We have to override this to keep the pistons in the correct positions.
159 virtual void ZeroOutputs();
160
joe93778a62014-02-15 13:22:14 -0800161 // Friend the test classes for acces to the internal state.
Austin Schuhd34569d2014-02-18 20:26:38 -0800162 friend class testing::ShooterTest_UnloadWindupPositive_Test;
163 friend class testing::ShooterTest_UnloadWindupNegative_Test;
Brian Silverman07202632014-08-09 21:53:07 -0700164 friend class testing::ShooterTest_RezeroWhileUnloading_Test;
joe93778a62014-02-15 13:22:14 -0800165
Austin Schuh30537882014-02-18 01:07:23 -0800166 // Enter state STATE_UNLOAD
167 void Unload() {
168 state_ = STATE_UNLOAD;
Austin Schuh06cbbf12014-02-22 02:07:31 -0800169 unload_timeout_ = Time::Now() + kUnloadTimeout;
Austin Schuh30537882014-02-18 01:07:23 -0800170 }
171 // Enter state STATE_LOAD
172 void Load() {
173 state_ = STATE_LOAD;
Austin Schuh06cbbf12014-02-22 02:07:31 -0800174 load_timeout_ = Time::Now() + kLoadTimeout;
Austin Schuh30537882014-02-18 01:07:23 -0800175 }
176
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000177 control_loops::ShooterGroup::Position last_position_;
178
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000179 ZeroedStateFeedbackLoop shooter_;
joe93778a62014-02-15 13:22:14 -0800180
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000181 // state machine state
182 State state_;
183
184 // time to giving up on loading problem
185 Time loading_problem_end_time_;
186
Austin Schuh30537882014-02-18 01:07:23 -0800187 // The end time when loading for it to timeout.
188 Time load_timeout_;
189
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000190 // wait for brake to set
191 Time shooter_brake_set_time_;
James Kuszmaul7290a942014-02-26 20:04:13 -0800192
Austin Schuh30537882014-02-18 01:07:23 -0800193 // The timeout for unloading.
194 Time unload_timeout_;
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000195
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000196 // time that shot must have completed
197 Time shot_end_time_;
198
199 // track cycles that we are stuck to detect errors
200 int cycles_not_moved_;
201
Austin Schuh30537882014-02-18 01:07:23 -0800202 double firing_starting_position_;
203
204 // True if the latch should be engaged and the brake should be engaged.
205 bool latch_piston_;
206 bool brake_piston_;
207 int32_t last_distal_posedge_count_;
208 int32_t last_proximal_posedge_count_;
Austin Schuh4edad872014-03-02 11:56:12 -0800209 uint32_t shot_count_;
Austin Schuh492331a2014-03-02 21:13:17 -0800210 bool zeroed_;
211 int distal_posedge_validation_cycles_left_;
212 int proximal_posedge_validation_cycles_left_;
Austin Schuh2e976812014-03-05 19:56:58 -0800213 bool last_distal_current_;
214 bool last_proximal_current_;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000215
joe93778a62014-02-15 13:22:14 -0800216 DISALLOW_COPY_AND_ASSIGN(ShooterMotor);
217};
218
219} // namespace control_loops
220} // namespace frc971
221
222#endif // FRC971_CONTROL_LOOPS_shooter_shooter_H_