blob: c999cacdea944c016ccb356cc2a4f9e3b44fb66d [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;
19constexpr double CollisionAvoidance::kEps;
20constexpr double CollisionAvoidance::kEpsIntake;
21constexpr double CollisionAvoidance::kEpsWrist;
22
23CollisionAvoidance::CollisionAvoidance() {
24 clear_min_wrist_goal();
25 clear_max_wrist_goal();
26 clear_min_elevator_goal();
27 clear_min_intake_goal();
28 clear_max_intake_goal();
29}
30
31bool CollisionAvoidance::IsCollided(const SuperstructureQueue::Status *status) {
32 const double wrist_position = status->wrist.position;
33 const double elevator_position = status->elevator.position;
34 const double intake_position = status->intake.position;
35
36 // Elevator is down, so the wrist can't be close to vertical.
37 if (elevator_position < kElevatorClearHeight) {
38 if (wrist_position < kWristElevatorCollisionMaxAngle &&
39 wrist_position > kWristElevatorCollisionMinAngle) {
40 return true;
41 }
42 }
43
44 // Elevator is down so wrist can't go below horizontal in either direction.
45 if (elevator_position < kElevatorClearWristDownHeight) {
46 if (wrist_position > kWristMaxAngle) {
47 return true;
48 }
49 if (wrist_position < kWristMinAngle) {
50 return true;
51 }
52 }
53
54 // Elevator is down so the intake has to be at either extreme.
Austin Schuh0158e6a2019-02-17 15:02:26 -080055 if (elevator_position < kElevatorClearIntakeHeight &&
56 wrist_position > kWristMaxAngle) {
Sabina Davis4b63ae52019-01-27 16:15:25 -080057 if (intake_position < kIntakeOutAngle && intake_position > kIntakeInAngle) {
58 return true;
59 }
60 }
61
62 // Nothing is hitting, we must be good.
63 return false;
64}
65
66void CollisionAvoidance::UpdateGoal(
67 const SuperstructureQueue::Status *status,
68 const SuperstructureQueue::Goal *unsafe_goal) {
69 const double wrist_position = status->wrist.position;
70 const double elevator_position = status->elevator.position;
71 const double intake_position = status->intake.position;
72
73 // Start with our constraints being wide open.
74 clear_max_wrist_goal();
75 clear_min_wrist_goal();
76 clear_max_intake_goal();
77 clear_min_intake_goal();
78
79 // If the elevator is low enough, we also can't transition the wrist.
80 if (elevator_position < kElevatorClearHeight) {
81 // Figure out which side the wrist is on and stay there.
Austin Schuh0158e6a2019-02-17 15:02:26 -080082 if (wrist_position < (2.0 * kWristElevatorCollisionMinAngle +
83 kWristElevatorCollisionMaxAngle) /
84 3.0) {
Sabina Davis4b63ae52019-01-27 16:15:25 -080085 update_max_wrist_goal(kWristElevatorCollisionMinAngle - kEpsWrist);
86 } else {
87 update_min_wrist_goal(kWristElevatorCollisionMaxAngle + kEpsWrist);
88 }
89 }
90
91 // If the elevator is too low, the wrist needs to be above the clearance
92 // angles to avoid crashing the frame.
93 if (elevator_position < kElevatorClearWristDownHeight) {
94 update_min_wrist_goal(kWristMinAngle + kEpsWrist);
95 update_max_wrist_goal(kWristMaxAngle - kEpsWrist);
96 }
97
98 constexpr double kIntakeMiddleAngle =
99 (kIntakeOutAngle + kIntakeInAngle) / 2.0;
100
101 // If the elevator is too low, the intake can't transition from in to out or
102 // back.
Austin Schuh0158e6a2019-02-17 15:02:26 -0800103 if (elevator_position < kElevatorClearIntakeHeight &&
104 wrist_position > kWristElevatorCollisionMaxAngle) {
Sabina Davis4b63ae52019-01-27 16:15:25 -0800105 // Figure out if the intake is in our out and keep it there.
106 if (intake_position < kIntakeMiddleAngle) {
107 update_max_intake_goal(kIntakeInAngle - kEpsIntake);
108 } else {
109 update_min_intake_goal(kIntakeOutAngle + kEpsIntake);
110 }
111 }
112
113 // Start with an unconstrained elevator.
114 clear_min_elevator_goal();
115
116 // If the intake is within the collision range, don't let the elevator down.
Austin Schuh0158e6a2019-02-17 15:02:26 -0800117 if (intake_position > kIntakeInAngle && intake_position < kIntakeOutAngle &&
118 wrist_position > kWristElevatorCollisionMaxAngle) {
Sabina Davis4b63ae52019-01-27 16:15:25 -0800119 update_min_elevator_goal(kElevatorClearIntakeHeight + kEps);
120 }
121
Austin Schuh0158e6a2019-02-17 15:02:26 -0800122 // If the intake is in the collision range and the elevator is down, don't let
123 // the wrist go far down.
124 if (intake_position > kIntakeInAngle && intake_position < kIntakeOutAngle &&
125 elevator_position < kElevatorClearIntakeHeight) {
126 update_max_wrist_goal(kWristMaxAngle - kEpsWrist);
127 }
128
Sabina Davis4b63ae52019-01-27 16:15:25 -0800129 // If the wrist is within the elevator collision range, don't let the elevator
130 // go down.
131 if (wrist_position > kWristElevatorCollisionMinAngle &&
132 wrist_position < kWristElevatorCollisionMaxAngle) {
133 update_min_elevator_goal(kElevatorClearHeight + kEps);
134 }
135
136 // If the wrist is far enough down that we are going to hit the frame, don't
137 // let the elevator go too far down.
138 if (wrist_position > kWristMaxAngle || wrist_position < kWristMinAngle) {
139 update_min_elevator_goal(kElevatorClearWristDownHeight + kEps);
140 }
141
142 if (unsafe_goal) {
Theo Bafrali00e42272019-02-12 01:07:46 -0800143 const double wrist_goal = unsafe_goal->wrist.unsafe_goal;
144 const double intake_goal = unsafe_goal->intake.unsafe_goal;
Sabina Davis4b63ae52019-01-27 16:15:25 -0800145
146 // Compute if we need to move the intake.
147 const bool intake_needs_to_move = (intake_position < kIntakeMiddleAngle) ^
148 (intake_goal < kIntakeMiddleAngle);
149
150 // Compute if we need to move the wrist across 0.
151 const bool wrist_needs_to_move =
152 (wrist_position < 0.0) ^ (wrist_goal < 0.0);
153
154 // If we need to move the intake, we've got to shove the elevator up. The
155 // intake is already constrained so it can't hit anything until it's clear.
Austin Schuh0158e6a2019-02-17 15:02:26 -0800156 if (intake_needs_to_move &&
157 wrist_position > kWristElevatorCollisionMaxAngle) {
Sabina Davis4b63ae52019-01-27 16:15:25 -0800158 update_min_elevator_goal(kElevatorClearIntakeHeight + kEps);
159 }
160 // If we need to move the wrist, we've got to shove the elevator up too. The
161 // wrist is already constrained so it can't hit anything until it's clear.
162 // If both the intake and wrist need to move, figure out which one will
163 // require the higher motion and move that.
164 if (wrist_needs_to_move) {
165 update_min_elevator_goal(kElevatorClearHeight + kEps);
166 }
167
168 // TODO(austin): We won't shove the elevator up if the wrist is asked to go
169 // down below horizontal. I think that's fine.
170 }
171}
172
173} // namespace superstructure
174} // namespace control_loops
175} // namespace y2019