blob: 9f7cc9b4e99b71d7dfc9a3f47965d7325a8430a6 [file] [log] [blame]
Sabina Davis4b63ae52019-01-27 16:15:25 -08001#include "y2019/control_loops/superstructure/collision_avoidance.h"
2
3#include <cmath>
4#include "y2019/control_loops/superstructure/superstructure.q.h"
5
6namespace y2019 {
7namespace control_loops {
8namespace superstructure {
9
10constexpr double CollisionAvoidance::kElevatorClearHeight;
11constexpr double CollisionAvoidance::kElevatorClearWristDownHeight;
12constexpr double CollisionAvoidance::kElevatorClearIntakeHeight;
13constexpr double CollisionAvoidance::kWristMaxAngle;
14constexpr double CollisionAvoidance::kWristMinAngle;
15constexpr double CollisionAvoidance::kIntakeOutAngle;
16constexpr double CollisionAvoidance::kIntakeInAngle;
17constexpr double CollisionAvoidance::kWristElevatorCollisionMinAngle;
18constexpr double CollisionAvoidance::kWristElevatorCollisionMaxAngle;
Tyler Chatowd180b252019-02-23 22:00:20 -080019constexpr double
20 CollisionAvoidance::kWristElevatorCollisionMaxAngleWithoutObject;
Sabina Davis4b63ae52019-01-27 16:15:25 -080021constexpr double CollisionAvoidance::kEps;
22constexpr double CollisionAvoidance::kEpsIntake;
23constexpr double CollisionAvoidance::kEpsWrist;
24
25CollisionAvoidance::CollisionAvoidance() {
26 clear_min_wrist_goal();
27 clear_max_wrist_goal();
28 clear_min_elevator_goal();
29 clear_min_intake_goal();
30 clear_max_intake_goal();
31}
32
33bool CollisionAvoidance::IsCollided(const SuperstructureQueue::Status *status) {
34 const double wrist_position = status->wrist.position;
35 const double elevator_position = status->elevator.position;
36 const double intake_position = status->intake.position;
Tyler Chatowd180b252019-02-23 22:00:20 -080037 const bool has_piece = status->has_piece;
38
39 const double wrist_elevator_collision_max_angle =
40 has_piece ? kWristElevatorCollisionMaxAngle
41 : kWristElevatorCollisionMaxAngleWithoutObject;
Sabina Davis4b63ae52019-01-27 16:15:25 -080042
43 // Elevator is down, so the wrist can't be close to vertical.
44 if (elevator_position < kElevatorClearHeight) {
Tyler Chatowd180b252019-02-23 22:00:20 -080045 if (wrist_position < wrist_elevator_collision_max_angle &&
Sabina Davis4b63ae52019-01-27 16:15:25 -080046 wrist_position > kWristElevatorCollisionMinAngle) {
47 return true;
48 }
49 }
50
51 // Elevator is down so wrist can't go below horizontal in either direction.
52 if (elevator_position < kElevatorClearWristDownHeight) {
53 if (wrist_position > kWristMaxAngle) {
54 return true;
55 }
56 if (wrist_position < kWristMinAngle) {
57 return true;
58 }
59 }
60
61 // Elevator is down so the intake has to be at either extreme.
Austin Schuh0158e6a2019-02-17 15:02:26 -080062 if (elevator_position < kElevatorClearIntakeHeight &&
63 wrist_position > kWristMaxAngle) {
Sabina Davis4b63ae52019-01-27 16:15:25 -080064 if (intake_position < kIntakeOutAngle && intake_position > kIntakeInAngle) {
65 return true;
66 }
67 }
68
69 // Nothing is hitting, we must be good.
70 return false;
71}
72
73void CollisionAvoidance::UpdateGoal(
74 const SuperstructureQueue::Status *status,
75 const SuperstructureQueue::Goal *unsafe_goal) {
76 const double wrist_position = status->wrist.position;
77 const double elevator_position = status->elevator.position;
78 const double intake_position = status->intake.position;
Tyler Chatowd180b252019-02-23 22:00:20 -080079 const bool has_piece = status->has_piece;
Sabina Davis4b63ae52019-01-27 16:15:25 -080080
81 // Start with our constraints being wide open.
82 clear_max_wrist_goal();
83 clear_min_wrist_goal();
84 clear_max_intake_goal();
85 clear_min_intake_goal();
86
Tyler Chatowd180b252019-02-23 22:00:20 -080087 const double wrist_elevator_collision_max_angle =
88 has_piece ? kWristElevatorCollisionMaxAngle
89 : kWristElevatorCollisionMaxAngleWithoutObject;
90
Sabina Davis4b63ae52019-01-27 16:15:25 -080091 // If the elevator is low enough, we also can't transition the wrist.
92 if (elevator_position < kElevatorClearHeight) {
93 // Figure out which side the wrist is on and stay there.
Austin Schuh0158e6a2019-02-17 15:02:26 -080094 if (wrist_position < (2.0 * kWristElevatorCollisionMinAngle +
95 kWristElevatorCollisionMaxAngle) /
96 3.0) {
Sabina Davis4b63ae52019-01-27 16:15:25 -080097 update_max_wrist_goal(kWristElevatorCollisionMinAngle - kEpsWrist);
98 } else {
Tyler Chatowd180b252019-02-23 22:00:20 -080099 update_min_wrist_goal(wrist_elevator_collision_max_angle + kEpsWrist);
Sabina Davis4b63ae52019-01-27 16:15:25 -0800100 }
101 }
102
103 // If the elevator is too low, the wrist needs to be above the clearance
104 // angles to avoid crashing the frame.
105 if (elevator_position < kElevatorClearWristDownHeight) {
106 update_min_wrist_goal(kWristMinAngle + kEpsWrist);
107 update_max_wrist_goal(kWristMaxAngle - kEpsWrist);
108 }
109
110 constexpr double kIntakeMiddleAngle =
111 (kIntakeOutAngle + kIntakeInAngle) / 2.0;
112
113 // If the elevator is too low, the intake can't transition from in to out or
114 // back.
Austin Schuh0158e6a2019-02-17 15:02:26 -0800115 if (elevator_position < kElevatorClearIntakeHeight &&
Tyler Chatowd180b252019-02-23 22:00:20 -0800116 wrist_position > wrist_elevator_collision_max_angle) {
Sabina Davis4b63ae52019-01-27 16:15:25 -0800117 // Figure out if the intake is in our out and keep it there.
118 if (intake_position < kIntakeMiddleAngle) {
119 update_max_intake_goal(kIntakeInAngle - kEpsIntake);
120 } else {
121 update_min_intake_goal(kIntakeOutAngle + kEpsIntake);
122 }
123 }
124
125 // Start with an unconstrained elevator.
126 clear_min_elevator_goal();
127
128 // If the intake is within the collision range, don't let the elevator down.
Austin Schuh0158e6a2019-02-17 15:02:26 -0800129 if (intake_position > kIntakeInAngle && intake_position < kIntakeOutAngle &&
Tyler Chatowd180b252019-02-23 22:00:20 -0800130 wrist_position > wrist_elevator_collision_max_angle) {
Sabina Davis4b63ae52019-01-27 16:15:25 -0800131 update_min_elevator_goal(kElevatorClearIntakeHeight + kEps);
132 }
133
Austin Schuh0158e6a2019-02-17 15:02:26 -0800134 // If the intake is in the collision range and the elevator is down, don't let
135 // the wrist go far down.
136 if (intake_position > kIntakeInAngle && intake_position < kIntakeOutAngle &&
137 elevator_position < kElevatorClearIntakeHeight) {
138 update_max_wrist_goal(kWristMaxAngle - kEpsWrist);
139 }
140
Sabina Davis4b63ae52019-01-27 16:15:25 -0800141 // If the wrist is within the elevator collision range, don't let the elevator
142 // go down.
143 if (wrist_position > kWristElevatorCollisionMinAngle &&
Tyler Chatowd180b252019-02-23 22:00:20 -0800144 wrist_position < wrist_elevator_collision_max_angle) {
Sabina Davis4b63ae52019-01-27 16:15:25 -0800145 update_min_elevator_goal(kElevatorClearHeight + kEps);
146 }
147
148 // If the wrist is far enough down that we are going to hit the frame, don't
149 // let the elevator go too far down.
150 if (wrist_position > kWristMaxAngle || wrist_position < kWristMinAngle) {
151 update_min_elevator_goal(kElevatorClearWristDownHeight + kEps);
152 }
153
154 if (unsafe_goal) {
Theo Bafrali00e42272019-02-12 01:07:46 -0800155 const double wrist_goal = unsafe_goal->wrist.unsafe_goal;
156 const double intake_goal = unsafe_goal->intake.unsafe_goal;
Sabina Davis4b63ae52019-01-27 16:15:25 -0800157
158 // Compute if we need to move the intake.
159 const bool intake_needs_to_move = (intake_position < kIntakeMiddleAngle) ^
160 (intake_goal < kIntakeMiddleAngle);
161
162 // Compute if we need to move the wrist across 0.
163 const bool wrist_needs_to_move =
164 (wrist_position < 0.0) ^ (wrist_goal < 0.0);
165
166 // If we need to move the intake, we've got to shove the elevator up. The
167 // intake is already constrained so it can't hit anything until it's clear.
Austin Schuh0158e6a2019-02-17 15:02:26 -0800168 if (intake_needs_to_move &&
Tyler Chatowd180b252019-02-23 22:00:20 -0800169 wrist_position > wrist_elevator_collision_max_angle) {
Sabina Davis4b63ae52019-01-27 16:15:25 -0800170 update_min_elevator_goal(kElevatorClearIntakeHeight + kEps);
171 }
172 // If we need to move the wrist, we've got to shove the elevator up too. The
173 // wrist is already constrained so it can't hit anything until it's clear.
174 // If both the intake and wrist need to move, figure out which one will
175 // require the higher motion and move that.
176 if (wrist_needs_to_move) {
177 update_min_elevator_goal(kElevatorClearHeight + kEps);
178 }
179
180 // TODO(austin): We won't shove the elevator up if the wrist is asked to go
181 // down below horizontal. I think that's fine.
182 }
183}
184
185} // namespace superstructure
186} // namespace control_loops
187} // namespace y2019