blob: 2098cd0f4c4f5c0cd7af108ade60a4cab6016aba [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
Sabina Davis8d20ca82018-02-19 13:17:45 -08005#include "aos/common/controls/control_loops.q.h"
6#include "aos/common/logging/logging.h"
7#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
Sabina Davis8d20ca82018-02-19 13:17:45 -080038Superstructure::Superstructure(
39 control_loops::SuperstructureQueue *superstructure_queue)
40 : aos::controls::ControlLoop<control_loops::SuperstructureQueue>(
41 superstructure_queue),
42 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 Schuhcb091712018-02-21 20:01:55 -080099 arm_.Iterate(
100 unsafe_goal != nullptr ? &(unsafe_goal->arm_goal_position) : nullptr,
Austin Schuh96341532018-03-09 21:17:24 -0800101 unsafe_goal != nullptr ? unsafe_goal->grab_box : false,
Neil Balchba9cbba2018-04-06 22:26:38 -0700102 unsafe_goal != nullptr ? unsafe_goal->open_claw : false,
103 unsafe_goal != nullptr ? unsafe_goal->close_claw : false,
104 &(position->arm), position->claw_beambreak_triggered,
Austin Schuh96341532018-03-09 21:17:24 -0800105 position->box_back_beambreak_triggered, intake_clear_of_box,
Austin Schuhcb091712018-02-21 20:01:55 -0800106 output != nullptr ? &(output->voltage_proximal) : nullptr,
107 output != nullptr ? &(output->voltage_distal) : nullptr,
108 output != nullptr ? &(output->release_arm_brake) : nullptr,
Austin Schuh17e484e2018-03-11 01:11:36 -0800109 output != nullptr ? &(output->claw_grabbed) : nullptr, &(status->arm),
110 unsafe_goal != nullptr ? unsafe_goal->voltage_winch > 1.0 : false);
111
112 if (output) {
113 if (unsafe_goal) {
114 output->hook_release = unsafe_goal->hook_release;
115 output->voltage_winch = unsafe_goal->voltage_winch;
116 output->forks_release = unsafe_goal->deploy_fork;
117 } else {
118 output->voltage_winch = 0.0;
119 output->hook_release = false;
120 output->forks_release = false;
121 }
122 }
Austin Schuhcb091712018-02-21 20:01:55 -0800123
124 status->estopped = status->left_intake.estopped ||
125 status->right_intake.estopped || status->arm.estopped;
126
127 status->zeroed = status->left_intake.zeroed && status->right_intake.zeroed &&
128 status->arm.zeroed;
Sabina Davis8d20ca82018-02-19 13:17:45 -0800129
130 if (output && unsafe_goal) {
Austin Schuh96341532018-03-09 21:17:24 -0800131 double roller_voltage = ::std::max(
Sabina Davis8d20ca82018-02-19 13:17:45 -0800132 -kMaxIntakeRollerVoltage, ::std::min(unsafe_goal->intake.roller_voltage,
133 kMaxIntakeRollerVoltage));
Neil Balchba9cbba2018-04-06 22:26:38 -0700134 constexpr int kReverseTime = 14;
135 if (unsafe_goal->intake.roller_voltage < 0.0 ||
136 unsafe_goal->disable_box_correct) {
Sabina Daviscfb872f2018-02-25 16:28:20 -0800137 output->left_intake.voltage_rollers = roller_voltage;
138 output->right_intake.voltage_rollers = roller_voltage;
Austin Schuh17dd0892018-03-02 20:06:31 -0800139 rotation_state_ = RotationState::NOT_ROTATING;
140 rotation_count_ = 0;
Neil Balchba9cbba2018-04-06 22:26:38 -0700141 stuck_count_ = 0;
Austin Schuh17dd0892018-03-02 20:06:31 -0800142 } else {
Neil Balchba9cbba2018-04-06 22:26:38 -0700143 monotonic_clock::time_point monotonic_now = monotonic_clock::now();
144 const bool stuck = position->box_distance < 0.20 &&
145 filtered_box_velocity_ > -0.05 &&
146 !position->box_back_beambreak_triggered;
147 // Make sure we don't declare ourselves re-stuck too quickly. We want to
148 // wait 400 ms before triggering the stuck condition again.
149 if (!stuck) {
150 last_unstuck_time_ = monotonic_now;
151 }
152 if (monotonic_now < last_stuck_time_ + chrono::milliseconds(400)) {
153 last_unstuck_time_ = monotonic_now;
154 }
155
Austin Schuh17dd0892018-03-02 20:06:31 -0800156 switch (rotation_state_) {
157 case RotationState::NOT_ROTATING:
Neil Balchba9cbba2018-04-06 22:26:38 -0700158 if (stuck &&
159 monotonic_now > last_stuck_time_ + chrono::milliseconds(400) &&
160 monotonic_now > last_unstuck_time_ + chrono::milliseconds(100)) {
161 rotation_state_ = RotationState::STUCK;
162 ++stuck_count_;
163 last_stuck_time_ = monotonic_now;
164 } else if (position->left_intake.beam_break) {
Austin Schuh17dd0892018-03-02 20:06:31 -0800165 rotation_state_ = RotationState::ROTATING_RIGHT;
166 rotation_count_ = kReverseTime;
167 break;
Sabina Daviscfb872f2018-02-25 16:28:20 -0800168 } else if (position->right_intake.beam_break) {
Austin Schuh17dd0892018-03-02 20:06:31 -0800169 rotation_state_ = RotationState::ROTATING_LEFT;
170 rotation_count_ = kReverseTime;
171 break;
172 } else {
173 break;
174 }
Neil Balchba9cbba2018-04-06 22:26:38 -0700175 case RotationState::STUCK: {
176 // Latch being stuck for 80 ms so we kick the box out far enough.
177 if (last_stuck_time_ + chrono::milliseconds(80) < monotonic_now) {
178 rotation_state_ = RotationState::NOT_ROTATING;
179 last_unstuck_time_ = monotonic_now;
180 }
181 } break;
Austin Schuh17dd0892018-03-02 20:06:31 -0800182 case RotationState::ROTATING_LEFT:
Sabina Daviscfb872f2018-02-25 16:28:20 -0800183 if (position->right_intake.beam_break) {
Austin Schuh17dd0892018-03-02 20:06:31 -0800184 rotation_count_ = kReverseTime;
185 } else {
186 --rotation_count_;
187 }
188 if (rotation_count_ == 0) {
189 rotation_state_ = RotationState::NOT_ROTATING;
190 }
191 break;
192 case RotationState::ROTATING_RIGHT:
Sabina Daviscfb872f2018-02-25 16:28:20 -0800193 if (position->left_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 }
203
Neil Balchba9cbba2018-04-06 22:26:38 -0700204 constexpr double kHoldVoltage = 1.0;
205 constexpr double kStuckVoltage = 10.0;
206
207 if (position->box_back_beambreak_triggered &&
208 roller_voltage > kHoldVoltage) {
209 roller_voltage = kHoldVoltage;
Austin Schuh96341532018-03-09 21:17:24 -0800210 }
Austin Schuh17dd0892018-03-02 20:06:31 -0800211 switch (rotation_state_) {
Neil Balchba9cbba2018-04-06 22:26:38 -0700212 case RotationState::NOT_ROTATING: {
213 double centering_gain = 13.0;
214 if (stuck_count_ > 1) {
215 if ((stuck_count_ - 1) % 2 == 0) {
216 centering_gain = 0.0;
217 }
218 }
219 output->left_intake.voltage_rollers =
220 roller_voltage - intake_center_error * centering_gain;
221 output->right_intake.voltage_rollers =
222 roller_voltage + intake_center_error * centering_gain;
223 } break;
224 case RotationState::STUCK: {
225 if (roller_voltage > kHoldVoltage) {
226 output->left_intake.voltage_rollers = -kStuckVoltage;
227 output->right_intake.voltage_rollers = -kStuckVoltage;
228 }
229 } break;
Austin Schuh17dd0892018-03-02 20:06:31 -0800230 case RotationState::ROTATING_LEFT:
Neil Balchba9cbba2018-04-06 22:26:38 -0700231 if (position->left_intake.beam_break) {
232 output->left_intake.voltage_rollers = -roller_voltage * 0.9;
233 } else {
234 output->left_intake.voltage_rollers = -roller_voltage * 0.6;
235 }
236 output->right_intake.voltage_rollers = roller_voltage;
Austin Schuh17dd0892018-03-02 20:06:31 -0800237 break;
238 case RotationState::ROTATING_RIGHT:
Neil Balchba9cbba2018-04-06 22:26:38 -0700239 output->left_intake.voltage_rollers = roller_voltage;
240 if (position->right_intake.beam_break) {
241 output->right_intake.voltage_rollers = -roller_voltage * 0.9;
242 } else {
243 output->right_intake.voltage_rollers = -roller_voltage * 0.6;
244 }
Austin Schuh17dd0892018-03-02 20:06:31 -0800245 break;
246 }
247 }
Neil Balchba9cbba2018-04-06 22:26:38 -0700248 } else {
249 rotation_state_ = RotationState::NOT_ROTATING;
250 rotation_count_ = 0;
251 stuck_count_ = 0;
Sabina Davis8d20ca82018-02-19 13:17:45 -0800252 }
Neil Balchba9cbba2018-04-06 22:26:38 -0700253 status->rotation_state = static_cast<uint32_t>(rotation_state_);
Austin Schuh8d5fff42018-05-30 20:44:12 -0700254
255 ::frc971::control_loops::drivetrain_queue.output.FetchLatest();
256
257 ::y2018::vision::vision_status.FetchLatest();
258 if (status->estopped) {
259 SendColors(0.5, 0.0, 0.0);
260 } else if (!y2018::vision::vision_status.get() ||
261 y2018::vision::vision_status.Age() > chrono::seconds(1)) {
262 SendColors(0.5, 0.5, 0.0);
263 } else if (rotation_state_ == RotationState::ROTATING_LEFT ||
264 rotation_state_ == RotationState::ROTATING_RIGHT) {
265 SendColors(0.5, 0.20, 0.0);
266 } else if (rotation_state_ == RotationState::STUCK) {
267 SendColors(0.5, 0.0, 0.5);
268 } else if (position->box_back_beambreak_triggered) {
269 SendColors(0.0, 0.0, 0.5);
270 } else if (position->box_distance < 0.2) {
271 SendColors(0.0, 0.5, 0.0);
272 } else if (::frc971::control_loops::drivetrain_queue.output.get() &&
273 ::std::max(::std::abs(::frc971::control_loops::drivetrain_queue
274 .output->left_voltage),
275 ::std::abs(::frc971::control_loops::drivetrain_queue
276 .output->right_voltage)) > 11.5) {
277 SendColors(0.5, 0.0, 0.5);
278 } else {
279 SendColors(0.0, 0.0, 0.0);
280 }
281
Neil Balchba9cbba2018-04-06 22:26:38 -0700282 last_box_distance_ = clipped_box_distance;
Sabina Davis8d20ca82018-02-19 13:17:45 -0800283}
284
285} // namespace superstructure
286} // namespace control_loops
287} // namespace y2018