blob: 37bcb26d69ee1cb69de0032e84217ff47fbae9fc [file] [log] [blame]
Austin Schuhd78ab542013-03-01 22:22:19 -08001#ifndef FRC971_CONTROL_LOOPS_WRIST_H_
2#define FRC971_CONTROL_LOOPS_WRIST_H_
3
Austin Schuhd78ab542013-03-01 22:22:19 -08004#include <deque>
Brian Silverman94195052013-03-09 13:45:05 -08005#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
20class IndexMotor
21 : public aos::control_loops::ControlLoop<control_loops::IndexLoop> {
22 public:
23 explicit IndexMotor(
Austin Schuhf8c52252013-03-03 02:25:49 -080024 control_loops::IndexLoop *my_index = &control_loops::index_loop);
25
26 static const double kTransferStartPosition;
27 static const double kIndexStartPosition;
28 // The distance from where the disc first grabs on the indexer to where it
29 // just bairly clears the loader.
30 static const double kIndexFreeLength;
31 // The distance to where the disc just starts to enter the loader.
32 static const double kLoaderFreeStopPosition;
Austin Schuh1b864a12013-03-07 00:46:50 -080033 // The distance to where the next disc gets positioned while the current disc
34 // is shooting.
35 static const double kReadyToPreload;
Austin Schuhf8c52252013-03-03 02:25:49 -080036
37 // Distance that the grabber pulls the disc in by.
38 static const double kGrabberLength;
39 // Distance to where the grabber takes over.
40 static const double kGrabberStartPosition;
41
42 // The distance to where the disc hits the back of the loader and is ready to
43 // lift.
44 static const double kReadyToLiftPosition;
45
46 static const double kGrabberMovementVelocity;
47 // TODO(aschuh): This depends on the shooter angle...
48 // Distance to where the shooter is up and ready to shoot.
49 static const double kLifterStopPosition;
50 static const double kLifterMovementVelocity;
51
52 // Distance to where the disc has been launched.
53 // TODO(aschuh): This depends on the shooter angle...
54 static const double kEjectorStopPosition;
55 static const double kEjectorMovementVelocity;
56
57 // Start and stop position of the bottom disc detect sensor in meters.
58 static const double kBottomDiscDetectStart;
59 static const double kBottomDiscDetectStop;
Austin Schuh6328daf2013-03-05 00:53:15 -080060 // Delay between the negedge of the disc detect and when it engages on the
61 // indexer.
62 static const double kBottomDiscIndexDelay;
Austin Schuhf8c52252013-03-03 02:25:49 -080063
64 static const double kTopDiscDetectStart;
65 static const double kTopDiscDetectStop;
Austin Schuhd78ab542013-03-01 22:22:19 -080066
Austin Schuh7c0e2aa2013-03-09 02:01:16 -080067 // Minimum distance between 2 frisbees as seen by the top disc detect sensor.
68 static const double kTopDiscDetectMinSeperation;
69
Austin Schuhd78ab542013-03-01 22:22:19 -080070 // Converts the angle of the indexer to the angle of the disc.
71 static double ConvertIndexToDiscAngle(const double angle);
72 // Converts the angle of the indexer to the position that the center of the
73 // disc has traveled.
74 static double ConvertIndexToDiscPosition(const double angle);
75
Austin Schuhf8c52252013-03-03 02:25:49 -080076 // Converts the angle of the transfer roller to the position that the center
77 // of the disc has traveled.
78 static double ConvertTransferToDiscPosition(const double angle);
79
80 // Converts the distance around the indexer to the position of
81 // the index roller.
82 static double ConvertDiscPositionToIndex(const double position);
Austin Schuhd78ab542013-03-01 22:22:19 -080083 // Converts the angle around the indexer to the position of the index roller.
84 static double ConvertDiscAngleToIndex(const double angle);
85 // Converts the angle around the indexer to the position of the disc in the
86 // indexer.
87 static double ConvertDiscAngleToDiscPosition(const double angle);
Austin Schuhf8c52252013-03-03 02:25:49 -080088 // Converts the distance around the indexer to the angle of the disc around
89 // the indexer.
90 static double ConvertDiscPositionToDiscAngle(const double position);
Austin Schuhd78ab542013-03-01 22:22:19 -080091
92 // Disc radius in meters.
Austin Schuhf8c52252013-03-03 02:25:49 -080093 static const double kDiscRadius;
Austin Schuhd78ab542013-03-01 22:22:19 -080094 // Roller radius in meters.
Austin Schuhf8c52252013-03-03 02:25:49 -080095 static const double kRollerRadius;
96 // Transfer roller radius in meters.
97 static const double kTransferRollerRadius;
Austin Schuhd78ab542013-03-01 22:22:19 -080098
Austin Schuhf8c52252013-03-03 02:25:49 -080099 // Time that it takes to grab the disc in cycles.
100 static const int kGrabbingDelay;
101 // Time that it takes to lift the loader in cycles.
102 static const int kLiftingDelay;
103 // Time that it takes to shoot the disc in cycles.
104 static const int kShootingDelay;
105 // Time that it takes to lower the loader in cycles.
106 static const int kLoweringDelay;
107
108 // Object representing a Frisbee tracked by the indexer.
Austin Schuhd78ab542013-03-01 22:22:19 -0800109 class Frisbee {
110 public:
111 Frisbee()
112 : bottom_posedge_time_(0, 0),
Austin Schuhf8c52252013-03-03 02:25:49 -0800113 bottom_negedge_time_(0, 0) {
Austin Schuhd78ab542013-03-01 22:22:19 -0800114 Reset();
115 }
116
Austin Schuhf8c52252013-03-03 02:25:49 -0800117 // Resets a Frisbee so it can be reused.
Austin Schuhd78ab542013-03-01 22:22:19 -0800118 void Reset() {
119 bottom_posedge_time_ = ::aos::time::Time(0, 0);
120 bottom_negedge_time_ = ::aos::time::Time(0, 0);
Austin Schuhd78ab542013-03-01 22:22:19 -0800121 has_been_indexed_ = false;
122 index_start_position_ = 0.0;
123 }
124
Austin Schuhf8c52252013-03-03 02:25:49 -0800125 // Returns true if the position is valid.
126 bool has_position() const {
127 return has_been_indexed_;
128 }
129
130 // Returns the most up to date and accurate position that we have for the
131 // disc. This is the indexer position that the disc grabbed at.
132 double position() const {
133 return index_start_position_;
134 }
135
Austin Schuh1b864a12013-03-07 00:46:50 -0800136 // Returns the absolute position of the disc in meters in the hopper given
137 // that the indexer is at the provided position.
138 double absolute_position(const double index_position) const {
139 return IndexMotor::ConvertIndexToDiscPosition(
140 index_position - index_start_position_) +
141 IndexMotor::kIndexStartPosition;
142 }
143
Austin Schuhbcdb90c2013-03-03 23:24:58 -0800144 // Shifts the disc down the indexer by the provided offset. This is to
145 // handle when the cRIO reboots.
146 void OffsetDisc(double offset) {
147 index_start_position_ += offset;
148 }
149
Austin Schuh825bde92013-03-06 00:16:46 -0800150 // Potentially offsets the position with the knowledge that no discs are
151 // currently blocking the top sensor. This knowledge can be used to move
152 // this disc if it is believed to be blocking the top sensor.
Austin Schuhdff24e22013-03-06 00:41:21 -0800153 // Returns the amount that the disc moved due to this observation.
154 double ObserveNoTopDiscSensor(double index_position, double index_velocity);
Austin Schuh825bde92013-03-06 00:16:46 -0800155
Austin Schuhf8c52252013-03-03 02:25:49 -0800156 // Posedge and negedge disc times.
Austin Schuhd78ab542013-03-01 22:22:19 -0800157 ::aos::time::Time bottom_posedge_time_;
158 ::aos::time::Time bottom_negedge_time_;
Austin Schuhf8c52252013-03-03 02:25:49 -0800159
160 // True if the disc has a valid index position.
Austin Schuhd78ab542013-03-01 22:22:19 -0800161 bool has_been_indexed_;
Austin Schuhf8c52252013-03-03 02:25:49 -0800162 // Location of the index when the disc first contacted it.
Austin Schuhd78ab542013-03-01 22:22:19 -0800163 double index_start_position_;
164 };
165
Austin Schuh7c0e2aa2013-03-09 02:01:16 -0800166 // Returns where the indexer thinks the frisbees are.
Austin Schuh1b864a12013-03-07 00:46:50 -0800167 const ::std::deque<Frisbee> &frisbees() const { return frisbees_; }
168
Austin Schuhd78ab542013-03-01 22:22:19 -0800169 protected:
170 virtual void RunIteration(
171 const control_loops::IndexLoop::Goal *goal,
172 const control_loops::IndexLoop::Position *position,
173 control_loops::IndexLoop::Output *output,
174 control_loops::IndexLoop::Status *status);
175
176 private:
Austin Schuhbcdb90c2013-03-03 23:24:58 -0800177 friend class testing::IndexTest_InvalidStateTest_Test;
Austin Schuh7c0e2aa2013-03-09 02:01:16 -0800178 friend class testing::IndexTest_LostDisc_Test;
Austin Schuh93485832013-03-04 00:01:34 -0800179
180 // This class implements the CapU function correctly given all the extra
181 // information that we know about from the wrist motor.
182 class IndexStateFeedbackLoop : public StateFeedbackLoop<2, 1, 1> {
183 public:
184 IndexStateFeedbackLoop(StateFeedbackLoop<2, 1, 1> loop)
185 : StateFeedbackLoop<2, 1, 1>(loop),
186 low_voltage_count_(0) {
187 }
188
189 // Voltage below which the indexer won't move with a disc in it.
190 static const double kMinMotionVoltage;
191 // Maximum number of cycles to apply a low voltage to the motor.
192 static const double kNoMotionCuttoffCount;
193
194 // Caps U, but disables the motor after a number of cycles of inactivity.
195 virtual void CapU();
196 private:
197 // Number of cycles that we have seen a small voltage being applied.
198 uint32_t low_voltage_count_;
199 };
200
Austin Schuhf8c52252013-03-03 02:25:49 -0800201 // Sets disc_position to the minimum or maximum disc position.
Austin Schuh1b864a12013-03-07 00:46:50 -0800202 // Sets found_disc to point to the frisbee that was found, and ignores it if
203 // found_disc is NULL.
Austin Schuhf8c52252013-03-03 02:25:49 -0800204 // Returns true if there were discs, and false if there weren't.
205 // On false, disc_position is left unmodified.
Austin Schuh1b864a12013-03-07 00:46:50 -0800206 bool MinDiscPosition(double *disc_position, Frisbee **found_disc);
207 bool MaxDiscPosition(double *disc_position, Frisbee **found_disc);
Austin Schuhd78ab542013-03-01 22:22:19 -0800208
209 // The state feedback control loop to talk to for the index.
Austin Schuh93485832013-03-04 00:01:34 -0800210 ::std::unique_ptr<IndexStateFeedbackLoop> wrist_loop_;
Austin Schuhd78ab542013-03-01 22:22:19 -0800211
Austin Schuhd78ab542013-03-01 22:22:19 -0800212 // Count of the number of discs that we have collected.
Austin Schuh7c0e2aa2013-03-09 02:01:16 -0800213 int32_t hopper_disc_count_;
214 int32_t total_disc_count_;
Austin Schuhd78ab542013-03-01 22:22:19 -0800215
Austin Schuhf8c52252013-03-03 02:25:49 -0800216 enum class Goal {
Austin Schuhd78ab542013-03-01 22:22:19 -0800217 // Hold position, in a low power state.
218 HOLD = 0,
219 // Get ready to load discs by shifting the discs down.
220 READY_LOWER = 1,
221 // Ready the discs, spin up the transfer roller, and accept discs.
222 INTAKE = 2,
223 // Get ready to shoot, and place a disc in the loader.
224 READY_SHOOTER = 3,
225 // Shoot at will.
226 SHOOT = 4
227 };
228
Austin Schuhf8c52252013-03-03 02:25:49 -0800229 // These two enums command and track the loader loading discs into the
230 // shooter.
231 enum class LoaderState {
232 // Open and down, ready to accept a disc.
233 READY,
234 // Closing the grabber.
235 GRABBING,
236 // Grabber closed.
237 GRABBED,
238 // Lifting the disc.
239 LIFTING,
240 // Disc lifted.
241 LIFTED,
242 // Ejecting the disc into the shooter.
243 SHOOTING,
244 // The disc has been shot.
245 SHOOT,
246 // Lowering the loader back down.
247 LOWERING,
248 // The indexer is lowered.
249 LOWERED
250 };
251
252 // TODO(aschuh): If we are grabbed and asked to be ready, now what?
253 // LOG ?
254 enum class LoaderGoal {
255 // Get the loader ready to accept another disc.
256 READY,
257 // Grab a disc now.
258 GRAB,
259 // Lift it up, shoot, and reset.
260 // Waits to shoot until the shooter is stable.
261 // Resets the goal to READY once one disc has been shot.
262 SHOOT_AND_RESET
263 };
264
Austin Schuhd78ab542013-03-01 22:22:19 -0800265 // The current goal
266 Goal safe_goal_;
267
Austin Schuhf8c52252013-03-03 02:25:49 -0800268 // Loader goal, state, and counter.
269 LoaderGoal loader_goal_;
270 LoaderState loader_state_;
271 int loader_countdown_;
272
Austin Schuhd78ab542013-03-01 22:22:19 -0800273 // Current state of the pistons.
274 bool loader_up_;
275 bool disc_clamped_;
276 bool disc_ejected_;
277
Austin Schuhd78ab542013-03-01 22:22:19 -0800278 // The frisbee that is flying through the transfer rollers.
279 Frisbee transfer_frisbee_;
280
Austin Schuhf8c52252013-03-03 02:25:49 -0800281 // Bottom disc detect from the last valid packet for detecting edges.
Austin Schuhd78ab542013-03-01 22:22:19 -0800282 bool last_bottom_disc_detect_;
Austin Schuh825bde92013-03-06 00:16:46 -0800283 bool last_top_disc_detect_;
Austin Schuh6328daf2013-03-05 00:53:15 -0800284 int32_t last_bottom_disc_posedge_count_;
285 int32_t last_bottom_disc_negedge_count_;
286 int32_t last_bottom_disc_negedge_wait_count_;
Austin Schuh825bde92013-03-06 00:16:46 -0800287 int32_t last_top_disc_posedge_count_;
Austin Schuh7c0e2aa2013-03-09 02:01:16 -0800288 int32_t last_top_disc_negedge_count_;
Austin Schuhd78ab542013-03-01 22:22:19 -0800289
290 // Frisbees are in order such that the newest frisbee is on the front.
291 ::std::deque<Frisbee> frisbees_;
Austin Schuhd78ab542013-03-01 22:22:19 -0800292
Austin Schuhbcdb90c2013-03-03 23:24:58 -0800293 // True if we haven't seen a position before.
294 bool no_prior_position_;
295 // Number of position messages that we have missed in a row.
296 uint32_t missing_position_count_;
297
Austin Schuh7c0e2aa2013-03-09 02:01:16 -0800298 // Upper position that is known to be open on the indexer because we saw it
299 // open.
300 double upper_open_index_position_;
301 // True if the upper position was set by a negedge and can be truly trusted.
302 bool upper_open_index_position_was_negedge_;
303 // Lower position that is known to be open on the indexer because we saw it
304 // open.
305 double lower_open_index_position_;
306 // True if the lower position was set by a negedge and can be truly trusted.
307 bool lower_open_index_position_was_negedge_;
308
Austin Schuhd78ab542013-03-01 22:22:19 -0800309 DISALLOW_COPY_AND_ASSIGN(IndexMotor);
310};
311
312} // namespace control_loops
313} // namespace frc971
314
315#endif // FRC971_CONTROL_LOOPS_WRIST_H_