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