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 | // The shoulder angle (in radians) below which the shooter must be in a |
| 65 | // stowing position. In other words the wrist must be at angle zero if the |
| 66 | // shoulder is below this angle. |
Austin Schuh | b1d682b | 2016-02-16 13:07:44 -0800 | [diff] [blame] | 67 | static constexpr double kMinShoulderAngleForHorizontalShooter = 0.6; |
Philipp Schrader | 0119eb1 | 2016-02-15 18:16:21 +0000 | [diff] [blame] | 68 | |
Campbell Crowley | 1836a43 | 2016-03-05 15:16:51 -0800 | [diff] [blame] | 69 | // The shoulder angle (in radians) below which the arm and the shooter have |
| 70 | // the potential to interfere with the intake. |
Austin Schuh | 6ca0f79 | 2016-03-12 14:06:14 -0800 | [diff] [blame] | 71 | static constexpr double kMinShoulderAngleForIntakeUpInterference = 1.3; |
| 72 | |
| 73 | // The shoulder angle (in radians) below which the shooter should be closer to |
| 74 | // level to fix the inverted case. |
| 75 | // TODO(austin): Verify |
| 76 | static constexpr double kMinShoulderAngleForIntakeInterference = 1.1; |
Philipp Schrader | 0119eb1 | 2016-02-15 18:16:21 +0000 | [diff] [blame] | 77 | |
| 78 | // The intake angle (in radians) above which the intake can interfere (i.e. |
| 79 | // collide) with the arm and/or shooter. |
Austin Schuh | 2c71786 | 2016-03-13 15:32:53 -0700 | [diff] [blame] | 80 | static constexpr double kMaxIntakeAngleBeforeArmInterference = 1.05; |
Philipp Schrader | 0119eb1 | 2016-02-15 18:16:21 +0000 | [diff] [blame] | 81 | |
| 82 | // The maximum absolute angle (in radians) that the wrist must be below in |
| 83 | // order for the shouler to be allowed to move below |
| 84 | // kMinShoulderAngleForHorizontalShooter. In other words, only allow the arm |
| 85 | // to move down into the belly pan if the shooter is horizontal, ready to |
| 86 | // also be placed into the belly pan. |
Austin Schuh | 2f5bfc8 | 2016-02-27 14:47:37 -0800 | [diff] [blame] | 87 | static constexpr double kMaxWristAngleForSafeArmStowing = 0.05; |
Philipp Schrader | 0119eb1 | 2016-02-15 18:16:21 +0000 | [diff] [blame] | 88 | |
Austin Schuh | 2c71786 | 2016-03-13 15:32:53 -0700 | [diff] [blame] | 89 | // The maximum angle in radians that the wrist can be from horizontal |
Austin Schuh | 6ca0f79 | 2016-03-12 14:06:14 -0800 | [diff] [blame] | 90 | // while it is near the intake. |
Austin Schuh | 6802a9d | 2016-03-12 21:34:53 -0800 | [diff] [blame] | 91 | static constexpr double kMaxWristAngleForMovingByIntake = 0.50; |
Austin Schuh | 2c71786 | 2016-03-13 15:32:53 -0700 | [diff] [blame] | 92 | // The minimum angle in radians that the wrist can be from horizontal |
| 93 | // while it is near the intake. |
Austin Schuh | 214164b | 2016-03-20 16:50:09 -0700 | [diff] [blame] | 94 | static constexpr double kMinWristAngleForMovingByIntake = -1.50; |
Austin Schuh | 6ca0f79 | 2016-03-12 14:06:14 -0800 | [diff] [blame] | 95 | |
Philipp Schrader | 0119eb1 | 2016-02-15 18:16:21 +0000 | [diff] [blame] | 96 | // The shoulder angle (in radians) below which the intake can safely move |
| 97 | // into the collision zone. This is necessary when the robot wants to fold up |
| 98 | // completely (i.e. stow the arm, shooter, and intake). |
Austin Schuh | 6ca0f79 | 2016-03-12 14:06:14 -0800 | [diff] [blame] | 99 | static constexpr double kMaxShoulderAngleUntilSafeIntakeStowing = 0.19; |
Philipp Schrader | 0119eb1 | 2016-02-15 18:16:21 +0000 | [diff] [blame] | 100 | |
| 101 | private: |
| 102 | Intake *intake_; |
| 103 | Arm *arm_; |
| 104 | }; |
| 105 | |
Comran Morshed | 25f81a0 | 2016-01-23 13:40:10 +0000 | [diff] [blame] | 106 | class Superstructure |
| 107 | : public ::aos::controls::ControlLoop<control_loops::SuperstructureQueue> { |
| 108 | public: |
| 109 | explicit Superstructure( |
| 110 | control_loops::SuperstructureQueue *my_superstructure = |
| 111 | &control_loops::superstructure_queue); |
Adam Snaider | 0677972 | 2016-02-14 15:26:22 -0800 | [diff] [blame] | 112 | |
Austin Schuh | f132dc5 | 2016-03-13 19:43:15 -0700 | [diff] [blame] | 113 | static constexpr double kZeroingVoltage = 6.0; |
Austin Schuh | fef64ac | 2016-04-24 19:08:01 -0700 | [diff] [blame] | 114 | static constexpr double kShooterHangingVoltage = 6.0; |
Austin Schuh | 0c001a8 | 2016-05-01 12:30:09 -0700 | [diff] [blame^] | 115 | static constexpr double kShooterHangingLowVoltage = 2.0; |
Philipp Schrader | 3da48ac | 2016-03-06 23:03:44 +0000 | [diff] [blame] | 116 | static constexpr double kOperatingVoltage = 12.0; |
Austin Schuh | 2c71786 | 2016-03-13 15:32:53 -0700 | [diff] [blame] | 117 | static constexpr double kLandingShoulderDownVoltage = -1.5; |
Philipp Schrader | 3da48ac | 2016-03-06 23:03:44 +0000 | [diff] [blame] | 118 | |
Adam Snaider | 0677972 | 2016-02-14 15:26:22 -0800 | [diff] [blame] | 119 | // This is the angle above which we will do a HIGH_ARM_ZERO, and below which |
| 120 | // we will do a LOW_ARM_ZERO. |
| 121 | static constexpr double kShoulderMiddleAngle = M_PI / 4.0; |
| 122 | // This is the large scale movement tolerance. |
| 123 | static constexpr double kLooseTolerance = 0.05; |
| 124 | |
| 125 | // This is the small scale movement tolerance. |
Austin Schuh | f132dc5 | 2016-03-13 19:43:15 -0700 | [diff] [blame] | 126 | static constexpr double kTightTolerance = 0.03; |
Adam Snaider | 0677972 | 2016-02-14 15:26:22 -0800 | [diff] [blame] | 127 | |
| 128 | // This is the angle such that the intake will clear the arm when the shooter |
| 129 | // is level. |
Austin Schuh | 6ca0f79 | 2016-03-12 14:06:14 -0800 | [diff] [blame] | 130 | static constexpr double kIntakeUpperClear = |
| 131 | CollisionAvoidance::kMaxIntakeAngleBeforeArmInterference; |
Adam Snaider | 0677972 | 2016-02-14 15:26:22 -0800 | [diff] [blame] | 132 | // This is the angle such that the intake will clear the arm when the shooter |
| 133 | // is at almost any position. |
Austin Schuh | 2f5bfc8 | 2016-02-27 14:47:37 -0800 | [diff] [blame] | 134 | static constexpr double kIntakeLowerClear = 0.4; |
Adam Snaider | 0677972 | 2016-02-14 15:26:22 -0800 | [diff] [blame] | 135 | |
| 136 | // This is the angle that the shoulder will go to when doing the |
| 137 | // HIGH_ARM_ZERO. |
| 138 | static constexpr double kShoulderUpAngle = M_PI / 2.0; |
| 139 | |
| 140 | // This is the angle that the shoulder will go down to when landing in the |
| 141 | // bellypan. |
| 142 | static constexpr double kShoulderLanded = -0.02; |
| 143 | |
Austin Schuh | b1d682b | 2016-02-16 13:07:44 -0800 | [diff] [blame] | 144 | // This is the angle below which the shoulder will slowly profile down and |
| 145 | // land. |
| 146 | static constexpr double kShoulderTransitionToLanded = 0.10; |
| 147 | |
Adam Snaider | 0677972 | 2016-02-14 15:26:22 -0800 | [diff] [blame] | 148 | // This is the angle below which we consider the wrist close enough to level |
| 149 | // that we should move it to level before doing anything. |
| 150 | static constexpr double kWristAlmostLevel = 0.10; |
| 151 | |
| 152 | // This is the angle that the shoulder will go down to when raising up before |
| 153 | // leveling the shooter for calibration. |
Austin Schuh | b1d682b | 2016-02-16 13:07:44 -0800 | [diff] [blame] | 154 | static constexpr double kShoulderWristClearAngle = |
| 155 | CollisionAvoidance::kMinShoulderAngleForHorizontalShooter; |
Adam Snaider | 0677972 | 2016-02-14 15:26:22 -0800 | [diff] [blame] | 156 | |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 157 | enum State { |
Adam Snaider | 0677972 | 2016-02-14 15:26:22 -0800 | [diff] [blame] | 158 | // Wait for all the filters to be ready before starting the initialization |
| 159 | // process. |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 160 | UNINITIALIZED = 0, |
Adam Snaider | 0677972 | 2016-02-14 15:26:22 -0800 | [diff] [blame] | 161 | |
| 162 | // We now are ready to decide how to zero. Decide what to do once we are |
| 163 | // enabled. |
| 164 | DISABLED_INITIALIZED = 1, |
| 165 | |
| 166 | // Lift the arm up out of the way. |
| 167 | HIGH_ARM_ZERO_LIFT_ARM = 2, |
| 168 | |
| 169 | HIGH_ARM_ZERO_LEVEL_SHOOTER = 3, |
| 170 | |
| 171 | HIGH_ARM_ZERO_MOVE_INTAKE_OUT = 4, |
| 172 | |
| 173 | HIGH_ARM_ZERO_LOWER_ARM = 6, |
| 174 | |
| 175 | LOW_ARM_ZERO_LOWER_INTAKE = 7, |
| 176 | LOW_ARM_ZERO_MAYBE_LEVEL_SHOOTER = 8, |
| 177 | LOW_ARM_ZERO_LIFT_SHOULDER = 9, |
| 178 | LOW_ARM_ZERO_LEVEL_SHOOTER = 11, |
| 179 | // Run, but limit power to zeroing voltages. |
| 180 | SLOW_RUNNING = 12, |
| 181 | // Run with full power. |
| 182 | RUNNING = 13, |
Austin Schuh | b1d682b | 2016-02-16 13:07:44 -0800 | [diff] [blame] | 183 | // Run, but limit power to zeroing voltages while landing. |
| 184 | LANDING_SLOW_RUNNING = 14, |
| 185 | // Run with full power while landing. |
| 186 | LANDING_RUNNING = 15, |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 187 | // Internal error caused the superstructure to abort. |
Austin Schuh | b1d682b | 2016-02-16 13:07:44 -0800 | [diff] [blame] | 188 | ESTOP = 16, |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 189 | }; |
| 190 | |
Austin Schuh | 9f4e8a7 | 2016-02-16 15:28:47 -0800 | [diff] [blame] | 191 | bool IsRunning() const { |
| 192 | return (state_ == SLOW_RUNNING || state_ == RUNNING || |
| 193 | state_ == LANDING_SLOW_RUNNING || state_ == LANDING_RUNNING); |
| 194 | } |
| 195 | |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 196 | State state() const { return state_; } |
Comran Morshed | 25f81a0 | 2016-01-23 13:40:10 +0000 | [diff] [blame] | 197 | |
Adam Snaider | 0677972 | 2016-02-14 15:26:22 -0800 | [diff] [blame] | 198 | // Returns the value to move the joint to such that it will stay below |
| 199 | // reference_angle starting at current_angle, but move at least move_distance |
| 200 | static double MoveButKeepBelow(double reference_angle, double current_angle, |
| 201 | double move_distance); |
| 202 | // Returns the value to move the joint to such that it will stay above |
| 203 | // reference_angle starting at current_angle, but move at least move_distance |
| 204 | static double MoveButKeepAbove(double reference_angle, double current_angle, |
| 205 | double move_distance); |
| 206 | |
Philipp Schrader | 0714753 | 2016-02-16 01:23:07 +0000 | [diff] [blame] | 207 | // Returns true if anything is currently considered "collided". |
| 208 | bool collided() const { return collision_avoidance_.collided(); } |
Philipp Schrader | 0119eb1 | 2016-02-15 18:16:21 +0000 | [diff] [blame] | 209 | |
Comran Morshed | 25f81a0 | 2016-01-23 13:40:10 +0000 | [diff] [blame] | 210 | protected: |
| 211 | virtual void RunIteration( |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 212 | const control_loops::SuperstructureQueue::Goal *unsafe_goal, |
Comran Morshed | 25f81a0 | 2016-01-23 13:40:10 +0000 | [diff] [blame] | 213 | const control_loops::SuperstructureQueue::Position *position, |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 214 | control_loops::SuperstructureQueue::Output *output, |
Comran Morshed | 25f81a0 | 2016-01-23 13:40:10 +0000 | [diff] [blame] | 215 | control_loops::SuperstructureQueue::Status *status) override; |
| 216 | |
| 217 | private: |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 218 | friend class testing::SuperstructureTest_DisabledGoalTest_Test; |
Diana Vandenberg | e2843c6 | 2016-02-13 17:44:20 -0800 | [diff] [blame] | 219 | friend class testing::SuperstructureTest_ArmZeroingErrorTest_Test; |
| 220 | friend class testing::SuperstructureTest_IntakeZeroingErrorTest_Test; |
Philipp Schrader | 0119eb1 | 2016-02-15 18:16:21 +0000 | [diff] [blame] | 221 | friend class testing::SuperstructureTest_RespectsRange_Test; |
| 222 | friend class testing::SuperstructureTest_UpperHardstopStartup_Test; |
Campbell Crowley | 152c7cf | 2016-02-14 21:20:50 -0800 | [diff] [blame] | 223 | friend class testing::SuperstructureTest_DisabledWhileZeroingHigh_Test; |
| 224 | friend class testing::SuperstructureTest_DisabledWhileZeroingLow_Test; |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 225 | Intake intake_; |
| 226 | Arm arm_; |
| 227 | |
Philipp Schrader | 0119eb1 | 2016-02-15 18:16:21 +0000 | [diff] [blame] | 228 | CollisionAvoidance collision_avoidance_; |
| 229 | |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 230 | State state_ = UNINITIALIZED; |
| 231 | State last_state_ = UNINITIALIZED; |
| 232 | |
Austin Schuh | be04115 | 2016-02-28 22:01:52 -0800 | [diff] [blame] | 233 | float last_shoulder_angle_ = 0.0; |
| 234 | float last_wrist_angle_ = 0.0; |
| 235 | float last_intake_angle_ = 0.0; |
| 236 | |
Comran Morshed | 71466fe | 2016-04-21 20:21:14 -0700 | [diff] [blame] | 237 | double kill_shoulder_accumulator_ = 0.0; |
| 238 | bool kill_shoulder_ = false; |
| 239 | |
Adam Snaider | 0677972 | 2016-02-14 15:26:22 -0800 | [diff] [blame] | 240 | // Returns true if the profile has finished, and the joint is within the |
| 241 | // specified tolerance. |
| 242 | bool IsArmNear(double tolerance); |
| 243 | bool IsArmNear(double shoulder_tolerance, double wrist_tolerance); |
| 244 | bool IsIntakeNear(double tolerance); |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 245 | |
Comran Morshed | 25f81a0 | 2016-01-23 13:40:10 +0000 | [diff] [blame] | 246 | DISALLOW_COPY_AND_ASSIGN(Superstructure); |
| 247 | }; |
| 248 | |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 249 | } // namespace superstructure |
Comran Morshed | 25f81a0 | 2016-01-23 13:40:10 +0000 | [diff] [blame] | 250 | } // namespace control_loops |
| 251 | } // namespace y2016 |
| 252 | |
| 253 | #endif // Y2016_CONTROL_LOOPS_SUPERSTRUCTURE_SUPERSTRUCTURE_H_ |