blob: cdd3948f68f084024e0903af8c3825bd068249bf [file] [log] [blame]
Brian Silverman17f503e2015-08-02 18:17:18 -07001#ifndef Y2014_CONTROL_LOOPS_CLAW_CLAW_H_
2#define Y2014_CONTROL_LOOPS_CLAW_CLAW_H_
3
4#include <memory>
5
6#include "aos/common/controls/control_loop.h"
7#include "aos/common/controls/polytope.h"
8#include "y2014/constants.h"
9#include "frc971/control_loops/state_feedback_loop.h"
10#include "frc971/control_loops/coerce_goal.h"
11#include "y2014/control_loops/claw/claw.q.h"
12#include "y2014/control_loops/claw/claw_motor_plant.h"
13#include "frc971/control_loops/hall_effect_tracker.h"
14
15namespace frc971 {
16namespace control_loops {
17namespace testing {
18class WindupClawTest;
19};
20
21// Note: Everything in this file assumes that there is a 1 cycle delay between
22// power being requested and it showing up at the motor. It assumes that
23// X_hat(2, 1) is the voltage being applied as well. It will go unstable if
24// that isn't true.
25
26class ClawLimitedLoop : public StateFeedbackLoop<4, 2, 2> {
27 public:
28 ClawLimitedLoop(StateFeedbackLoop<4, 2, 2> &&loop);
29 virtual void CapU();
30
31 void set_is_zeroing(bool is_zeroing) { is_zeroing_ = is_zeroing; }
32 void set_positions_known(bool top_known, bool bottom_known) {
33 top_known_ = top_known;
34 bottom_known_ = bottom_known;
35 }
36
37 void ChangeTopOffset(double doffset);
38 void ChangeBottomOffset(double doffset);
39
40 double uncapped_average_voltage() const { return uncapped_average_voltage_; }
41
42 private:
43 double uncapped_average_voltage_;
44 bool is_zeroing_;
45
46 bool top_known_ = false, bottom_known_ = false;
47
48 const ::aos::controls::HPolytope<2> U_Poly_, U_Poly_zeroing_;
49};
50
51class ClawMotor;
52
53// This class implements the CapU function correctly given all the extra
54// information that we know about from the wrist motor.
55// It does not have any zeroing logic in it, only logic to deal with a delta U
56// controller.
57class ZeroedStateFeedbackLoop {
58 public:
59 ZeroedStateFeedbackLoop(const char *name, ClawMotor *motor);
60
61 const static int kZeroingMaxVoltage = 5;
62
63 enum JointZeroingState {
64 // We don't know where the joint is at all.
65 UNKNOWN_POSITION,
66 // We have an approximate position for where the claw is using.
67 APPROXIMATE_CALIBRATION,
68 // We observed the calibration edge while disabled. This is good enough for
69 // autonomous mode.
70 DISABLED_CALIBRATION,
71 // Ready for use during teleop.
72 CALIBRATED
73 };
74
75 void set_zeroing_state(JointZeroingState zeroing_state) {
76 zeroing_state_ = zeroing_state;
77 }
78 JointZeroingState zeroing_state() const { return zeroing_state_; }
79
80 void SetPositionValues(const HalfClawPosition &claw);
81
82 void Reset(const HalfClawPosition &claw);
83
84 double absolute_position() const { return encoder() + offset(); }
85
86 const HallEffectTracker &front() const { return front_; }
87 const HallEffectTracker &calibration() const { return calibration_; }
88 const HallEffectTracker &back() const { return back_; }
89
90 bool any_hall_effect_changed() const {
91 return front().either_count_changed() ||
92 calibration().either_count_changed() ||
93 back().either_count_changed();
94 }
95 bool front_or_back_triggered() const {
96 return front().value() || back().value();
97 }
98 bool any_triggered() const {
99 return calibration().value() || front().value() || back().value();
100 }
101
102 double encoder() const { return encoder_; }
103 double last_encoder() const { return last_encoder_; }
104
105 double offset() const { return offset_; }
106
107 // Returns true if an edge was detected in the last cycle and then sets the
108 // edge_position to the absolute position of the edge.
109 bool GetPositionOfEdge(const constants::Values::Claws::Claw &claw,
110 double *edge_encoder, double *edge_angle);
111
112 bool SawFilteredPosedge(const HallEffectTracker &this_sensor,
113 const HallEffectTracker &sensorA,
114 const HallEffectTracker &sensorB);
115
116 bool SawFilteredNegedge(const HallEffectTracker &this_sensor,
117 const HallEffectTracker &sensorA,
118 const HallEffectTracker &sensorB);
119
120#undef COUNT_SETTER_GETTER
121
122 protected:
123 // The accumulated voltage to apply to the motor.
124 double offset_;
125 const char *name_;
126
127 ClawMotor *motor_;
128
129 HallEffectTracker front_, calibration_, back_;
130
131 JointZeroingState zeroing_state_;
Brian Silverman17f503e2015-08-02 18:17:18 -0700132 double min_hall_effect_on_angle_;
133 double max_hall_effect_on_angle_;
134 double min_hall_effect_off_angle_;
135 double max_hall_effect_off_angle_;
136 double encoder_;
137 double last_encoder_;
138 double last_on_encoder_;
139 double last_off_encoder_;
140 bool any_triggered_last_;
141
142 const HallEffectTracker* posedge_filter_ = nullptr;
143 const HallEffectTracker* negedge_filter_ = nullptr;
144
145 private:
146 // Does the edges of 1 sensor for GetPositionOfEdge.
147 bool DoGetPositionOfEdge(const constants::Values::Claws::AnglePair &angles,
148 double *edge_encoder, double *edge_angle,
149 const HallEffectTracker &sensor,
150 const HallEffectTracker &sensorA,
151 const HallEffectTracker &sensorB,
152 const char *hall_effect_name);
153};
154
155class TopZeroedStateFeedbackLoop : public ZeroedStateFeedbackLoop {
156 public:
157 TopZeroedStateFeedbackLoop(ClawMotor *motor)
158 : ZeroedStateFeedbackLoop("top", motor) {}
159 // Sets the calibration offset given the absolute angle and the corresponding
160 // encoder value.
161 void SetCalibration(double edge_encoder, double edge_angle);
162
163 bool SetCalibrationOnEdge(const constants::Values::Claws::Claw &claw_values,
164 JointZeroingState zeroing_state);
165 double ComputeCalibrationChange(double edge_encoder, double edge_angle);
166 void HandleCalibrationError(
167 const constants::Values::Claws::Claw &claw_values);
168};
169
170class BottomZeroedStateFeedbackLoop : public ZeroedStateFeedbackLoop {
171 public:
172 BottomZeroedStateFeedbackLoop(ClawMotor *motor)
173 : ZeroedStateFeedbackLoop("bottom", motor) {}
174 // Sets the calibration offset given the absolute angle and the corrisponding
175 // encoder value.
176 void SetCalibration(double edge_encoder, double edge_angle);
177
178 bool SetCalibrationOnEdge(const constants::Values::Claws::Claw &claw_values,
179 JointZeroingState zeroing_state);
180 double ComputeCalibrationChange(double edge_encoder, double edge_angle);
181 void HandleCalibrationError(
182 const constants::Values::Claws::Claw &claw_values);
183};
184
Brian Silvermanbe5ded62015-05-14 00:23:49 -0400185class ClawMotor : public aos::controls::ControlLoop<control_loops::ClawQueue> {
Brian Silverman17f503e2015-08-02 18:17:18 -0700186 public:
Brian Silvermanbe5ded62015-05-14 00:23:49 -0400187 explicit ClawMotor(control_loops::ClawQueue *my_claw =
188 &control_loops::claw_queue);
Brian Silverman17f503e2015-08-02 18:17:18 -0700189
190 // True if the state machine is ready.
191 bool capped_goal() const { return capped_goal_; }
192
193 double uncapped_average_voltage() const {
194 return claw_.uncapped_average_voltage();
195 }
196
197 // True if the claw is zeroing.
198 bool is_zeroing() const;
199
200 // True if the state machine is ready.
201 bool is_ready() const;
202
203 void ChangeTopOffset(double doffset);
204 void ChangeBottomOffset(double doffset);
205
206 enum CalibrationMode {
207 READY,
208 PREP_FINE_TUNE_TOP,
209 FINE_TUNE_TOP,
210 PREP_FINE_TUNE_BOTTOM,
211 FINE_TUNE_BOTTOM,
212 UNKNOWN_LOCATION
213 };
214
215 CalibrationMode mode() const { return mode_; }
216
217 protected:
Brian Silvermanbe5ded62015-05-14 00:23:49 -0400218 virtual void RunIteration(const control_loops::ClawQueue::Goal *goal,
219 const control_loops::ClawQueue::Position *position,
220 control_loops::ClawQueue::Output *output,
221 control_loops::ClawQueue::Status *status);
Brian Silverman17f503e2015-08-02 18:17:18 -0700222
223 double top_absolute_position() const {
224 return claw_.X_hat(1, 0) + claw_.X_hat(0, 0);
225 }
226 double bottom_absolute_position() const { return claw_.X_hat(0, 0); }
227
228 private:
229 // Friend the test classes for acces to the internal state.
230 friend class testing::WindupClawTest;
231
232 // The zeroed joint to use.
233 bool has_top_claw_goal_;
234 double top_claw_goal_;
235 TopZeroedStateFeedbackLoop top_claw_;
236
237 bool has_bottom_claw_goal_;
238 double bottom_claw_goal_;
239 BottomZeroedStateFeedbackLoop bottom_claw_;
240
241 // The claw loop.
242 ClawLimitedLoop claw_;
243
244 bool was_enabled_;
245 bool doing_calibration_fine_tune_;
246
247 // The initial separation when disabled. Used as the safe separation
248 // distance.
249 double initial_separation_;
250
251 bool capped_goal_;
252 CalibrationMode mode_;
253
254 DISALLOW_COPY_AND_ASSIGN(ClawMotor);
255};
256
257// Modifies the bottom and top goal such that they are within the limits and
258// their separation isn't too much or little.
259void LimitClawGoal(double *bottom_goal, double *top_goal,
260 const frc971::constants::Values &values);
261
262} // namespace control_loops
263} // namespace frc971
264
265#endif // Y2014_CONTROL_LOOPS_CLAW_CLAW_H_