blob: 25b7939e3141a469eee0299122e02cef003579cf [file] [log] [blame]
Comran Morshed25f81a02016-01-23 13:40:10 +00001#ifndef Y2016_CONTROL_LOOPS_SUPERSTRUCTURE_SUPERSTRUCTURE_H_
2#define Y2016_CONTROL_LOOPS_SUPERSTRUCTURE_SUPERSTRUCTURE_H_
3
4#include <memory>
5
6#include "aos/common/controls/control_loop.h"
Austin Schuh2fc10fa2016-02-08 00:44:34 -08007#include "aos/common/util/trapezoid_profile.h"
Austin Schuh10c2d112016-02-14 13:42:28 -08008#include "frc971/control_loops/state_feedback_loop.h"
Comran Morshed25f81a02016-01-23 13:40:10 +00009
Austin Schuh2fc10fa2016-02-08 00:44:34 -080010#include "frc971/zeroing/zeroing.h"
Comran Morshed25f81a02016-01-23 13:40:10 +000011#include "y2016/control_loops/superstructure/superstructure.q.h"
Austin Schuh10c2d112016-02-14 13:42:28 -080012#include "y2016/control_loops/superstructure/superstructure_controls.h"
Comran Morshed25f81a02016-01-23 13:40:10 +000013
14namespace y2016 {
15namespace control_loops {
Austin Schuh2fc10fa2016-02-08 00:44:34 -080016namespace superstructure {
17namespace testing {
Philipp Schrader0119eb12016-02-15 18:16:21 +000018class SuperstructureTest_RespectsRange_Test;
Austin Schuh2fc10fa2016-02-08 00:44:34 -080019class SuperstructureTest_DisabledGoalTest_Test;
Diana Vandenberge2843c62016-02-13 17:44:20 -080020class SuperstructureTest_ArmZeroingErrorTest_Test;
21class SuperstructureTest_IntakeZeroingErrorTest_Test;
Philipp Schrader0119eb12016-02-15 18:16:21 +000022class SuperstructureTest_UpperHardstopStartup_Test;
Austin Schuh2fc10fa2016-02-08 00:44:34 -080023} // namespace testing
24
Philipp Schrader0119eb12016-02-15 18:16:21 +000025// Helper class to prevent parts from crashing into each other. The parts in
26// question here are: the frame, the arm (plus shooter), and the intake.
27// Assumptions:
28// - The shoulder, the wrist, and intake are horizontal when at angle 0.
29// - The arm (i.e. shoulder) and shooter (i.e. wrist) are stored when they are
30// both at zero degrees.
31// - The intake at angle 0 is in a position to help get a ball in the robot.
32// - The intake at angle PI is in a "stowed" position. In other words, it is
33// folded over the arm and shooter when they are also in a stowed position.
34// - The shooter must remain horizontal when the arm is folding into the robot.
35// Otherwise, the shooter will collide with the frame.
36// - The arm has priority over the intake. If the arm wants to move in such a
37// way that interferes with the intake's movement then the intake must move
38// out of the way.
39class CollisionAvoidance {
40 public:
41 // Set up collision avoidance for an arm and intake.
42 CollisionAvoidance(Intake *intake, Arm *arm) : intake_(intake), arm_(arm) {}
43
44 // This function accepts goals for the intake and the arm and modifies them
45 // in such a way that collisions between all the different parts of the robot
46 // are avoided. The modified goals are then sent to the arm and intake as
47 // unprofiled goals.
48 void UpdateGoal(double shoulder_angle_goal, double wrist_angle_goal,
49 double intake_angle_goal);
50
Philipp Schrader07147532016-02-16 01:23:07 +000051 // Returns true if any of the limbs and frame are somehow currently
52 // interfering with one another. This is based purely on the angles that the
53 // limbs are reporting.
54 bool collided() const;
55
56 // Detects collision with the specified angles. This is especially useful for
57 // unit testing where we have proper ground truth for all the angles.
58 static bool collided_with_given_angles(double shoulder_angle,
59 double wrist_angle,
60 double intake_angle);
61
Philipp Schrader0119eb12016-02-15 18:16:21 +000062 // TODO(phil): Verify that these numbers actually make sense. Someone needs
63 // to verify these either on the CAD or the real robot.
64
65 // The shoulder angle (in radians) below which the shooter must be in a
66 // stowing position. In other words the wrist must be at angle zero if the
67 // shoulder is below this angle.
68 static constexpr double kMinShoulderAngleForHorizontalShooter = 0.1;
69
70 // The shoulder angle (in radians) below which the arm as a whole has the
71 // potential to interfere with the intake.
72 static constexpr double kMinShoulderAngleForIntakeInterference = M_PI / 3.0;
73
74 // The intake angle (in radians) above which the intake can interfere (i.e.
75 // collide) with the arm and/or shooter.
76 static constexpr double kMaxIntakeAngleBeforeArmInterference = M_PI / 2.0;
77
78 // The maximum absolute angle (in radians) that the wrist must be below in
79 // order for the shouler to be allowed to move below
80 // kMinShoulderAngleForHorizontalShooter. In other words, only allow the arm
81 // to move down into the belly pan if the shooter is horizontal, ready to
82 // also be placed into the belly pan.
83 static constexpr double kMaxWristAngleForSafeArmStowing = 0.01;
84
85 // The shoulder angle (in radians) below which the intake can safely move
86 // into the collision zone. This is necessary when the robot wants to fold up
87 // completely (i.e. stow the arm, shooter, and intake).
88 static constexpr double kMaxShoulderAngleUntilSafeIntakeStowing = 0.01;
89
90 private:
91 Intake *intake_;
92 Arm *arm_;
93};
94
Comran Morshed25f81a02016-01-23 13:40:10 +000095class Superstructure
96 : public ::aos::controls::ControlLoop<control_loops::SuperstructureQueue> {
97 public:
98 explicit Superstructure(
99 control_loops::SuperstructureQueue *my_superstructure =
100 &control_loops::superstructure_queue);
Adam Snaider06779722016-02-14 15:26:22 -0800101
102 // This is the angle above which we will do a HIGH_ARM_ZERO, and below which
103 // we will do a LOW_ARM_ZERO.
104 static constexpr double kShoulderMiddleAngle = M_PI / 4.0;
105 // This is the large scale movement tolerance.
106 static constexpr double kLooseTolerance = 0.05;
107
108 // This is the small scale movement tolerance.
109 static constexpr double kTightTolerance = 0.01;
110
111 // This is the angle such that the intake will clear the arm when the shooter
112 // is level.
113 static constexpr double kIntakeUpperClear = 1.1;
114 // This is the angle such that the intake will clear the arm when the shooter
115 // is at almost any position.
116 static constexpr double kIntakeLowerClear = 0.5;
117
118 // This is the angle that the shoulder will go to when doing the
119 // HIGH_ARM_ZERO.
120 static constexpr double kShoulderUpAngle = M_PI / 2.0;
121
122 // This is the angle that the shoulder will go down to when landing in the
123 // bellypan.
124 static constexpr double kShoulderLanded = -0.02;
125
126 // This is the angle below which we consider the wrist close enough to level
127 // that we should move it to level before doing anything.
128 static constexpr double kWristAlmostLevel = 0.10;
129
130 // This is the angle that the shoulder will go down to when raising up before
131 // leveling the shooter for calibration.
132 static constexpr double kShoulderWristClearAngle = 0.6;
133
Austin Schuh2fc10fa2016-02-08 00:44:34 -0800134 enum State {
Adam Snaider06779722016-02-14 15:26:22 -0800135 // Wait for all the filters to be ready before starting the initialization
136 // process.
Austin Schuh2fc10fa2016-02-08 00:44:34 -0800137 UNINITIALIZED = 0,
Adam Snaider06779722016-02-14 15:26:22 -0800138
139 // We now are ready to decide how to zero. Decide what to do once we are
140 // enabled.
141 DISABLED_INITIALIZED = 1,
142
143 // Lift the arm up out of the way.
144 HIGH_ARM_ZERO_LIFT_ARM = 2,
145
146 HIGH_ARM_ZERO_LEVEL_SHOOTER = 3,
147
148 HIGH_ARM_ZERO_MOVE_INTAKE_OUT = 4,
149
150 HIGH_ARM_ZERO_LOWER_ARM = 6,
151
152 LOW_ARM_ZERO_LOWER_INTAKE = 7,
153 LOW_ARM_ZERO_MAYBE_LEVEL_SHOOTER = 8,
154 LOW_ARM_ZERO_LIFT_SHOULDER = 9,
155 LOW_ARM_ZERO_LEVEL_SHOOTER = 11,
156 // Run, but limit power to zeroing voltages.
157 SLOW_RUNNING = 12,
158 // Run with full power.
159 RUNNING = 13,
Austin Schuh2fc10fa2016-02-08 00:44:34 -0800160 // Internal error caused the superstructure to abort.
Adam Snaider06779722016-02-14 15:26:22 -0800161 ESTOP = 14,
Austin Schuh2fc10fa2016-02-08 00:44:34 -0800162 };
163
164 State state() const { return state_; }
Comran Morshed25f81a02016-01-23 13:40:10 +0000165
Adam Snaider06779722016-02-14 15:26:22 -0800166 // Returns the value to move the joint to such that it will stay below
167 // reference_angle starting at current_angle, but move at least move_distance
168 static double MoveButKeepBelow(double reference_angle, double current_angle,
169 double move_distance);
170 // Returns the value to move the joint to such that it will stay above
171 // reference_angle starting at current_angle, but move at least move_distance
172 static double MoveButKeepAbove(double reference_angle, double current_angle,
173 double move_distance);
174
Philipp Schrader0119eb12016-02-15 18:16:21 +0000175 // Returns true if collision avoidance is turned on. False if not.
Philipp Schrader07147532016-02-16 01:23:07 +0000176 bool collision_avoidance_enabled() const { return collision_avoidance_enabled_; }
177
178 // Returns true if anything is currently considered "collided".
179 bool collided() const { return collision_avoidance_.collided(); }
Philipp Schrader0119eb12016-02-15 18:16:21 +0000180
Comran Morshed25f81a02016-01-23 13:40:10 +0000181 protected:
182 virtual void RunIteration(
Austin Schuh2fc10fa2016-02-08 00:44:34 -0800183 const control_loops::SuperstructureQueue::Goal *unsafe_goal,
Comran Morshed25f81a02016-01-23 13:40:10 +0000184 const control_loops::SuperstructureQueue::Position *position,
Austin Schuh2fc10fa2016-02-08 00:44:34 -0800185 control_loops::SuperstructureQueue::Output *output,
Comran Morshed25f81a02016-01-23 13:40:10 +0000186 control_loops::SuperstructureQueue::Status *status) override;
187
188 private:
Austin Schuh2fc10fa2016-02-08 00:44:34 -0800189 friend class testing::SuperstructureTest_DisabledGoalTest_Test;
Diana Vandenberge2843c62016-02-13 17:44:20 -0800190 friend class testing::SuperstructureTest_ArmZeroingErrorTest_Test;
191 friend class testing::SuperstructureTest_IntakeZeroingErrorTest_Test;
Philipp Schrader0119eb12016-02-15 18:16:21 +0000192 friend class testing::SuperstructureTest_RespectsRange_Test;
193 friend class testing::SuperstructureTest_UpperHardstopStartup_Test;
Austin Schuh2fc10fa2016-02-08 00:44:34 -0800194 Intake intake_;
195 Arm arm_;
196
Philipp Schrader0119eb12016-02-15 18:16:21 +0000197 CollisionAvoidance collision_avoidance_;
198
199 // NOTE: Only touch this if you absolutely know what you're doing!
200 bool collision_avoidance_enabled_ = true;
201
Austin Schuh2fc10fa2016-02-08 00:44:34 -0800202 State state_ = UNINITIALIZED;
203 State last_state_ = UNINITIALIZED;
204
Adam Snaider06779722016-02-14 15:26:22 -0800205 // Returns true if the profile has finished, and the joint is within the
206 // specified tolerance.
207 bool IsArmNear(double tolerance);
208 bool IsArmNear(double shoulder_tolerance, double wrist_tolerance);
209 bool IsIntakeNear(double tolerance);
Austin Schuh2fc10fa2016-02-08 00:44:34 -0800210
Comran Morshed25f81a02016-01-23 13:40:10 +0000211 DISALLOW_COPY_AND_ASSIGN(Superstructure);
212};
213
Austin Schuh2fc10fa2016-02-08 00:44:34 -0800214} // namespace superstructure
Comran Morshed25f81a02016-01-23 13:40:10 +0000215} // namespace control_loops
216} // namespace y2016
217
218#endif // Y2016_CONTROL_LOOPS_SUPERSTRUCTURE_SUPERSTRUCTURE_H_