blob: 34786b85df0787773f7e80ed087215b288c93df3 [file] [log] [blame]
Austin Schuh3bb9a442014-02-02 16:01:45 -08001#ifndef FRC971_CONTROL_LOOPS_CLAW_CLAW_H_
2#define FRC971_CONTROL_LOOPS_CLAW_CLAW_H_
3
4#include <memory>
5
6#include "aos/common/control_loop/ControlLoop.h"
Austin Schuhf9286cd2014-02-11 00:51:09 -08007#include "frc971/constants.h"
Austin Schuh3bb9a442014-02-02 16:01:45 -08008#include "frc971/control_loops/state_feedback_loop.h"
9#include "frc971/control_loops/claw/claw.q.h"
Austin Schuhcda86af2014-02-16 16:16:39 -080010#include "frc971/control_loops/claw/claw_motor_plant.h"
Austin Schuh3bb9a442014-02-02 16:01:45 -080011
Austin Schuh3bb9a442014-02-02 16:01:45 -080012namespace frc971 {
13namespace control_loops {
14namespace testing {
Austin Schuhe7f90d12014-02-17 00:48:25 -080015class WindupClawTest;
Austin Schuh3bb9a442014-02-02 16:01:45 -080016};
17
Austin Schuh4b7b5d02014-02-10 21:20:34 -080018// Note: Everything in this file assumes that there is a 1 cycle delay between
19// power being requested and it showing up at the motor. It assumes that
20// X_hat(2, 1) is the voltage being applied as well. It will go unstable if
21// that isn't true.
22
Austin Schuhcda86af2014-02-16 16:16:39 -080023class ClawLimitedLoop : public StateFeedbackLoop<4, 2, 2> {
24 public:
25 ClawLimitedLoop(StateFeedbackLoop<4, 2, 2> loop)
Austin Schuh4cb047f2014-02-16 21:10:19 -080026 : StateFeedbackLoop<4, 2, 2>(loop),
27 uncapped_average_voltage_(0.0),
28 is_zeroing_(true) {}
Austin Schuhcda86af2014-02-16 16:16:39 -080029 virtual void CapU();
30
Austin Schuh4cb047f2014-02-16 21:10:19 -080031 void set_is_zeroing(bool is_zeroing) { is_zeroing_ = is_zeroing; }
32
Austin Schuhcda86af2014-02-16 16:16:39 -080033 void ChangeTopOffset(double doffset);
34 void ChangeBottomOffset(double doffset);
Austin Schuh4cb047f2014-02-16 21:10:19 -080035
36 double uncapped_average_voltage() const { return uncapped_average_voltage_; }
37
38 private:
39 double uncapped_average_voltage_;
40 bool is_zeroing_;
Austin Schuhcda86af2014-02-16 16:16:39 -080041};
42
43class ClawMotor;
44
Austin Schuh4b7b5d02014-02-10 21:20:34 -080045// This class implements the CapU function correctly given all the extra
46// information that we know about from the wrist motor.
47// It does not have any zeroing logic in it, only logic to deal with a delta U
48// controller.
Austin Schuhcda86af2014-02-16 16:16:39 -080049class ZeroedStateFeedbackLoop {
Austin Schuh3bb9a442014-02-02 16:01:45 -080050 public:
Austin Schuhcda86af2014-02-16 16:16:39 -080051 ZeroedStateFeedbackLoop(const char *name, ClawMotor *motor)
52 : offset_(0.0),
53 name_(name),
54 motor_(motor),
Austin Schuh4b7b5d02014-02-10 21:20:34 -080055 front_hall_effect_posedge_count_(0.0),
56 previous_front_hall_effect_posedge_count_(0.0),
57 front_hall_effect_negedge_count_(0.0),
58 previous_front_hall_effect_negedge_count_(0.0),
59 calibration_hall_effect_posedge_count_(0.0),
60 previous_calibration_hall_effect_posedge_count_(0.0),
61 calibration_hall_effect_negedge_count_(0.0),
62 previous_calibration_hall_effect_negedge_count_(0.0),
63 back_hall_effect_posedge_count_(0.0),
64 previous_back_hall_effect_posedge_count_(0.0),
65 back_hall_effect_negedge_count_(0.0),
66 previous_back_hall_effect_negedge_count_(0.0),
Austin Schuhcda86af2014-02-16 16:16:39 -080067 front_hall_effect_(false),
68 calibration_hall_effect_(false),
69 back_hall_effect_(false),
Austin Schuhf9286cd2014-02-11 00:51:09 -080070 zeroing_state_(UNKNOWN_POSITION),
71 posedge_value_(0.0),
72 negedge_value_(0.0),
73 encoder_(0.0),
Austin Schuhcda86af2014-02-16 16:16:39 -080074 last_encoder_(0.0) {}
Austin Schuh3bb9a442014-02-02 16:01:45 -080075
Austin Schuh4b7b5d02014-02-10 21:20:34 -080076 const static int kZeroingMaxVoltage = 5;
Austin Schuh3bb9a442014-02-02 16:01:45 -080077
Austin Schuh4b7b5d02014-02-10 21:20:34 -080078 enum JointZeroingState {
79 // We don't know where the joint is at all.
80 UNKNOWN_POSITION,
81 // We have an approximate position for where the claw is using.
82 APPROXIMATE_CALIBRATION,
83 // We observed the calibration edge while disabled. This is good enough for
84 // autonomous mode.
85 DISABLED_CALIBRATION,
86 // Ready for use during teleop.
87 CALIBRATED
88 };
89
90 void set_zeroing_state(JointZeroingState zeroing_state) {
91 zeroing_state_ = zeroing_state;
92 }
93 JointZeroingState zeroing_state() const { return zeroing_state_; }
94
Austin Schuh4339ebb2014-02-11 00:56:44 -080095 void SetPositionValues(const HalfClawPosition &claw) {
Austin Schuhf9286cd2014-02-11 00:51:09 -080096 set_front_hall_effect_posedge_count(claw.front_hall_effect_posedge_count);
97 set_front_hall_effect_negedge_count(claw.front_hall_effect_negedge_count);
98 set_calibration_hall_effect_posedge_count(
99 claw.calibration_hall_effect_posedge_count);
100 set_calibration_hall_effect_negedge_count(
101 claw.calibration_hall_effect_negedge_count);
102 set_back_hall_effect_posedge_count(claw.back_hall_effect_posedge_count);
103 set_back_hall_effect_negedge_count(claw.back_hall_effect_negedge_count);
104
105 posedge_value_ = claw.posedge_value;
106 negedge_value_ = claw.negedge_value;
Austin Schuhcda86af2014-02-16 16:16:39 -0800107 last_encoder_ = encoder_;
108 encoder_ = claw.position;
109
110 front_hall_effect_ = claw.front_hall_effect;
111 calibration_hall_effect_ = claw.calibration_hall_effect;
112 back_hall_effect_ = claw.back_hall_effect;
Austin Schuhf9286cd2014-02-11 00:51:09 -0800113 }
114
Austin Schuhcda86af2014-02-16 16:16:39 -0800115 double absolute_position() const { return encoder() + offset(); }
116
117 bool front_hall_effect() const { return front_hall_effect_; }
118 bool calibration_hall_effect() const { return calibration_hall_effect_; }
119 bool back_hall_effect() const { return back_hall_effect_; }
120
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800121#define COUNT_SETTER_GETTER(variable) \
122 void set_##variable(int32_t value) { \
123 previous_##variable##_ = variable##_; \
124 variable##_ = value; \
125 } \
126 int32_t variable() const { return variable##_; } \
127 bool variable##_changed() const { \
128 return previous_##variable##_ != variable##_; \
129 }
130
Austin Schuhf9286cd2014-02-11 00:51:09 -0800131 // TODO(austin): Pull all this out of the new sub structure.
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800132 COUNT_SETTER_GETTER(front_hall_effect_posedge_count);
133 COUNT_SETTER_GETTER(front_hall_effect_negedge_count);
134 COUNT_SETTER_GETTER(calibration_hall_effect_posedge_count);
135 COUNT_SETTER_GETTER(calibration_hall_effect_negedge_count);
136 COUNT_SETTER_GETTER(back_hall_effect_posedge_count);
137 COUNT_SETTER_GETTER(back_hall_effect_negedge_count);
138
139 bool any_hall_effect_changed() const {
140 return front_hall_effect_posedge_count_changed() ||
141 front_hall_effect_negedge_count_changed() ||
142 calibration_hall_effect_posedge_count_changed() ||
143 calibration_hall_effect_negedge_count_changed() ||
144 back_hall_effect_posedge_count_changed() ||
145 back_hall_effect_negedge_count_changed();
146 }
147
Austin Schuhf9286cd2014-02-11 00:51:09 -0800148 double encoder() const { return encoder_; }
149 double last_encoder() const { return last_encoder_; }
150
Austin Schuhcda86af2014-02-16 16:16:39 -0800151 double offset() const { return offset_; }
152
Austin Schuhf9286cd2014-02-11 00:51:09 -0800153 // Returns true if an edge was detected in the last cycle and then sets the
154 // edge_position to the absolute position of the edge.
Austin Schuhd27931c2014-02-16 19:18:20 -0800155 bool GetPositionOfEdge(const constants::Values::Claws::Claw &claw,
Austin Schuhf9286cd2014-02-11 00:51:09 -0800156 double *edge_encoder, double *edge_angle);
157
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800158#undef COUNT_SETTER_GETTER
159
Austin Schuhcda86af2014-02-16 16:16:39 -0800160 protected:
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800161 // The accumulated voltage to apply to the motor.
Austin Schuhf9286cd2014-02-11 00:51:09 -0800162 double offset_;
Austin Schuhcda86af2014-02-16 16:16:39 -0800163 const char *name_;
Austin Schuhf9286cd2014-02-11 00:51:09 -0800164
Austin Schuhcda86af2014-02-16 16:16:39 -0800165 ClawMotor *motor_;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800166
167 int32_t front_hall_effect_posedge_count_;
168 int32_t previous_front_hall_effect_posedge_count_;
169 int32_t front_hall_effect_negedge_count_;
170 int32_t previous_front_hall_effect_negedge_count_;
171 int32_t calibration_hall_effect_posedge_count_;
172 int32_t previous_calibration_hall_effect_posedge_count_;
173 int32_t calibration_hall_effect_negedge_count_;
174 int32_t previous_calibration_hall_effect_negedge_count_;
175 int32_t back_hall_effect_posedge_count_;
176 int32_t previous_back_hall_effect_posedge_count_;
177 int32_t back_hall_effect_negedge_count_;
178 int32_t previous_back_hall_effect_negedge_count_;
Austin Schuhcda86af2014-02-16 16:16:39 -0800179 bool front_hall_effect_;
180 bool calibration_hall_effect_;
181 bool back_hall_effect_;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800182
183 JointZeroingState zeroing_state_;
Austin Schuhf9286cd2014-02-11 00:51:09 -0800184 double posedge_value_;
185 double negedge_value_;
186 double encoder_;
187 double last_encoder_;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800188};
189
Austin Schuhcda86af2014-02-16 16:16:39 -0800190class TopZeroedStateFeedbackLoop : public ZeroedStateFeedbackLoop {
191 public:
192 TopZeroedStateFeedbackLoop(ClawMotor *motor)
193 : ZeroedStateFeedbackLoop("top", motor) {}
194 // Sets the calibration offset given the absolute angle and the corrisponding
195 // encoder value.
196 void SetCalibration(double edge_encoder, double edge_angle);
197
Austin Schuhd27931c2014-02-16 19:18:20 -0800198 bool SetCalibrationOnEdge(const constants::Values::Claws::Claw &claw_values,
Austin Schuhcda86af2014-02-16 16:16:39 -0800199 JointZeroingState zeroing_state) {
200 double edge_encoder;
201 double edge_angle;
202 if (GetPositionOfEdge(claw_values, &edge_encoder, &edge_angle)) {
203 LOG(INFO, "Calibration edge.\n");
204 SetCalibration(edge_encoder, edge_angle);
205 set_zeroing_state(zeroing_state);
206 return true;
207 }
208 return false;
209 }
210};
211
212class BottomZeroedStateFeedbackLoop : public ZeroedStateFeedbackLoop {
213 public:
214 BottomZeroedStateFeedbackLoop(ClawMotor *motor)
215 : ZeroedStateFeedbackLoop("bottom", motor) {}
216 // Sets the calibration offset given the absolute angle and the corrisponding
217 // encoder value.
218 void SetCalibration(double edge_encoder, double edge_angle);
219
Austin Schuhd27931c2014-02-16 19:18:20 -0800220 bool SetCalibrationOnEdge(const constants::Values::Claws::Claw &claw_values,
Austin Schuhcda86af2014-02-16 16:16:39 -0800221 JointZeroingState zeroing_state) {
222 double edge_encoder;
223 double edge_angle;
224 if (GetPositionOfEdge(claw_values, &edge_encoder, &edge_angle)) {
225 LOG(INFO, "Calibration edge.\n");
226 SetCalibration(edge_encoder, edge_angle);
227 set_zeroing_state(zeroing_state);
228 return true;
229 }
230 return false;
231 }
232};
Ben Fredrickson9b388422014-02-13 06:15:31 +0000233
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800234class ClawMotor
235 : public aos::control_loops::ControlLoop<control_loops::ClawGroup> {
236 public:
237 explicit ClawMotor(control_loops::ClawGroup *my_claw =
238 &control_loops::claw_queue_group);
Austin Schuh3bb9a442014-02-02 16:01:45 -0800239
240 // True if the state machine is ready.
Austin Schuh4cb047f2014-02-16 21:10:19 -0800241 bool capped_goal() const { return capped_goal_; }
242
Austin Schuhe7f90d12014-02-17 00:48:25 -0800243 double uncapped_average_voltage() const {
244 return claw_.uncapped_average_voltage();
245 }
246
247 // True if the claw is zeroing.
248 bool is_zeroing() const;
249
Austin Schuh4cb047f2014-02-16 21:10:19 -0800250 // True if the state machine is ready.
Austin Schuhe7f90d12014-02-17 00:48:25 -0800251 bool is_ready() const;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800252
Austin Schuhcda86af2014-02-16 16:16:39 -0800253 void ChangeTopOffset(double doffset);
254 void ChangeBottomOffset(double doffset);
255
Austin Schuhe7f90d12014-02-17 00:48:25 -0800256 enum CalibrationMode {
257 READY,
258 PREP_FINE_TUNE_TOP,
259 FINE_TUNE_TOP,
260 PREP_FINE_TUNE_BOTTOM,
261 FINE_TUNE_BOTTOM,
262 UNKNOWN_LOCATION
263 };
264
265 CalibrationMode mode() const { return mode_; }
266
Austin Schuh3bb9a442014-02-02 16:01:45 -0800267 protected:
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800268 virtual void RunIteration(const control_loops::ClawGroup::Goal *goal,
269 const control_loops::ClawGroup::Position *position,
270 control_loops::ClawGroup::Output *output,
271 ::aos::control_loops::Status *status);
272
Austin Schuhcda86af2014-02-16 16:16:39 -0800273 double top_absolute_position() const {
274 return claw_.X_hat(1, 0) + claw_.X_hat(0, 0);
275 }
276 double bottom_absolute_position() const { return claw_.X_hat(0, 0); }
Austin Schuh3bb9a442014-02-02 16:01:45 -0800277
278 private:
279 // Friend the test classes for acces to the internal state.
Austin Schuhe7f90d12014-02-17 00:48:25 -0800280 friend class testing::WindupClawTest;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800281
282 // The zeroed joint to use.
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800283 bool has_top_claw_goal_;
284 double top_claw_goal_;
Austin Schuhcda86af2014-02-16 16:16:39 -0800285 TopZeroedStateFeedbackLoop top_claw_;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800286
287 bool has_bottom_claw_goal_;
288 double bottom_claw_goal_;
Austin Schuhcda86af2014-02-16 16:16:39 -0800289 BottomZeroedStateFeedbackLoop bottom_claw_;
290
291 // The claw loop.
292 ClawLimitedLoop claw_;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800293
294 bool was_enabled_;
Ben Fredrickson9b388422014-02-13 06:15:31 +0000295 bool doing_calibration_fine_tune_;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800296
Austin Schuhcda86af2014-02-16 16:16:39 -0800297 // The initial seperation when disabled. Used as the safe seperation
298 // distance.
Austin Schuhe7f90d12014-02-17 00:48:25 -0800299 double initial_separation_;
Austin Schuhcda86af2014-02-16 16:16:39 -0800300
Austin Schuh4cb047f2014-02-16 21:10:19 -0800301 bool capped_goal_;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800302 CalibrationMode mode_;
Austin Schuh4cb047f2014-02-16 21:10:19 -0800303
Austin Schuh3bb9a442014-02-02 16:01:45 -0800304 DISALLOW_COPY_AND_ASSIGN(ClawMotor);
305};
306
307} // namespace control_loops
308} // namespace frc971
309
310#endif // FRC971_CONTROL_LOOPS_CLAW_CLAW_H_