blob: 01096a0dee004db9c9c4ba145984af74fa94b867 [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
John Park33858a32018-09-28 23:05:48 -07006#include "aos/controls/control_loop.h"
Brian Silverman17f503e2015-08-02 18:17:18 -07007#include "frc971/control_loops/state_feedback_loop.h"
John Park33858a32018-09-28 23:05:48 -07008#include "aos/time/time.h"
Brian Silverman17f503e2015-08-02 18:17:18 -07009
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
Austin Schuhaebfb4f2019-01-27 13:26:38 -080044 void CapU() override;
Brian Silverman17f503e2015-08-02 18:17:18 -070045
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,
Austin Schuhc5fceb82017-02-25 16:24:12 -080086 (-plant().A(1, 0) / plant().A(1, 2) *
87 (desired_position - kPositionOffset) -
88 plant().A(1, 1) / plant().A(1, 2) * desired_velocity);
Brian Silverman17f503e2015-08-02 18:17:18 -070089 }
90
91 double position() const { return X_hat(0, 0) - offset_ + kPositionOffset; }
92
93 void set_max_voltage(double max_voltage) { max_voltage_ = max_voltage; }
94 bool capped_goal() const { return capped_goal_; }
95
96 void CapGoal();
97
98 // Friend the test classes for acces to the internal state.
99 friend class testing::ShooterTest_RezeroWhileUnloading_Test;
100
101 private:
102 // The offset between what is '0' (0 rate on the spring) and the 0 (all the
103 // way cocked).
Austin Schuh9d4aca82015-11-08 14:41:31 -0800104 constexpr static double kPositionOffset =
105 ::y2014::control_loops::shooter::kMaxExtension;
Brian Silverman17f503e2015-08-02 18:17:18 -0700106 // The accumulated voltage to apply to the motor.
107 double voltage_;
108 double last_voltage_;
109 double uncapped_voltage_;
110 double offset_;
111 double max_voltage_;
112 bool capped_goal_;
113};
114
Austin Schuh214e9c12016-11-25 17:26:20 -0800115static constexpr ::std::chrono::nanoseconds kUnloadTimeout =
116 ::std::chrono::seconds(10);
117static constexpr ::std::chrono::nanoseconds kLoadTimeout =
118 ::std::chrono::seconds(2);
119static constexpr ::std::chrono::nanoseconds kLoadProblemEndTimeout =
120 ::std::chrono::seconds(1);
121static constexpr ::std::chrono::nanoseconds kShooterBrakeSetTime =
122 ::std::chrono::milliseconds(50);
Brian Silverman17f503e2015-08-02 18:17:18 -0700123// Time to wait after releasing the latch piston before winching back again.
Austin Schuh214e9c12016-11-25 17:26:20 -0800124static constexpr ::std::chrono::nanoseconds kShotEndTimeout =
125 ::std::chrono::milliseconds(200);
126static constexpr ::std::chrono::nanoseconds kPrepareFireEndTime =
127 ::std::chrono::milliseconds(40);
Brian Silverman17f503e2015-08-02 18:17:18 -0700128
129class ShooterMotor
Brian Silvermanb601d892015-12-20 18:24:38 -0500130 : public aos::controls::ControlLoop<::y2014::control_loops::ShooterQueue> {
Brian Silverman17f503e2015-08-02 18:17:18 -0700131 public:
Austin Schuh55a13dc2019-01-27 22:39:03 -0800132 explicit ShooterMotor(
133 ::aos::EventLoop *event_loop,
134 const ::std::string &name = ".y2014.control_loops.shooter_queue");
Brian Silverman17f503e2015-08-02 18:17:18 -0700135
136 // True if the goal was moved to avoid goal windup.
137 bool capped_goal() const { return shooter_.capped_goal(); }
138
139 double PowerToPosition(double power);
140 double PositionToPower(double position);
Austin Schuh24957102015-11-28 16:04:40 -0800141 void CheckCalibrations(
Brian Silvermanb601d892015-12-20 18:24:38 -0500142 const ::y2014::control_loops::ShooterQueue::Position *position);
Brian Silverman17f503e2015-08-02 18:17:18 -0700143
144 typedef enum {
145 STATE_INITIALIZE = 0,
146 STATE_REQUEST_LOAD = 1,
147 STATE_LOAD_BACKTRACK = 2,
148 STATE_LOAD = 3,
149 STATE_LOADING_PROBLEM = 4,
150 STATE_PREPARE_SHOT = 5,
151 STATE_READY = 6,
152 STATE_FIRE = 8,
153 STATE_UNLOAD = 9,
154 STATE_UNLOAD_MOVE = 10,
155 STATE_READY_UNLOAD = 11,
156 STATE_ESTOP = 12
157 } State;
158
159 State state() { return state_; }
160
161 protected:
Austin Schuhaebfb4f2019-01-27 13:26:38 -0800162 void RunIteration(
Brian Silvermanb601d892015-12-20 18:24:38 -0500163 const ::y2014::control_loops::ShooterQueue::Goal *goal,
164 const ::y2014::control_loops::ShooterQueue::Position *position,
165 ::y2014::control_loops::ShooterQueue::Output *output,
Austin Schuhaebfb4f2019-01-27 13:26:38 -0800166 ::y2014::control_loops::ShooterQueue::Status *status) override;
Brian Silverman17f503e2015-08-02 18:17:18 -0700167
168 private:
169 // We have to override this to keep the pistons in the correct positions.
Austin Schuhaebfb4f2019-01-27 13:26:38 -0800170 void Zero(::y2014::control_loops::ShooterQueue::Output *output) override;
Brian Silverman17f503e2015-08-02 18:17:18 -0700171
172 // Friend the test classes for acces to the internal state.
173 friend class testing::ShooterTest_UnloadWindupPositive_Test;
174 friend class testing::ShooterTest_UnloadWindupNegative_Test;
175 friend class testing::ShooterTest_RezeroWhileUnloading_Test;
176
177 // Enter state STATE_UNLOAD
Austin Schuh9fe68f72019-08-10 19:32:03 -0700178 void Unload(::aos::monotonic_clock::time_point monotonic_now) {
Brian Silverman17f503e2015-08-02 18:17:18 -0700179 state_ = STATE_UNLOAD;
Austin Schuh9fe68f72019-08-10 19:32:03 -0700180 unload_timeout_ = monotonic_now + kUnloadTimeout;
Brian Silverman17f503e2015-08-02 18:17:18 -0700181 }
182 // Enter state STATE_LOAD
Austin Schuh9fe68f72019-08-10 19:32:03 -0700183 void Load(::aos::monotonic_clock::time_point monotonic_now) {
Brian Silverman17f503e2015-08-02 18:17:18 -0700184 state_ = STATE_LOAD;
Austin Schuh9fe68f72019-08-10 19:32:03 -0700185 load_timeout_ = monotonic_now + kLoadTimeout;
Brian Silverman17f503e2015-08-02 18:17:18 -0700186 }
187
Brian Silvermanb601d892015-12-20 18:24:38 -0500188 ::y2014::control_loops::ShooterQueue::Position last_position_;
Brian Silverman17f503e2015-08-02 18:17:18 -0700189
190 ZeroedStateFeedbackLoop shooter_;
191
192 // state machine state
193 State state_;
194
195 // time to giving up on loading problem
Austin Schuh214e9c12016-11-25 17:26:20 -0800196 ::aos::monotonic_clock::time_point loading_problem_end_time_ =
197 ::aos::monotonic_clock::min_time;
Brian Silverman17f503e2015-08-02 18:17:18 -0700198
199 // The end time when loading for it to timeout.
Austin Schuh214e9c12016-11-25 17:26:20 -0800200 ::aos::monotonic_clock::time_point load_timeout_ =
201 ::aos::monotonic_clock::min_time;
Brian Silverman17f503e2015-08-02 18:17:18 -0700202
203 // wait for brake to set
Austin Schuh214e9c12016-11-25 17:26:20 -0800204 ::aos::monotonic_clock::time_point shooter_brake_set_time_ =
205 ::aos::monotonic_clock::min_time;
Brian Silverman17f503e2015-08-02 18:17:18 -0700206
207 // The timeout for unloading.
Austin Schuh214e9c12016-11-25 17:26:20 -0800208 ::aos::monotonic_clock::time_point unload_timeout_ =
209 ::aos::monotonic_clock::min_time;
Brian Silverman17f503e2015-08-02 18:17:18 -0700210
211 // time that shot must have completed
Austin Schuh214e9c12016-11-25 17:26:20 -0800212 ::aos::monotonic_clock::time_point shot_end_time_ =
213 ::aos::monotonic_clock::min_time;
Brian Silverman17f503e2015-08-02 18:17:18 -0700214
215 // track cycles that we are stuck to detect errors
216 int cycles_not_moved_;
217
218 double firing_starting_position_;
219
220 // True if the latch should be engaged and the brake should be engaged.
221 bool latch_piston_;
222 bool brake_piston_;
223 int32_t last_distal_posedge_count_;
224 int32_t last_proximal_posedge_count_;
225 uint32_t shot_count_;
226 bool zeroed_;
227 int distal_posedge_validation_cycles_left_;
228 int proximal_posedge_validation_cycles_left_;
229 bool last_distal_current_;
230 bool last_proximal_current_;
231
232 DISALLOW_COPY_AND_ASSIGN(ShooterMotor);
233};
234
235} // namespace control_loops
Austin Schuh24957102015-11-28 16:04:40 -0800236} // namespace y2014
Brian Silverman17f503e2015-08-02 18:17:18 -0700237
238#endif // Y2014_CONTROL_LOOPS_shooter_shooter_H_