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 | |
James Kuszmaul | 6175066 | 2021-06-21 21:32:33 -0700 | [diff] [blame^] | 6 | #include "frc971/control_loops/control_loop.h" |
John Park | 33858a3 | 2018-09-28 23:05:48 -0700 | [diff] [blame] | 7 | #include "aos/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" |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 9 | #include "frc971/zeroing/zeroing.h" |
Austin Schuh | 10c2d11 | 2016-02-14 13:42:28 -0800 | [diff] [blame] | 10 | #include "y2016/control_loops/superstructure/superstructure_controls.h" |
Alex Perry | cb7da4b | 2019-08-28 19:35:56 -0700 | [diff] [blame] | 11 | #include "y2016/control_loops/superstructure/superstructure_goal_generated.h" |
| 12 | #include "y2016/control_loops/superstructure/superstructure_output_generated.h" |
| 13 | #include "y2016/control_loops/superstructure/superstructure_position_generated.h" |
| 14 | #include "y2016/control_loops/superstructure/superstructure_status_generated.h" |
| 15 | #include "y2016/queues/ball_detector_generated.h" |
Comran Morshed | 25f81a0 | 2016-01-23 13:40:10 +0000 | [diff] [blame] | 16 | |
| 17 | namespace y2016 { |
| 18 | namespace control_loops { |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 19 | namespace superstructure { |
| 20 | namespace testing { |
Philipp Schrader | 0119eb1 | 2016-02-15 18:16:21 +0000 | [diff] [blame] | 21 | class SuperstructureTest_RespectsRange_Test; |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 22 | class SuperstructureTest_DisabledGoalTest_Test; |
Diana Vandenberg | e2843c6 | 2016-02-13 17:44:20 -0800 | [diff] [blame] | 23 | class SuperstructureTest_ArmZeroingErrorTest_Test; |
| 24 | class SuperstructureTest_IntakeZeroingErrorTest_Test; |
Philipp Schrader | 0119eb1 | 2016-02-15 18:16:21 +0000 | [diff] [blame] | 25 | class SuperstructureTest_UpperHardstopStartup_Test; |
Campbell Crowley | 152c7cf | 2016-02-14 21:20:50 -0800 | [diff] [blame] | 26 | class SuperstructureTest_DisabledWhileZeroingHigh_Test; |
| 27 | class SuperstructureTest_DisabledWhileZeroingLow_Test; |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 28 | } // namespace testing |
| 29 | |
Philipp Schrader | 0119eb1 | 2016-02-15 18:16:21 +0000 | [diff] [blame] | 30 | // Helper class to prevent parts from crashing into each other. The parts in |
| 31 | // question here are: the frame, the arm (plus shooter), and the intake. |
| 32 | // Assumptions: |
| 33 | // - The shoulder, the wrist, and intake are horizontal when at angle 0. |
| 34 | // - The arm (i.e. shoulder) and shooter (i.e. wrist) are stored when they are |
| 35 | // both at zero degrees. |
| 36 | // - The intake at angle 0 is in a position to help get a ball in the robot. |
| 37 | // - The intake at angle PI is in a "stowed" position. In other words, it is |
| 38 | // folded over the arm and shooter when they are also in a stowed position. |
| 39 | // - The shooter must remain horizontal when the arm is folding into the robot. |
| 40 | // Otherwise, the shooter will collide with the frame. |
| 41 | // - The arm has priority over the intake. If the arm wants to move in such a |
| 42 | // way that interferes with the intake's movement then the intake must move |
| 43 | // out of the way. |
| 44 | class CollisionAvoidance { |
| 45 | public: |
| 46 | // Set up collision avoidance for an arm and intake. |
| 47 | CollisionAvoidance(Intake *intake, Arm *arm) : intake_(intake), arm_(arm) {} |
| 48 | |
| 49 | // This function accepts goals for the intake and the arm and modifies them |
| 50 | // in such a way that collisions between all the different parts of the robot |
| 51 | // are avoided. The modified goals are then sent to the arm and intake as |
| 52 | // unprofiled goals. |
| 53 | void UpdateGoal(double shoulder_angle_goal, double wrist_angle_goal, |
| 54 | double intake_angle_goal); |
| 55 | |
Philipp Schrader | 0714753 | 2016-02-16 01:23:07 +0000 | [diff] [blame] | 56 | // Returns true if any of the limbs and frame are somehow currently |
| 57 | // interfering with one another. This is based purely on the angles that the |
| 58 | // limbs are reporting. |
| 59 | bool collided() const; |
| 60 | |
| 61 | // Detects collision with the specified angles. This is especially useful for |
| 62 | // unit testing where we have proper ground truth for all the angles. |
| 63 | static bool collided_with_given_angles(double shoulder_angle, |
| 64 | double wrist_angle, |
| 65 | double intake_angle); |
| 66 | |
Philipp Schrader | 0119eb1 | 2016-02-15 18:16:21 +0000 | [diff] [blame] | 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 | |
Campbell Crowley | 1836a43 | 2016-03-05 15:16:51 -0800 | [diff] [blame] | 72 | // The shoulder angle (in radians) below which the arm and the shooter have |
| 73 | // the potential to interfere with the intake. |
Austin Schuh | 6ca0f79 | 2016-03-12 14:06:14 -0800 | [diff] [blame] | 74 | static constexpr double kMinShoulderAngleForIntakeUpInterference = 1.3; |
| 75 | |
| 76 | // The shoulder angle (in radians) below which the shooter should be closer to |
| 77 | // level to fix the inverted case. |
| 78 | // TODO(austin): Verify |
| 79 | static constexpr double kMinShoulderAngleForIntakeInterference = 1.1; |
Philipp Schrader | 0119eb1 | 2016-02-15 18:16:21 +0000 | [diff] [blame] | 80 | |
| 81 | // The intake angle (in radians) above which the intake can interfere (i.e. |
| 82 | // collide) with the arm and/or shooter. |
Austin Schuh | 2c71786 | 2016-03-13 15:32:53 -0700 | [diff] [blame] | 83 | static constexpr double kMaxIntakeAngleBeforeArmInterference = 1.05; |
Philipp Schrader | 0119eb1 | 2016-02-15 18:16:21 +0000 | [diff] [blame] | 84 | |
| 85 | // The maximum absolute angle (in radians) that the wrist must be below in |
| 86 | // order for the shouler to be allowed to move below |
| 87 | // kMinShoulderAngleForHorizontalShooter. In other words, only allow the arm |
| 88 | // to move down into the belly pan if the shooter is horizontal, ready to |
| 89 | // also be placed into the belly pan. |
Austin Schuh | 2f5bfc8 | 2016-02-27 14:47:37 -0800 | [diff] [blame] | 90 | static constexpr double kMaxWristAngleForSafeArmStowing = 0.05; |
Philipp Schrader | 0119eb1 | 2016-02-15 18:16:21 +0000 | [diff] [blame] | 91 | |
Austin Schuh | 2c71786 | 2016-03-13 15:32:53 -0700 | [diff] [blame] | 92 | // The maximum angle in radians that the wrist can be from horizontal |
Austin Schuh | 6ca0f79 | 2016-03-12 14:06:14 -0800 | [diff] [blame] | 93 | // while it is near the intake. |
Austin Schuh | 6802a9d | 2016-03-12 21:34:53 -0800 | [diff] [blame] | 94 | static constexpr double kMaxWristAngleForMovingByIntake = 0.50; |
Austin Schuh | 2c71786 | 2016-03-13 15:32:53 -0700 | [diff] [blame] | 95 | // The minimum angle in radians that the wrist can be from horizontal |
| 96 | // while it is near the intake. |
Austin Schuh | 214164b | 2016-03-20 16:50:09 -0700 | [diff] [blame] | 97 | static constexpr double kMinWristAngleForMovingByIntake = -1.50; |
Austin Schuh | 6ca0f79 | 2016-03-12 14:06:14 -0800 | [diff] [blame] | 98 | |
Philipp Schrader | 0119eb1 | 2016-02-15 18:16:21 +0000 | [diff] [blame] | 99 | // The shoulder angle (in radians) below which the intake can safely move |
| 100 | // into the collision zone. This is necessary when the robot wants to fold up |
| 101 | // completely (i.e. stow the arm, shooter, and intake). |
Austin Schuh | 6ca0f79 | 2016-03-12 14:06:14 -0800 | [diff] [blame] | 102 | static constexpr double kMaxShoulderAngleUntilSafeIntakeStowing = 0.19; |
Philipp Schrader | 0119eb1 | 2016-02-15 18:16:21 +0000 | [diff] [blame] | 103 | |
| 104 | private: |
| 105 | Intake *intake_; |
| 106 | Arm *arm_; |
| 107 | }; |
| 108 | |
Comran Morshed | 25f81a0 | 2016-01-23 13:40:10 +0000 | [diff] [blame] | 109 | class Superstructure |
James Kuszmaul | 6175066 | 2021-06-21 21:32:33 -0700 | [diff] [blame^] | 110 | : public ::frc971::controls::ControlLoop<Goal, Position, Status, Output> { |
Comran Morshed | 25f81a0 | 2016-01-23 13:40:10 +0000 | [diff] [blame] | 111 | public: |
Alex Perry | cb7da4b | 2019-08-28 19:35:56 -0700 | [diff] [blame] | 112 | explicit Superstructure(::aos::EventLoop *event_loop, |
| 113 | const ::std::string &name = "/superstructure"); |
Adam Snaider | 0677972 | 2016-02-14 15:26:22 -0800 | [diff] [blame] | 114 | |
Austin Schuh | f132dc5 | 2016-03-13 19:43:15 -0700 | [diff] [blame] | 115 | static constexpr double kZeroingVoltage = 6.0; |
Austin Schuh | fef64ac | 2016-04-24 19:08:01 -0700 | [diff] [blame] | 116 | static constexpr double kShooterHangingVoltage = 6.0; |
Austin Schuh | 0c001a8 | 2016-05-01 12:30:09 -0700 | [diff] [blame] | 117 | static constexpr double kShooterHangingLowVoltage = 2.0; |
Philipp Schrader | 3da48ac | 2016-03-06 23:03:44 +0000 | [diff] [blame] | 118 | static constexpr double kOperatingVoltage = 12.0; |
Austin Schuh | 2c71786 | 2016-03-13 15:32:53 -0700 | [diff] [blame] | 119 | static constexpr double kLandingShoulderDownVoltage = -1.5; |
Philipp Schrader | 3da48ac | 2016-03-06 23:03:44 +0000 | [diff] [blame] | 120 | |
Adam Snaider | 0677972 | 2016-02-14 15:26:22 -0800 | [diff] [blame] | 121 | // This is the angle above which we will do a HIGH_ARM_ZERO, and below which |
| 122 | // we will do a LOW_ARM_ZERO. |
| 123 | static constexpr double kShoulderMiddleAngle = M_PI / 4.0; |
| 124 | // This is the large scale movement tolerance. |
| 125 | static constexpr double kLooseTolerance = 0.05; |
| 126 | |
| 127 | // This is the small scale movement tolerance. |
Austin Schuh | f132dc5 | 2016-03-13 19:43:15 -0700 | [diff] [blame] | 128 | static constexpr double kTightTolerance = 0.03; |
Adam Snaider | 0677972 | 2016-02-14 15:26:22 -0800 | [diff] [blame] | 129 | |
| 130 | // This is the angle such that the intake will clear the arm when the shooter |
| 131 | // is level. |
Austin Schuh | 6ca0f79 | 2016-03-12 14:06:14 -0800 | [diff] [blame] | 132 | static constexpr double kIntakeUpperClear = |
| 133 | CollisionAvoidance::kMaxIntakeAngleBeforeArmInterference; |
Adam Snaider | 0677972 | 2016-02-14 15:26:22 -0800 | [diff] [blame] | 134 | // This is the angle such that the intake will clear the arm when the shooter |
| 135 | // is at almost any position. |
Austin Schuh | 2f5bfc8 | 2016-02-27 14:47:37 -0800 | [diff] [blame] | 136 | static constexpr double kIntakeLowerClear = 0.4; |
Adam Snaider | 0677972 | 2016-02-14 15:26:22 -0800 | [diff] [blame] | 137 | |
| 138 | // This is the angle that the shoulder will go to when doing the |
| 139 | // HIGH_ARM_ZERO. |
| 140 | static constexpr double kShoulderUpAngle = M_PI / 2.0; |
| 141 | |
| 142 | // This is the angle that the shoulder will go down to when landing in the |
| 143 | // bellypan. |
| 144 | static constexpr double kShoulderLanded = -0.02; |
| 145 | |
Austin Schuh | b1d682b | 2016-02-16 13:07:44 -0800 | [diff] [blame] | 146 | // This is the angle below which the shoulder will slowly profile down and |
| 147 | // land. |
| 148 | static constexpr double kShoulderTransitionToLanded = 0.10; |
| 149 | |
Adam Snaider | 0677972 | 2016-02-14 15:26:22 -0800 | [diff] [blame] | 150 | // This is the angle below which we consider the wrist close enough to level |
| 151 | // that we should move it to level before doing anything. |
| 152 | static constexpr double kWristAlmostLevel = 0.10; |
| 153 | |
| 154 | // This is the angle that the shoulder will go down to when raising up before |
| 155 | // leveling the shooter for calibration. |
Austin Schuh | b1d682b | 2016-02-16 13:07:44 -0800 | [diff] [blame] | 156 | static constexpr double kShoulderWristClearAngle = |
| 157 | CollisionAvoidance::kMinShoulderAngleForHorizontalShooter; |
Adam Snaider | 0677972 | 2016-02-14 15:26:22 -0800 | [diff] [blame] | 158 | |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 159 | enum State { |
Adam Snaider | 0677972 | 2016-02-14 15:26:22 -0800 | [diff] [blame] | 160 | // Wait for all the filters to be ready before starting the initialization |
| 161 | // process. |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 162 | UNINITIALIZED = 0, |
Adam Snaider | 0677972 | 2016-02-14 15:26:22 -0800 | [diff] [blame] | 163 | |
| 164 | // We now are ready to decide how to zero. Decide what to do once we are |
| 165 | // enabled. |
| 166 | DISABLED_INITIALIZED = 1, |
| 167 | |
| 168 | // Lift the arm up out of the way. |
| 169 | HIGH_ARM_ZERO_LIFT_ARM = 2, |
| 170 | |
| 171 | HIGH_ARM_ZERO_LEVEL_SHOOTER = 3, |
| 172 | |
| 173 | HIGH_ARM_ZERO_MOVE_INTAKE_OUT = 4, |
| 174 | |
| 175 | HIGH_ARM_ZERO_LOWER_ARM = 6, |
| 176 | |
| 177 | LOW_ARM_ZERO_LOWER_INTAKE = 7, |
| 178 | LOW_ARM_ZERO_MAYBE_LEVEL_SHOOTER = 8, |
| 179 | LOW_ARM_ZERO_LIFT_SHOULDER = 9, |
| 180 | LOW_ARM_ZERO_LEVEL_SHOOTER = 11, |
| 181 | // Run, but limit power to zeroing voltages. |
| 182 | SLOW_RUNNING = 12, |
| 183 | // Run with full power. |
| 184 | RUNNING = 13, |
Austin Schuh | b1d682b | 2016-02-16 13:07:44 -0800 | [diff] [blame] | 185 | // Run, but limit power to zeroing voltages while landing. |
| 186 | LANDING_SLOW_RUNNING = 14, |
| 187 | // Run with full power while landing. |
| 188 | LANDING_RUNNING = 15, |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 189 | // Internal error caused the superstructure to abort. |
Austin Schuh | b1d682b | 2016-02-16 13:07:44 -0800 | [diff] [blame] | 190 | ESTOP = 16, |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 191 | }; |
| 192 | |
Austin Schuh | 9f4e8a7 | 2016-02-16 15:28:47 -0800 | [diff] [blame] | 193 | bool IsRunning() const { |
| 194 | return (state_ == SLOW_RUNNING || state_ == RUNNING || |
| 195 | state_ == LANDING_SLOW_RUNNING || state_ == LANDING_RUNNING); |
| 196 | } |
| 197 | |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 198 | State state() const { return state_; } |
Comran Morshed | 25f81a0 | 2016-01-23 13:40:10 +0000 | [diff] [blame] | 199 | |
Adam Snaider | 0677972 | 2016-02-14 15:26:22 -0800 | [diff] [blame] | 200 | // Returns the value to move the joint to such that it will stay below |
| 201 | // reference_angle starting at current_angle, but move at least move_distance |
| 202 | static double MoveButKeepBelow(double reference_angle, double current_angle, |
| 203 | double move_distance); |
| 204 | // Returns the value to move the joint to such that it will stay above |
| 205 | // reference_angle starting at current_angle, but move at least move_distance |
| 206 | static double MoveButKeepAbove(double reference_angle, double current_angle, |
| 207 | double move_distance); |
| 208 | |
Philipp Schrader | 0714753 | 2016-02-16 01:23:07 +0000 | [diff] [blame] | 209 | // Returns true if anything is currently considered "collided". |
| 210 | bool collided() const { return collision_avoidance_.collided(); } |
Philipp Schrader | 0119eb1 | 2016-02-15 18:16:21 +0000 | [diff] [blame] | 211 | |
Comran Morshed | 25f81a0 | 2016-01-23 13:40:10 +0000 | [diff] [blame] | 212 | protected: |
Alex Perry | cb7da4b | 2019-08-28 19:35:56 -0700 | [diff] [blame] | 213 | virtual void RunIteration(const Goal *unsafe_goal, const Position *position, |
| 214 | aos::Sender<Output>::Builder *output, |
| 215 | aos::Sender<Status>::Builder *status) override; |
Comran Morshed | 25f81a0 | 2016-01-23 13:40:10 +0000 | [diff] [blame] | 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 | 4b652c9 | 2019-05-27 13:22:27 -0700 | [diff] [blame] | 225 | |
| 226 | ::aos::Fetcher<::y2016::sensors::BallDetector> ball_detector_fetcher_; |
| 227 | |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 228 | Intake intake_; |
| 229 | Arm arm_; |
| 230 | |
Philipp Schrader | 0119eb1 | 2016-02-15 18:16:21 +0000 | [diff] [blame] | 231 | CollisionAvoidance collision_avoidance_; |
| 232 | |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 233 | State state_ = UNINITIALIZED; |
| 234 | State last_state_ = UNINITIALIZED; |
| 235 | |
Austin Schuh | be04115 | 2016-02-28 22:01:52 -0800 | [diff] [blame] | 236 | float last_shoulder_angle_ = 0.0; |
| 237 | float last_wrist_angle_ = 0.0; |
| 238 | float last_intake_angle_ = 0.0; |
| 239 | |
Comran Morshed | 71466fe | 2016-04-21 20:21:14 -0700 | [diff] [blame] | 240 | double kill_shoulder_accumulator_ = 0.0; |
| 241 | bool kill_shoulder_ = false; |
| 242 | |
Adam Snaider | 0677972 | 2016-02-14 15:26:22 -0800 | [diff] [blame] | 243 | // Returns true if the profile has finished, and the joint is within the |
| 244 | // specified tolerance. |
| 245 | bool IsArmNear(double tolerance); |
| 246 | bool IsArmNear(double shoulder_tolerance, double wrist_tolerance); |
| 247 | bool IsIntakeNear(double tolerance); |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 248 | |
Comran Morshed | 25f81a0 | 2016-01-23 13:40:10 +0000 | [diff] [blame] | 249 | DISALLOW_COPY_AND_ASSIGN(Superstructure); |
| 250 | }; |
| 251 | |
Austin Schuh | 2fc10fa | 2016-02-08 00:44:34 -0800 | [diff] [blame] | 252 | } // namespace superstructure |
Comran Morshed | 25f81a0 | 2016-01-23 13:40:10 +0000 | [diff] [blame] | 253 | } // namespace control_loops |
| 254 | } // namespace y2016 |
| 255 | |
| 256 | #endif // Y2016_CONTROL_LOOPS_SUPERSTRUCTURE_SUPERSTRUCTURE_H_ |