blob: fb991e35bb0a606997e7b1d151953356b4b14fee [file] [log] [blame]
Brian Silverman17f503e2015-08-02 18:17:18 -07001#ifndef Y2014_CONTROL_LOOPS_shooter_shooter_H_
2#define Y2014_CONTROL_LOOPS_shooter_shooter_H_
3
4#include <memory>
5
6#include "aos/common/controls/control_loop.h"
7#include "frc971/control_loops/state_feedback_loop.h"
8#include "aos/common/time.h"
9
10#include "y2014/constants.h"
11#include "y2014/control_loops/shooter/shooter_motor_plant.h"
12#include "y2014/control_loops/shooter/shooter.q.h"
13
Austin Schuh24957102015-11-28 16:04:40 -080014namespace y2014 {
Brian Silverman17f503e2015-08-02 18:17:18 -070015namespace control_loops {
16namespace testing {
17class ShooterTest_UnloadWindupPositive_Test;
18class ShooterTest_UnloadWindupNegative_Test;
19class ShooterTest_RezeroWhileUnloading_Test;
20};
21
Brian Silverman17f503e2015-08-02 18:17:18 -070022// Note: Everything in this file assumes that there is a 1 cycle delay between
23// power being requested and it showing up at the motor. It assumes that
24// X_hat(2, 1) is the voltage being applied as well. It will go unstable if
25// that isn't true.
26
27// This class implements the CapU function correctly given all the extra
28// information that we know about.
29// It does not have any zeroing logic in it, only logic to deal with a delta U
30// controller.
31class ZeroedStateFeedbackLoop : public StateFeedbackLoop<3, 1, 1> {
32 public:
33 ZeroedStateFeedbackLoop(StateFeedbackLoop<3, 1, 1> &&loop)
34 : StateFeedbackLoop<3, 1, 1>(::std::move(loop)),
35 voltage_(0.0),
36 last_voltage_(0.0),
37 uncapped_voltage_(0.0),
38 offset_(0.0),
39 max_voltage_(12.0),
40 capped_goal_(false) {}
41
42 const static int kZeroingMaxVoltage = 5;
43
44 virtual void CapU();
45
46 // Returns the accumulated voltage.
47 double voltage() const { return voltage_; }
48
49 // Returns the uncapped voltage.
50 double uncapped_voltage() const { return uncapped_voltage_; }
51
52 // Zeros the accumulator.
53 void ZeroPower() { voltage_ = 0.0; }
54
55 // Sets the calibration offset given the absolute angle and the corrisponding
56 // encoder value.
57 void SetCalibration(double encoder_val, double known_position);
58
59 double offset() const { return offset_; }
60
61 double absolute_position() const { return X_hat(0, 0) + kPositionOffset; }
62 double absolute_velocity() const { return X_hat(1, 0); }
63
64 void CorrectPosition(double position) {
65 Eigen::Matrix<double, 1, 1> Y;
66 Y << position + offset_ - kPositionOffset;
67 Correct(Y);
68 }
69
70 // Recomputes the power goal for the current controller and position/velocity.
71 void RecalculatePowerGoal();
72
73 double goal_position() const { return R(0, 0) + kPositionOffset; }
74 double goal_velocity() const { return R(1, 0); }
75 void InitializeState(double position) {
76 mutable_X_hat(0, 0) = position - kPositionOffset;
77 mutable_X_hat(1, 0) = 0.0;
78 mutable_X_hat(2, 0) = 0.0;
79 }
80
81 void SetGoalPosition(double desired_position, double desired_velocity) {
82 LOG(DEBUG, "Goal position: %f Goal velocity: %f\n", desired_position,
83 desired_velocity);
84
85 mutable_R() << desired_position - kPositionOffset, desired_velocity,
86 (-A(1, 0) / A(1, 2) * (desired_position - kPositionOffset) -
87 A(1, 1) / A(1, 2) * desired_velocity);
88 }
89
90 double position() const { return X_hat(0, 0) - offset_ + kPositionOffset; }
91
92 void set_max_voltage(double max_voltage) { max_voltage_ = max_voltage; }
93 bool capped_goal() const { return capped_goal_; }
94
95 void CapGoal();
96
97 // Friend the test classes for acces to the internal state.
98 friend class testing::ShooterTest_RezeroWhileUnloading_Test;
99
100 private:
101 // The offset between what is '0' (0 rate on the spring) and the 0 (all the
102 // way cocked).
Austin Schuh9d4aca82015-11-08 14:41:31 -0800103 constexpr static double kPositionOffset =
104 ::y2014::control_loops::shooter::kMaxExtension;
Brian Silverman17f503e2015-08-02 18:17:18 -0700105 // The accumulated voltage to apply to the motor.
106 double voltage_;
107 double last_voltage_;
108 double uncapped_voltage_;
109 double offset_;
110 double max_voltage_;
111 bool capped_goal_;
112};
113
Austin Schuh214e9c12016-11-25 17:26:20 -0800114static constexpr ::std::chrono::nanoseconds kUnloadTimeout =
115 ::std::chrono::seconds(10);
116static constexpr ::std::chrono::nanoseconds kLoadTimeout =
117 ::std::chrono::seconds(2);
118static constexpr ::std::chrono::nanoseconds kLoadProblemEndTimeout =
119 ::std::chrono::seconds(1);
120static constexpr ::std::chrono::nanoseconds kShooterBrakeSetTime =
121 ::std::chrono::milliseconds(50);
Brian Silverman17f503e2015-08-02 18:17:18 -0700122// Time to wait after releasing the latch piston before winching back again.
Austin Schuh214e9c12016-11-25 17:26:20 -0800123static constexpr ::std::chrono::nanoseconds kShotEndTimeout =
124 ::std::chrono::milliseconds(200);
125static constexpr ::std::chrono::nanoseconds kPrepareFireEndTime =
126 ::std::chrono::milliseconds(40);
Brian Silverman17f503e2015-08-02 18:17:18 -0700127
128class ShooterMotor
Brian Silvermanb601d892015-12-20 18:24:38 -0500129 : public aos::controls::ControlLoop<::y2014::control_loops::ShooterQueue> {
Brian Silverman17f503e2015-08-02 18:17:18 -0700130 public:
Brian Silvermanb601d892015-12-20 18:24:38 -0500131 explicit ShooterMotor(::y2014::control_loops::ShooterQueue *my_shooter =
132 &::y2014::control_loops::shooter_queue);
Brian Silverman17f503e2015-08-02 18:17:18 -0700133
134 // True if the goal was moved to avoid goal windup.
135 bool capped_goal() const { return shooter_.capped_goal(); }
136
137 double PowerToPosition(double power);
138 double PositionToPower(double position);
Austin Schuh24957102015-11-28 16:04:40 -0800139 void CheckCalibrations(
Brian Silvermanb601d892015-12-20 18:24:38 -0500140 const ::y2014::control_loops::ShooterQueue::Position *position);
Brian Silverman17f503e2015-08-02 18:17:18 -0700141
142 typedef enum {
143 STATE_INITIALIZE = 0,
144 STATE_REQUEST_LOAD = 1,
145 STATE_LOAD_BACKTRACK = 2,
146 STATE_LOAD = 3,
147 STATE_LOADING_PROBLEM = 4,
148 STATE_PREPARE_SHOT = 5,
149 STATE_READY = 6,
150 STATE_FIRE = 8,
151 STATE_UNLOAD = 9,
152 STATE_UNLOAD_MOVE = 10,
153 STATE_READY_UNLOAD = 11,
154 STATE_ESTOP = 12
155 } State;
156
157 State state() { return state_; }
158
159 protected:
160 virtual void RunIteration(
Brian Silvermanb601d892015-12-20 18:24:38 -0500161 const ::y2014::control_loops::ShooterQueue::Goal *goal,
162 const ::y2014::control_loops::ShooterQueue::Position *position,
163 ::y2014::control_loops::ShooterQueue::Output *output,
164 ::y2014::control_loops::ShooterQueue::Status *status);
Brian Silverman17f503e2015-08-02 18:17:18 -0700165
166 private:
167 // We have to override this to keep the pistons in the correct positions.
168 virtual void ZeroOutputs();
169
170 // Friend the test classes for acces to the internal state.
171 friend class testing::ShooterTest_UnloadWindupPositive_Test;
172 friend class testing::ShooterTest_UnloadWindupNegative_Test;
173 friend class testing::ShooterTest_RezeroWhileUnloading_Test;
174
175 // Enter state STATE_UNLOAD
176 void Unload() {
177 state_ = STATE_UNLOAD;
Austin Schuh214e9c12016-11-25 17:26:20 -0800178 unload_timeout_ = ::aos::monotonic_clock::now() + kUnloadTimeout;
Brian Silverman17f503e2015-08-02 18:17:18 -0700179 }
180 // Enter state STATE_LOAD
181 void Load() {
182 state_ = STATE_LOAD;
Austin Schuh214e9c12016-11-25 17:26:20 -0800183 load_timeout_ = ::aos::monotonic_clock::now() + kLoadTimeout;
Brian Silverman17f503e2015-08-02 18:17:18 -0700184 }
185
Brian Silvermanb601d892015-12-20 18:24:38 -0500186 ::y2014::control_loops::ShooterQueue::Position last_position_;
Brian Silverman17f503e2015-08-02 18:17:18 -0700187
188 ZeroedStateFeedbackLoop shooter_;
189
190 // state machine state
191 State state_;
192
193 // time to giving up on loading problem
Austin Schuh214e9c12016-11-25 17:26:20 -0800194 ::aos::monotonic_clock::time_point loading_problem_end_time_ =
195 ::aos::monotonic_clock::min_time;
Brian Silverman17f503e2015-08-02 18:17:18 -0700196
197 // The end time when loading for it to timeout.
Austin Schuh214e9c12016-11-25 17:26:20 -0800198 ::aos::monotonic_clock::time_point load_timeout_ =
199 ::aos::monotonic_clock::min_time;
Brian Silverman17f503e2015-08-02 18:17:18 -0700200
201 // wait for brake to set
Austin Schuh214e9c12016-11-25 17:26:20 -0800202 ::aos::monotonic_clock::time_point shooter_brake_set_time_ =
203 ::aos::monotonic_clock::min_time;
Brian Silverman17f503e2015-08-02 18:17:18 -0700204
205 // The timeout for unloading.
Austin Schuh214e9c12016-11-25 17:26:20 -0800206 ::aos::monotonic_clock::time_point unload_timeout_ =
207 ::aos::monotonic_clock::min_time;
Brian Silverman17f503e2015-08-02 18:17:18 -0700208
209 // time that shot must have completed
Austin Schuh214e9c12016-11-25 17:26:20 -0800210 ::aos::monotonic_clock::time_point shot_end_time_ =
211 ::aos::monotonic_clock::min_time;
Brian Silverman17f503e2015-08-02 18:17:18 -0700212
213 // track cycles that we are stuck to detect errors
214 int cycles_not_moved_;
215
216 double firing_starting_position_;
217
218 // True if the latch should be engaged and the brake should be engaged.
219 bool latch_piston_;
220 bool brake_piston_;
221 int32_t last_distal_posedge_count_;
222 int32_t last_proximal_posedge_count_;
223 uint32_t shot_count_;
224 bool zeroed_;
225 int distal_posedge_validation_cycles_left_;
226 int proximal_posedge_validation_cycles_left_;
227 bool last_distal_current_;
228 bool last_proximal_current_;
229
230 DISALLOW_COPY_AND_ASSIGN(ShooterMotor);
231};
232
233} // namespace control_loops
Austin Schuh24957102015-11-28 16:04:40 -0800234} // namespace y2014
Brian Silverman17f503e2015-08-02 18:17:18 -0700235
236#endif // Y2014_CONTROL_LOOPS_shooter_shooter_H_