blob: aa4375825e8bc0aa106a4863eb9e7ea0a3322479 [file] [log] [blame]
Comran Morshed25f81a02016-01-23 13:40:10 +00001#ifndef Y2016_CONTROL_LOOPS_SUPERSTRUCTURE_SUPERSTRUCTURE_H_
2#define Y2016_CONTROL_LOOPS_SUPERSTRUCTURE_SUPERSTRUCTURE_H_
3
4#include <memory>
5
6#include "aos/common/controls/control_loop.h"
7#include "frc971/control_loops/state_feedback_loop.h"
Austin Schuh2fc10fa2016-02-08 00:44:34 -08008#include "aos/common/util/trapezoid_profile.h"
Comran Morshed25f81a02016-01-23 13:40:10 +00009
Austin Schuh2fc10fa2016-02-08 00:44:34 -080010#include "frc971/zeroing/zeroing.h"
Comran Morshed25f81a02016-01-23 13:40:10 +000011#include "y2016/control_loops/superstructure/superstructure.q.h"
12
13namespace y2016 {
14namespace control_loops {
Austin Schuh2fc10fa2016-02-08 00:44:34 -080015namespace superstructure {
16namespace testing {
17class SuperstructureTest_DisabledGoalTest_Test;
18} // namespace testing
19
20using ::frc971::PotAndIndexPosition;
21using ::frc971::EstimatorState;
22
23class SimpleCappedStateFeedbackLoop : public StateFeedbackLoop<3, 1, 1> {
24 public:
25 SimpleCappedStateFeedbackLoop(StateFeedbackLoop<3, 1, 1> &&loop)
26 : StateFeedbackLoop<3, 1, 1>(::std::move(loop)), max_voltage_(12.0) {}
27
28 void set_max_voltage(double max_voltage) {
29 max_voltage_ = ::std::max(0.0, ::std::min(12.0, max_voltage));
30 }
31
32 void CapU() override;
33
34 private:
35 double max_voltage_;
36};
37
38class DoubleCappedStateFeedbackLoop : public StateFeedbackLoop<6, 2, 2> {
39 public:
40 DoubleCappedStateFeedbackLoop(StateFeedbackLoop<6, 2, 2> &&loop)
41 : StateFeedbackLoop<6, 2, 2>(::std::move(loop)),
42 shoulder_max_voltage_(12.0),
43 wrist_max_voltage_(12.0) {}
44
45 void set_max_voltage(double shoulder_max_voltage, double wrist_max_voltage) {
46 shoulder_max_voltage_ = ::std::max(0.0, ::std::min(12.0, shoulder_max_voltage));
47 wrist_max_voltage_ = ::std::max(0.0, ::std::min(12.0, wrist_max_voltage));
48 }
49
50 void CapU() override;
51
52 private:
53 double shoulder_max_voltage_;
54 double wrist_max_voltage_;
55};
56
57class Intake {
58 public:
59 Intake();
60 // Returns whether the estimators have been initialized and zeroed.
61 bool initialized() const { return initialized_; }
62 bool zeroed() const { return zeroed_; }
63
64 // Updates our estimator with the latest position.
65 void Correct(PotAndIndexPosition position);
66
67 // Forces the current goal to the provided goal, bypassing the profiler.
68 void ForceGoal(double goal);
69 // Sets the unprofiled goal. The profiler will generate a profile to go to
70 // this goal.
71 void set_unprofiled_goal(double unprofiled_goal);
72
73 // Runs the controller and profile generator for a cycle.
74 void Update(bool disabled);
75
76 // Limits our profiles to a max velocity and acceleration for proper motion.
77 void AdjustProfile(double max_angular_velocity,
78 double max_angular_acceleration);
79 // Sets the maximum voltage that will be commanded by the loop.
80 void set_max_voltage(double voltage);
81
82 // Returns true if we have exceeded any hard limits.
83 bool CheckHardLimits();
84 // Resets the internal state.
85 void Reset();
86
87 // Returns the current internal estimator state for logging.
88 EstimatorState IntakeEstimatorState();
89
90 // Returns the requested intake voltage.
91 double intake_voltage() const { return loop_->U(0, 0); }
92
93 // Returns the current position.
94 double angle() const { return Y_(0, 0); }
95
96 // Returns the filtered goal.
97 const Eigen::Matrix<double, 3, 1> &goal() const { return loop_->R(); }
98 double goal(int row, int col) const { return loop_->R(row, col); }
99
100 // Returns the current state estimate.
101 const Eigen::Matrix<double, 3, 1> &X_hat() const { return loop_->X_hat(); }
102 double X_hat(int row, int col) const { return loop_->X_hat(row, col); }
103
104 private:
105 // Limits the provided goal to the soft limits. Prints "name" when it fails
106 // to aid debugging.
107 void CapGoal(const char *name, Eigen::Matrix<double, 3, 1> *goal);
108
109 void UpdateIntakeOffset(double offset);
110
111 ::std::unique_ptr<SimpleCappedStateFeedbackLoop> loop_;
112
113 ::frc971::zeroing::ZeroingEstimator estimator_;
114 aos::util::TrapezoidProfile profile_;
115
116 // Current measurement.
117 Eigen::Matrix<double, 1, 1> Y_;
118 // Current offset. Y_ = offset_ + raw_sensor;
119 Eigen::Matrix<double, 1, 1> offset_;
120
121 // The goal that the profile tries to reach.
122 Eigen::Matrix<double, 3, 1> unprofiled_goal_;
123
124 bool initialized_ = false;
125 bool zeroed_ = false;
126};
127
128class Arm {
129 public:
130 Arm();
131 // Returns whether the estimators have been initialized and zeroed.
132 bool initialized() const { return initialized_; }
133 bool zeroed() const { return shoulder_zeroed_ && wrist_zeroed_; }
134 bool shoulder_zeroed() const { return shoulder_zeroed_; }
135 bool wrist_zeroed() const { return wrist_zeroed_; }
136
137 // Updates our estimator with the latest position.
138 void Correct(PotAndIndexPosition position_shoulder,
139 PotAndIndexPosition position_wrist);
140
141 // Forces the goal to be the provided goal.
142 void ForceGoal(double unprofiled_goal_shoulder, double unprofiled_goal_wrist);
143 // Sets the unprofiled goal. The profiler will generate a profile to go to
144 // this goal.
145 void set_unprofiled_goal(double unprofiled_goal_shoulder,
146 double unprofiled_goal_wrist);
147
148 // Runs the controller and profile generator for a cycle.
149 void Update(bool disabled);
150
151 // Limits our profiles to a max velocity and acceleration for proper motion.
152 void AdjustProfile(double max_angular_velocity_shoulder,
153 double max_angular_acceleration_shoulder,
154 double max_angular_velocity_wrist,
155 double max_angular_acceleration_wrist);
156 void set_max_voltage(double shoulder_max_voltage, double wrist_max_voltage);
157
158 // Returns true if we have exceeded any hard limits.
159 bool CheckHardLimits();
160 // Resets the internal state.
161 void Reset();
162
163 // Returns the current internal estimator state for logging.
164 EstimatorState ShoulderEstimatorState();
165 EstimatorState WristEstimatorState();
166
167 // Returns the requested shoulder and wrist voltages.
168 double shoulder_voltage() const { return loop_->U(0, 0); }
169 double wrist_voltage() const { return loop_->U(1, 0); }
170
171 // Returns the current positions.
172 double shoulder_angle() const { return Y_(0, 0); }
173 double wrist_angle() const { return Y_(1, 0) + Y_(0, 0); }
174
175 // Returns the filtered goal.
176 const Eigen::Matrix<double, 6, 1> &goal() const { return loop_->R(); }
177 double goal(int row, int col) const { return loop_->R(row, col); }
178
179 // Returns the current state estimate.
180 const Eigen::Matrix<double, 6, 1> &X_hat() const { return loop_->X_hat(); }
181 double X_hat(int row, int col) const { return loop_->X_hat(row, col); }
182
183 private:
184 // Limits the provided goal to the soft limits. Prints "name" when it fails
185 // to aid debugging.
186 void CapGoal(const char *name, Eigen::Matrix<double, 6, 1> *goal);
187
188 // Updates the offset
189 void UpdateWristOffset(double offset);
190 void UpdateShoulderOffset(double offset);
191
192 friend class testing::SuperstructureTest_DisabledGoalTest_Test;
193 ::std::unique_ptr<DoubleCappedStateFeedbackLoop> loop_;
194
195 aos::util::TrapezoidProfile shoulder_profile_, wrist_profile_;
196 ::frc971::zeroing::ZeroingEstimator shoulder_estimator_, wrist_estimator_;
197
198 // Current measurement.
199 Eigen::Matrix<double, 2, 1> Y_;
200 // Current offset. Y_ = offset_ + raw_sensor;
201 Eigen::Matrix<double, 2, 1> offset_;
202
203 // The goal that the profile tries to reach.
204 Eigen::Matrix<double, 6, 1> unprofiled_goal_;
205
206 bool initialized_ = false;
207 bool shoulder_zeroed_ = false;
208 bool wrist_zeroed_ = false;
209};
Comran Morshed25f81a02016-01-23 13:40:10 +0000210
211class Superstructure
212 : public ::aos::controls::ControlLoop<control_loops::SuperstructureQueue> {
213 public:
214 explicit Superstructure(
215 control_loops::SuperstructureQueue *my_superstructure =
216 &control_loops::superstructure_queue);
Austin Schuh2fc10fa2016-02-08 00:44:34 -0800217 enum State {
218 // Waiting to receive data before doing anything.
219 UNINITIALIZED = 0,
220 // Estimating the starting location.
221 INITIALIZING = 1,
222 // Moving the intake to find an index pulse.
223 ZEROING_INTAKE = 2,
224 // Moving the arm to find an index pulse.
225 ZEROING_ARM = 3,
226 // All good!
227 RUNNING = 4,
228 // Internal error caused the superstructure to abort.
229 ESTOP = 5,
230 };
231
232 State state() const { return state_; }
Comran Morshed25f81a02016-01-23 13:40:10 +0000233
234 protected:
235 virtual void RunIteration(
Austin Schuh2fc10fa2016-02-08 00:44:34 -0800236 const control_loops::SuperstructureQueue::Goal *unsafe_goal,
Comran Morshed25f81a02016-01-23 13:40:10 +0000237 const control_loops::SuperstructureQueue::Position *position,
Austin Schuh2fc10fa2016-02-08 00:44:34 -0800238 control_loops::SuperstructureQueue::Output *output,
Comran Morshed25f81a02016-01-23 13:40:10 +0000239 control_loops::SuperstructureQueue::Status *status) override;
240
241 private:
Austin Schuh2fc10fa2016-02-08 00:44:34 -0800242 friend class testing::SuperstructureTest_DisabledGoalTest_Test;
243 Intake intake_;
244 Arm arm_;
245
246 State state_ = UNINITIALIZED;
247 State last_state_ = UNINITIALIZED;
248
249 // Sets state_ to the correct state given the current state of the zeroing
250 // estimators.
251 void UpdateZeroingState();
252
Comran Morshed25f81a02016-01-23 13:40:10 +0000253 DISALLOW_COPY_AND_ASSIGN(Superstructure);
254};
255
Austin Schuh2fc10fa2016-02-08 00:44:34 -0800256} // namespace superstructure
Comran Morshed25f81a02016-01-23 13:40:10 +0000257} // namespace control_loops
258} // namespace y2016
259
260#endif // Y2016_CONTROL_LOOPS_SUPERSTRUCTURE_SUPERSTRUCTURE_H_