blob: 75a05dba7ba63cbdb1be54c34ddbf81f0e2d1ae5 [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:
Brian Silvermanb601d892015-12-20 18:24:38 -0500132 explicit ShooterMotor(::y2014::control_loops::ShooterQueue *my_shooter =
133 &::y2014::control_loops::shooter_queue);
Brian Silverman17f503e2015-08-02 18:17:18 -0700134
135 // True if the goal was moved to avoid goal windup.
136 bool capped_goal() const { return shooter_.capped_goal(); }
137
138 double PowerToPosition(double power);
139 double PositionToPower(double position);
Austin Schuh24957102015-11-28 16:04:40 -0800140 void CheckCalibrations(
Brian Silvermanb601d892015-12-20 18:24:38 -0500141 const ::y2014::control_loops::ShooterQueue::Position *position);
Brian Silverman17f503e2015-08-02 18:17:18 -0700142
143 typedef enum {
144 STATE_INITIALIZE = 0,
145 STATE_REQUEST_LOAD = 1,
146 STATE_LOAD_BACKTRACK = 2,
147 STATE_LOAD = 3,
148 STATE_LOADING_PROBLEM = 4,
149 STATE_PREPARE_SHOT = 5,
150 STATE_READY = 6,
151 STATE_FIRE = 8,
152 STATE_UNLOAD = 9,
153 STATE_UNLOAD_MOVE = 10,
154 STATE_READY_UNLOAD = 11,
155 STATE_ESTOP = 12
156 } State;
157
158 State state() { return state_; }
159
160 protected:
Austin Schuhaebfb4f2019-01-27 13:26:38 -0800161 void RunIteration(
Brian Silvermanb601d892015-12-20 18:24:38 -0500162 const ::y2014::control_loops::ShooterQueue::Goal *goal,
163 const ::y2014::control_loops::ShooterQueue::Position *position,
164 ::y2014::control_loops::ShooterQueue::Output *output,
Austin Schuhaebfb4f2019-01-27 13:26:38 -0800165 ::y2014::control_loops::ShooterQueue::Status *status) override;
Brian Silverman17f503e2015-08-02 18:17:18 -0700166
167 private:
168 // We have to override this to keep the pistons in the correct positions.
Austin Schuhaebfb4f2019-01-27 13:26:38 -0800169 void Zero(::y2014::control_loops::ShooterQueue::Output *output) override;
Brian Silverman17f503e2015-08-02 18:17:18 -0700170
171 // Friend the test classes for acces to the internal state.
172 friend class testing::ShooterTest_UnloadWindupPositive_Test;
173 friend class testing::ShooterTest_UnloadWindupNegative_Test;
174 friend class testing::ShooterTest_RezeroWhileUnloading_Test;
175
176 // Enter state STATE_UNLOAD
177 void Unload() {
178 state_ = STATE_UNLOAD;
Austin Schuh214e9c12016-11-25 17:26:20 -0800179 unload_timeout_ = ::aos::monotonic_clock::now() + kUnloadTimeout;
Brian Silverman17f503e2015-08-02 18:17:18 -0700180 }
181 // Enter state STATE_LOAD
182 void Load() {
183 state_ = STATE_LOAD;
Austin Schuh214e9c12016-11-25 17:26:20 -0800184 load_timeout_ = ::aos::monotonic_clock::now() + kLoadTimeout;
Brian Silverman17f503e2015-08-02 18:17:18 -0700185 }
186
Brian Silvermanb601d892015-12-20 18:24:38 -0500187 ::y2014::control_loops::ShooterQueue::Position last_position_;
Brian Silverman17f503e2015-08-02 18:17:18 -0700188
189 ZeroedStateFeedbackLoop shooter_;
190
191 // state machine state
192 State state_;
193
194 // time to giving up on loading problem
Austin Schuh214e9c12016-11-25 17:26:20 -0800195 ::aos::monotonic_clock::time_point loading_problem_end_time_ =
196 ::aos::monotonic_clock::min_time;
Brian Silverman17f503e2015-08-02 18:17:18 -0700197
198 // The end time when loading for it to timeout.
Austin Schuh214e9c12016-11-25 17:26:20 -0800199 ::aos::monotonic_clock::time_point load_timeout_ =
200 ::aos::monotonic_clock::min_time;
Brian Silverman17f503e2015-08-02 18:17:18 -0700201
202 // wait for brake to set
Austin Schuh214e9c12016-11-25 17:26:20 -0800203 ::aos::monotonic_clock::time_point shooter_brake_set_time_ =
204 ::aos::monotonic_clock::min_time;
Brian Silverman17f503e2015-08-02 18:17:18 -0700205
206 // The timeout for unloading.
Austin Schuh214e9c12016-11-25 17:26:20 -0800207 ::aos::monotonic_clock::time_point unload_timeout_ =
208 ::aos::monotonic_clock::min_time;
Brian Silverman17f503e2015-08-02 18:17:18 -0700209
210 // time that shot must have completed
Austin Schuh214e9c12016-11-25 17:26:20 -0800211 ::aos::monotonic_clock::time_point shot_end_time_ =
212 ::aos::monotonic_clock::min_time;
Brian Silverman17f503e2015-08-02 18:17:18 -0700213
214 // track cycles that we are stuck to detect errors
215 int cycles_not_moved_;
216
217 double firing_starting_position_;
218
219 // True if the latch should be engaged and the brake should be engaged.
220 bool latch_piston_;
221 bool brake_piston_;
222 int32_t last_distal_posedge_count_;
223 int32_t last_proximal_posedge_count_;
224 uint32_t shot_count_;
225 bool zeroed_;
226 int distal_posedge_validation_cycles_left_;
227 int proximal_posedge_validation_cycles_left_;
228 bool last_distal_current_;
229 bool last_proximal_current_;
230
231 DISALLOW_COPY_AND_ASSIGN(ShooterMotor);
232};
233
234} // namespace control_loops
Austin Schuh24957102015-11-28 16:04:40 -0800235} // namespace y2014
Brian Silverman17f503e2015-08-02 18:17:18 -0700236
237#endif // Y2014_CONTROL_LOOPS_shooter_shooter_H_