blob: d0ff71d29142a6b62f2738ed1e42ec5060de9b90 [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 Schuh55a13dc2019-01-27 22:39:03 -080027Superstructure::Superstructure(::aos::EventLoop *event_loop,
28 const ::std::string &name)
29 : aos::controls::ControlLoop<control_loops::SuperstructureQueue>(event_loop,
30 name),
Austin Schuh01a9f2a2019-05-27 13:36:30 -070031 status_light_sender_(
32 event_loop->MakeSender<::y2018::StatusLight>(".y2018.status_light")),
Austin Schuh300f2f62019-05-27 13:49:23 -070033 vision_status_fetcher_(
34 event_loop->MakeFetcher<::y2018::vision::VisionStatus>(
35 ".y2018.vision.vision_status")),
Sabina Davis8d20ca82018-02-19 13:17:45 -080036 intake_left_(constants::GetValues().left_intake.zeroing),
37 intake_right_(constants::GetValues().right_intake.zeroing) {}
38
39void Superstructure::RunIteration(
40 const control_loops::SuperstructureQueue::Goal *unsafe_goal,
41 const control_loops::SuperstructureQueue::Position *position,
42 control_loops::SuperstructureQueue::Output *output,
43 control_loops::SuperstructureQueue::Status *status) {
44 if (WasReset()) {
45 LOG(ERROR, "WPILib reset, restarting\n");
46 intake_left_.Reset();
47 intake_right_.Reset();
Austin Schuhcb091712018-02-21 20:01:55 -080048 arm_.Reset();
Sabina Davis8d20ca82018-02-19 13:17:45 -080049 }
50
Neil Balchba9cbba2018-04-06 22:26:38 -070051 const double clipped_box_distance =
52 ::std::min(1.0, ::std::max(0.0, position->box_distance));
53
54 const double box_velocity =
55 (clipped_box_distance - last_box_distance_) / 0.005;
56
57 constexpr double kFilteredBoxVelocityAlpha = 0.02;
58 filtered_box_velocity_ =
59 box_velocity * kFilteredBoxVelocityAlpha +
60 (1.0 - kFilteredBoxVelocityAlpha) * filtered_box_velocity_;
61 status->filtered_box_velocity = filtered_box_velocity_;
62
63 constexpr double kCenteringAngleGain = 0.0;
64 const double left_intake_goal =
65 ::std::min(
66 arm_.max_intake_override(),
67 (unsafe_goal == nullptr ? 0.0
68 : unsafe_goal->intake.left_intake_angle)) +
69 last_intake_center_error_ * kCenteringAngleGain;
70 const double right_intake_goal =
71 ::std::min(
72 arm_.max_intake_override(),
73 (unsafe_goal == nullptr ? 0.0
74 : unsafe_goal->intake.right_intake_angle)) -
75 last_intake_center_error_ * kCenteringAngleGain;
Austin Schuh83cdd8a2018-03-21 20:49:02 -070076
Austin Schuh96341532018-03-09 21:17:24 -080077 intake_left_.Iterate(unsafe_goal != nullptr ? &(left_intake_goal) : nullptr,
Sabina Daviscfb872f2018-02-25 16:28:20 -080078 &(position->left_intake),
79 output != nullptr ? &(output->left_intake) : nullptr,
Sabina Davis8d20ca82018-02-19 13:17:45 -080080 &(status->left_intake));
81
Austin Schuh96341532018-03-09 21:17:24 -080082 intake_right_.Iterate(unsafe_goal != nullptr ? &(right_intake_goal) : nullptr,
Sabina Daviscfb872f2018-02-25 16:28:20 -080083 &(position->right_intake),
84 output != nullptr ? &(output->right_intake) : nullptr,
Sabina Davis8d20ca82018-02-19 13:17:45 -080085 &(status->right_intake));
86
Neil Balchba9cbba2018-04-06 22:26:38 -070087 const double intake_center_error =
88 intake_right_.output_position() - intake_left_.output_position();
89 last_intake_center_error_ = intake_center_error;
90
Austin Schuh96341532018-03-09 21:17:24 -080091 const bool intake_clear_of_box =
92 intake_left_.clear_of_box() && intake_right_.clear_of_box();
Austin Schuhd76546a2018-07-08 16:05:14 -070093
94 bool open_claw = unsafe_goal != nullptr ? unsafe_goal->open_claw : false;
95 if (unsafe_goal) {
96 if (unsafe_goal->open_threshold != 0.0) {
97 if (arm_.current_node() != unsafe_goal->arm_goal_position ||
98 arm_.path_distance_to_go() > unsafe_goal->open_threshold) {
99 open_claw = false;
100 }
101 }
102 }
Austin Schuhcb091712018-02-21 20:01:55 -0800103 arm_.Iterate(
104 unsafe_goal != nullptr ? &(unsafe_goal->arm_goal_position) : nullptr,
Austin Schuhd76546a2018-07-08 16:05:14 -0700105 unsafe_goal != nullptr ? unsafe_goal->grab_box : false, open_claw,
Neil Balchba9cbba2018-04-06 22:26:38 -0700106 unsafe_goal != nullptr ? unsafe_goal->close_claw : false,
107 &(position->arm), position->claw_beambreak_triggered,
Austin Schuh96341532018-03-09 21:17:24 -0800108 position->box_back_beambreak_triggered, intake_clear_of_box,
Austin Schuhd76546a2018-07-08 16:05:14 -0700109 unsafe_goal != nullptr ? unsafe_goal->voltage_winch > 1.0 : false,
110 unsafe_goal != nullptr ? unsafe_goal->trajectory_override : false,
Austin Schuhcb091712018-02-21 20:01:55 -0800111 output != nullptr ? &(output->voltage_proximal) : nullptr,
112 output != nullptr ? &(output->voltage_distal) : nullptr,
113 output != nullptr ? &(output->release_arm_brake) : nullptr,
Austin Schuhd76546a2018-07-08 16:05:14 -0700114 output != nullptr ? &(output->claw_grabbed) : nullptr, &(status->arm));
Austin Schuh17e484e2018-03-11 01:11:36 -0800115
116 if (output) {
117 if (unsafe_goal) {
118 output->hook_release = unsafe_goal->hook_release;
119 output->voltage_winch = unsafe_goal->voltage_winch;
120 output->forks_release = unsafe_goal->deploy_fork;
121 } else {
122 output->voltage_winch = 0.0;
123 output->hook_release = false;
124 output->forks_release = false;
125 }
126 }
Austin Schuhcb091712018-02-21 20:01:55 -0800127
128 status->estopped = status->left_intake.estopped ||
129 status->right_intake.estopped || status->arm.estopped;
130
131 status->zeroed = status->left_intake.zeroed && status->right_intake.zeroed &&
132 status->arm.zeroed;
Sabina Davis8d20ca82018-02-19 13:17:45 -0800133
134 if (output && unsafe_goal) {
Austin Schuh96341532018-03-09 21:17:24 -0800135 double roller_voltage = ::std::max(
Sabina Davis8d20ca82018-02-19 13:17:45 -0800136 -kMaxIntakeRollerVoltage, ::std::min(unsafe_goal->intake.roller_voltage,
137 kMaxIntakeRollerVoltage));
Neil Balchba9cbba2018-04-06 22:26:38 -0700138 constexpr int kReverseTime = 14;
139 if (unsafe_goal->intake.roller_voltage < 0.0 ||
140 unsafe_goal->disable_box_correct) {
Sabina Daviscfb872f2018-02-25 16:28:20 -0800141 output->left_intake.voltage_rollers = roller_voltage;
142 output->right_intake.voltage_rollers = roller_voltage;
Austin Schuh17dd0892018-03-02 20:06:31 -0800143 rotation_state_ = RotationState::NOT_ROTATING;
144 rotation_count_ = 0;
Neil Balchba9cbba2018-04-06 22:26:38 -0700145 stuck_count_ = 0;
Austin Schuh17dd0892018-03-02 20:06:31 -0800146 } else {
Neil Balchba9cbba2018-04-06 22:26:38 -0700147 monotonic_clock::time_point monotonic_now = monotonic_clock::now();
148 const bool stuck = position->box_distance < 0.20 &&
149 filtered_box_velocity_ > -0.05 &&
150 !position->box_back_beambreak_triggered;
151 // Make sure we don't declare ourselves re-stuck too quickly. We want to
152 // wait 400 ms before triggering the stuck condition again.
153 if (!stuck) {
154 last_unstuck_time_ = monotonic_now;
155 }
156 if (monotonic_now < last_stuck_time_ + chrono::milliseconds(400)) {
157 last_unstuck_time_ = monotonic_now;
158 }
159
Austin Schuh17dd0892018-03-02 20:06:31 -0800160 switch (rotation_state_) {
161 case RotationState::NOT_ROTATING:
Neil Balchba9cbba2018-04-06 22:26:38 -0700162 if (stuck &&
163 monotonic_now > last_stuck_time_ + chrono::milliseconds(400) &&
164 monotonic_now > last_unstuck_time_ + chrono::milliseconds(100)) {
165 rotation_state_ = RotationState::STUCK;
166 ++stuck_count_;
167 last_stuck_time_ = monotonic_now;
168 } else if (position->left_intake.beam_break) {
Austin Schuh17dd0892018-03-02 20:06:31 -0800169 rotation_state_ = RotationState::ROTATING_RIGHT;
170 rotation_count_ = kReverseTime;
171 break;
Sabina Daviscfb872f2018-02-25 16:28:20 -0800172 } else if (position->right_intake.beam_break) {
Austin Schuh17dd0892018-03-02 20:06:31 -0800173 rotation_state_ = RotationState::ROTATING_LEFT;
174 rotation_count_ = kReverseTime;
175 break;
176 } else {
177 break;
178 }
Neil Balchba9cbba2018-04-06 22:26:38 -0700179 case RotationState::STUCK: {
180 // Latch being stuck for 80 ms so we kick the box out far enough.
181 if (last_stuck_time_ + chrono::milliseconds(80) < monotonic_now) {
182 rotation_state_ = RotationState::NOT_ROTATING;
183 last_unstuck_time_ = monotonic_now;
184 }
185 } break;
Austin Schuh17dd0892018-03-02 20:06:31 -0800186 case RotationState::ROTATING_LEFT:
Sabina Daviscfb872f2018-02-25 16:28:20 -0800187 if (position->right_intake.beam_break) {
Austin Schuh17dd0892018-03-02 20:06:31 -0800188 rotation_count_ = kReverseTime;
189 } else {
190 --rotation_count_;
191 }
192 if (rotation_count_ == 0) {
193 rotation_state_ = RotationState::NOT_ROTATING;
194 }
195 break;
196 case RotationState::ROTATING_RIGHT:
Sabina Daviscfb872f2018-02-25 16:28:20 -0800197 if (position->left_intake.beam_break) {
Austin Schuh17dd0892018-03-02 20:06:31 -0800198 rotation_count_ = kReverseTime;
199 } else {
200 --rotation_count_;
201 }
202 if (rotation_count_ == 0) {
203 rotation_state_ = RotationState::NOT_ROTATING;
204 }
205 break;
206 }
207
Neil Balchba9cbba2018-04-06 22:26:38 -0700208 constexpr double kHoldVoltage = 1.0;
209 constexpr double kStuckVoltage = 10.0;
210
211 if (position->box_back_beambreak_triggered &&
212 roller_voltage > kHoldVoltage) {
213 roller_voltage = kHoldVoltage;
Austin Schuh96341532018-03-09 21:17:24 -0800214 }
Austin Schuh17dd0892018-03-02 20:06:31 -0800215 switch (rotation_state_) {
Neil Balchba9cbba2018-04-06 22:26:38 -0700216 case RotationState::NOT_ROTATING: {
217 double centering_gain = 13.0;
218 if (stuck_count_ > 1) {
219 if ((stuck_count_ - 1) % 2 == 0) {
220 centering_gain = 0.0;
221 }
222 }
223 output->left_intake.voltage_rollers =
224 roller_voltage - intake_center_error * centering_gain;
225 output->right_intake.voltage_rollers =
226 roller_voltage + intake_center_error * centering_gain;
227 } break;
228 case RotationState::STUCK: {
229 if (roller_voltage > kHoldVoltage) {
230 output->left_intake.voltage_rollers = -kStuckVoltage;
231 output->right_intake.voltage_rollers = -kStuckVoltage;
232 }
233 } break;
Austin Schuh17dd0892018-03-02 20:06:31 -0800234 case RotationState::ROTATING_LEFT:
Neil Balchba9cbba2018-04-06 22:26:38 -0700235 if (position->left_intake.beam_break) {
236 output->left_intake.voltage_rollers = -roller_voltage * 0.9;
237 } else {
238 output->left_intake.voltage_rollers = -roller_voltage * 0.6;
239 }
240 output->right_intake.voltage_rollers = roller_voltage;
Austin Schuh17dd0892018-03-02 20:06:31 -0800241 break;
242 case RotationState::ROTATING_RIGHT:
Neil Balchba9cbba2018-04-06 22:26:38 -0700243 output->left_intake.voltage_rollers = roller_voltage;
244 if (position->right_intake.beam_break) {
245 output->right_intake.voltage_rollers = -roller_voltage * 0.9;
246 } else {
247 output->right_intake.voltage_rollers = -roller_voltage * 0.6;
248 }
Austin Schuh17dd0892018-03-02 20:06:31 -0800249 break;
250 }
251 }
Neil Balchba9cbba2018-04-06 22:26:38 -0700252 } else {
253 rotation_state_ = RotationState::NOT_ROTATING;
254 rotation_count_ = 0;
255 stuck_count_ = 0;
Sabina Davis8d20ca82018-02-19 13:17:45 -0800256 }
Neil Balchba9cbba2018-04-06 22:26:38 -0700257 status->rotation_state = static_cast<uint32_t>(rotation_state_);
Austin Schuh8d5fff42018-05-30 20:44:12 -0700258
259 ::frc971::control_loops::drivetrain_queue.output.FetchLatest();
260
Austin Schuh300f2f62019-05-27 13:49:23 -0700261 vision_status_fetcher_.Fetch();
262 monotonic_clock::time_point monotonic_now = event_loop()->monotonic_now();
Austin Schuh8d5fff42018-05-30 20:44:12 -0700263 if (status->estopped) {
264 SendColors(0.5, 0.0, 0.0);
Austin Schuh300f2f62019-05-27 13:49:23 -0700265 } else if (!vision_status_fetcher_.get() ||
266 monotonic_now >
267 vision_status_fetcher_->sent_time + chrono::seconds(1)) {
Austin Schuh8d5fff42018-05-30 20:44:12 -0700268 SendColors(0.5, 0.5, 0.0);
269 } else if (rotation_state_ == RotationState::ROTATING_LEFT ||
270 rotation_state_ == RotationState::ROTATING_RIGHT) {
271 SendColors(0.5, 0.20, 0.0);
272 } else if (rotation_state_ == RotationState::STUCK) {
273 SendColors(0.5, 0.0, 0.5);
274 } else if (position->box_back_beambreak_triggered) {
275 SendColors(0.0, 0.0, 0.5);
276 } else if (position->box_distance < 0.2) {
277 SendColors(0.0, 0.5, 0.0);
278 } else if (::frc971::control_loops::drivetrain_queue.output.get() &&
279 ::std::max(::std::abs(::frc971::control_loops::drivetrain_queue
280 .output->left_voltage),
281 ::std::abs(::frc971::control_loops::drivetrain_queue
282 .output->right_voltage)) > 11.5) {
283 SendColors(0.5, 0.0, 0.5);
284 } else {
285 SendColors(0.0, 0.0, 0.0);
286 }
287
Neil Balchba9cbba2018-04-06 22:26:38 -0700288 last_box_distance_ = clipped_box_distance;
Sabina Davis8d20ca82018-02-19 13:17:45 -0800289}
290
Austin Schuh01a9f2a2019-05-27 13:36:30 -0700291void Superstructure::SendColors(float red, float green, float blue) {
292 auto new_status_light = status_light_sender_.MakeMessage();
293 new_status_light->red = red;
294 new_status_light->green = green;
295 new_status_light->blue = blue;
296
297 if (!new_status_light.Send()) {
298 LOG(ERROR, "Failed to send lights.\n");
299 }
300}
301
Sabina Davis8d20ca82018-02-19 13:17:45 -0800302} // namespace superstructure
303} // namespace control_loops
304} // namespace y2018