blob: 322a5569a43c5b85e076cb2bba2a8c3fd9756cbb [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 {
Austin Schuhd34569d2014-02-18 20:26:38 -080017class ShooterTest_UnloadWindupPositive_Test;
18class ShooterTest_UnloadWindupNegative_Test;
joe93778a62014-02-15 13:22:14 -080019};
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),
Austin Schuhd34569d2014-02-18 20:26:38 -080039 offset_(0.0),
40 max_voltage_(12.0),
41 capped_goal_(false) {}
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
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
Austin Schuh30537882014-02-18 01:07:23 -080063 double absolute_position() const { return X_hat(0, 0) + kPositionOffset; }
Austin Schuhbe1401f2014-02-18 03:18:41 -080064 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;
Brian Silverman2508c082014-02-17 15:45:02 -080069 LOG(DEBUG, "Setting position to %f\n", position);
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000070 Correct(Y);
71 }
72
Austin Schuhd34569d2014-02-18 20:26:38 -080073 // Recomputes the power goal for the current controller and position/velocity.
74 void RecalculatePowerGoal();
75
Austin Schuh30537882014-02-18 01:07:23 -080076 double goal_position() const { return R(0, 0) + kPositionOffset; }
77 double goal_velocity() const { return R(1, 0); }
78 void InitializeState(double position) {
79 X_hat(0, 0) = position - kPositionOffset;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000080 }
81
Austin Schuh30537882014-02-18 01:07:23 -080082 void SetGoalPosition(double desired_position, double desired_velocity) {
Austin Schuhbe1401f2014-02-18 03:18:41 -080083 LOG(DEBUG, "Goal position: %f Goal velocity: %f\n", desired_position, desired_velocity);
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000084
Austin Schuh30537882014-02-18 01:07:23 -080085 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
Austin Schuh30537882014-02-18 01:07:23 -080090 double position() const { return X_hat(0, 0) - offset_ + kPositionOffset; }
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000091
Austin Schuhd34569d2014-02-18 20:26:38 -080092 void set_max_voltage(const double max_voltage) { max_voltage_ = max_voltage; }
93 bool capped_goal() const { return capped_goal_; }
94
95 void CapGoal();
96
Ben Fredrickson1f633ef2014-02-16 05:35:45 +000097 private:
Austin Schuh30537882014-02-18 01:07:23 -080098 // The offset between what is '0' (0 rate on the spring) and the 0 (all the
99 // way cocked).
100 constexpr static double kPositionOffset = 0.305054 + 0.0254;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000101 // The accumulated voltage to apply to the motor.
102 double voltage_;
103 double last_voltage_;
104 double uncapped_voltage_;
105 double offset_;
Austin Schuhd34569d2014-02-18 20:26:38 -0800106 double max_voltage_;
107 bool capped_goal_;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000108};
109
joe93778a62014-02-15 13:22:14 -0800110class ShooterMotor
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000111 : public aos::control_loops::ControlLoop<control_loops::ShooterGroup> {
joe93778a62014-02-15 13:22:14 -0800112 public:
Ben Fredrickson22c93322014-02-17 05:56:33 +0000113 explicit ShooterMotor(control_loops::ShooterGroup *my_shooter =
114 &control_loops::shooter_queue_group);
joe93778a62014-02-15 13:22:14 -0800115
116 // True if the goal was moved to avoid goal windup.
Austin Schuhd34569d2014-02-18 20:26:38 -0800117 bool capped_goal() const { return shooter_.capped_goal(); }
joe93778a62014-02-15 13:22:14 -0800118
Austin Schuh30537882014-02-18 01:07:23 -0800119 double PowerToPosition(double power);
Ben Fredrickson4413f3b2014-02-16 23:25:36 +0000120
Ben Fredrickson22c93322014-02-17 05:56:33 +0000121 typedef enum {
122 STATE_INITIALIZE = 0,
123 STATE_REQUEST_LOAD = 1,
124 STATE_LOAD_BACKTRACK = 2,
125 STATE_LOAD = 3,
126 STATE_LOADING_PROBLEM = 4,
127 STATE_PREPARE_SHOT = 5,
128 STATE_READY = 6,
Austin Schuh30537882014-02-18 01:07:23 -0800129 STATE_PREPARE_FIRE = 7,
130 STATE_FIRE = 8,
131 STATE_UNLOAD = 9,
132 STATE_UNLOAD_MOVE = 10,
133 STATE_READY_UNLOAD = 11,
134 STATE_ESTOP = 12
Ben Fredrickson22c93322014-02-17 05:56:33 +0000135 } State;
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000136
Austin Schuh30537882014-02-18 01:07:23 -0800137 State state() { return state_; }
Ben Fredricksona6d77542014-02-17 07:54:43 +0000138
joe93778a62014-02-15 13:22:14 -0800139 protected:
140 virtual void RunIteration(
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000141 const ShooterGroup::Goal *goal,
142 const control_loops::ShooterGroup::Position *position,
Ben Fredrickson22c93322014-02-17 05:56:33 +0000143 ShooterGroup::Output *output, ShooterGroup::Status *status);
joe93778a62014-02-15 13:22:14 -0800144
145 private:
146 // Friend the test classes for acces to the internal state.
Austin Schuhd34569d2014-02-18 20:26:38 -0800147 friend class testing::ShooterTest_UnloadWindupPositive_Test;
148 friend class testing::ShooterTest_UnloadWindupNegative_Test;
joe93778a62014-02-15 13:22:14 -0800149
Austin Schuh30537882014-02-18 01:07:23 -0800150 // Enter state STATE_UNLOAD
151 void Unload() {
152 state_ = STATE_UNLOAD;
153 unload_timeout_ = Time::Now() + Time::InSeconds(1);
154 }
155 // Enter state STATE_LOAD
156 void Load() {
157 state_ = STATE_LOAD;
158 load_timeout_ = Time::Now() + Time::InSeconds(1);
159 }
160
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000161 control_loops::ShooterGroup::Position last_position_;
162
Ben Fredrickson1f633ef2014-02-16 05:35:45 +0000163 ZeroedStateFeedbackLoop shooter_;
joe93778a62014-02-15 13:22:14 -0800164
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000165 // state machine state
166 State state_;
167
168 // time to giving up on loading problem
169 Time loading_problem_end_time_;
170
Austin Schuh30537882014-02-18 01:07:23 -0800171 // The end time when loading for it to timeout.
172 Time load_timeout_;
173
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000174 // wait for brake to set
175 Time shooter_brake_set_time_;
Austin Schuh30537882014-02-18 01:07:23 -0800176
177 // The timeout for unloading.
178 Time unload_timeout_;
Ben Fredricksonedf0e092014-02-16 10:46:50 +0000179
180 // we are attempting to take up some of the backlash
181 // in the gears before the plunger hits
182 Time prepare_fire_end_time_;
183
184 // time that shot must have completed
185 Time shot_end_time_;
186
187 // track cycles that we are stuck to detect errors
188 int cycles_not_moved_;
189
Austin Schuh30537882014-02-18 01:07:23 -0800190 double firing_starting_position_;
191
192 // True if the latch should be engaged and the brake should be engaged.
193 bool latch_piston_;
194 bool brake_piston_;
195 int32_t last_distal_posedge_count_;
196 int32_t last_proximal_posedge_count_;
Ben Fredrickson22c93322014-02-17 05:56:33 +0000197
joe93778a62014-02-15 13:22:14 -0800198 DISALLOW_COPY_AND_ASSIGN(ShooterMotor);
199};
200
201} // namespace control_loops
202} // namespace frc971
203
204#endif // FRC971_CONTROL_LOOPS_shooter_shooter_H_