blob: c52141b5b3de8aab078508bdd6d66794e5042972 [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
Stephan Pleinesf63bde82024-01-13 15:59:33 -080010namespace y2019::control_loops::superstructure {
Sabina Davis4b63ae52019-01-27 16:15:25 -080011
12constexpr double CollisionAvoidance::kElevatorClearHeight;
13constexpr double CollisionAvoidance::kElevatorClearWristDownHeight;
14constexpr double CollisionAvoidance::kElevatorClearIntakeHeight;
15constexpr double CollisionAvoidance::kWristMaxAngle;
16constexpr double CollisionAvoidance::kWristMinAngle;
17constexpr double CollisionAvoidance::kIntakeOutAngle;
18constexpr double CollisionAvoidance::kIntakeInAngle;
19constexpr double CollisionAvoidance::kWristElevatorCollisionMinAngle;
20constexpr double CollisionAvoidance::kWristElevatorCollisionMaxAngle;
Tyler Chatowd180b252019-02-23 22:00:20 -080021constexpr double
22 CollisionAvoidance::kWristElevatorCollisionMaxAngleWithoutObject;
Sabina Davis4b63ae52019-01-27 16:15:25 -080023constexpr double CollisionAvoidance::kEps;
24constexpr double CollisionAvoidance::kEpsIntake;
25constexpr double CollisionAvoidance::kEpsWrist;
26
27CollisionAvoidance::CollisionAvoidance() {
28 clear_min_wrist_goal();
29 clear_max_wrist_goal();
30 clear_min_elevator_goal();
31 clear_min_intake_goal();
32 clear_max_intake_goal();
33}
34
Alex Perrycb7da4b2019-08-28 19:35:56 -070035bool CollisionAvoidance::IsCollided(const Status *status) {
36 return IsCollided(status->wrist()->position(), status->elevator()->position(),
37 status->intake()->position(), status->has_piece());
Austin Schuh9fe68f72019-08-10 19:32:03 -070038}
Tyler Chatowd180b252019-02-23 22:00:20 -080039
Austin Schuh9fe68f72019-08-10 19:32:03 -070040bool CollisionAvoidance::IsCollided(const double wrist_position,
41 const double elevator_position,
42 const double intake_position,
43 const bool has_piece) {
Tyler Chatowd180b252019-02-23 22:00:20 -080044 const double wrist_elevator_collision_max_angle =
45 has_piece ? kWristElevatorCollisionMaxAngle
46 : kWristElevatorCollisionMaxAngleWithoutObject;
Sabina Davis4b63ae52019-01-27 16:15:25 -080047
48 // Elevator is down, so the wrist can't be close to vertical.
49 if (elevator_position < kElevatorClearHeight) {
Tyler Chatowd180b252019-02-23 22:00:20 -080050 if (wrist_position < wrist_elevator_collision_max_angle &&
Sabina Davis4b63ae52019-01-27 16:15:25 -080051 wrist_position > kWristElevatorCollisionMinAngle) {
52 return true;
53 }
54 }
55
56 // Elevator is down so wrist can't go below horizontal in either direction.
57 if (elevator_position < kElevatorClearWristDownHeight) {
58 if (wrist_position > kWristMaxAngle) {
59 return true;
60 }
61 if (wrist_position < kWristMinAngle) {
62 return true;
63 }
64 }
65
66 // Elevator is down so the intake has to be at either extreme.
Austin Schuh0158e6a2019-02-17 15:02:26 -080067 if (elevator_position < kElevatorClearIntakeHeight &&
68 wrist_position > kWristMaxAngle) {
Sabina Davis4b63ae52019-01-27 16:15:25 -080069 if (intake_position < kIntakeOutAngle && intake_position > kIntakeInAngle) {
70 return true;
71 }
72 }
73
74 // Nothing is hitting, we must be good.
75 return false;
76}
77
Alex Perrycb7da4b2019-08-28 19:35:56 -070078void CollisionAvoidance::UpdateGoal(const Status *status,
79 const Goal *unsafe_goal) {
80 const double wrist_position = status->wrist()->position();
81 const double elevator_position = status->elevator()->position();
82 const double intake_position = status->intake()->position();
83 const bool has_piece = status->has_piece();
Sabina Davis4b63ae52019-01-27 16:15:25 -080084
85 // Start with our constraints being wide open.
86 clear_max_wrist_goal();
87 clear_min_wrist_goal();
88 clear_max_intake_goal();
89 clear_min_intake_goal();
90
Tyler Chatowd180b252019-02-23 22:00:20 -080091 const double wrist_elevator_collision_max_angle =
92 has_piece ? kWristElevatorCollisionMaxAngle
93 : kWristElevatorCollisionMaxAngleWithoutObject;
94
Sabina Davis4b63ae52019-01-27 16:15:25 -080095 // If the elevator is low enough, we also can't transition the wrist.
96 if (elevator_position < kElevatorClearHeight) {
97 // Figure out which side the wrist is on and stay there.
Austin Schuh0158e6a2019-02-17 15:02:26 -080098 if (wrist_position < (2.0 * kWristElevatorCollisionMinAngle +
99 kWristElevatorCollisionMaxAngle) /
100 3.0) {
Sabina Davis4b63ae52019-01-27 16:15:25 -0800101 update_max_wrist_goal(kWristElevatorCollisionMinAngle - kEpsWrist);
102 } else {
Tyler Chatowd180b252019-02-23 22:00:20 -0800103 update_min_wrist_goal(wrist_elevator_collision_max_angle + kEpsWrist);
Sabina Davis4b63ae52019-01-27 16:15:25 -0800104 }
105 }
106
107 // If the elevator is too low, the wrist needs to be above the clearance
108 // angles to avoid crashing the frame.
109 if (elevator_position < kElevatorClearWristDownHeight) {
110 update_min_wrist_goal(kWristMinAngle + kEpsWrist);
111 update_max_wrist_goal(kWristMaxAngle - kEpsWrist);
112 }
113
114 constexpr double kIntakeMiddleAngle =
115 (kIntakeOutAngle + kIntakeInAngle) / 2.0;
116
117 // If the elevator is too low, the intake can't transition from in to out or
118 // back.
Austin Schuh0158e6a2019-02-17 15:02:26 -0800119 if (elevator_position < kElevatorClearIntakeHeight &&
Tyler Chatowd180b252019-02-23 22:00:20 -0800120 wrist_position > wrist_elevator_collision_max_angle) {
Sabina Davis4b63ae52019-01-27 16:15:25 -0800121 // Figure out if the intake is in our out and keep it there.
122 if (intake_position < kIntakeMiddleAngle) {
123 update_max_intake_goal(kIntakeInAngle - kEpsIntake);
124 } else {
125 update_min_intake_goal(kIntakeOutAngle + kEpsIntake);
126 }
127 }
128
129 // Start with an unconstrained elevator.
130 clear_min_elevator_goal();
131
132 // If the intake is within the collision range, don't let the elevator down.
Austin Schuh0158e6a2019-02-17 15:02:26 -0800133 if (intake_position > kIntakeInAngle && intake_position < kIntakeOutAngle &&
Tyler Chatowd180b252019-02-23 22:00:20 -0800134 wrist_position > wrist_elevator_collision_max_angle) {
Sabina Davis4b63ae52019-01-27 16:15:25 -0800135 update_min_elevator_goal(kElevatorClearIntakeHeight + kEps);
136 }
137
Austin Schuh0158e6a2019-02-17 15:02:26 -0800138 // If the intake is in the collision range and the elevator is down, don't let
139 // the wrist go far down.
140 if (intake_position > kIntakeInAngle && intake_position < kIntakeOutAngle &&
141 elevator_position < kElevatorClearIntakeHeight) {
142 update_max_wrist_goal(kWristMaxAngle - kEpsWrist);
143 }
144
Sabina Davis4b63ae52019-01-27 16:15:25 -0800145 // If the wrist is within the elevator collision range, don't let the elevator
146 // go down.
147 if (wrist_position > kWristElevatorCollisionMinAngle &&
Tyler Chatowd180b252019-02-23 22:00:20 -0800148 wrist_position < wrist_elevator_collision_max_angle) {
Sabina Davis4b63ae52019-01-27 16:15:25 -0800149 update_min_elevator_goal(kElevatorClearHeight + kEps);
150 }
151
152 // If the wrist is far enough down that we are going to hit the frame, don't
153 // let the elevator go too far down.
154 if (wrist_position > kWristMaxAngle || wrist_position < kWristMinAngle) {
155 update_min_elevator_goal(kElevatorClearWristDownHeight + kEps);
156 }
157
158 if (unsafe_goal) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700159 const double wrist_goal = unsafe_goal->wrist()->unsafe_goal();
160 const double intake_goal = unsafe_goal->intake()->unsafe_goal();
Sabina Davis4b63ae52019-01-27 16:15:25 -0800161
162 // Compute if we need to move the intake.
163 const bool intake_needs_to_move = (intake_position < kIntakeMiddleAngle) ^
164 (intake_goal < kIntakeMiddleAngle);
165
166 // Compute if we need to move the wrist across 0.
167 const bool wrist_needs_to_move =
168 (wrist_position < 0.0) ^ (wrist_goal < 0.0);
169
170 // If we need to move the intake, we've got to shove the elevator up. The
171 // intake is already constrained so it can't hit anything until it's clear.
Austin Schuh0158e6a2019-02-17 15:02:26 -0800172 if (intake_needs_to_move &&
Tyler Chatowd180b252019-02-23 22:00:20 -0800173 wrist_position > wrist_elevator_collision_max_angle) {
Sabina Davis4b63ae52019-01-27 16:15:25 -0800174 update_min_elevator_goal(kElevatorClearIntakeHeight + kEps);
175 }
176 // If we need to move the wrist, we've got to shove the elevator up too. The
177 // wrist is already constrained so it can't hit anything until it's clear.
178 // If both the intake and wrist need to move, figure out which one will
179 // require the higher motion and move that.
180 if (wrist_needs_to_move) {
181 update_min_elevator_goal(kElevatorClearHeight + kEps);
182 }
183
184 // TODO(austin): We won't shove the elevator up if the wrist is asked to go
185 // down below horizontal. I think that's fine.
186 }
187}
188
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800189} // namespace y2019::control_loops::superstructure