blob: 50076a7239dba5af4bc499f57de19e7dee5d1163 [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"
Brian Silvermane0a95462014-02-17 00:41:09 -080011#include "frc971/control_loops/hall_effect_tracker.h"
Austin Schuh3bb9a442014-02-02 16:01:45 -080012
Austin Schuh3bb9a442014-02-02 16:01:45 -080013namespace frc971 {
14namespace control_loops {
15namespace testing {
Austin Schuhe7f90d12014-02-17 00:48:25 -080016class WindupClawTest;
Austin Schuh3bb9a442014-02-02 16:01:45 -080017};
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 Schuhf9286cd2014-02-11 00:51:09 -080056 zeroing_state_(UNKNOWN_POSITION),
57 posedge_value_(0.0),
58 negedge_value_(0.0),
59 encoder_(0.0),
Austin Schuhcda86af2014-02-16 16:16:39 -080060 last_encoder_(0.0) {}
Austin Schuh3bb9a442014-02-02 16:01:45 -080061
Austin Schuh4b7b5d02014-02-10 21:20:34 -080062 const static int kZeroingMaxVoltage = 5;
Austin Schuh3bb9a442014-02-02 16:01:45 -080063
Austin Schuh4b7b5d02014-02-10 21:20:34 -080064 enum JointZeroingState {
65 // We don't know where the joint is at all.
66 UNKNOWN_POSITION,
67 // We have an approximate position for where the claw is using.
68 APPROXIMATE_CALIBRATION,
69 // We observed the calibration edge while disabled. This is good enough for
70 // autonomous mode.
71 DISABLED_CALIBRATION,
72 // Ready for use during teleop.
73 CALIBRATED
74 };
75
76 void set_zeroing_state(JointZeroingState zeroing_state) {
77 zeroing_state_ = zeroing_state;
78 }
79 JointZeroingState zeroing_state() const { return zeroing_state_; }
80
Austin Schuh4339ebb2014-02-11 00:56:44 -080081 void SetPositionValues(const HalfClawPosition &claw) {
Brian Silvermane0a95462014-02-17 00:41:09 -080082 front_.Update(claw.front);
83 calibration_.Update(claw.calibration);
84 back_.Update(claw.back);
Austin Schuhf9286cd2014-02-11 00:51:09 -080085
Ben Fredricksonade3eab2014-02-22 07:30:53 +000086 if (any_hall_effect_changed()) {
Ben Fredrickson4283bb42014-02-22 08:31:50 +000087 // if the hall effect has changed we are new edge
88 // so we zero out the interval this new edge has covered
89 min_current_hall_effect_edge_ = claw.position;
90 max_current_hall_effect_edge_ = claw.position;
Ben Fredricksonade3eab2014-02-22 07:30:53 +000091 } else if (claw.position > max_current_hall_effect_edge_) {
92 max_current_hall_effect_edge_ = claw.position;
93 } else if (claw.position < min_current_hall_effect_edge_) {
94 min_current_hall_effect_edge_ = claw.position;
95 }
96
Austin Schuhf9286cd2014-02-11 00:51:09 -080097 posedge_value_ = claw.posedge_value;
98 negedge_value_ = claw.negedge_value;
Austin Schuhcda86af2014-02-16 16:16:39 -080099 last_encoder_ = encoder_;
100 encoder_ = claw.position;
Austin Schuhf9286cd2014-02-11 00:51:09 -0800101 }
102
Austin Schuhcda86af2014-02-16 16:16:39 -0800103 double absolute_position() const { return encoder() + offset(); }
104
Brian Silvermane0a95462014-02-17 00:41:09 -0800105 const HallEffectTracker &front() const { return front_; }
106 const HallEffectTracker &calibration() const { return calibration_; }
107 const HallEffectTracker &back() const { return back_; }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800108
109 bool any_hall_effect_changed() const {
Brian Silvermane0a95462014-02-17 00:41:09 -0800110 return front().either_count_changed() ||
111 calibration().either_count_changed() ||
112 back().either_count_changed();
113 }
114 bool front_or_back_triggered() const {
115 return front().value() || back().value();
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800116 }
117
Austin Schuhf9286cd2014-02-11 00:51:09 -0800118 double encoder() const { return encoder_; }
119 double last_encoder() const { return last_encoder_; }
120
Austin Schuhcda86af2014-02-16 16:16:39 -0800121 double offset() const { return offset_; }
122
Austin Schuhf9286cd2014-02-11 00:51:09 -0800123 // Returns true if an edge was detected in the last cycle and then sets the
124 // edge_position to the absolute position of the edge.
Austin Schuhd27931c2014-02-16 19:18:20 -0800125 bool GetPositionOfEdge(const constants::Values::Claws::Claw &claw,
Austin Schuhf9286cd2014-02-11 00:51:09 -0800126 double *edge_encoder, double *edge_angle);
127
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800128#undef COUNT_SETTER_GETTER
129
Austin Schuhcda86af2014-02-16 16:16:39 -0800130 protected:
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800131 // The accumulated voltage to apply to the motor.
Austin Schuhf9286cd2014-02-11 00:51:09 -0800132 double offset_;
Austin Schuhcda86af2014-02-16 16:16:39 -0800133 const char *name_;
Austin Schuhf9286cd2014-02-11 00:51:09 -0800134
Austin Schuhcda86af2014-02-16 16:16:39 -0800135 ClawMotor *motor_;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800136
Brian Silvermane0a95462014-02-17 00:41:09 -0800137 HallEffectTracker front_, calibration_, back_;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800138
139 JointZeroingState zeroing_state_;
Austin Schuhf9286cd2014-02-11 00:51:09 -0800140 double posedge_value_;
141 double negedge_value_;
Ben Fredrickson4283bb42014-02-22 08:31:50 +0000142 double last_edge_value_;
143 double min_current_hall_effect_edge_;
144 double max_current_hall_effect_edge_;
Austin Schuhf9286cd2014-02-11 00:51:09 -0800145 double encoder_;
146 double last_encoder_;
Brian Silvermane0a95462014-02-17 00:41:09 -0800147
148 private:
149 // Does the edges of 1 sensor for GetPositionOfEdge.
150 bool DoGetPositionOfEdge(const constants::Values::Claws::AnglePair &angles,
151 double *edge_encoder, double *edge_angle,
152 const HallEffectTracker &sensor,
153 const char *hall_effect_name);
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800154};
155
Austin Schuhcda86af2014-02-16 16:16:39 -0800156class TopZeroedStateFeedbackLoop : public ZeroedStateFeedbackLoop {
157 public:
158 TopZeroedStateFeedbackLoop(ClawMotor *motor)
159 : ZeroedStateFeedbackLoop("top", motor) {}
160 // Sets the calibration offset given the absolute angle and the corrisponding
161 // encoder value.
162 void SetCalibration(double edge_encoder, double edge_angle);
163
Austin Schuhd27931c2014-02-16 19:18:20 -0800164 bool SetCalibrationOnEdge(const constants::Values::Claws::Claw &claw_values,
Austin Schuhcda86af2014-02-16 16:16:39 -0800165 JointZeroingState zeroing_state) {
166 double edge_encoder;
167 double edge_angle;
168 if (GetPositionOfEdge(claw_values, &edge_encoder, &edge_angle)) {
169 LOG(INFO, "Calibration edge.\n");
170 SetCalibration(edge_encoder, edge_angle);
171 set_zeroing_state(zeroing_state);
172 return true;
173 }
174 return false;
175 }
176};
177
178class BottomZeroedStateFeedbackLoop : public ZeroedStateFeedbackLoop {
179 public:
180 BottomZeroedStateFeedbackLoop(ClawMotor *motor)
181 : ZeroedStateFeedbackLoop("bottom", motor) {}
182 // Sets the calibration offset given the absolute angle and the corrisponding
183 // encoder value.
184 void SetCalibration(double edge_encoder, double edge_angle);
185
Austin Schuhd27931c2014-02-16 19:18:20 -0800186 bool SetCalibrationOnEdge(const constants::Values::Claws::Claw &claw_values,
Austin Schuhcda86af2014-02-16 16:16:39 -0800187 JointZeroingState zeroing_state) {
188 double edge_encoder;
189 double edge_angle;
190 if (GetPositionOfEdge(claw_values, &edge_encoder, &edge_angle)) {
191 LOG(INFO, "Calibration edge.\n");
192 SetCalibration(edge_encoder, edge_angle);
193 set_zeroing_state(zeroing_state);
194 return true;
195 }
196 return false;
197 }
198};
Ben Fredrickson9b388422014-02-13 06:15:31 +0000199
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800200class ClawMotor
201 : public aos::control_loops::ControlLoop<control_loops::ClawGroup> {
202 public:
203 explicit ClawMotor(control_loops::ClawGroup *my_claw =
204 &control_loops::claw_queue_group);
Austin Schuh3bb9a442014-02-02 16:01:45 -0800205
206 // True if the state machine is ready.
Austin Schuh4cb047f2014-02-16 21:10:19 -0800207 bool capped_goal() const { return capped_goal_; }
208
Austin Schuhe7f90d12014-02-17 00:48:25 -0800209 double uncapped_average_voltage() const {
210 return claw_.uncapped_average_voltage();
211 }
212
213 // True if the claw is zeroing.
214 bool is_zeroing() const;
215
Austin Schuh4cb047f2014-02-16 21:10:19 -0800216 // True if the state machine is ready.
Austin Schuhe7f90d12014-02-17 00:48:25 -0800217 bool is_ready() const;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800218
Austin Schuhcda86af2014-02-16 16:16:39 -0800219 void ChangeTopOffset(double doffset);
220 void ChangeBottomOffset(double doffset);
221
Austin Schuhe7f90d12014-02-17 00:48:25 -0800222 enum CalibrationMode {
223 READY,
224 PREP_FINE_TUNE_TOP,
225 FINE_TUNE_TOP,
226 PREP_FINE_TUNE_BOTTOM,
227 FINE_TUNE_BOTTOM,
228 UNKNOWN_LOCATION
229 };
230
231 CalibrationMode mode() const { return mode_; }
232
Austin Schuh3bb9a442014-02-02 16:01:45 -0800233 protected:
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800234 virtual void RunIteration(const control_loops::ClawGroup::Goal *goal,
235 const control_loops::ClawGroup::Position *position,
236 control_loops::ClawGroup::Output *output,
237 ::aos::control_loops::Status *status);
238
Austin Schuhcda86af2014-02-16 16:16:39 -0800239 double top_absolute_position() const {
240 return claw_.X_hat(1, 0) + claw_.X_hat(0, 0);
241 }
242 double bottom_absolute_position() const { return claw_.X_hat(0, 0); }
Austin Schuh3bb9a442014-02-02 16:01:45 -0800243
244 private:
245 // Friend the test classes for acces to the internal state.
Austin Schuhe7f90d12014-02-17 00:48:25 -0800246 friend class testing::WindupClawTest;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800247
248 // The zeroed joint to use.
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800249 bool has_top_claw_goal_;
250 double top_claw_goal_;
Austin Schuhcda86af2014-02-16 16:16:39 -0800251 TopZeroedStateFeedbackLoop top_claw_;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800252
253 bool has_bottom_claw_goal_;
254 double bottom_claw_goal_;
Austin Schuhcda86af2014-02-16 16:16:39 -0800255 BottomZeroedStateFeedbackLoop bottom_claw_;
256
257 // The claw loop.
258 ClawLimitedLoop claw_;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800259
260 bool was_enabled_;
Ben Fredrickson9b388422014-02-13 06:15:31 +0000261 bool doing_calibration_fine_tune_;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800262
Brian Silverman7c021c42014-02-17 15:15:56 -0800263 // The initial separation when disabled. Used as the safe separation
Austin Schuhcda86af2014-02-16 16:16:39 -0800264 // distance.
Austin Schuhe7f90d12014-02-17 00:48:25 -0800265 double initial_separation_;
Austin Schuhcda86af2014-02-16 16:16:39 -0800266
Austin Schuh4cb047f2014-02-16 21:10:19 -0800267 bool capped_goal_;
Austin Schuhe7f90d12014-02-17 00:48:25 -0800268 CalibrationMode mode_;
Austin Schuh4cb047f2014-02-16 21:10:19 -0800269
Austin Schuh3bb9a442014-02-02 16:01:45 -0800270 DISALLOW_COPY_AND_ASSIGN(ClawMotor);
271};
272
Austin Schuh069143b2014-02-17 02:46:26 -0800273// Modifies the bottom and top goal such that they are within the limits and
274// their separation isn't too much or little.
275void LimitClawGoal(double *bottom_goal, double *top_goal,
276 const frc971::constants::Values &values);
277
Austin Schuh3bb9a442014-02-02 16:01:45 -0800278} // namespace control_loops
279} // namespace frc971
280
281#endif // FRC971_CONTROL_LOOPS_CLAW_CLAW_H_