blob: 20b30b6091de8a8af374b6c6709c4c14f202a76c [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 {
15class ClawTest_NoWindupPositive_Test;
16class ClawTest_NoWindupNegative_Test;
17};
18
Austin Schuh4b7b5d02014-02-10 21:20:34 -080019// Note: Everything in this file assumes that there is a 1 cycle delay between
20// power being requested and it showing up at the motor. It assumes that
21// X_hat(2, 1) is the voltage being applied as well. It will go unstable if
22// that isn't true.
23
Austin Schuhcda86af2014-02-16 16:16:39 -080024class ClawLimitedLoop : public StateFeedbackLoop<4, 2, 2> {
25 public:
26 ClawLimitedLoop(StateFeedbackLoop<4, 2, 2> loop)
Austin Schuh4cb047f2014-02-16 21:10:19 -080027 : StateFeedbackLoop<4, 2, 2>(loop),
28 uncapped_average_voltage_(0.0),
29 is_zeroing_(true) {}
Austin Schuhcda86af2014-02-16 16:16:39 -080030 virtual void CapU();
31
Austin Schuh4cb047f2014-02-16 21:10:19 -080032 void set_is_zeroing(bool is_zeroing) { is_zeroing_ = is_zeroing; }
33
Austin Schuhcda86af2014-02-16 16:16:39 -080034 void ChangeTopOffset(double doffset);
35 void ChangeBottomOffset(double doffset);
Austin Schuh4cb047f2014-02-16 21:10:19 -080036
37 double uncapped_average_voltage() const { return uncapped_average_voltage_; }
38
39 private:
40 double uncapped_average_voltage_;
41 bool is_zeroing_;
Austin Schuhcda86af2014-02-16 16:16:39 -080042};
43
44class ClawMotor;
45
Austin Schuh4b7b5d02014-02-10 21:20:34 -080046// This class implements the CapU function correctly given all the extra
47// information that we know about from the wrist motor.
48// It does not have any zeroing logic in it, only logic to deal with a delta U
49// controller.
Austin Schuhcda86af2014-02-16 16:16:39 -080050class ZeroedStateFeedbackLoop {
Austin Schuh3bb9a442014-02-02 16:01:45 -080051 public:
Austin Schuhcda86af2014-02-16 16:16:39 -080052 ZeroedStateFeedbackLoop(const char *name, ClawMotor *motor)
53 : offset_(0.0),
54 name_(name),
55 motor_(motor),
Austin Schuh4b7b5d02014-02-10 21:20:34 -080056 front_hall_effect_posedge_count_(0.0),
57 previous_front_hall_effect_posedge_count_(0.0),
58 front_hall_effect_negedge_count_(0.0),
59 previous_front_hall_effect_negedge_count_(0.0),
60 calibration_hall_effect_posedge_count_(0.0),
61 previous_calibration_hall_effect_posedge_count_(0.0),
62 calibration_hall_effect_negedge_count_(0.0),
63 previous_calibration_hall_effect_negedge_count_(0.0),
64 back_hall_effect_posedge_count_(0.0),
65 previous_back_hall_effect_posedge_count_(0.0),
66 back_hall_effect_negedge_count_(0.0),
67 previous_back_hall_effect_negedge_count_(0.0),
Austin Schuhcda86af2014-02-16 16:16:39 -080068 front_hall_effect_(false),
69 calibration_hall_effect_(false),
70 back_hall_effect_(false),
Austin Schuhf9286cd2014-02-11 00:51:09 -080071 zeroing_state_(UNKNOWN_POSITION),
72 posedge_value_(0.0),
73 negedge_value_(0.0),
74 encoder_(0.0),
Austin Schuhcda86af2014-02-16 16:16:39 -080075 last_encoder_(0.0) {}
Austin Schuh3bb9a442014-02-02 16:01:45 -080076
Austin Schuh4b7b5d02014-02-10 21:20:34 -080077 const static int kZeroingMaxVoltage = 5;
Austin Schuh3bb9a442014-02-02 16:01:45 -080078
Austin Schuh4b7b5d02014-02-10 21:20:34 -080079 enum JointZeroingState {
80 // We don't know where the joint is at all.
81 UNKNOWN_POSITION,
82 // We have an approximate position for where the claw is using.
83 APPROXIMATE_CALIBRATION,
84 // We observed the calibration edge while disabled. This is good enough for
85 // autonomous mode.
86 DISABLED_CALIBRATION,
87 // Ready for use during teleop.
88 CALIBRATED
89 };
90
91 void set_zeroing_state(JointZeroingState zeroing_state) {
92 zeroing_state_ = zeroing_state;
93 }
94 JointZeroingState zeroing_state() const { return zeroing_state_; }
95
Austin Schuh4339ebb2014-02-11 00:56:44 -080096 void SetPositionValues(const HalfClawPosition &claw) {
Austin Schuhf9286cd2014-02-11 00:51:09 -080097 set_front_hall_effect_posedge_count(claw.front_hall_effect_posedge_count);
98 set_front_hall_effect_negedge_count(claw.front_hall_effect_negedge_count);
99 set_calibration_hall_effect_posedge_count(
100 claw.calibration_hall_effect_posedge_count);
101 set_calibration_hall_effect_negedge_count(
102 claw.calibration_hall_effect_negedge_count);
103 set_back_hall_effect_posedge_count(claw.back_hall_effect_posedge_count);
104 set_back_hall_effect_negedge_count(claw.back_hall_effect_negedge_count);
105
106 posedge_value_ = claw.posedge_value;
107 negedge_value_ = claw.negedge_value;
Austin Schuhcda86af2014-02-16 16:16:39 -0800108 last_encoder_ = encoder_;
109 encoder_ = claw.position;
110
111 front_hall_effect_ = claw.front_hall_effect;
112 calibration_hall_effect_ = claw.calibration_hall_effect;
113 back_hall_effect_ = claw.back_hall_effect;
Austin Schuhf9286cd2014-02-11 00:51:09 -0800114 }
115
Austin Schuhcda86af2014-02-16 16:16:39 -0800116 double absolute_position() const { return encoder() + offset(); }
117
118 bool front_hall_effect() const { return front_hall_effect_; }
119 bool calibration_hall_effect() const { return calibration_hall_effect_; }
120 bool back_hall_effect() const { return back_hall_effect_; }
121
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800122#define COUNT_SETTER_GETTER(variable) \
123 void set_##variable(int32_t value) { \
124 previous_##variable##_ = variable##_; \
125 variable##_ = value; \
126 } \
127 int32_t variable() const { return variable##_; } \
128 bool variable##_changed() const { \
129 return previous_##variable##_ != variable##_; \
130 }
131
Austin Schuhf9286cd2014-02-11 00:51:09 -0800132 // TODO(austin): Pull all this out of the new sub structure.
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800133 COUNT_SETTER_GETTER(front_hall_effect_posedge_count);
134 COUNT_SETTER_GETTER(front_hall_effect_negedge_count);
135 COUNT_SETTER_GETTER(calibration_hall_effect_posedge_count);
136 COUNT_SETTER_GETTER(calibration_hall_effect_negedge_count);
137 COUNT_SETTER_GETTER(back_hall_effect_posedge_count);
138 COUNT_SETTER_GETTER(back_hall_effect_negedge_count);
139
140 bool any_hall_effect_changed() const {
141 return front_hall_effect_posedge_count_changed() ||
142 front_hall_effect_negedge_count_changed() ||
143 calibration_hall_effect_posedge_count_changed() ||
144 calibration_hall_effect_negedge_count_changed() ||
145 back_hall_effect_posedge_count_changed() ||
146 back_hall_effect_negedge_count_changed();
147 }
148
Austin Schuhf9286cd2014-02-11 00:51:09 -0800149 double encoder() const { return encoder_; }
150 double last_encoder() const { return last_encoder_; }
151
Austin Schuhcda86af2014-02-16 16:16:39 -0800152 double offset() const { return offset_; }
153
Austin Schuhf9286cd2014-02-11 00:51:09 -0800154 // Returns true if an edge was detected in the last cycle and then sets the
155 // edge_position to the absolute position of the edge.
Austin Schuhd27931c2014-02-16 19:18:20 -0800156 bool GetPositionOfEdge(const constants::Values::Claws::Claw &claw,
Austin Schuhf9286cd2014-02-11 00:51:09 -0800157 double *edge_encoder, double *edge_angle);
158
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800159#undef COUNT_SETTER_GETTER
160
Austin Schuhcda86af2014-02-16 16:16:39 -0800161 protected:
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800162 // The accumulated voltage to apply to the motor.
Austin Schuhf9286cd2014-02-11 00:51:09 -0800163 double offset_;
Austin Schuhcda86af2014-02-16 16:16:39 -0800164 const char *name_;
Austin Schuhf9286cd2014-02-11 00:51:09 -0800165
Austin Schuhcda86af2014-02-16 16:16:39 -0800166 ClawMotor *motor_;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800167
168 int32_t front_hall_effect_posedge_count_;
169 int32_t previous_front_hall_effect_posedge_count_;
170 int32_t front_hall_effect_negedge_count_;
171 int32_t previous_front_hall_effect_negedge_count_;
172 int32_t calibration_hall_effect_posedge_count_;
173 int32_t previous_calibration_hall_effect_posedge_count_;
174 int32_t calibration_hall_effect_negedge_count_;
175 int32_t previous_calibration_hall_effect_negedge_count_;
176 int32_t back_hall_effect_posedge_count_;
177 int32_t previous_back_hall_effect_posedge_count_;
178 int32_t back_hall_effect_negedge_count_;
179 int32_t previous_back_hall_effect_negedge_count_;
Austin Schuhcda86af2014-02-16 16:16:39 -0800180 bool front_hall_effect_;
181 bool calibration_hall_effect_;
182 bool back_hall_effect_;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800183
184 JointZeroingState zeroing_state_;
Austin Schuhf9286cd2014-02-11 00:51:09 -0800185 double posedge_value_;
186 double negedge_value_;
187 double encoder_;
188 double last_encoder_;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800189};
190
Austin Schuhcda86af2014-02-16 16:16:39 -0800191class TopZeroedStateFeedbackLoop : public ZeroedStateFeedbackLoop {
192 public:
193 TopZeroedStateFeedbackLoop(ClawMotor *motor)
194 : ZeroedStateFeedbackLoop("top", motor) {}
195 // Sets the calibration offset given the absolute angle and the corrisponding
196 // encoder value.
197 void SetCalibration(double edge_encoder, double edge_angle);
198
Austin Schuhd27931c2014-02-16 19:18:20 -0800199 bool SetCalibrationOnEdge(const constants::Values::Claws::Claw &claw_values,
Austin Schuhcda86af2014-02-16 16:16:39 -0800200 JointZeroingState zeroing_state) {
201 double edge_encoder;
202 double edge_angle;
203 if (GetPositionOfEdge(claw_values, &edge_encoder, &edge_angle)) {
204 LOG(INFO, "Calibration edge.\n");
205 SetCalibration(edge_encoder, edge_angle);
206 set_zeroing_state(zeroing_state);
207 return true;
208 }
209 return false;
210 }
211};
212
213class BottomZeroedStateFeedbackLoop : public ZeroedStateFeedbackLoop {
214 public:
215 BottomZeroedStateFeedbackLoop(ClawMotor *motor)
216 : ZeroedStateFeedbackLoop("bottom", motor) {}
217 // Sets the calibration offset given the absolute angle and the corrisponding
218 // encoder value.
219 void SetCalibration(double edge_encoder, double edge_angle);
220
Austin Schuhd27931c2014-02-16 19:18:20 -0800221 bool SetCalibrationOnEdge(const constants::Values::Claws::Claw &claw_values,
Austin Schuhcda86af2014-02-16 16:16:39 -0800222 JointZeroingState zeroing_state) {
223 double edge_encoder;
224 double edge_angle;
225 if (GetPositionOfEdge(claw_values, &edge_encoder, &edge_angle)) {
226 LOG(INFO, "Calibration edge.\n");
227 SetCalibration(edge_encoder, edge_angle);
228 set_zeroing_state(zeroing_state);
229 return true;
230 }
231 return false;
232 }
233};
Ben Fredrickson9b388422014-02-13 06:15:31 +0000234
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800235class ClawMotor
236 : public aos::control_loops::ControlLoop<control_loops::ClawGroup> {
237 public:
238 explicit ClawMotor(control_loops::ClawGroup *my_claw =
239 &control_loops::claw_queue_group);
Austin Schuh3bb9a442014-02-02 16:01:45 -0800240
241 // True if the state machine is ready.
Austin Schuh4cb047f2014-02-16 21:10:19 -0800242 bool capped_goal() const { return capped_goal_; }
243
244 // True if the state machine is ready.
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800245 bool is_ready() const { return false; }
Austin Schuh3bb9a442014-02-02 16:01:45 -0800246
Austin Schuhcda86af2014-02-16 16:16:39 -0800247 void ChangeTopOffset(double doffset);
248 void ChangeBottomOffset(double doffset);
249
Austin Schuh3bb9a442014-02-02 16:01:45 -0800250 protected:
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800251 virtual void RunIteration(const control_loops::ClawGroup::Goal *goal,
252 const control_loops::ClawGroup::Position *position,
253 control_loops::ClawGroup::Output *output,
254 ::aos::control_loops::Status *status);
255
Austin Schuhcda86af2014-02-16 16:16:39 -0800256 double top_absolute_position() const {
257 return claw_.X_hat(1, 0) + claw_.X_hat(0, 0);
258 }
259 double bottom_absolute_position() const { return claw_.X_hat(0, 0); }
Austin Schuh3bb9a442014-02-02 16:01:45 -0800260
261 private:
262 // Friend the test classes for acces to the internal state.
263 friend class testing::ClawTest_NoWindupPositive_Test;
264 friend class testing::ClawTest_NoWindupNegative_Test;
265
266 // The zeroed joint to use.
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800267 bool has_top_claw_goal_;
268 double top_claw_goal_;
Austin Schuhcda86af2014-02-16 16:16:39 -0800269 TopZeroedStateFeedbackLoop top_claw_;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800270
271 bool has_bottom_claw_goal_;
272 double bottom_claw_goal_;
Austin Schuhcda86af2014-02-16 16:16:39 -0800273 BottomZeroedStateFeedbackLoop bottom_claw_;
274
275 // The claw loop.
276 ClawLimitedLoop claw_;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800277
278 bool was_enabled_;
Ben Fredrickson9b388422014-02-13 06:15:31 +0000279 bool doing_calibration_fine_tune_;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800280
Austin Schuhcda86af2014-02-16 16:16:39 -0800281 // The initial seperation when disabled. Used as the safe seperation
282 // distance.
283 double initial_seperation_;
284
Austin Schuh4cb047f2014-02-16 21:10:19 -0800285 bool capped_goal_;
286
Austin Schuh3bb9a442014-02-02 16:01:45 -0800287 DISALLOW_COPY_AND_ASSIGN(ClawMotor);
288};
289
290} // namespace control_loops
291} // namespace frc971
292
293#endif // FRC971_CONTROL_LOOPS_CLAW_CLAW_H_