blob: 0be4801b180503390ea1cf78a7d4d7a1796ac241 [file] [log] [blame]
Brian Silverman43bb73e2013-03-17 13:39:47 -07001#ifndef FRC971_CONTROL_LOOPS_INDEX_INDEX_H_
2#define FRC971_CONTROL_LOOPS_INDEX_INDEX_H_
Austin Schuhd78ab542013-03-01 22:22:19 -08003
Austin Schuhd78ab542013-03-01 22:22:19 -08004#include <deque>
Brian Silverman26683e22013-03-16 14:12:16 -07005#include "aos/common/libstdc++/memory"
Austin Schuhd78ab542013-03-01 22:22:19 -08006
7#include "aos/common/control_loop/ControlLoop.h"
8#include "aos/common/time.h"
9#include "frc971/control_loops/state_feedback_loop.h"
Austin Schuh00558222013-03-03 14:16:16 -080010#include "frc971/control_loops/index/index_motor.q.h"
11#include "frc971/control_loops/index/index_motor_plant.h"
Austin Schuhd78ab542013-03-01 22:22:19 -080012
13namespace frc971 {
14namespace control_loops {
Austin Schuhbcdb90c2013-03-03 23:24:58 -080015namespace testing {
16class IndexTest_InvalidStateTest_Test;
Austin Schuh7c0e2aa2013-03-09 02:01:16 -080017class IndexTest_LostDisc_Test;
Austin Schuhbcdb90c2013-03-03 23:24:58 -080018}
Austin Schuhd78ab542013-03-01 22:22:19 -080019
Austin Schuh723770b2013-03-10 13:26:20 -070020// This class represents a region of space.
21class Region {
22 public:
23 Region () : upper_bound_(0.0), lower_bound_(0.0) {}
24
25 // Restarts the region tracking by starting over with a 0 width region with
26 // the bounds at [edge, edge].
27 void Restart(double edge) {
28 upper_bound_ = edge;
29 lower_bound_ = edge;
30 }
31
32 // Expands the region to include the new point.
33 void Expand(double new_point) {
34 if (new_point > upper_bound_) {
35 upper_bound_ = new_point;
36 } else if (new_point < lower_bound_) {
37 lower_bound_ = new_point;
38 }
39 }
40
41 // Returns the width of the region.
42 double width() const { return upper_bound_ - lower_bound_; }
43 // Returns the upper and lower bounds.
44 double upper_bound() const { return upper_bound_; }
45 double lower_bound() const { return lower_bound_; }
46
47 private:
48 // Upper bound of the region.
49 double upper_bound_;
50 // Lower bound of the region.
51 double lower_bound_;
52};
53
Austin Schuhd78ab542013-03-01 22:22:19 -080054class IndexMotor
55 : public aos::control_loops::ControlLoop<control_loops::IndexLoop> {
56 public:
57 explicit IndexMotor(
Austin Schuhf8c52252013-03-03 02:25:49 -080058 control_loops::IndexLoop *my_index = &control_loops::index_loop);
59
60 static const double kTransferStartPosition;
61 static const double kIndexStartPosition;
62 // The distance from where the disc first grabs on the indexer to where it
63 // just bairly clears the loader.
64 static const double kIndexFreeLength;
65 // The distance to where the disc just starts to enter the loader.
66 static const double kLoaderFreeStopPosition;
Austin Schuh1b864a12013-03-07 00:46:50 -080067 // The distance to where the next disc gets positioned while the current disc
68 // is shooting.
69 static const double kReadyToPreload;
Austin Schuhf8c52252013-03-03 02:25:49 -080070
71 // Distance that the grabber pulls the disc in by.
72 static const double kGrabberLength;
73 // Distance to where the grabber takes over.
74 static const double kGrabberStartPosition;
75
76 // The distance to where the disc hits the back of the loader and is ready to
77 // lift.
78 static const double kReadyToLiftPosition;
79
80 static const double kGrabberMovementVelocity;
81 // TODO(aschuh): This depends on the shooter angle...
82 // Distance to where the shooter is up and ready to shoot.
83 static const double kLifterStopPosition;
84 static const double kLifterMovementVelocity;
85
86 // Distance to where the disc has been launched.
87 // TODO(aschuh): This depends on the shooter angle...
88 static const double kEjectorStopPosition;
89 static const double kEjectorMovementVelocity;
90
91 // Start and stop position of the bottom disc detect sensor in meters.
92 static const double kBottomDiscDetectStart;
93 static const double kBottomDiscDetectStop;
Austin Schuh6328daf2013-03-05 00:53:15 -080094 // Delay between the negedge of the disc detect and when it engages on the
95 // indexer.
96 static const double kBottomDiscIndexDelay;
Austin Schuhf8c52252013-03-03 02:25:49 -080097
Austin Schuhd3d0fbf2013-03-14 00:37:00 -070098 // Time after seeing the fourth disc that we need to wait before turning the
99 // transfer roller off.
100 static const ::aos::time::Time kTransferOffDelay;
101
Austin Schuhf8c52252013-03-03 02:25:49 -0800102 static const double kTopDiscDetectStart;
103 static const double kTopDiscDetectStop;
Austin Schuhd78ab542013-03-01 22:22:19 -0800104
Austin Schuh7c0e2aa2013-03-09 02:01:16 -0800105 // Minimum distance between 2 frisbees as seen by the top disc detect sensor.
106 static const double kTopDiscDetectMinSeperation;
107
Austin Schuhd78ab542013-03-01 22:22:19 -0800108 // Converts the angle of the indexer to the angle of the disc.
109 static double ConvertIndexToDiscAngle(const double angle);
110 // Converts the angle of the indexer to the position that the center of the
111 // disc has traveled.
112 static double ConvertIndexToDiscPosition(const double angle);
113
Austin Schuhf8c52252013-03-03 02:25:49 -0800114 // Converts the angle of the transfer roller to the position that the center
115 // of the disc has traveled.
116 static double ConvertTransferToDiscPosition(const double angle);
117
118 // Converts the distance around the indexer to the position of
119 // the index roller.
120 static double ConvertDiscPositionToIndex(const double position);
Austin Schuhd78ab542013-03-01 22:22:19 -0800121 // Converts the angle around the indexer to the position of the index roller.
122 static double ConvertDiscAngleToIndex(const double angle);
123 // Converts the angle around the indexer to the position of the disc in the
124 // indexer.
125 static double ConvertDiscAngleToDiscPosition(const double angle);
Austin Schuhf8c52252013-03-03 02:25:49 -0800126 // Converts the distance around the indexer to the angle of the disc around
127 // the indexer.
128 static double ConvertDiscPositionToDiscAngle(const double position);
Austin Schuhd78ab542013-03-01 22:22:19 -0800129
130 // Disc radius in meters.
Austin Schuhf8c52252013-03-03 02:25:49 -0800131 static const double kDiscRadius;
Austin Schuhd78ab542013-03-01 22:22:19 -0800132 // Roller radius in meters.
Austin Schuhf8c52252013-03-03 02:25:49 -0800133 static const double kRollerRadius;
134 // Transfer roller radius in meters.
135 static const double kTransferRollerRadius;
Austin Schuhd78ab542013-03-01 22:22:19 -0800136
Austin Schuhf8c52252013-03-03 02:25:49 -0800137 // Time that it takes to grab the disc in cycles.
138 static const int kGrabbingDelay;
Brian Silverman25329e62013-09-21 23:52:10 -0700139 // Time that it takes to finish lifting the loader after the sensor is
140 // triggered in cycles.
Austin Schuhf8c52252013-03-03 02:25:49 -0800141 static const int kLiftingDelay;
Brian Silvermanc540ab82013-09-22 00:00:28 -0700142 // Time until we give up lifting and move on in cycles.
143 static const int kLiftingTimeout;
Austin Schuhf8c52252013-03-03 02:25:49 -0800144 // Time that it takes to shoot the disc in cycles.
145 static const int kShootingDelay;
Brian Silverman004ec812013-09-26 15:47:58 -0700146 // Time that it takes to finish lowering the loader after the sensor is
147 // triggered in cycles.
Austin Schuhf8c52252013-03-03 02:25:49 -0800148 static const int kLoweringDelay;
Brian Silverman004ec812013-09-26 15:47:58 -0700149 // Time until we give up lowering and move on in cycles.
150 // It's a long time because we really don't want to ever hit this.
151 static const int kLoweringTimeout;
Austin Schuhf8c52252013-03-03 02:25:49 -0800152
153 // Object representing a Frisbee tracked by the indexer.
Austin Schuhd78ab542013-03-01 22:22:19 -0800154 class Frisbee {
155 public:
156 Frisbee()
157 : bottom_posedge_time_(0, 0),
Austin Schuhf8c52252013-03-03 02:25:49 -0800158 bottom_negedge_time_(0, 0) {
Austin Schuhd78ab542013-03-01 22:22:19 -0800159 Reset();
160 }
161
Austin Schuhf8c52252013-03-03 02:25:49 -0800162 // Resets a Frisbee so it can be reused.
Austin Schuhd78ab542013-03-01 22:22:19 -0800163 void Reset() {
164 bottom_posedge_time_ = ::aos::time::Time(0, 0);
165 bottom_negedge_time_ = ::aos::time::Time(0, 0);
Austin Schuhd78ab542013-03-01 22:22:19 -0800166 has_been_indexed_ = false;
167 index_start_position_ = 0.0;
168 }
169
Austin Schuhf8c52252013-03-03 02:25:49 -0800170 // Returns true if the position is valid.
171 bool has_position() const {
172 return has_been_indexed_;
173 }
174
175 // Returns the most up to date and accurate position that we have for the
176 // disc. This is the indexer position that the disc grabbed at.
177 double position() const {
178 return index_start_position_;
179 }
180
Austin Schuh1b864a12013-03-07 00:46:50 -0800181 // Returns the absolute position of the disc in meters in the hopper given
182 // that the indexer is at the provided position.
183 double absolute_position(const double index_position) const {
184 return IndexMotor::ConvertIndexToDiscPosition(
185 index_position - index_start_position_) +
186 IndexMotor::kIndexStartPosition;
187 }
188
Austin Schuhbcdb90c2013-03-03 23:24:58 -0800189 // Shifts the disc down the indexer by the provided offset. This is to
190 // handle when the cRIO reboots.
191 void OffsetDisc(double offset) {
192 index_start_position_ += offset;
193 }
194
Austin Schuh825bde92013-03-06 00:16:46 -0800195 // Potentially offsets the position with the knowledge that no discs are
196 // currently blocking the top sensor. This knowledge can be used to move
197 // this disc if it is believed to be blocking the top sensor.
Austin Schuhdff24e22013-03-06 00:41:21 -0800198 // Returns the amount that the disc moved due to this observation.
Austin Schuh6b1ad2f2013-03-11 23:23:00 -0700199 double ObserveNoTopDiscSensor(double index_position);
Austin Schuh825bde92013-03-06 00:16:46 -0800200
Austin Schuhf8c52252013-03-03 02:25:49 -0800201 // Posedge and negedge disc times.
Austin Schuhd78ab542013-03-01 22:22:19 -0800202 ::aos::time::Time bottom_posedge_time_;
203 ::aos::time::Time bottom_negedge_time_;
Austin Schuhf8c52252013-03-03 02:25:49 -0800204
205 // True if the disc has a valid index position.
Austin Schuhd78ab542013-03-01 22:22:19 -0800206 bool has_been_indexed_;
Austin Schuhf8c52252013-03-03 02:25:49 -0800207 // Location of the index when the disc first contacted it.
Austin Schuhd78ab542013-03-01 22:22:19 -0800208 double index_start_position_;
209 };
210
Austin Schuh7c0e2aa2013-03-09 02:01:16 -0800211 // Returns where the indexer thinks the frisbees are.
Austin Schuh1b864a12013-03-07 00:46:50 -0800212 const ::std::deque<Frisbee> &frisbees() const { return frisbees_; }
213
Austin Schuhd78ab542013-03-01 22:22:19 -0800214 protected:
215 virtual void RunIteration(
216 const control_loops::IndexLoop::Goal *goal,
217 const control_loops::IndexLoop::Position *position,
218 control_loops::IndexLoop::Output *output,
219 control_loops::IndexLoop::Status *status);
220
221 private:
Austin Schuhbcdb90c2013-03-03 23:24:58 -0800222 friend class testing::IndexTest_InvalidStateTest_Test;
Austin Schuh7c0e2aa2013-03-09 02:01:16 -0800223 friend class testing::IndexTest_LostDisc_Test;
Austin Schuh93485832013-03-04 00:01:34 -0800224
225 // This class implements the CapU function correctly given all the extra
226 // information that we know about from the wrist motor.
227 class IndexStateFeedbackLoop : public StateFeedbackLoop<2, 1, 1> {
228 public:
229 IndexStateFeedbackLoop(StateFeedbackLoop<2, 1, 1> loop)
230 : StateFeedbackLoop<2, 1, 1>(loop),
231 low_voltage_count_(0) {
232 }
233
234 // Voltage below which the indexer won't move with a disc in it.
235 static const double kMinMotionVoltage;
236 // Maximum number of cycles to apply a low voltage to the motor.
237 static const double kNoMotionCuttoffCount;
238
239 // Caps U, but disables the motor after a number of cycles of inactivity.
240 virtual void CapU();
241 private:
242 // Number of cycles that we have seen a small voltage being applied.
243 uint32_t low_voltage_count_;
244 };
245
Austin Schuhf8c52252013-03-03 02:25:49 -0800246 // Sets disc_position to the minimum or maximum disc position.
Austin Schuh1b864a12013-03-07 00:46:50 -0800247 // Sets found_disc to point to the frisbee that was found, and ignores it if
248 // found_disc is NULL.
Austin Schuhf8c52252013-03-03 02:25:49 -0800249 // Returns true if there were discs, and false if there weren't.
250 // On false, disc_position is left unmodified.
Austin Schuh1b864a12013-03-07 00:46:50 -0800251 bool MinDiscPosition(double *disc_position, Frisbee **found_disc);
252 bool MaxDiscPosition(double *disc_position, Frisbee **found_disc);
Austin Schuhd78ab542013-03-01 22:22:19 -0800253
254 // The state feedback control loop to talk to for the index.
Austin Schuh93485832013-03-04 00:01:34 -0800255 ::std::unique_ptr<IndexStateFeedbackLoop> wrist_loop_;
Austin Schuhd78ab542013-03-01 22:22:19 -0800256
Austin Schuhd78ab542013-03-01 22:22:19 -0800257 // Count of the number of discs that we have collected.
Austin Schuh7c0e2aa2013-03-09 02:01:16 -0800258 int32_t hopper_disc_count_;
259 int32_t total_disc_count_;
Austin Schuh70be1ba2013-03-10 13:37:17 -0700260 int32_t shot_disc_count_;
Austin Schuhd78ab542013-03-01 22:22:19 -0800261
Austin Schuhf8c52252013-03-03 02:25:49 -0800262 enum class Goal {
Austin Schuhd78ab542013-03-01 22:22:19 -0800263 // Hold position, in a low power state.
264 HOLD = 0,
265 // Get ready to load discs by shifting the discs down.
266 READY_LOWER = 1,
267 // Ready the discs, spin up the transfer roller, and accept discs.
268 INTAKE = 2,
269 // Get ready to shoot, and place a disc in the loader.
270 READY_SHOOTER = 3,
271 // Shoot at will.
Brian Silvermanb8d389f2013-03-19 22:54:06 -0700272 SHOOT = 4,
273 // Reinitialize.
274 REINITIALIZE = 5
Austin Schuhd78ab542013-03-01 22:22:19 -0800275 };
276
Austin Schuhf8c52252013-03-03 02:25:49 -0800277 // These two enums command and track the loader loading discs into the
278 // shooter.
279 enum class LoaderState {
280 // Open and down, ready to accept a disc.
281 READY,
282 // Closing the grabber.
283 GRABBING,
284 // Grabber closed.
285 GRABBED,
286 // Lifting the disc.
287 LIFTING,
288 // Disc lifted.
289 LIFTED,
290 // Ejecting the disc into the shooter.
291 SHOOTING,
292 // The disc has been shot.
293 SHOOT,
294 // Lowering the loader back down.
295 LOWERING,
296 // The indexer is lowered.
297 LOWERED
298 };
299
300 // TODO(aschuh): If we are grabbed and asked to be ready, now what?
301 // LOG ?
302 enum class LoaderGoal {
303 // Get the loader ready to accept another disc.
304 READY,
305 // Grab a disc now.
306 GRAB,
307 // Lift it up, shoot, and reset.
308 // Waits to shoot until the shooter is stable.
309 // Resets the goal to READY once one disc has been shot.
310 SHOOT_AND_RESET
311 };
312
Austin Schuhd78ab542013-03-01 22:22:19 -0800313 // The current goal
314 Goal safe_goal_;
315
Austin Schuhf8c52252013-03-03 02:25:49 -0800316 // Loader goal, state, and counter.
317 LoaderGoal loader_goal_;
318 LoaderState loader_state_;
Brian Silvermanc540ab82013-09-22 00:00:28 -0700319 int loader_countdown_, loader_timeout_;
Brian Silverman967c4422013-09-29 16:58:59 -0700320 // Whether or not we (might have) failed to shoot a disk that's now (probably)
321 // still in the loader.
322 bool disk_stuck_in_loader_;
Austin Schuhf8c52252013-03-03 02:25:49 -0800323
Austin Schuhd78ab542013-03-01 22:22:19 -0800324 // Current state of the pistons.
325 bool loader_up_;
326 bool disc_clamped_;
327 bool disc_ejected_;
328
Brian Silverman7ffb1382013-09-29 16:55:12 -0700329 bool is_shooting_;
330
Austin Schuhd78ab542013-03-01 22:22:19 -0800331 // The frisbee that is flying through the transfer rollers.
332 Frisbee transfer_frisbee_;
333
Austin Schuhf8c52252013-03-03 02:25:49 -0800334 // Bottom disc detect from the last valid packet for detecting edges.
Austin Schuhd78ab542013-03-01 22:22:19 -0800335 bool last_bottom_disc_detect_;
Austin Schuh825bde92013-03-06 00:16:46 -0800336 bool last_top_disc_detect_;
Brian Silverman7d39d862013-09-29 17:00:30 -0700337 bool hopper_clear_;
Austin Schuh6328daf2013-03-05 00:53:15 -0800338 int32_t last_bottom_disc_posedge_count_;
339 int32_t last_bottom_disc_negedge_count_;
340 int32_t last_bottom_disc_negedge_wait_count_;
Austin Schuh825bde92013-03-06 00:16:46 -0800341 int32_t last_top_disc_posedge_count_;
Austin Schuh7c0e2aa2013-03-09 02:01:16 -0800342 int32_t last_top_disc_negedge_count_;
Austin Schuhd78ab542013-03-01 22:22:19 -0800343
344 // Frisbees are in order such that the newest frisbee is on the front.
345 ::std::deque<Frisbee> frisbees_;
Austin Schuhd78ab542013-03-01 22:22:19 -0800346
Austin Schuhbcdb90c2013-03-03 23:24:58 -0800347 // True if we haven't seen a position before.
348 bool no_prior_position_;
349 // Number of position messages that we have missed in a row.
350 uint32_t missing_position_count_;
351
Austin Schuh723770b2013-03-10 13:26:20 -0700352 // The no-disc regions for both the bottom and top beam break sensors.
353 Region upper_open_region_;
354 Region lower_open_region_;
Austin Schuh7c0e2aa2013-03-09 02:01:16 -0800355
Austin Schuhd78ab542013-03-01 22:22:19 -0800356 DISALLOW_COPY_AND_ASSIGN(IndexMotor);
357};
Austin Schuhd78ab542013-03-01 22:22:19 -0800358} // namespace control_loops
359} // namespace frc971
360
Brian Silverman43bb73e2013-03-17 13:39:47 -0700361#endif // FRC971_CONTROL_LOOPS_INDEX_INDEX_H_