blob: 1e7d4aa455f006346c38b29436adfea835326b9a [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"
Alex Perrycb7da4b2019-08-28 19:35:56 -070011#include "y2014/control_loops/shooter/shooter_goal_generated.h"
Brian Silverman17f503e2015-08-02 18:17:18 -070012#include "y2014/control_loops/shooter/shooter_motor_plant.h"
Alex Perrycb7da4b2019-08-28 19:35:56 -070013#include "y2014/control_loops/shooter/shooter_output_generated.h"
14#include "y2014/control_loops/shooter/shooter_position_generated.h"
15#include "y2014/control_loops/shooter/shooter_status_generated.h"
Brian Silverman17f503e2015-08-02 18:17:18 -070016
Austin Schuh24957102015-11-28 16:04:40 -080017namespace y2014 {
Brian Silverman17f503e2015-08-02 18:17:18 -070018namespace control_loops {
Alex Perrycb7da4b2019-08-28 19:35:56 -070019namespace shooter {
Brian Silverman17f503e2015-08-02 18:17:18 -070020namespace testing {
21class ShooterTest_UnloadWindupPositive_Test;
22class ShooterTest_UnloadWindupNegative_Test;
23class ShooterTest_RezeroWhileUnloading_Test;
24};
25
Brian Silverman17f503e2015-08-02 18:17:18 -070026// Note: Everything in this file assumes that there is a 1 cycle delay between
27// power being requested and it showing up at the motor. It assumes that
28// X_hat(2, 1) is the voltage being applied as well. It will go unstable if
29// that isn't true.
30
31// This class implements the CapU function correctly given all the extra
32// information that we know about.
33// It does not have any zeroing logic in it, only logic to deal with a delta U
34// controller.
35class ZeroedStateFeedbackLoop : public StateFeedbackLoop<3, 1, 1> {
36 public:
37 ZeroedStateFeedbackLoop(StateFeedbackLoop<3, 1, 1> &&loop)
38 : StateFeedbackLoop<3, 1, 1>(::std::move(loop)),
39 voltage_(0.0),
40 last_voltage_(0.0),
41 uncapped_voltage_(0.0),
42 offset_(0.0),
43 max_voltage_(12.0),
44 capped_goal_(false) {}
45
46 const static int kZeroingMaxVoltage = 5;
47
Austin Schuhaebfb4f2019-01-27 13:26:38 -080048 void CapU() override;
Brian Silverman17f503e2015-08-02 18:17:18 -070049
50 // Returns the accumulated voltage.
51 double voltage() const { return voltage_; }
52
53 // Returns the uncapped voltage.
54 double uncapped_voltage() const { return uncapped_voltage_; }
55
56 // Zeros the accumulator.
57 void ZeroPower() { voltage_ = 0.0; }
58
59 // Sets the calibration offset given the absolute angle and the corrisponding
60 // encoder value.
61 void SetCalibration(double encoder_val, double known_position);
62
63 double offset() const { return offset_; }
64
65 double absolute_position() const { return X_hat(0, 0) + kPositionOffset; }
66 double absolute_velocity() const { return X_hat(1, 0); }
67
68 void CorrectPosition(double position) {
69 Eigen::Matrix<double, 1, 1> Y;
70 Y << position + offset_ - kPositionOffset;
71 Correct(Y);
72 }
73
74 // Recomputes the power goal for the current controller and position/velocity.
75 void RecalculatePowerGoal();
76
77 double goal_position() const { return R(0, 0) + kPositionOffset; }
78 double goal_velocity() const { return R(1, 0); }
79 void InitializeState(double position) {
80 mutable_X_hat(0, 0) = position - kPositionOffset;
81 mutable_X_hat(1, 0) = 0.0;
82 mutable_X_hat(2, 0) = 0.0;
83 }
84
85 void SetGoalPosition(double desired_position, double desired_velocity) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070086 AOS_LOG(DEBUG, "Goal position: %f Goal velocity: %f\n", desired_position,
87 desired_velocity);
Brian Silverman17f503e2015-08-02 18:17:18 -070088
89 mutable_R() << desired_position - kPositionOffset, desired_velocity,
Austin Schuhc5fceb82017-02-25 16:24:12 -080090 (-plant().A(1, 0) / plant().A(1, 2) *
91 (desired_position - kPositionOffset) -
92 plant().A(1, 1) / plant().A(1, 2) * desired_velocity);
Brian Silverman17f503e2015-08-02 18:17:18 -070093 }
94
95 double position() const { return X_hat(0, 0) - offset_ + kPositionOffset; }
96
97 void set_max_voltage(double max_voltage) { max_voltage_ = max_voltage; }
98 bool capped_goal() const { return capped_goal_; }
99
100 void CapGoal();
101
102 // Friend the test classes for acces to the internal state.
103 friend class testing::ShooterTest_RezeroWhileUnloading_Test;
104
105 private:
106 // The offset between what is '0' (0 rate on the spring) and the 0 (all the
107 // way cocked).
Austin Schuh9d4aca82015-11-08 14:41:31 -0800108 constexpr static double kPositionOffset =
109 ::y2014::control_loops::shooter::kMaxExtension;
Brian Silverman17f503e2015-08-02 18:17:18 -0700110 // The accumulated voltage to apply to the motor.
111 double voltage_;
112 double last_voltage_;
113 double uncapped_voltage_;
114 double offset_;
115 double max_voltage_;
116 bool capped_goal_;
117};
118
Austin Schuh214e9c12016-11-25 17:26:20 -0800119static constexpr ::std::chrono::nanoseconds kUnloadTimeout =
120 ::std::chrono::seconds(10);
121static constexpr ::std::chrono::nanoseconds kLoadTimeout =
122 ::std::chrono::seconds(2);
123static constexpr ::std::chrono::nanoseconds kLoadProblemEndTimeout =
124 ::std::chrono::seconds(1);
125static constexpr ::std::chrono::nanoseconds kShooterBrakeSetTime =
126 ::std::chrono::milliseconds(50);
Brian Silverman17f503e2015-08-02 18:17:18 -0700127// Time to wait after releasing the latch piston before winching back again.
Austin Schuh214e9c12016-11-25 17:26:20 -0800128static constexpr ::std::chrono::nanoseconds kShotEndTimeout =
129 ::std::chrono::milliseconds(200);
130static constexpr ::std::chrono::nanoseconds kPrepareFireEndTime =
131 ::std::chrono::milliseconds(40);
Brian Silverman17f503e2015-08-02 18:17:18 -0700132
133class ShooterMotor
Alex Perrycb7da4b2019-08-28 19:35:56 -0700134 : public aos::controls::ControlLoop<Goal, Position, Status, Output> {
Brian Silverman17f503e2015-08-02 18:17:18 -0700135 public:
Alex Perrycb7da4b2019-08-28 19:35:56 -0700136 explicit ShooterMotor(::aos::EventLoop *event_loop,
137 const ::std::string &name = "/shooter");
Brian Silverman17f503e2015-08-02 18:17:18 -0700138
139 // True if the goal was moved to avoid goal windup.
140 bool capped_goal() const { return shooter_.capped_goal(); }
141
142 double PowerToPosition(double power);
143 double PositionToPower(double position);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700144 void CheckCalibrations(const Position *position);
Brian Silverman17f503e2015-08-02 18:17:18 -0700145
146 typedef enum {
147 STATE_INITIALIZE = 0,
148 STATE_REQUEST_LOAD = 1,
149 STATE_LOAD_BACKTRACK = 2,
150 STATE_LOAD = 3,
151 STATE_LOADING_PROBLEM = 4,
152 STATE_PREPARE_SHOT = 5,
153 STATE_READY = 6,
154 STATE_FIRE = 8,
155 STATE_UNLOAD = 9,
156 STATE_UNLOAD_MOVE = 10,
157 STATE_READY_UNLOAD = 11,
158 STATE_ESTOP = 12
159 } State;
160
161 State state() { return state_; }
162
163 protected:
Alex Perrycb7da4b2019-08-28 19:35:56 -0700164 void RunIteration(const Goal *goal, const Position *position,
165 aos::Sender<Output>::Builder *output,
166 aos::Sender<Status>::Builder *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.
Alex Perrycb7da4b2019-08-28 19:35:56 -0700170 flatbuffers::Offset<Output> Zero(
171 aos::Sender<Output>::Builder *output) override;
Brian Silverman17f503e2015-08-02 18:17:18 -0700172
173 // Friend the test classes for acces to the internal state.
174 friend class testing::ShooterTest_UnloadWindupPositive_Test;
175 friend class testing::ShooterTest_UnloadWindupNegative_Test;
176 friend class testing::ShooterTest_RezeroWhileUnloading_Test;
177
178 // Enter state STATE_UNLOAD
Austin Schuh9fe68f72019-08-10 19:32:03 -0700179 void Unload(::aos::monotonic_clock::time_point monotonic_now) {
Brian Silverman17f503e2015-08-02 18:17:18 -0700180 state_ = STATE_UNLOAD;
Austin Schuh9fe68f72019-08-10 19:32:03 -0700181 unload_timeout_ = monotonic_now + kUnloadTimeout;
Brian Silverman17f503e2015-08-02 18:17:18 -0700182 }
183 // Enter state STATE_LOAD
Austin Schuh9fe68f72019-08-10 19:32:03 -0700184 void Load(::aos::monotonic_clock::time_point monotonic_now) {
Brian Silverman17f503e2015-08-02 18:17:18 -0700185 state_ = STATE_LOAD;
Austin Schuh9fe68f72019-08-10 19:32:03 -0700186 load_timeout_ = monotonic_now + kLoadTimeout;
Brian Silverman17f503e2015-08-02 18:17:18 -0700187 }
188
Alex Perrycb7da4b2019-08-28 19:35:56 -0700189 bool last_position_latch_ = false;
190 bool last_position_plunger_ = false;
191 double last_position_position_ = 0.0;
Brian Silverman17f503e2015-08-02 18:17:18 -0700192
193 ZeroedStateFeedbackLoop shooter_;
194
195 // state machine state
196 State state_;
197
198 // time to giving up on loading problem
Austin Schuh214e9c12016-11-25 17:26:20 -0800199 ::aos::monotonic_clock::time_point loading_problem_end_time_ =
200 ::aos::monotonic_clock::min_time;
Brian Silverman17f503e2015-08-02 18:17:18 -0700201
202 // The end time when loading for it to timeout.
Austin Schuh214e9c12016-11-25 17:26:20 -0800203 ::aos::monotonic_clock::time_point load_timeout_ =
204 ::aos::monotonic_clock::min_time;
Brian Silverman17f503e2015-08-02 18:17:18 -0700205
206 // wait for brake to set
Austin Schuh214e9c12016-11-25 17:26:20 -0800207 ::aos::monotonic_clock::time_point shooter_brake_set_time_ =
208 ::aos::monotonic_clock::min_time;
Brian Silverman17f503e2015-08-02 18:17:18 -0700209
210 // The timeout for unloading.
Austin Schuh214e9c12016-11-25 17:26:20 -0800211 ::aos::monotonic_clock::time_point unload_timeout_ =
212 ::aos::monotonic_clock::min_time;
Brian Silverman17f503e2015-08-02 18:17:18 -0700213
214 // time that shot must have completed
Austin Schuh214e9c12016-11-25 17:26:20 -0800215 ::aos::monotonic_clock::time_point shot_end_time_ =
216 ::aos::monotonic_clock::min_time;
Brian Silverman17f503e2015-08-02 18:17:18 -0700217
218 // track cycles that we are stuck to detect errors
219 int cycles_not_moved_;
220
221 double firing_starting_position_;
222
223 // True if the latch should be engaged and the brake should be engaged.
224 bool latch_piston_;
225 bool brake_piston_;
226 int32_t last_distal_posedge_count_;
227 int32_t last_proximal_posedge_count_;
228 uint32_t shot_count_;
229 bool zeroed_;
230 int distal_posedge_validation_cycles_left_;
231 int proximal_posedge_validation_cycles_left_;
232 bool last_distal_current_;
233 bool last_proximal_current_;
234
235 DISALLOW_COPY_AND_ASSIGN(ShooterMotor);
236};
237
Alex Perrycb7da4b2019-08-28 19:35:56 -0700238} // namespace shooter
Brian Silverman17f503e2015-08-02 18:17:18 -0700239} // namespace control_loops
Austin Schuh24957102015-11-28 16:04:40 -0800240} // namespace y2014
Brian Silverman17f503e2015-08-02 18:17:18 -0700241
242#endif // Y2014_CONTROL_LOOPS_shooter_shooter_H_