blob: 01b0463d7aecc90adeb4c2b96478ef973bf73187 [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
50bool CollisionAvoidance::TurretCollided(double intake_position,
51 double turret_position,
52 double min_turret_collision_position,
53 double max_turret_collision_position) {
54 const auto turret_position_wrapped_pair = WrapTurretAngle(turret_position);
55 const double turret_position_wrapped = turret_position_wrapped_pair.first;
56
57 // Checks if turret is in the collision area.
58 if (turret_position_wrapped >= min_turret_collision_position &&
59 turret_position_wrapped <= max_turret_collision_position) {
60 // Reterns true if the intake is raised.
milind-u3e297d32022-03-05 10:31:12 -080061 if (intake_position > kCollisionZoneIntake) {
Milind Upadhyay225156b2022-02-25 22:42:12 -080062 return true;
63 }
64 } else {
65 return false;
66 }
67 return false;
68}
69
Ravago Jones5da06352022-03-04 20:26:24 -080070void CollisionAvoidance::UpdateGoal(
71 const CollisionAvoidance::Status &status,
72 const frc971::control_loops::StaticZeroingSingleDOFProfiledSubsystemGoal
73 *unsafe_turret_goal) {
Milind Upadhyay225156b2022-02-25 22:42:12 -080074 // Start with our constraints being wide open.
75 clear_max_turret_goal();
76 clear_min_turret_goal();
77 clear_max_intake_front_goal();
78 clear_min_intake_front_goal();
79 clear_max_intake_back_goal();
80 clear_min_intake_back_goal();
81
82 const double intake_front_position = status.intake_front_position;
83 const double intake_back_position = status.intake_back_position;
84 const double turret_position = status.turret_position;
85
Ravago Jones5da06352022-03-04 20:26:24 -080086 const double turret_goal = (unsafe_turret_goal != nullptr
87 ? unsafe_turret_goal->unsafe_goal()
88 : std::numeric_limits<double>::quiet_NaN());
Milind Upadhyay225156b2022-02-25 22:42:12 -080089
90 // Calculating the avoidance with either intake, and when the turret is
91 // wrapped.
92
93 CalculateAvoidance(true, intake_front_position, turret_goal,
94 kMinCollisionZoneFrontTurret, kMaxCollisionZoneFrontTurret,
95 turret_position);
96 CalculateAvoidance(false, intake_back_position, turret_goal,
97 kMinCollisionZoneBackTurret, kMaxCollisionZoneBackTurret,
98 turret_position);
99}
100
101void CollisionAvoidance::CalculateAvoidance(bool intake_front,
102 double intake_position,
103 double turret_goal,
104 double min_turret_collision_goal,
105 double max_turret_collision_goal,
106 double turret_position) {
107 auto [turret_position_wrapped, turret_position_wraps] =
108 WrapTurretAngle(turret_position);
109
110 // If the turret goal is in a collison zone or moving through one, limit
111 // intake.
112 const bool turret_pos_unsafe =
113 (turret_position_wrapped >= min_turret_collision_goal &&
114 turret_position_wrapped <= max_turret_collision_goal);
115
116 const bool turret_moving_forward = (turret_goal > turret_position);
117
118 // To figure out if we are moving past an intake, find the unwrapped min/max
119 // angles closest to the turret position on the journey.
120 int bounds_wraps = turret_position_wraps;
121 double min_turret_collision_goal_unwrapped =
122 UnwrapTurretAngle(min_turret_collision_goal, bounds_wraps);
123 if (turret_moving_forward &&
124 min_turret_collision_goal_unwrapped < turret_position) {
125 bounds_wraps++;
126 } else if (!turret_moving_forward &&
127 min_turret_collision_goal_unwrapped > turret_position) {
128 bounds_wraps--;
129 }
130 min_turret_collision_goal_unwrapped =
131 UnwrapTurretAngle(min_turret_collision_goal, bounds_wraps);
132 const double max_turret_collision_goal_unwrapped =
133 UnwrapTurretAngle(max_turret_collision_goal, bounds_wraps);
134
135 // Check if the closest unwrapped angles are going to be passed
136 const bool turret_moving_past_intake =
137 ((turret_moving_forward &&
138 (turret_position <= max_turret_collision_goal_unwrapped &&
139 turret_goal >= min_turret_collision_goal_unwrapped)) ||
140 (!turret_moving_forward &&
141 (turret_position >= min_turret_collision_goal_unwrapped &&
142 turret_goal <= max_turret_collision_goal_unwrapped)));
143
144 if (turret_pos_unsafe || turret_moving_past_intake) {
145 // If the turret is unsafe, limit the intake
146 if (intake_front) {
milind-u3e297d32022-03-05 10:31:12 -0800147 update_max_intake_front_goal(kCollisionZoneIntake - kEpsIntake);
Milind Upadhyay225156b2022-02-25 22:42:12 -0800148 } else {
milind-u3e297d32022-03-05 10:31:12 -0800149 update_max_intake_back_goal(kCollisionZoneIntake - kEpsIntake);
Milind Upadhyay225156b2022-02-25 22:42:12 -0800150 }
151
152 // If the intake is in the way, limit the turret until moved. Otherwise,
153 // let'errip!
milind-u3e297d32022-03-05 10:31:12 -0800154 if (!turret_pos_unsafe && (intake_position > kCollisionZoneIntake)) {
Milind Upadhyay225156b2022-02-25 22:42:12 -0800155 if (turret_position < min_turret_collision_goal_unwrapped) {
156 update_max_turret_goal(min_turret_collision_goal_unwrapped -
157 kEpsTurret);
158 } else {
159 update_min_turret_goal(max_turret_collision_goal_unwrapped +
160 kEpsTurret);
161 }
162 }
163 }
164}
165
166} // namespace superstructure
167} // namespace control_loops
168} // namespace y2022