blob: 9c2bf93b3152f7aa31a0541e0a4c3f2e61efb6b5 [file] [log] [blame]
Sabina Davis4b63ae52019-01-27 16:15:25 -08001#include "y2019/control_loops/superstructure/collision_avoidance.h"
2
3#include <cmath>
Alex Perrycb7da4b2019-08-28 19:35:56 -07004
5#include "frc971/control_loops/control_loops_generated.h"
6#include "frc971/control_loops/profiled_subsystem_generated.h"
7#include "y2019/control_loops/superstructure/superstructure_goal_generated.h"
8#include "y2019/control_loops/superstructure/superstructure_status_generated.h"
Sabina Davis4b63ae52019-01-27 16:15:25 -08009
10namespace y2019 {
11namespace control_loops {
12namespace superstructure {
13
14constexpr double CollisionAvoidance::kElevatorClearHeight;
15constexpr double CollisionAvoidance::kElevatorClearWristDownHeight;
16constexpr double CollisionAvoidance::kElevatorClearIntakeHeight;
17constexpr double CollisionAvoidance::kWristMaxAngle;
18constexpr double CollisionAvoidance::kWristMinAngle;
19constexpr double CollisionAvoidance::kIntakeOutAngle;
20constexpr double CollisionAvoidance::kIntakeInAngle;
21constexpr double CollisionAvoidance::kWristElevatorCollisionMinAngle;
22constexpr double CollisionAvoidance::kWristElevatorCollisionMaxAngle;
Tyler Chatowd180b252019-02-23 22:00:20 -080023constexpr double
24 CollisionAvoidance::kWristElevatorCollisionMaxAngleWithoutObject;
Sabina Davis4b63ae52019-01-27 16:15:25 -080025constexpr double CollisionAvoidance::kEps;
26constexpr double CollisionAvoidance::kEpsIntake;
27constexpr double CollisionAvoidance::kEpsWrist;
28
29CollisionAvoidance::CollisionAvoidance() {
30 clear_min_wrist_goal();
31 clear_max_wrist_goal();
32 clear_min_elevator_goal();
33 clear_min_intake_goal();
34 clear_max_intake_goal();
35}
36
Alex Perrycb7da4b2019-08-28 19:35:56 -070037bool CollisionAvoidance::IsCollided(const Status *status) {
38 return IsCollided(status->wrist()->position(), status->elevator()->position(),
39 status->intake()->position(), status->has_piece());
Austin Schuh9fe68f72019-08-10 19:32:03 -070040}
Tyler Chatowd180b252019-02-23 22:00:20 -080041
Austin Schuh9fe68f72019-08-10 19:32:03 -070042bool CollisionAvoidance::IsCollided(const double wrist_position,
43 const double elevator_position,
44 const double intake_position,
45 const bool has_piece) {
Tyler Chatowd180b252019-02-23 22:00:20 -080046 const double wrist_elevator_collision_max_angle =
47 has_piece ? kWristElevatorCollisionMaxAngle
48 : kWristElevatorCollisionMaxAngleWithoutObject;
Sabina Davis4b63ae52019-01-27 16:15:25 -080049
50 // Elevator is down, so the wrist can't be close to vertical.
51 if (elevator_position < kElevatorClearHeight) {
Tyler Chatowd180b252019-02-23 22:00:20 -080052 if (wrist_position < wrist_elevator_collision_max_angle &&
Sabina Davis4b63ae52019-01-27 16:15:25 -080053 wrist_position > kWristElevatorCollisionMinAngle) {
54 return true;
55 }
56 }
57
58 // Elevator is down so wrist can't go below horizontal in either direction.
59 if (elevator_position < kElevatorClearWristDownHeight) {
60 if (wrist_position > kWristMaxAngle) {
61 return true;
62 }
63 if (wrist_position < kWristMinAngle) {
64 return true;
65 }
66 }
67
68 // Elevator is down so the intake has to be at either extreme.
Austin Schuh0158e6a2019-02-17 15:02:26 -080069 if (elevator_position < kElevatorClearIntakeHeight &&
70 wrist_position > kWristMaxAngle) {
Sabina Davis4b63ae52019-01-27 16:15:25 -080071 if (intake_position < kIntakeOutAngle && intake_position > kIntakeInAngle) {
72 return true;
73 }
74 }
75
76 // Nothing is hitting, we must be good.
77 return false;
78}
79
Alex Perrycb7da4b2019-08-28 19:35:56 -070080void CollisionAvoidance::UpdateGoal(const Status *status,
81 const Goal *unsafe_goal) {
82 const double wrist_position = status->wrist()->position();
83 const double elevator_position = status->elevator()->position();
84 const double intake_position = status->intake()->position();
85 const bool has_piece = status->has_piece();
Sabina Davis4b63ae52019-01-27 16:15:25 -080086
87 // Start with our constraints being wide open.
88 clear_max_wrist_goal();
89 clear_min_wrist_goal();
90 clear_max_intake_goal();
91 clear_min_intake_goal();
92
Tyler Chatowd180b252019-02-23 22:00:20 -080093 const double wrist_elevator_collision_max_angle =
94 has_piece ? kWristElevatorCollisionMaxAngle
95 : kWristElevatorCollisionMaxAngleWithoutObject;
96
Sabina Davis4b63ae52019-01-27 16:15:25 -080097 // If the elevator is low enough, we also can't transition the wrist.
98 if (elevator_position < kElevatorClearHeight) {
99 // Figure out which side the wrist is on and stay there.
Austin Schuh0158e6a2019-02-17 15:02:26 -0800100 if (wrist_position < (2.0 * kWristElevatorCollisionMinAngle +
101 kWristElevatorCollisionMaxAngle) /
102 3.0) {
Sabina Davis4b63ae52019-01-27 16:15:25 -0800103 update_max_wrist_goal(kWristElevatorCollisionMinAngle - kEpsWrist);
104 } else {
Tyler Chatowd180b252019-02-23 22:00:20 -0800105 update_min_wrist_goal(wrist_elevator_collision_max_angle + kEpsWrist);
Sabina Davis4b63ae52019-01-27 16:15:25 -0800106 }
107 }
108
109 // If the elevator is too low, the wrist needs to be above the clearance
110 // angles to avoid crashing the frame.
111 if (elevator_position < kElevatorClearWristDownHeight) {
112 update_min_wrist_goal(kWristMinAngle + kEpsWrist);
113 update_max_wrist_goal(kWristMaxAngle - kEpsWrist);
114 }
115
116 constexpr double kIntakeMiddleAngle =
117 (kIntakeOutAngle + kIntakeInAngle) / 2.0;
118
119 // If the elevator is too low, the intake can't transition from in to out or
120 // back.
Austin Schuh0158e6a2019-02-17 15:02:26 -0800121 if (elevator_position < kElevatorClearIntakeHeight &&
Tyler Chatowd180b252019-02-23 22:00:20 -0800122 wrist_position > wrist_elevator_collision_max_angle) {
Sabina Davis4b63ae52019-01-27 16:15:25 -0800123 // Figure out if the intake is in our out and keep it there.
124 if (intake_position < kIntakeMiddleAngle) {
125 update_max_intake_goal(kIntakeInAngle - kEpsIntake);
126 } else {
127 update_min_intake_goal(kIntakeOutAngle + kEpsIntake);
128 }
129 }
130
131 // Start with an unconstrained elevator.
132 clear_min_elevator_goal();
133
134 // If the intake is within the collision range, don't let the elevator down.
Austin Schuh0158e6a2019-02-17 15:02:26 -0800135 if (intake_position > kIntakeInAngle && intake_position < kIntakeOutAngle &&
Tyler Chatowd180b252019-02-23 22:00:20 -0800136 wrist_position > wrist_elevator_collision_max_angle) {
Sabina Davis4b63ae52019-01-27 16:15:25 -0800137 update_min_elevator_goal(kElevatorClearIntakeHeight + kEps);
138 }
139
Austin Schuh0158e6a2019-02-17 15:02:26 -0800140 // If the intake is in the collision range and the elevator is down, don't let
141 // the wrist go far down.
142 if (intake_position > kIntakeInAngle && intake_position < kIntakeOutAngle &&
143 elevator_position < kElevatorClearIntakeHeight) {
144 update_max_wrist_goal(kWristMaxAngle - kEpsWrist);
145 }
146
Sabina Davis4b63ae52019-01-27 16:15:25 -0800147 // If the wrist is within the elevator collision range, don't let the elevator
148 // go down.
149 if (wrist_position > kWristElevatorCollisionMinAngle &&
Tyler Chatowd180b252019-02-23 22:00:20 -0800150 wrist_position < wrist_elevator_collision_max_angle) {
Sabina Davis4b63ae52019-01-27 16:15:25 -0800151 update_min_elevator_goal(kElevatorClearHeight + kEps);
152 }
153
154 // If the wrist is far enough down that we are going to hit the frame, don't
155 // let the elevator go too far down.
156 if (wrist_position > kWristMaxAngle || wrist_position < kWristMinAngle) {
157 update_min_elevator_goal(kElevatorClearWristDownHeight + kEps);
158 }
159
160 if (unsafe_goal) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700161 const double wrist_goal = unsafe_goal->wrist()->unsafe_goal();
162 const double intake_goal = unsafe_goal->intake()->unsafe_goal();
Sabina Davis4b63ae52019-01-27 16:15:25 -0800163
164 // Compute if we need to move the intake.
165 const bool intake_needs_to_move = (intake_position < kIntakeMiddleAngle) ^
166 (intake_goal < kIntakeMiddleAngle);
167
168 // Compute if we need to move the wrist across 0.
169 const bool wrist_needs_to_move =
170 (wrist_position < 0.0) ^ (wrist_goal < 0.0);
171
172 // If we need to move the intake, we've got to shove the elevator up. The
173 // intake is already constrained so it can't hit anything until it's clear.
Austin Schuh0158e6a2019-02-17 15:02:26 -0800174 if (intake_needs_to_move &&
Tyler Chatowd180b252019-02-23 22:00:20 -0800175 wrist_position > wrist_elevator_collision_max_angle) {
Sabina Davis4b63ae52019-01-27 16:15:25 -0800176 update_min_elevator_goal(kElevatorClearIntakeHeight + kEps);
177 }
178 // If we need to move the wrist, we've got to shove the elevator up too. The
179 // wrist is already constrained so it can't hit anything until it's clear.
180 // If both the intake and wrist need to move, figure out which one will
181 // require the higher motion and move that.
182 if (wrist_needs_to_move) {
183 update_min_elevator_goal(kElevatorClearHeight + kEps);
184 }
185
186 // TODO(austin): We won't shove the elevator up if the wrist is asked to go
187 // down below horizontal. I think that's fine.
188 }
189}
190
191} // namespace superstructure
192} // namespace control_loops
193} // namespace y2019