Comran Morshed | 25f81a0 | 2016-01-23 13:40:10 +0000 | [diff] [blame] | 1 | #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 Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 7 | #include "aos/common/util/trapezoid_profile.h" |
Austin Schuh | 10c2d11 | 2016-02-14 13:42:28 -0800 | [diff] [blame] | 8 | #include "frc971/control_loops/state_feedback_loop.h" |
Comran Morshed | 25f81a0 | 2016-01-23 13:40:10 +0000 | [diff] [blame] | 9 | |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 10 | #include "frc971/zeroing/zeroing.h" |
Comran Morshed | 25f81a0 | 2016-01-23 13:40:10 +0000 | [diff] [blame] | 11 | #include "y2016/control_loops/superstructure/superstructure.q.h" |
Austin Schuh | 10c2d11 | 2016-02-14 13:42:28 -0800 | [diff] [blame] | 12 | #include "y2016/control_loops/superstructure/superstructure_controls.h" |
Comran Morshed | 25f81a0 | 2016-01-23 13:40:10 +0000 | [diff] [blame] | 13 | |
| 14 | namespace y2016 { |
| 15 | namespace control_loops { |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 16 | namespace superstructure { |
| 17 | namespace testing { |
Philipp Schrader | 0119eb1 | 2016-02-15 18:16:21 +0000 | [diff] [blame] | 18 | class SuperstructureTest_RespectsRange_Test; |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 19 | class SuperstructureTest_DisabledGoalTest_Test; |
Diana Vandenberg | e2843c6 | 2016-02-13 17:44:20 -0800 | [diff] [blame] | 20 | class SuperstructureTest_ArmZeroingErrorTest_Test; |
| 21 | class SuperstructureTest_IntakeZeroingErrorTest_Test; |
Philipp Schrader | 0119eb1 | 2016-02-15 18:16:21 +0000 | [diff] [blame] | 22 | class SuperstructureTest_UpperHardstopStartup_Test; |
Campbell Crowley | 152c7cf | 2016-02-14 21:20:50 -0800 | [diff] [blame^] | 23 | class SuperstructureTest_DisabledWhileZeroingHigh_Test; |
| 24 | class SuperstructureTest_DisabledWhileZeroingLow_Test; |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 25 | } // namespace testing |
| 26 | |
Philipp Schrader | 0119eb1 | 2016-02-15 18:16:21 +0000 | [diff] [blame] | 27 | // Helper class to prevent parts from crashing into each other. The parts in |
| 28 | // question here are: the frame, the arm (plus shooter), and the intake. |
| 29 | // Assumptions: |
| 30 | // - The shoulder, the wrist, and intake are horizontal when at angle 0. |
| 31 | // - The arm (i.e. shoulder) and shooter (i.e. wrist) are stored when they are |
| 32 | // both at zero degrees. |
| 33 | // - The intake at angle 0 is in a position to help get a ball in the robot. |
| 34 | // - The intake at angle PI is in a "stowed" position. In other words, it is |
| 35 | // folded over the arm and shooter when they are also in a stowed position. |
| 36 | // - The shooter must remain horizontal when the arm is folding into the robot. |
| 37 | // Otherwise, the shooter will collide with the frame. |
| 38 | // - The arm has priority over the intake. If the arm wants to move in such a |
| 39 | // way that interferes with the intake's movement then the intake must move |
| 40 | // out of the way. |
| 41 | class CollisionAvoidance { |
| 42 | public: |
| 43 | // Set up collision avoidance for an arm and intake. |
| 44 | CollisionAvoidance(Intake *intake, Arm *arm) : intake_(intake), arm_(arm) {} |
| 45 | |
| 46 | // This function accepts goals for the intake and the arm and modifies them |
| 47 | // in such a way that collisions between all the different parts of the robot |
| 48 | // are avoided. The modified goals are then sent to the arm and intake as |
| 49 | // unprofiled goals. |
| 50 | void UpdateGoal(double shoulder_angle_goal, double wrist_angle_goal, |
| 51 | double intake_angle_goal); |
| 52 | |
Philipp Schrader | 0714753 | 2016-02-16 01:23:07 +0000 | [diff] [blame] | 53 | // Returns true if any of the limbs and frame are somehow currently |
| 54 | // interfering with one another. This is based purely on the angles that the |
| 55 | // limbs are reporting. |
| 56 | bool collided() const; |
| 57 | |
| 58 | // Detects collision with the specified angles. This is especially useful for |
| 59 | // unit testing where we have proper ground truth for all the angles. |
| 60 | static bool collided_with_given_angles(double shoulder_angle, |
| 61 | double wrist_angle, |
| 62 | double intake_angle); |
| 63 | |
Philipp Schrader | 0119eb1 | 2016-02-15 18:16:21 +0000 | [diff] [blame] | 64 | // TODO(phil): Verify that these numbers actually make sense. Someone needs |
| 65 | // to verify these either on the CAD or the real robot. |
| 66 | |
| 67 | // The shoulder angle (in radians) below which the shooter must be in a |
| 68 | // stowing position. In other words the wrist must be at angle zero if the |
| 69 | // shoulder is below this angle. |
Austin Schuh | b1d682b | 2016-02-16 13:07:44 -0800 | [diff] [blame] | 70 | static constexpr double kMinShoulderAngleForHorizontalShooter = 0.6; |
Philipp Schrader | 0119eb1 | 2016-02-15 18:16:21 +0000 | [diff] [blame] | 71 | |
| 72 | // The shoulder angle (in radians) below which the arm as a whole has the |
| 73 | // potential to interfere with the intake. |
| 74 | static constexpr double kMinShoulderAngleForIntakeInterference = M_PI / 3.0; |
| 75 | |
| 76 | // The intake angle (in radians) above which the intake can interfere (i.e. |
| 77 | // collide) with the arm and/or shooter. |
| 78 | static constexpr double kMaxIntakeAngleBeforeArmInterference = M_PI / 2.0; |
| 79 | |
| 80 | // The maximum absolute angle (in radians) that the wrist must be below in |
| 81 | // order for the shouler to be allowed to move below |
| 82 | // kMinShoulderAngleForHorizontalShooter. In other words, only allow the arm |
| 83 | // to move down into the belly pan if the shooter is horizontal, ready to |
| 84 | // also be placed into the belly pan. |
| 85 | static constexpr double kMaxWristAngleForSafeArmStowing = 0.01; |
| 86 | |
| 87 | // The shoulder angle (in radians) below which the intake can safely move |
| 88 | // into the collision zone. This is necessary when the robot wants to fold up |
| 89 | // completely (i.e. stow the arm, shooter, and intake). |
| 90 | static constexpr double kMaxShoulderAngleUntilSafeIntakeStowing = 0.01; |
| 91 | |
| 92 | private: |
| 93 | Intake *intake_; |
| 94 | Arm *arm_; |
| 95 | }; |
| 96 | |
Comran Morshed | 25f81a0 | 2016-01-23 13:40:10 +0000 | [diff] [blame] | 97 | class Superstructure |
| 98 | : public ::aos::controls::ControlLoop<control_loops::SuperstructureQueue> { |
| 99 | public: |
| 100 | explicit Superstructure( |
| 101 | control_loops::SuperstructureQueue *my_superstructure = |
| 102 | &control_loops::superstructure_queue); |
Adam Snaider | 0677972 | 2016-02-14 15:26:22 -0800 | [diff] [blame] | 103 | |
| 104 | // This is the angle above which we will do a HIGH_ARM_ZERO, and below which |
| 105 | // we will do a LOW_ARM_ZERO. |
| 106 | static constexpr double kShoulderMiddleAngle = M_PI / 4.0; |
| 107 | // This is the large scale movement tolerance. |
| 108 | static constexpr double kLooseTolerance = 0.05; |
| 109 | |
| 110 | // This is the small scale movement tolerance. |
| 111 | static constexpr double kTightTolerance = 0.01; |
| 112 | |
| 113 | // This is the angle such that the intake will clear the arm when the shooter |
| 114 | // is level. |
| 115 | static constexpr double kIntakeUpperClear = 1.1; |
| 116 | // This is the angle such that the intake will clear the arm when the shooter |
| 117 | // is at almost any position. |
| 118 | static constexpr double kIntakeLowerClear = 0.5; |
| 119 | |
| 120 | // This is the angle that the shoulder will go to when doing the |
| 121 | // HIGH_ARM_ZERO. |
| 122 | static constexpr double kShoulderUpAngle = M_PI / 2.0; |
| 123 | |
| 124 | // This is the angle that the shoulder will go down to when landing in the |
| 125 | // bellypan. |
| 126 | static constexpr double kShoulderLanded = -0.02; |
| 127 | |
Austin Schuh | b1d682b | 2016-02-16 13:07:44 -0800 | [diff] [blame] | 128 | // This is the angle below which the shoulder will slowly profile down and |
| 129 | // land. |
| 130 | static constexpr double kShoulderTransitionToLanded = 0.10; |
| 131 | |
Adam Snaider | 0677972 | 2016-02-14 15:26:22 -0800 | [diff] [blame] | 132 | // This is the angle below which we consider the wrist close enough to level |
| 133 | // that we should move it to level before doing anything. |
| 134 | static constexpr double kWristAlmostLevel = 0.10; |
| 135 | |
| 136 | // This is the angle that the shoulder will go down to when raising up before |
| 137 | // leveling the shooter for calibration. |
Austin Schuh | b1d682b | 2016-02-16 13:07:44 -0800 | [diff] [blame] | 138 | static constexpr double kShoulderWristClearAngle = |
| 139 | CollisionAvoidance::kMinShoulderAngleForHorizontalShooter; |
Adam Snaider | 0677972 | 2016-02-14 15:26:22 -0800 | [diff] [blame] | 140 | |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 141 | enum State { |
Adam Snaider | 0677972 | 2016-02-14 15:26:22 -0800 | [diff] [blame] | 142 | // Wait for all the filters to be ready before starting the initialization |
| 143 | // process. |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 144 | UNINITIALIZED = 0, |
Adam Snaider | 0677972 | 2016-02-14 15:26:22 -0800 | [diff] [blame] | 145 | |
| 146 | // We now are ready to decide how to zero. Decide what to do once we are |
| 147 | // enabled. |
| 148 | DISABLED_INITIALIZED = 1, |
| 149 | |
| 150 | // Lift the arm up out of the way. |
| 151 | HIGH_ARM_ZERO_LIFT_ARM = 2, |
| 152 | |
| 153 | HIGH_ARM_ZERO_LEVEL_SHOOTER = 3, |
| 154 | |
| 155 | HIGH_ARM_ZERO_MOVE_INTAKE_OUT = 4, |
| 156 | |
| 157 | HIGH_ARM_ZERO_LOWER_ARM = 6, |
| 158 | |
| 159 | LOW_ARM_ZERO_LOWER_INTAKE = 7, |
| 160 | LOW_ARM_ZERO_MAYBE_LEVEL_SHOOTER = 8, |
| 161 | LOW_ARM_ZERO_LIFT_SHOULDER = 9, |
| 162 | LOW_ARM_ZERO_LEVEL_SHOOTER = 11, |
| 163 | // Run, but limit power to zeroing voltages. |
| 164 | SLOW_RUNNING = 12, |
| 165 | // Run with full power. |
| 166 | RUNNING = 13, |
Austin Schuh | b1d682b | 2016-02-16 13:07:44 -0800 | [diff] [blame] | 167 | // Run, but limit power to zeroing voltages while landing. |
| 168 | LANDING_SLOW_RUNNING = 14, |
| 169 | // Run with full power while landing. |
| 170 | LANDING_RUNNING = 15, |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 171 | // Internal error caused the superstructure to abort. |
Austin Schuh | b1d682b | 2016-02-16 13:07:44 -0800 | [diff] [blame] | 172 | ESTOP = 16, |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 173 | }; |
| 174 | |
Austin Schuh | 9f4e8a7 | 2016-02-16 15:28:47 -0800 | [diff] [blame] | 175 | bool IsRunning() const { |
| 176 | return (state_ == SLOW_RUNNING || state_ == RUNNING || |
| 177 | state_ == LANDING_SLOW_RUNNING || state_ == LANDING_RUNNING); |
| 178 | } |
| 179 | |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 180 | State state() const { return state_; } |
Comran Morshed | 25f81a0 | 2016-01-23 13:40:10 +0000 | [diff] [blame] | 181 | |
Adam Snaider | 0677972 | 2016-02-14 15:26:22 -0800 | [diff] [blame] | 182 | // Returns the value to move the joint to such that it will stay below |
| 183 | // reference_angle starting at current_angle, but move at least move_distance |
| 184 | static double MoveButKeepBelow(double reference_angle, double current_angle, |
| 185 | double move_distance); |
| 186 | // Returns the value to move the joint to such that it will stay above |
| 187 | // reference_angle starting at current_angle, but move at least move_distance |
| 188 | static double MoveButKeepAbove(double reference_angle, double current_angle, |
| 189 | double move_distance); |
| 190 | |
Philipp Schrader | 0714753 | 2016-02-16 01:23:07 +0000 | [diff] [blame] | 191 | // Returns true if anything is currently considered "collided". |
| 192 | bool collided() const { return collision_avoidance_.collided(); } |
Philipp Schrader | 0119eb1 | 2016-02-15 18:16:21 +0000 | [diff] [blame] | 193 | |
Comran Morshed | 25f81a0 | 2016-01-23 13:40:10 +0000 | [diff] [blame] | 194 | protected: |
| 195 | virtual void RunIteration( |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 196 | const control_loops::SuperstructureQueue::Goal *unsafe_goal, |
Comran Morshed | 25f81a0 | 2016-01-23 13:40:10 +0000 | [diff] [blame] | 197 | const control_loops::SuperstructureQueue::Position *position, |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 198 | control_loops::SuperstructureQueue::Output *output, |
Comran Morshed | 25f81a0 | 2016-01-23 13:40:10 +0000 | [diff] [blame] | 199 | control_loops::SuperstructureQueue::Status *status) override; |
| 200 | |
| 201 | private: |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 202 | friend class testing::SuperstructureTest_DisabledGoalTest_Test; |
Diana Vandenberg | e2843c6 | 2016-02-13 17:44:20 -0800 | [diff] [blame] | 203 | friend class testing::SuperstructureTest_ArmZeroingErrorTest_Test; |
| 204 | friend class testing::SuperstructureTest_IntakeZeroingErrorTest_Test; |
Philipp Schrader | 0119eb1 | 2016-02-15 18:16:21 +0000 | [diff] [blame] | 205 | friend class testing::SuperstructureTest_RespectsRange_Test; |
| 206 | friend class testing::SuperstructureTest_UpperHardstopStartup_Test; |
Campbell Crowley | 152c7cf | 2016-02-14 21:20:50 -0800 | [diff] [blame^] | 207 | friend class testing::SuperstructureTest_DisabledWhileZeroingHigh_Test; |
| 208 | friend class testing::SuperstructureTest_DisabledWhileZeroingLow_Test; |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 209 | Intake intake_; |
| 210 | Arm arm_; |
| 211 | |
Philipp Schrader | 0119eb1 | 2016-02-15 18:16:21 +0000 | [diff] [blame] | 212 | CollisionAvoidance collision_avoidance_; |
| 213 | |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 214 | State state_ = UNINITIALIZED; |
| 215 | State last_state_ = UNINITIALIZED; |
| 216 | |
Adam Snaider | 0677972 | 2016-02-14 15:26:22 -0800 | [diff] [blame] | 217 | // Returns true if the profile has finished, and the joint is within the |
| 218 | // specified tolerance. |
| 219 | bool IsArmNear(double tolerance); |
| 220 | bool IsArmNear(double shoulder_tolerance, double wrist_tolerance); |
| 221 | bool IsIntakeNear(double tolerance); |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 222 | |
Comran Morshed | 25f81a0 | 2016-01-23 13:40:10 +0000 | [diff] [blame] | 223 | DISALLOW_COPY_AND_ASSIGN(Superstructure); |
| 224 | }; |
| 225 | |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 226 | } // namespace superstructure |
Comran Morshed | 25f81a0 | 2016-01-23 13:40:10 +0000 | [diff] [blame] | 227 | } // namespace control_loops |
| 228 | } // namespace y2016 |
| 229 | |
| 230 | #endif // Y2016_CONTROL_LOOPS_SUPERSTRUCTURE_SUPERSTRUCTURE_H_ |