blob: d87054a96f83b692788c5d77548ec2641bc3be09 [file] [log] [blame]
Milind Upadhyay225156b2022-02-25 22:42:12 -08001#include "y2022/control_loops/superstructure/collision_avoidance.h"
2
3#include <cmath>
4
5#include "absl/functional/bind_front.h"
6#include "glog/logging.h"
7
8namespace y2022 {
9namespace control_loops {
10namespace superstructure {
11
12CollisionAvoidance::CollisionAvoidance() {
13 clear_min_intake_front_goal();
14 clear_max_intake_front_goal();
15 clear_min_intake_back_goal();
16 clear_max_intake_back_goal();
17 clear_min_turret_goal();
18 clear_max_turret_goal();
19}
20
21bool CollisionAvoidance::IsCollided(const CollisionAvoidance::Status &status) {
22 // Checks if intake front is collided.
23 if (TurretCollided(status.intake_front_position, status.turret_position,
24 kMinCollisionZoneFrontTurret,
25 kMaxCollisionZoneFrontTurret)) {
26 return true;
27 }
28
29 // Checks if intake back is collided.
30 if (TurretCollided(status.intake_back_position, status.turret_position,
31 kMinCollisionZoneBackTurret,
32 kMaxCollisionZoneBackTurret)) {
33 return true;
34 }
35
36 return false;
37}
38
39std::pair<double, int> WrapTurretAngle(double turret_angle) {
40 double wrapped = std::remainder(turret_angle - M_PI, 2 * M_PI) + M_PI;
41 int wraps =
42 static_cast<int>(std::round((turret_angle - wrapped) / (2 * M_PI)));
43 return {wrapped, wraps};
44}
45
46double UnwrapTurretAngle(double wrapped, int wraps) {
47 return wrapped + 2.0 * M_PI * wraps;
48}
49
Milind Upadhyay8e2582b2022-03-06 15:14:15 -080050bool AngleInRange(double theta, double theta_min, double theta_max) {
51 return (
52 (theta >= theta_min && theta <= theta_max) ||
53 (theta_min > theta_max && (theta >= theta_min || theta <= theta_max)));
54}
55
Milind Upadhyay225156b2022-02-25 22:42:12 -080056bool CollisionAvoidance::TurretCollided(double intake_position,
57 double turret_position,
58 double min_turret_collision_position,
59 double max_turret_collision_position) {
60 const auto turret_position_wrapped_pair = WrapTurretAngle(turret_position);
61 const double turret_position_wrapped = turret_position_wrapped_pair.first;
62
63 // Checks if turret is in the collision area.
Milind Upadhyay8e2582b2022-03-06 15:14:15 -080064 if (AngleInRange(turret_position_wrapped, min_turret_collision_position,
65 max_turret_collision_position)) {
Milind Upadhyay225156b2022-02-25 22:42:12 -080066 // Reterns true if the intake is raised.
milind-u3e297d32022-03-05 10:31:12 -080067 if (intake_position > kCollisionZoneIntake) {
Milind Upadhyay225156b2022-02-25 22:42:12 -080068 return true;
69 }
70 } else {
71 return false;
72 }
73 return false;
74}
75
Ravago Jones5da06352022-03-04 20:26:24 -080076void CollisionAvoidance::UpdateGoal(
77 const CollisionAvoidance::Status &status,
78 const frc971::control_loops::StaticZeroingSingleDOFProfiledSubsystemGoal
79 *unsafe_turret_goal) {
Milind Upadhyay225156b2022-02-25 22:42:12 -080080 // Start with our constraints being wide open.
81 clear_max_turret_goal();
82 clear_min_turret_goal();
83 clear_max_intake_front_goal();
84 clear_min_intake_front_goal();
85 clear_max_intake_back_goal();
86 clear_min_intake_back_goal();
87
88 const double intake_front_position = status.intake_front_position;
89 const double intake_back_position = status.intake_back_position;
90 const double turret_position = status.turret_position;
91
Ravago Jones5da06352022-03-04 20:26:24 -080092 const double turret_goal = (unsafe_turret_goal != nullptr
93 ? unsafe_turret_goal->unsafe_goal()
94 : std::numeric_limits<double>::quiet_NaN());
Milind Upadhyay225156b2022-02-25 22:42:12 -080095
96 // Calculating the avoidance with either intake, and when the turret is
97 // wrapped.
98
99 CalculateAvoidance(true, intake_front_position, turret_goal,
100 kMinCollisionZoneFrontTurret, kMaxCollisionZoneFrontTurret,
101 turret_position);
102 CalculateAvoidance(false, intake_back_position, turret_goal,
103 kMinCollisionZoneBackTurret, kMaxCollisionZoneBackTurret,
104 turret_position);
105}
106
107void CollisionAvoidance::CalculateAvoidance(bool intake_front,
108 double intake_position,
109 double turret_goal,
110 double min_turret_collision_goal,
111 double max_turret_collision_goal,
112 double turret_position) {
113 auto [turret_position_wrapped, turret_position_wraps] =
114 WrapTurretAngle(turret_position);
115
116 // If the turret goal is in a collison zone or moving through one, limit
117 // intake.
118 const bool turret_pos_unsafe =
Milind Upadhyay8e2582b2022-03-06 15:14:15 -0800119 AngleInRange(turret_position_wrapped, min_turret_collision_goal,
120 max_turret_collision_goal);
Milind Upadhyay225156b2022-02-25 22:42:12 -0800121
122 const bool turret_moving_forward = (turret_goal > turret_position);
123
124 // To figure out if we are moving past an intake, find the unwrapped min/max
125 // angles closest to the turret position on the journey.
126 int bounds_wraps = turret_position_wraps;
127 double min_turret_collision_goal_unwrapped =
128 UnwrapTurretAngle(min_turret_collision_goal, bounds_wraps);
129 if (turret_moving_forward &&
130 min_turret_collision_goal_unwrapped < turret_position) {
131 bounds_wraps++;
132 } else if (!turret_moving_forward &&
133 min_turret_collision_goal_unwrapped > turret_position) {
134 bounds_wraps--;
135 }
136 min_turret_collision_goal_unwrapped =
137 UnwrapTurretAngle(min_turret_collision_goal, bounds_wraps);
Milind Upadhyay8e2582b2022-03-06 15:14:15 -0800138 // If we are checking the back intake, the max turret angle is on the wrap
139 // after the min, so add 1 to the number of wraps for it
Milind Upadhyay225156b2022-02-25 22:42:12 -0800140 const double max_turret_collision_goal_unwrapped =
Milind Upadhyay8e2582b2022-03-06 15:14:15 -0800141 UnwrapTurretAngle(max_turret_collision_goal,
142 intake_front ? bounds_wraps : bounds_wraps + 1);
Milind Upadhyay225156b2022-02-25 22:42:12 -0800143
144 // Check if the closest unwrapped angles are going to be passed
145 const bool turret_moving_past_intake =
146 ((turret_moving_forward &&
147 (turret_position <= max_turret_collision_goal_unwrapped &&
148 turret_goal >= min_turret_collision_goal_unwrapped)) ||
149 (!turret_moving_forward &&
150 (turret_position >= min_turret_collision_goal_unwrapped &&
151 turret_goal <= max_turret_collision_goal_unwrapped)));
152
153 if (turret_pos_unsafe || turret_moving_past_intake) {
154 // If the turret is unsafe, limit the intake
155 if (intake_front) {
milind-u3e297d32022-03-05 10:31:12 -0800156 update_max_intake_front_goal(kCollisionZoneIntake - kEpsIntake);
Milind Upadhyay225156b2022-02-25 22:42:12 -0800157 } else {
milind-u3e297d32022-03-05 10:31:12 -0800158 update_max_intake_back_goal(kCollisionZoneIntake - kEpsIntake);
Milind Upadhyay225156b2022-02-25 22:42:12 -0800159 }
160
161 // If the intake is in the way, limit the turret until moved. Otherwise,
162 // let'errip!
milind-u3e297d32022-03-05 10:31:12 -0800163 if (!turret_pos_unsafe && (intake_position > kCollisionZoneIntake)) {
Milind Upadhyay225156b2022-02-25 22:42:12 -0800164 if (turret_position < min_turret_collision_goal_unwrapped) {
165 update_max_turret_goal(min_turret_collision_goal_unwrapped -
166 kEpsTurret);
167 } else {
168 update_min_turret_goal(max_turret_collision_goal_unwrapped +
169 kEpsTurret);
170 }
171 }
172 }
173}
174
175} // namespace superstructure
176} // namespace control_loops
177} // namespace y2022