blob: 9474b6d7f1664793f59aa6cf47cbc86049abe8fb [file] [log] [blame]
Sabina Davis8d20ca82018-02-19 13:17:45 -08001#include "y2018/control_loops/superstructure/superstructure.h"
2
Neil Balchba9cbba2018-04-06 22:26:38 -07003#include <chrono>
4
John Park33858a32018-09-28 23:05:48 -07005#include "aos/controls/control_loops.q.h"
6#include "aos/logging/logging.h"
Sabina Davis8d20ca82018-02-19 13:17:45 -08007#include "frc971/control_loops/control_loops.q.h"
Austin Schuh8d5fff42018-05-30 20:44:12 -07008#include "frc971/control_loops/drivetrain/drivetrain.q.h"
Sabina Davis8d20ca82018-02-19 13:17:45 -08009#include "y2018/constants.h"
10#include "y2018/control_loops/superstructure/intake/intake.h"
Austin Schuh8d5fff42018-05-30 20:44:12 -070011#include "y2018/status_light.q.h"
12#include "y2018/vision/vision.q.h"
Sabina Davis8d20ca82018-02-19 13:17:45 -080013
14namespace y2018 {
15namespace control_loops {
16namespace superstructure {
17
Neil Balchba9cbba2018-04-06 22:26:38 -070018using ::aos::monotonic_clock;
19
20namespace chrono = ::std::chrono;
21
Sabina Davis8d20ca82018-02-19 13:17:45 -080022namespace {
23// The maximum voltage the intake roller will be allowed to use.
24constexpr double kMaxIntakeRollerVoltage = 12.0;
25} // namespace
26
Austin Schuh8d5fff42018-05-30 20:44:12 -070027void SendColors(float red, float green, float blue) {
28 auto new_status_light = status_light.MakeMessage();
29 new_status_light->red = red;
30 new_status_light->green = green;
31 new_status_light->blue = blue;
32
33 if (!new_status_light.Send()) {
34 LOG(ERROR, "Failed to send lights.\n");
35 }
36}
37
Austin Schuh55a13dc2019-01-27 22:39:03 -080038Superstructure::Superstructure(::aos::EventLoop *event_loop,
39 const ::std::string &name)
40 : aos::controls::ControlLoop<control_loops::SuperstructureQueue>(event_loop,
41 name),
Sabina Davis8d20ca82018-02-19 13:17:45 -080042 intake_left_(constants::GetValues().left_intake.zeroing),
43 intake_right_(constants::GetValues().right_intake.zeroing) {}
44
45void Superstructure::RunIteration(
46 const control_loops::SuperstructureQueue::Goal *unsafe_goal,
47 const control_loops::SuperstructureQueue::Position *position,
48 control_loops::SuperstructureQueue::Output *output,
49 control_loops::SuperstructureQueue::Status *status) {
50 if (WasReset()) {
51 LOG(ERROR, "WPILib reset, restarting\n");
52 intake_left_.Reset();
53 intake_right_.Reset();
Austin Schuhcb091712018-02-21 20:01:55 -080054 arm_.Reset();
Sabina Davis8d20ca82018-02-19 13:17:45 -080055 }
56
Neil Balchba9cbba2018-04-06 22:26:38 -070057 const double clipped_box_distance =
58 ::std::min(1.0, ::std::max(0.0, position->box_distance));
59
60 const double box_velocity =
61 (clipped_box_distance - last_box_distance_) / 0.005;
62
63 constexpr double kFilteredBoxVelocityAlpha = 0.02;
64 filtered_box_velocity_ =
65 box_velocity * kFilteredBoxVelocityAlpha +
66 (1.0 - kFilteredBoxVelocityAlpha) * filtered_box_velocity_;
67 status->filtered_box_velocity = filtered_box_velocity_;
68
69 constexpr double kCenteringAngleGain = 0.0;
70 const double left_intake_goal =
71 ::std::min(
72 arm_.max_intake_override(),
73 (unsafe_goal == nullptr ? 0.0
74 : unsafe_goal->intake.left_intake_angle)) +
75 last_intake_center_error_ * kCenteringAngleGain;
76 const double right_intake_goal =
77 ::std::min(
78 arm_.max_intake_override(),
79 (unsafe_goal == nullptr ? 0.0
80 : unsafe_goal->intake.right_intake_angle)) -
81 last_intake_center_error_ * kCenteringAngleGain;
Austin Schuh83cdd8a2018-03-21 20:49:02 -070082
Austin Schuh96341532018-03-09 21:17:24 -080083 intake_left_.Iterate(unsafe_goal != nullptr ? &(left_intake_goal) : nullptr,
Sabina Daviscfb872f2018-02-25 16:28:20 -080084 &(position->left_intake),
85 output != nullptr ? &(output->left_intake) : nullptr,
Sabina Davis8d20ca82018-02-19 13:17:45 -080086 &(status->left_intake));
87
Austin Schuh96341532018-03-09 21:17:24 -080088 intake_right_.Iterate(unsafe_goal != nullptr ? &(right_intake_goal) : nullptr,
Sabina Daviscfb872f2018-02-25 16:28:20 -080089 &(position->right_intake),
90 output != nullptr ? &(output->right_intake) : nullptr,
Sabina Davis8d20ca82018-02-19 13:17:45 -080091 &(status->right_intake));
92
Neil Balchba9cbba2018-04-06 22:26:38 -070093 const double intake_center_error =
94 intake_right_.output_position() - intake_left_.output_position();
95 last_intake_center_error_ = intake_center_error;
96
Austin Schuh96341532018-03-09 21:17:24 -080097 const bool intake_clear_of_box =
98 intake_left_.clear_of_box() && intake_right_.clear_of_box();
Austin Schuhd76546a2018-07-08 16:05:14 -070099
100 bool open_claw = unsafe_goal != nullptr ? unsafe_goal->open_claw : false;
101 if (unsafe_goal) {
102 if (unsafe_goal->open_threshold != 0.0) {
103 if (arm_.current_node() != unsafe_goal->arm_goal_position ||
104 arm_.path_distance_to_go() > unsafe_goal->open_threshold) {
105 open_claw = false;
106 }
107 }
108 }
Austin Schuhcb091712018-02-21 20:01:55 -0800109 arm_.Iterate(
110 unsafe_goal != nullptr ? &(unsafe_goal->arm_goal_position) : nullptr,
Austin Schuhd76546a2018-07-08 16:05:14 -0700111 unsafe_goal != nullptr ? unsafe_goal->grab_box : false, open_claw,
Neil Balchba9cbba2018-04-06 22:26:38 -0700112 unsafe_goal != nullptr ? unsafe_goal->close_claw : false,
113 &(position->arm), position->claw_beambreak_triggered,
Austin Schuh96341532018-03-09 21:17:24 -0800114 position->box_back_beambreak_triggered, intake_clear_of_box,
Austin Schuhd76546a2018-07-08 16:05:14 -0700115 unsafe_goal != nullptr ? unsafe_goal->voltage_winch > 1.0 : false,
116 unsafe_goal != nullptr ? unsafe_goal->trajectory_override : false,
Austin Schuhcb091712018-02-21 20:01:55 -0800117 output != nullptr ? &(output->voltage_proximal) : nullptr,
118 output != nullptr ? &(output->voltage_distal) : nullptr,
119 output != nullptr ? &(output->release_arm_brake) : nullptr,
Austin Schuhd76546a2018-07-08 16:05:14 -0700120 output != nullptr ? &(output->claw_grabbed) : nullptr, &(status->arm));
Austin Schuh17e484e2018-03-11 01:11:36 -0800121
122 if (output) {
123 if (unsafe_goal) {
124 output->hook_release = unsafe_goal->hook_release;
125 output->voltage_winch = unsafe_goal->voltage_winch;
126 output->forks_release = unsafe_goal->deploy_fork;
127 } else {
128 output->voltage_winch = 0.0;
129 output->hook_release = false;
130 output->forks_release = false;
131 }
132 }
Austin Schuhcb091712018-02-21 20:01:55 -0800133
134 status->estopped = status->left_intake.estopped ||
135 status->right_intake.estopped || status->arm.estopped;
136
137 status->zeroed = status->left_intake.zeroed && status->right_intake.zeroed &&
138 status->arm.zeroed;
Sabina Davis8d20ca82018-02-19 13:17:45 -0800139
140 if (output && unsafe_goal) {
Austin Schuh96341532018-03-09 21:17:24 -0800141 double roller_voltage = ::std::max(
Sabina Davis8d20ca82018-02-19 13:17:45 -0800142 -kMaxIntakeRollerVoltage, ::std::min(unsafe_goal->intake.roller_voltage,
143 kMaxIntakeRollerVoltage));
Neil Balchba9cbba2018-04-06 22:26:38 -0700144 constexpr int kReverseTime = 14;
145 if (unsafe_goal->intake.roller_voltage < 0.0 ||
146 unsafe_goal->disable_box_correct) {
Sabina Daviscfb872f2018-02-25 16:28:20 -0800147 output->left_intake.voltage_rollers = roller_voltage;
148 output->right_intake.voltage_rollers = roller_voltage;
Austin Schuh17dd0892018-03-02 20:06:31 -0800149 rotation_state_ = RotationState::NOT_ROTATING;
150 rotation_count_ = 0;
Neil Balchba9cbba2018-04-06 22:26:38 -0700151 stuck_count_ = 0;
Austin Schuh17dd0892018-03-02 20:06:31 -0800152 } else {
Neil Balchba9cbba2018-04-06 22:26:38 -0700153 monotonic_clock::time_point monotonic_now = monotonic_clock::now();
154 const bool stuck = position->box_distance < 0.20 &&
155 filtered_box_velocity_ > -0.05 &&
156 !position->box_back_beambreak_triggered;
157 // Make sure we don't declare ourselves re-stuck too quickly. We want to
158 // wait 400 ms before triggering the stuck condition again.
159 if (!stuck) {
160 last_unstuck_time_ = monotonic_now;
161 }
162 if (monotonic_now < last_stuck_time_ + chrono::milliseconds(400)) {
163 last_unstuck_time_ = monotonic_now;
164 }
165
Austin Schuh17dd0892018-03-02 20:06:31 -0800166 switch (rotation_state_) {
167 case RotationState::NOT_ROTATING:
Neil Balchba9cbba2018-04-06 22:26:38 -0700168 if (stuck &&
169 monotonic_now > last_stuck_time_ + chrono::milliseconds(400) &&
170 monotonic_now > last_unstuck_time_ + chrono::milliseconds(100)) {
171 rotation_state_ = RotationState::STUCK;
172 ++stuck_count_;
173 last_stuck_time_ = monotonic_now;
174 } else if (position->left_intake.beam_break) {
Austin Schuh17dd0892018-03-02 20:06:31 -0800175 rotation_state_ = RotationState::ROTATING_RIGHT;
176 rotation_count_ = kReverseTime;
177 break;
Sabina Daviscfb872f2018-02-25 16:28:20 -0800178 } else if (position->right_intake.beam_break) {
Austin Schuh17dd0892018-03-02 20:06:31 -0800179 rotation_state_ = RotationState::ROTATING_LEFT;
180 rotation_count_ = kReverseTime;
181 break;
182 } else {
183 break;
184 }
Neil Balchba9cbba2018-04-06 22:26:38 -0700185 case RotationState::STUCK: {
186 // Latch being stuck for 80 ms so we kick the box out far enough.
187 if (last_stuck_time_ + chrono::milliseconds(80) < monotonic_now) {
188 rotation_state_ = RotationState::NOT_ROTATING;
189 last_unstuck_time_ = monotonic_now;
190 }
191 } break;
Austin Schuh17dd0892018-03-02 20:06:31 -0800192 case RotationState::ROTATING_LEFT:
Sabina Daviscfb872f2018-02-25 16:28:20 -0800193 if (position->right_intake.beam_break) {
Austin Schuh17dd0892018-03-02 20:06:31 -0800194 rotation_count_ = kReverseTime;
195 } else {
196 --rotation_count_;
197 }
198 if (rotation_count_ == 0) {
199 rotation_state_ = RotationState::NOT_ROTATING;
200 }
201 break;
202 case RotationState::ROTATING_RIGHT:
Sabina Daviscfb872f2018-02-25 16:28:20 -0800203 if (position->left_intake.beam_break) {
Austin Schuh17dd0892018-03-02 20:06:31 -0800204 rotation_count_ = kReverseTime;
205 } else {
206 --rotation_count_;
207 }
208 if (rotation_count_ == 0) {
209 rotation_state_ = RotationState::NOT_ROTATING;
210 }
211 break;
212 }
213
Neil Balchba9cbba2018-04-06 22:26:38 -0700214 constexpr double kHoldVoltage = 1.0;
215 constexpr double kStuckVoltage = 10.0;
216
217 if (position->box_back_beambreak_triggered &&
218 roller_voltage > kHoldVoltage) {
219 roller_voltage = kHoldVoltage;
Austin Schuh96341532018-03-09 21:17:24 -0800220 }
Austin Schuh17dd0892018-03-02 20:06:31 -0800221 switch (rotation_state_) {
Neil Balchba9cbba2018-04-06 22:26:38 -0700222 case RotationState::NOT_ROTATING: {
223 double centering_gain = 13.0;
224 if (stuck_count_ > 1) {
225 if ((stuck_count_ - 1) % 2 == 0) {
226 centering_gain = 0.0;
227 }
228 }
229 output->left_intake.voltage_rollers =
230 roller_voltage - intake_center_error * centering_gain;
231 output->right_intake.voltage_rollers =
232 roller_voltage + intake_center_error * centering_gain;
233 } break;
234 case RotationState::STUCK: {
235 if (roller_voltage > kHoldVoltage) {
236 output->left_intake.voltage_rollers = -kStuckVoltage;
237 output->right_intake.voltage_rollers = -kStuckVoltage;
238 }
239 } break;
Austin Schuh17dd0892018-03-02 20:06:31 -0800240 case RotationState::ROTATING_LEFT:
Neil Balchba9cbba2018-04-06 22:26:38 -0700241 if (position->left_intake.beam_break) {
242 output->left_intake.voltage_rollers = -roller_voltage * 0.9;
243 } else {
244 output->left_intake.voltage_rollers = -roller_voltage * 0.6;
245 }
246 output->right_intake.voltage_rollers = roller_voltage;
Austin Schuh17dd0892018-03-02 20:06:31 -0800247 break;
248 case RotationState::ROTATING_RIGHT:
Neil Balchba9cbba2018-04-06 22:26:38 -0700249 output->left_intake.voltage_rollers = roller_voltage;
250 if (position->right_intake.beam_break) {
251 output->right_intake.voltage_rollers = -roller_voltage * 0.9;
252 } else {
253 output->right_intake.voltage_rollers = -roller_voltage * 0.6;
254 }
Austin Schuh17dd0892018-03-02 20:06:31 -0800255 break;
256 }
257 }
Neil Balchba9cbba2018-04-06 22:26:38 -0700258 } else {
259 rotation_state_ = RotationState::NOT_ROTATING;
260 rotation_count_ = 0;
261 stuck_count_ = 0;
Sabina Davis8d20ca82018-02-19 13:17:45 -0800262 }
Neil Balchba9cbba2018-04-06 22:26:38 -0700263 status->rotation_state = static_cast<uint32_t>(rotation_state_);
Austin Schuh8d5fff42018-05-30 20:44:12 -0700264
265 ::frc971::control_loops::drivetrain_queue.output.FetchLatest();
266
267 ::y2018::vision::vision_status.FetchLatest();
268 if (status->estopped) {
269 SendColors(0.5, 0.0, 0.0);
270 } else if (!y2018::vision::vision_status.get() ||
271 y2018::vision::vision_status.Age() > chrono::seconds(1)) {
272 SendColors(0.5, 0.5, 0.0);
273 } else if (rotation_state_ == RotationState::ROTATING_LEFT ||
274 rotation_state_ == RotationState::ROTATING_RIGHT) {
275 SendColors(0.5, 0.20, 0.0);
276 } else if (rotation_state_ == RotationState::STUCK) {
277 SendColors(0.5, 0.0, 0.5);
278 } else if (position->box_back_beambreak_triggered) {
279 SendColors(0.0, 0.0, 0.5);
280 } else if (position->box_distance < 0.2) {
281 SendColors(0.0, 0.5, 0.0);
282 } else if (::frc971::control_loops::drivetrain_queue.output.get() &&
283 ::std::max(::std::abs(::frc971::control_loops::drivetrain_queue
284 .output->left_voltage),
285 ::std::abs(::frc971::control_loops::drivetrain_queue
286 .output->right_voltage)) > 11.5) {
287 SendColors(0.5, 0.0, 0.5);
288 } else {
289 SendColors(0.0, 0.0, 0.0);
290 }
291
Neil Balchba9cbba2018-04-06 22:26:38 -0700292 last_box_distance_ = clipped_box_distance;
Sabina Davis8d20ca82018-02-19 13:17:45 -0800293}
294
295} // namespace superstructure
296} // namespace control_loops
297} // namespace y2018