Niko Sohmers | ac4d887 | 2024-02-23 13:55:47 -0800 | [diff] [blame] | 1 | #include "y2024/control_loops/superstructure/collision_avoidance.h" |
| 2 | |
| 3 | #include <cmath> |
| 4 | |
| 5 | #include "absl/functional/bind_front.h" |
Austin Schuh | 99f7c6a | 2024-06-25 22:07:44 -0700 | [diff] [blame^] | 6 | #include "absl/log/check.h" |
| 7 | #include "absl/log/log.h" |
Niko Sohmers | ac4d887 | 2024-02-23 13:55:47 -0800 | [diff] [blame] | 8 | |
| 9 | namespace y2024::control_loops::superstructure { |
| 10 | |
| 11 | CollisionAvoidance::CollisionAvoidance() { |
| 12 | clear_min_intake_pivot_goal(); |
| 13 | clear_max_intake_pivot_goal(); |
| 14 | clear_min_turret_goal(); |
| 15 | clear_max_turret_goal(); |
Austin Schuh | 027fd62 | 2024-03-01 21:26:07 -0800 | [diff] [blame] | 16 | clear_min_extend_goal(); |
| 17 | clear_max_extend_goal(); |
Niko Sohmers | ac4d887 | 2024-02-23 13:55:47 -0800 | [diff] [blame] | 18 | } |
| 19 | |
| 20 | bool CollisionAvoidance::IsCollided(const CollisionAvoidance::Status &status) { |
| 21 | // Checks if intake front is collided. |
| 22 | if (TurretCollided(status.intake_pivot_position, status.turret_position, |
Austin Schuh | 027fd62 | 2024-03-01 21:26:07 -0800 | [diff] [blame] | 23 | status.extend_position)) { |
Niko Sohmers | ac4d887 | 2024-02-23 13:55:47 -0800 | [diff] [blame] | 24 | return true; |
| 25 | } |
| 26 | |
| 27 | return false; |
| 28 | } |
| 29 | |
| 30 | bool AngleInRange(double theta, double theta_min, double theta_max) { |
| 31 | return ( |
| 32 | (theta >= theta_min && theta <= theta_max) || |
| 33 | (theta_min > theta_max && (theta >= theta_min || theta <= theta_max))); |
| 34 | } |
| 35 | |
| 36 | bool CollisionAvoidance::TurretCollided(double intake_position, |
| 37 | double turret_position, |
Austin Schuh | 027fd62 | 2024-03-01 21:26:07 -0800 | [diff] [blame] | 38 | double extend_position) { |
Niko Sohmers | ac4d887 | 2024-02-23 13:55:47 -0800 | [diff] [blame] | 39 | // Checks if turret is in the collision area. |
Austin Schuh | 027fd62 | 2024-03-01 21:26:07 -0800 | [diff] [blame] | 40 | if (AngleInRange(turret_position, kMinCollisionZoneTurret, |
| 41 | kMaxCollisionZoneTurret)) { |
Niko Sohmers | ac4d887 | 2024-02-23 13:55:47 -0800 | [diff] [blame] | 42 | // Returns true if the intake is raised. |
| 43 | if (intake_position > kCollisionZoneIntake) { |
| 44 | return true; |
| 45 | } |
Niko Sohmers | ac4d887 | 2024-02-23 13:55:47 -0800 | [diff] [blame] | 46 | } |
Austin Schuh | 027fd62 | 2024-03-01 21:26:07 -0800 | [diff] [blame] | 47 | return ExtendCollided(intake_position, turret_position, extend_position); |
| 48 | } |
| 49 | |
| 50 | bool CollisionAvoidance::ExtendCollided(double /*intake_position*/, |
| 51 | double turret_position, |
| 52 | double extend_position) { |
| 53 | // Checks if turret is in the collision area. |
| 54 | if (!AngleInRange(turret_position, kSafeTurretExtendedPosition - kEpsTurret, |
| 55 | kSafeTurretExtendedPosition + kEpsTurret)) { |
| 56 | // Returns true if the extend is raised. |
| 57 | if (extend_position > kMinCollisionZoneExtend) { |
| 58 | return true; |
| 59 | } |
| 60 | } |
| 61 | |
Niko Sohmers | ac4d887 | 2024-02-23 13:55:47 -0800 | [diff] [blame] | 62 | return false; |
| 63 | } |
| 64 | |
| 65 | void CollisionAvoidance::UpdateGoal(const CollisionAvoidance::Status &status, |
Austin Schuh | 027fd62 | 2024-03-01 21:26:07 -0800 | [diff] [blame] | 66 | const double turret_goal_position, |
| 67 | const double extend_goal_position) { |
Niko Sohmers | ac4d887 | 2024-02-23 13:55:47 -0800 | [diff] [blame] | 68 | // Start with our constraints being wide open. |
Austin Schuh | 027fd62 | 2024-03-01 21:26:07 -0800 | [diff] [blame] | 69 | clear_min_extend_goal(); |
| 70 | clear_max_extend_goal(); |
Niko Sohmers | ac4d887 | 2024-02-23 13:55:47 -0800 | [diff] [blame] | 71 | clear_max_turret_goal(); |
| 72 | clear_min_turret_goal(); |
| 73 | clear_max_intake_pivot_goal(); |
| 74 | clear_min_intake_pivot_goal(); |
| 75 | |
| 76 | const double intake_pivot_position = status.intake_pivot_position; |
| 77 | const double turret_position = status.turret_position; |
Austin Schuh | 027fd62 | 2024-03-01 21:26:07 -0800 | [diff] [blame] | 78 | const double extend_position = status.extend_position; |
Niko Sohmers | ac4d887 | 2024-02-23 13:55:47 -0800 | [diff] [blame] | 79 | |
| 80 | const double turret_goal = turret_goal_position; |
Austin Schuh | 027fd62 | 2024-03-01 21:26:07 -0800 | [diff] [blame] | 81 | const double extend_goal = extend_goal_position; |
Niko Sohmers | ac4d887 | 2024-02-23 13:55:47 -0800 | [diff] [blame] | 82 | |
| 83 | // Calculating the avoidance with the intake |
| 84 | |
Austin Schuh | 027fd62 | 2024-03-01 21:26:07 -0800 | [diff] [blame] | 85 | CalculateAvoidance(intake_pivot_position, turret_position, extend_position, |
| 86 | turret_goal, extend_goal); |
Niko Sohmers | ac4d887 | 2024-02-23 13:55:47 -0800 | [diff] [blame] | 87 | } |
| 88 | |
Austin Schuh | 027fd62 | 2024-03-01 21:26:07 -0800 | [diff] [blame] | 89 | void CollisionAvoidance::CalculateAvoidance(double intake_position, |
Niko Sohmers | ac4d887 | 2024-02-23 13:55:47 -0800 | [diff] [blame] | 90 | double turret_position, |
Austin Schuh | 027fd62 | 2024-03-01 21:26:07 -0800 | [diff] [blame] | 91 | double extend_position, |
Niko Sohmers | ac4d887 | 2024-02-23 13:55:47 -0800 | [diff] [blame] | 92 | double turret_goal, |
Austin Schuh | 027fd62 | 2024-03-01 21:26:07 -0800 | [diff] [blame] | 93 | double extend_goal) { |
Niko Sohmers | ac4d887 | 2024-02-23 13:55:47 -0800 | [diff] [blame] | 94 | // If the turret goal is in a collison zone or moving through one, limit |
| 95 | // intake. |
Austin Schuh | 027fd62 | 2024-03-01 21:26:07 -0800 | [diff] [blame] | 96 | const bool turret_intake_pos_unsafe = AngleInRange( |
| 97 | turret_position, kMinCollisionZoneTurret, kMaxCollisionZoneTurret); |
| 98 | const bool turret_extend_pos_unsafe = |
| 99 | turret_position > kEpsTurret + kSafeTurretExtendedPosition || |
| 100 | turret_position < -kEpsTurret + kSafeTurretExtendedPosition; |
| 101 | |
| 102 | const bool extend_goal_unsafe = |
| 103 | extend_goal > kMinCollisionZoneExtend - kEpsExtend; |
| 104 | const bool extend_position_unsafe = |
| 105 | extend_position > kMinCollisionZoneExtend - kEpsExtend; |
| 106 | |
| 107 | // OK, we are trying to move the extend, and need the turret to be at 0. |
| 108 | // Pretend that's the goal. |
| 109 | if (extend_goal_unsafe || extend_position_unsafe) { |
| 110 | turret_goal = kSafeTurretExtendedPosition; |
| 111 | } |
Niko Sohmers | ac4d887 | 2024-02-23 13:55:47 -0800 | [diff] [blame] | 112 | |
| 113 | const bool turret_moving_forward = (turret_goal > turret_position); |
| 114 | |
| 115 | // Check if the closest angles are going to be passed |
| 116 | const bool turret_moving_past_intake = |
Austin Schuh | 027fd62 | 2024-03-01 21:26:07 -0800 | [diff] [blame] | 117 | ((turret_moving_forward && (turret_position <= kMaxCollisionZoneTurret && |
| 118 | turret_goal >= kMinCollisionZoneTurret)) || |
| 119 | (!turret_moving_forward && (turret_position >= kMinCollisionZoneTurret && |
| 120 | turret_goal <= kMaxCollisionZoneTurret))); |
Niko Sohmers | ac4d887 | 2024-02-23 13:55:47 -0800 | [diff] [blame] | 121 | |
Austin Schuh | 027fd62 | 2024-03-01 21:26:07 -0800 | [diff] [blame] | 122 | if (turret_intake_pos_unsafe || turret_moving_past_intake) { |
Niko Sohmers | ac4d887 | 2024-02-23 13:55:47 -0800 | [diff] [blame] | 123 | // If the turret is unsafe, limit the intake |
Austin Schuh | 027fd62 | 2024-03-01 21:26:07 -0800 | [diff] [blame] | 124 | update_max_intake_pivot_goal(kCollisionZoneIntake - kEpsIntake); |
Niko Sohmers | ac4d887 | 2024-02-23 13:55:47 -0800 | [diff] [blame] | 125 | |
| 126 | // If the intake is in the way, limit the turret until moved. Otherwise, |
| 127 | // let'errip! |
Austin Schuh | 027fd62 | 2024-03-01 21:26:07 -0800 | [diff] [blame] | 128 | if (!turret_intake_pos_unsafe && (intake_position > kCollisionZoneIntake)) { |
Niko Sohmers | ac4d887 | 2024-02-23 13:55:47 -0800 | [diff] [blame] | 129 | if (turret_position < |
Austin Schuh | 027fd62 | 2024-03-01 21:26:07 -0800 | [diff] [blame] | 130 | (kMinCollisionZoneTurret + kMaxCollisionZoneTurret) / 2.) { |
| 131 | update_max_turret_goal(kMinCollisionZoneTurret - kEpsTurret); |
Niko Sohmers | ac4d887 | 2024-02-23 13:55:47 -0800 | [diff] [blame] | 132 | } else { |
Austin Schuh | 027fd62 | 2024-03-01 21:26:07 -0800 | [diff] [blame] | 133 | update_min_turret_goal(kMaxCollisionZoneTurret + kEpsTurret); |
Niko Sohmers | ac4d887 | 2024-02-23 13:55:47 -0800 | [diff] [blame] | 134 | } |
| 135 | } |
| 136 | } |
Austin Schuh | 027fd62 | 2024-03-01 21:26:07 -0800 | [diff] [blame] | 137 | |
| 138 | // OK, the logic is pretty simple. The turret needs to be at |
| 139 | // kSafeTurretExtendedPosition any time extend is > kMinCollisionZoneExtend. |
| 140 | // |
| 141 | // Extend can't go up if the turret isn't near 0. |
| 142 | if (turret_extend_pos_unsafe) { |
| 143 | update_max_extend_goal(kMinCollisionZoneExtend - kEpsExtend); |
| 144 | } |
| 145 | |
| 146 | // Turret is bound to the safe position if extend wants to be, or is unsafe. |
| 147 | if (extend_goal_unsafe || extend_position_unsafe) { |
| 148 | // If the turret isn't allowed to go to 0, don't drive it there. |
| 149 | if (min_turret_goal() < kSafeTurretExtendedPosition && |
| 150 | max_turret_goal() > kSafeTurretExtendedPosition) { |
| 151 | update_min_turret_goal(kSafeTurretExtendedPosition); |
| 152 | update_max_turret_goal(kSafeTurretExtendedPosition); |
| 153 | } |
| 154 | } |
Niko Sohmers | ac4d887 | 2024-02-23 13:55:47 -0800 | [diff] [blame] | 155 | } |
| 156 | |
| 157 | } // namespace y2024::control_loops::superstructure |