blob: eb5b59130c86937650f252a6110860948174b944 [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) {
Austin Schuh9fe68f72019-08-10 19:32:03 -070034 return IsCollided(status->wrist.position, status->elevator.position,
35 status->intake.position, status->has_piece);
36}
Tyler Chatowd180b252019-02-23 22:00:20 -080037
Austin Schuh9fe68f72019-08-10 19:32:03 -070038bool CollisionAvoidance::IsCollided(const double wrist_position,
39 const double elevator_position,
40 const double intake_position,
41 const bool has_piece) {
Tyler Chatowd180b252019-02-23 22:00:20 -080042 const double wrist_elevator_collision_max_angle =
43 has_piece ? kWristElevatorCollisionMaxAngle
44 : kWristElevatorCollisionMaxAngleWithoutObject;
Sabina Davis4b63ae52019-01-27 16:15:25 -080045
46 // Elevator is down, so the wrist can't be close to vertical.
47 if (elevator_position < kElevatorClearHeight) {
Tyler Chatowd180b252019-02-23 22:00:20 -080048 if (wrist_position < wrist_elevator_collision_max_angle &&
Sabina Davis4b63ae52019-01-27 16:15:25 -080049 wrist_position > kWristElevatorCollisionMinAngle) {
50 return true;
51 }
52 }
53
54 // Elevator is down so wrist can't go below horizontal in either direction.
55 if (elevator_position < kElevatorClearWristDownHeight) {
56 if (wrist_position > kWristMaxAngle) {
57 return true;
58 }
59 if (wrist_position < kWristMinAngle) {
60 return true;
61 }
62 }
63
64 // Elevator is down so the intake has to be at either extreme.
Austin Schuh0158e6a2019-02-17 15:02:26 -080065 if (elevator_position < kElevatorClearIntakeHeight &&
66 wrist_position > kWristMaxAngle) {
Sabina Davis4b63ae52019-01-27 16:15:25 -080067 if (intake_position < kIntakeOutAngle && intake_position > kIntakeInAngle) {
68 return true;
69 }
70 }
71
72 // Nothing is hitting, we must be good.
73 return false;
74}
75
76void CollisionAvoidance::UpdateGoal(
77 const SuperstructureQueue::Status *status,
78 const SuperstructureQueue::Goal *unsafe_goal) {
79 const double wrist_position = status->wrist.position;
80 const double elevator_position = status->elevator.position;
81 const double intake_position = status->intake.position;
Tyler Chatowd180b252019-02-23 22:00:20 -080082 const bool has_piece = status->has_piece;
Sabina Davis4b63ae52019-01-27 16:15:25 -080083
84 // Start with our constraints being wide open.
85 clear_max_wrist_goal();
86 clear_min_wrist_goal();
87 clear_max_intake_goal();
88 clear_min_intake_goal();
89
Tyler Chatowd180b252019-02-23 22:00:20 -080090 const double wrist_elevator_collision_max_angle =
91 has_piece ? kWristElevatorCollisionMaxAngle
92 : kWristElevatorCollisionMaxAngleWithoutObject;
93
Sabina Davis4b63ae52019-01-27 16:15:25 -080094 // If the elevator is low enough, we also can't transition the wrist.
95 if (elevator_position < kElevatorClearHeight) {
96 // Figure out which side the wrist is on and stay there.
Austin Schuh0158e6a2019-02-17 15:02:26 -080097 if (wrist_position < (2.0 * kWristElevatorCollisionMinAngle +
98 kWristElevatorCollisionMaxAngle) /
99 3.0) {
Sabina Davis4b63ae52019-01-27 16:15:25 -0800100 update_max_wrist_goal(kWristElevatorCollisionMinAngle - kEpsWrist);
101 } else {
Tyler Chatowd180b252019-02-23 22:00:20 -0800102 update_min_wrist_goal(wrist_elevator_collision_max_angle + kEpsWrist);
Sabina Davis4b63ae52019-01-27 16:15:25 -0800103 }
104 }
105
106 // If the elevator is too low, the wrist needs to be above the clearance
107 // angles to avoid crashing the frame.
108 if (elevator_position < kElevatorClearWristDownHeight) {
109 update_min_wrist_goal(kWristMinAngle + kEpsWrist);
110 update_max_wrist_goal(kWristMaxAngle - kEpsWrist);
111 }
112
113 constexpr double kIntakeMiddleAngle =
114 (kIntakeOutAngle + kIntakeInAngle) / 2.0;
115
116 // If the elevator is too low, the intake can't transition from in to out or
117 // back.
Austin Schuh0158e6a2019-02-17 15:02:26 -0800118 if (elevator_position < kElevatorClearIntakeHeight &&
Tyler Chatowd180b252019-02-23 22:00:20 -0800119 wrist_position > wrist_elevator_collision_max_angle) {
Sabina Davis4b63ae52019-01-27 16:15:25 -0800120 // Figure out if the intake is in our out and keep it there.
121 if (intake_position < kIntakeMiddleAngle) {
122 update_max_intake_goal(kIntakeInAngle - kEpsIntake);
123 } else {
124 update_min_intake_goal(kIntakeOutAngle + kEpsIntake);
125 }
126 }
127
128 // Start with an unconstrained elevator.
129 clear_min_elevator_goal();
130
131 // If the intake is within the collision range, don't let the elevator down.
Austin Schuh0158e6a2019-02-17 15:02:26 -0800132 if (intake_position > kIntakeInAngle && intake_position < kIntakeOutAngle &&
Tyler Chatowd180b252019-02-23 22:00:20 -0800133 wrist_position > wrist_elevator_collision_max_angle) {
Sabina Davis4b63ae52019-01-27 16:15:25 -0800134 update_min_elevator_goal(kElevatorClearIntakeHeight + kEps);
135 }
136
Austin Schuh0158e6a2019-02-17 15:02:26 -0800137 // If the intake is in the collision range and the elevator is down, don't let
138 // the wrist go far down.
139 if (intake_position > kIntakeInAngle && intake_position < kIntakeOutAngle &&
140 elevator_position < kElevatorClearIntakeHeight) {
141 update_max_wrist_goal(kWristMaxAngle - kEpsWrist);
142 }
143
Sabina Davis4b63ae52019-01-27 16:15:25 -0800144 // If the wrist is within the elevator collision range, don't let the elevator
145 // go down.
146 if (wrist_position > kWristElevatorCollisionMinAngle &&
Tyler Chatowd180b252019-02-23 22:00:20 -0800147 wrist_position < wrist_elevator_collision_max_angle) {
Sabina Davis4b63ae52019-01-27 16:15:25 -0800148 update_min_elevator_goal(kElevatorClearHeight + kEps);
149 }
150
151 // If the wrist is far enough down that we are going to hit the frame, don't
152 // let the elevator go too far down.
153 if (wrist_position > kWristMaxAngle || wrist_position < kWristMinAngle) {
154 update_min_elevator_goal(kElevatorClearWristDownHeight + kEps);
155 }
156
157 if (unsafe_goal) {
Theo Bafrali00e42272019-02-12 01:07:46 -0800158 const double wrist_goal = unsafe_goal->wrist.unsafe_goal;
159 const double intake_goal = unsafe_goal->intake.unsafe_goal;
Sabina Davis4b63ae52019-01-27 16:15:25 -0800160
161 // Compute if we need to move the intake.
162 const bool intake_needs_to_move = (intake_position < kIntakeMiddleAngle) ^
163 (intake_goal < kIntakeMiddleAngle);
164
165 // Compute if we need to move the wrist across 0.
166 const bool wrist_needs_to_move =
167 (wrist_position < 0.0) ^ (wrist_goal < 0.0);
168
169 // If we need to move the intake, we've got to shove the elevator up. The
170 // intake is already constrained so it can't hit anything until it's clear.
Austin Schuh0158e6a2019-02-17 15:02:26 -0800171 if (intake_needs_to_move &&
Tyler Chatowd180b252019-02-23 22:00:20 -0800172 wrist_position > wrist_elevator_collision_max_angle) {
Sabina Davis4b63ae52019-01-27 16:15:25 -0800173 update_min_elevator_goal(kElevatorClearIntakeHeight + kEps);
174 }
175 // If we need to move the wrist, we've got to shove the elevator up too. The
176 // wrist is already constrained so it can't hit anything until it's clear.
177 // If both the intake and wrist need to move, figure out which one will
178 // require the higher motion and move that.
179 if (wrist_needs_to_move) {
180 update_min_elevator_goal(kElevatorClearHeight + kEps);
181 }
182
183 // TODO(austin): We won't shove the elevator up if the wrist is asked to go
184 // down below horizontal. I think that's fine.
185 }
186}
187
188} // namespace superstructure
189} // namespace control_loops
190} // namespace y2019