blob: 7a26b90d8a5a696ec9c88f1db45b86dcfd872133 [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.
55 if (elevator_position < kElevatorClearIntakeHeight) {
56 if (intake_position < kIntakeOutAngle && intake_position > kIntakeInAngle) {
57 return true;
58 }
59 }
60
61 // Nothing is hitting, we must be good.
62 return false;
63}
64
65void CollisionAvoidance::UpdateGoal(
66 const SuperstructureQueue::Status *status,
67 const SuperstructureQueue::Goal *unsafe_goal) {
68 const double wrist_position = status->wrist.position;
69 const double elevator_position = status->elevator.position;
70 const double intake_position = status->intake.position;
71
72 // Start with our constraints being wide open.
73 clear_max_wrist_goal();
74 clear_min_wrist_goal();
75 clear_max_intake_goal();
76 clear_min_intake_goal();
77
78 // If the elevator is low enough, we also can't transition the wrist.
79 if (elevator_position < kElevatorClearHeight) {
80 // Figure out which side the wrist is on and stay there.
81 if (wrist_position < 0.0) {
82 update_max_wrist_goal(kWristElevatorCollisionMinAngle - kEpsWrist);
83 } else {
84 update_min_wrist_goal(kWristElevatorCollisionMaxAngle + kEpsWrist);
85 }
86 }
87
88 // If the elevator is too low, the wrist needs to be above the clearance
89 // angles to avoid crashing the frame.
90 if (elevator_position < kElevatorClearWristDownHeight) {
91 update_min_wrist_goal(kWristMinAngle + kEpsWrist);
92 update_max_wrist_goal(kWristMaxAngle - kEpsWrist);
93 }
94
95 constexpr double kIntakeMiddleAngle =
96 (kIntakeOutAngle + kIntakeInAngle) / 2.0;
97
98 // If the elevator is too low, the intake can't transition from in to out or
99 // back.
100 if (elevator_position < kElevatorClearIntakeHeight) {
101 // Figure out if the intake is in our out and keep it there.
102 if (intake_position < kIntakeMiddleAngle) {
103 update_max_intake_goal(kIntakeInAngle - kEpsIntake);
104 } else {
105 update_min_intake_goal(kIntakeOutAngle + kEpsIntake);
106 }
107 }
108
109 // Start with an unconstrained elevator.
110 clear_min_elevator_goal();
111
112 // If the intake is within the collision range, don't let the elevator down.
113 if (intake_position > kIntakeInAngle && intake_position < kIntakeOutAngle) {
114 update_min_elevator_goal(kElevatorClearIntakeHeight + kEps);
115 }
116
117 // If the wrist is within the elevator collision range, don't let the elevator
118 // go down.
119 if (wrist_position > kWristElevatorCollisionMinAngle &&
120 wrist_position < kWristElevatorCollisionMaxAngle) {
121 update_min_elevator_goal(kElevatorClearHeight + kEps);
122 }
123
124 // If the wrist is far enough down that we are going to hit the frame, don't
125 // let the elevator go too far down.
126 if (wrist_position > kWristMaxAngle || wrist_position < kWristMinAngle) {
127 update_min_elevator_goal(kElevatorClearWristDownHeight + kEps);
128 }
129
130 if (unsafe_goal) {
131 const double wrist_goal = unsafe_goal->wrist.angle;
132 const double intake_goal = unsafe_goal->intake.joint_angle;
133
134 // Compute if we need to move the intake.
135 const bool intake_needs_to_move = (intake_position < kIntakeMiddleAngle) ^
136 (intake_goal < kIntakeMiddleAngle);
137
138 // Compute if we need to move the wrist across 0.
139 const bool wrist_needs_to_move =
140 (wrist_position < 0.0) ^ (wrist_goal < 0.0);
141
142 // If we need to move the intake, we've got to shove the elevator up. The
143 // intake is already constrained so it can't hit anything until it's clear.
144 if (intake_needs_to_move && wrist_position > 0) {
145 update_min_elevator_goal(kElevatorClearIntakeHeight + kEps);
146 }
147 // If we need to move the wrist, we've got to shove the elevator up too. The
148 // wrist is already constrained so it can't hit anything until it's clear.
149 // If both the intake and wrist need to move, figure out which one will
150 // require the higher motion and move that.
151 if (wrist_needs_to_move) {
152 update_min_elevator_goal(kElevatorClearHeight + kEps);
153 }
154
155 // TODO(austin): We won't shove the elevator up if the wrist is asked to go
156 // down below horizontal. I think that's fine.
157 }
158}
159
160} // namespace superstructure
161} // namespace control_loops
162} // namespace y2019