blob: 24a8880da18cc2ec6d1289df0d6f049a65e7550c [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")),
Austin Schuhbd0a40f2019-06-30 14:56:31 -070036 drivetrain_output_fetcher_(
37 event_loop
38 ->MakeFetcher<::frc971::control_loops::DrivetrainQueue::Output>(
39 ".frc971.control_loops.drivetrain_queue.output")),
Sabina Davis8d20ca82018-02-19 13:17:45 -080040 intake_left_(constants::GetValues().left_intake.zeroing),
41 intake_right_(constants::GetValues().right_intake.zeroing) {}
42
43void Superstructure::RunIteration(
44 const control_loops::SuperstructureQueue::Goal *unsafe_goal,
45 const control_loops::SuperstructureQueue::Position *position,
46 control_loops::SuperstructureQueue::Output *output,
47 control_loops::SuperstructureQueue::Status *status) {
48 if (WasReset()) {
49 LOG(ERROR, "WPILib reset, restarting\n");
50 intake_left_.Reset();
51 intake_right_.Reset();
Austin Schuhcb091712018-02-21 20:01:55 -080052 arm_.Reset();
Sabina Davis8d20ca82018-02-19 13:17:45 -080053 }
54
Neil Balchba9cbba2018-04-06 22:26:38 -070055 const double clipped_box_distance =
56 ::std::min(1.0, ::std::max(0.0, position->box_distance));
57
58 const double box_velocity =
59 (clipped_box_distance - last_box_distance_) / 0.005;
60
61 constexpr double kFilteredBoxVelocityAlpha = 0.02;
62 filtered_box_velocity_ =
63 box_velocity * kFilteredBoxVelocityAlpha +
64 (1.0 - kFilteredBoxVelocityAlpha) * filtered_box_velocity_;
65 status->filtered_box_velocity = filtered_box_velocity_;
66
67 constexpr double kCenteringAngleGain = 0.0;
68 const double left_intake_goal =
69 ::std::min(
70 arm_.max_intake_override(),
71 (unsafe_goal == nullptr ? 0.0
72 : unsafe_goal->intake.left_intake_angle)) +
73 last_intake_center_error_ * kCenteringAngleGain;
74 const double right_intake_goal =
75 ::std::min(
76 arm_.max_intake_override(),
77 (unsafe_goal == nullptr ? 0.0
78 : unsafe_goal->intake.right_intake_angle)) -
79 last_intake_center_error_ * kCenteringAngleGain;
Austin Schuh83cdd8a2018-03-21 20:49:02 -070080
Austin Schuh96341532018-03-09 21:17:24 -080081 intake_left_.Iterate(unsafe_goal != nullptr ? &(left_intake_goal) : nullptr,
Sabina Daviscfb872f2018-02-25 16:28:20 -080082 &(position->left_intake),
83 output != nullptr ? &(output->left_intake) : nullptr,
Sabina Davis8d20ca82018-02-19 13:17:45 -080084 &(status->left_intake));
85
Austin Schuh96341532018-03-09 21:17:24 -080086 intake_right_.Iterate(unsafe_goal != nullptr ? &(right_intake_goal) : nullptr,
Sabina Daviscfb872f2018-02-25 16:28:20 -080087 &(position->right_intake),
88 output != nullptr ? &(output->right_intake) : nullptr,
Sabina Davis8d20ca82018-02-19 13:17:45 -080089 &(status->right_intake));
90
Neil Balchba9cbba2018-04-06 22:26:38 -070091 const double intake_center_error =
92 intake_right_.output_position() - intake_left_.output_position();
93 last_intake_center_error_ = intake_center_error;
94
Austin Schuh96341532018-03-09 21:17:24 -080095 const bool intake_clear_of_box =
96 intake_left_.clear_of_box() && intake_right_.clear_of_box();
Austin Schuhd76546a2018-07-08 16:05:14 -070097
98 bool open_claw = unsafe_goal != nullptr ? unsafe_goal->open_claw : false;
99 if (unsafe_goal) {
100 if (unsafe_goal->open_threshold != 0.0) {
101 if (arm_.current_node() != unsafe_goal->arm_goal_position ||
102 arm_.path_distance_to_go() > unsafe_goal->open_threshold) {
103 open_claw = false;
104 }
105 }
106 }
Austin Schuhcb091712018-02-21 20:01:55 -0800107 arm_.Iterate(
108 unsafe_goal != nullptr ? &(unsafe_goal->arm_goal_position) : nullptr,
Austin Schuhd76546a2018-07-08 16:05:14 -0700109 unsafe_goal != nullptr ? unsafe_goal->grab_box : false, open_claw,
Neil Balchba9cbba2018-04-06 22:26:38 -0700110 unsafe_goal != nullptr ? unsafe_goal->close_claw : false,
111 &(position->arm), position->claw_beambreak_triggered,
Austin Schuh96341532018-03-09 21:17:24 -0800112 position->box_back_beambreak_triggered, intake_clear_of_box,
Austin Schuhd76546a2018-07-08 16:05:14 -0700113 unsafe_goal != nullptr ? unsafe_goal->voltage_winch > 1.0 : false,
114 unsafe_goal != nullptr ? unsafe_goal->trajectory_override : false,
Austin Schuhcb091712018-02-21 20:01:55 -0800115 output != nullptr ? &(output->voltage_proximal) : nullptr,
116 output != nullptr ? &(output->voltage_distal) : nullptr,
117 output != nullptr ? &(output->release_arm_brake) : nullptr,
Austin Schuhd76546a2018-07-08 16:05:14 -0700118 output != nullptr ? &(output->claw_grabbed) : nullptr, &(status->arm));
Austin Schuh17e484e2018-03-11 01:11:36 -0800119
120 if (output) {
121 if (unsafe_goal) {
122 output->hook_release = unsafe_goal->hook_release;
123 output->voltage_winch = unsafe_goal->voltage_winch;
124 output->forks_release = unsafe_goal->deploy_fork;
125 } else {
126 output->voltage_winch = 0.0;
127 output->hook_release = false;
128 output->forks_release = false;
129 }
130 }
Austin Schuhcb091712018-02-21 20:01:55 -0800131
132 status->estopped = status->left_intake.estopped ||
133 status->right_intake.estopped || status->arm.estopped;
134
135 status->zeroed = status->left_intake.zeroed && status->right_intake.zeroed &&
136 status->arm.zeroed;
Sabina Davis8d20ca82018-02-19 13:17:45 -0800137
138 if (output && unsafe_goal) {
Austin Schuh96341532018-03-09 21:17:24 -0800139 double roller_voltage = ::std::max(
Sabina Davis8d20ca82018-02-19 13:17:45 -0800140 -kMaxIntakeRollerVoltage, ::std::min(unsafe_goal->intake.roller_voltage,
141 kMaxIntakeRollerVoltage));
Neil Balchba9cbba2018-04-06 22:26:38 -0700142 constexpr int kReverseTime = 14;
143 if (unsafe_goal->intake.roller_voltage < 0.0 ||
144 unsafe_goal->disable_box_correct) {
Sabina Daviscfb872f2018-02-25 16:28:20 -0800145 output->left_intake.voltage_rollers = roller_voltage;
146 output->right_intake.voltage_rollers = roller_voltage;
Austin Schuh17dd0892018-03-02 20:06:31 -0800147 rotation_state_ = RotationState::NOT_ROTATING;
148 rotation_count_ = 0;
Neil Balchba9cbba2018-04-06 22:26:38 -0700149 stuck_count_ = 0;
Austin Schuh17dd0892018-03-02 20:06:31 -0800150 } else {
Neil Balchba9cbba2018-04-06 22:26:38 -0700151 monotonic_clock::time_point monotonic_now = monotonic_clock::now();
152 const bool stuck = position->box_distance < 0.20 &&
153 filtered_box_velocity_ > -0.05 &&
154 !position->box_back_beambreak_triggered;
155 // Make sure we don't declare ourselves re-stuck too quickly. We want to
156 // wait 400 ms before triggering the stuck condition again.
157 if (!stuck) {
158 last_unstuck_time_ = monotonic_now;
159 }
160 if (monotonic_now < last_stuck_time_ + chrono::milliseconds(400)) {
161 last_unstuck_time_ = monotonic_now;
162 }
163
Austin Schuh17dd0892018-03-02 20:06:31 -0800164 switch (rotation_state_) {
165 case RotationState::NOT_ROTATING:
Neil Balchba9cbba2018-04-06 22:26:38 -0700166 if (stuck &&
167 monotonic_now > last_stuck_time_ + chrono::milliseconds(400) &&
168 monotonic_now > last_unstuck_time_ + chrono::milliseconds(100)) {
169 rotation_state_ = RotationState::STUCK;
170 ++stuck_count_;
171 last_stuck_time_ = monotonic_now;
172 } else if (position->left_intake.beam_break) {
Austin Schuh17dd0892018-03-02 20:06:31 -0800173 rotation_state_ = RotationState::ROTATING_RIGHT;
174 rotation_count_ = kReverseTime;
175 break;
Sabina Daviscfb872f2018-02-25 16:28:20 -0800176 } else if (position->right_intake.beam_break) {
Austin Schuh17dd0892018-03-02 20:06:31 -0800177 rotation_state_ = RotationState::ROTATING_LEFT;
178 rotation_count_ = kReverseTime;
179 break;
180 } else {
181 break;
182 }
Neil Balchba9cbba2018-04-06 22:26:38 -0700183 case RotationState::STUCK: {
184 // Latch being stuck for 80 ms so we kick the box out far enough.
185 if (last_stuck_time_ + chrono::milliseconds(80) < monotonic_now) {
186 rotation_state_ = RotationState::NOT_ROTATING;
187 last_unstuck_time_ = monotonic_now;
188 }
189 } break;
Austin Schuh17dd0892018-03-02 20:06:31 -0800190 case RotationState::ROTATING_LEFT:
Sabina Daviscfb872f2018-02-25 16:28:20 -0800191 if (position->right_intake.beam_break) {
Austin Schuh17dd0892018-03-02 20:06:31 -0800192 rotation_count_ = kReverseTime;
193 } else {
194 --rotation_count_;
195 }
196 if (rotation_count_ == 0) {
197 rotation_state_ = RotationState::NOT_ROTATING;
198 }
199 break;
200 case RotationState::ROTATING_RIGHT:
Sabina Daviscfb872f2018-02-25 16:28:20 -0800201 if (position->left_intake.beam_break) {
Austin Schuh17dd0892018-03-02 20:06:31 -0800202 rotation_count_ = kReverseTime;
203 } else {
204 --rotation_count_;
205 }
206 if (rotation_count_ == 0) {
207 rotation_state_ = RotationState::NOT_ROTATING;
208 }
209 break;
210 }
211
Neil Balchba9cbba2018-04-06 22:26:38 -0700212 constexpr double kHoldVoltage = 1.0;
213 constexpr double kStuckVoltage = 10.0;
214
215 if (position->box_back_beambreak_triggered &&
216 roller_voltage > kHoldVoltage) {
217 roller_voltage = kHoldVoltage;
Austin Schuh96341532018-03-09 21:17:24 -0800218 }
Austin Schuh17dd0892018-03-02 20:06:31 -0800219 switch (rotation_state_) {
Neil Balchba9cbba2018-04-06 22:26:38 -0700220 case RotationState::NOT_ROTATING: {
221 double centering_gain = 13.0;
222 if (stuck_count_ > 1) {
223 if ((stuck_count_ - 1) % 2 == 0) {
224 centering_gain = 0.0;
225 }
226 }
227 output->left_intake.voltage_rollers =
228 roller_voltage - intake_center_error * centering_gain;
229 output->right_intake.voltage_rollers =
230 roller_voltage + intake_center_error * centering_gain;
231 } break;
232 case RotationState::STUCK: {
233 if (roller_voltage > kHoldVoltage) {
234 output->left_intake.voltage_rollers = -kStuckVoltage;
235 output->right_intake.voltage_rollers = -kStuckVoltage;
236 }
237 } break;
Austin Schuh17dd0892018-03-02 20:06:31 -0800238 case RotationState::ROTATING_LEFT:
Neil Balchba9cbba2018-04-06 22:26:38 -0700239 if (position->left_intake.beam_break) {
240 output->left_intake.voltage_rollers = -roller_voltage * 0.9;
241 } else {
242 output->left_intake.voltage_rollers = -roller_voltage * 0.6;
243 }
244 output->right_intake.voltage_rollers = roller_voltage;
Austin Schuh17dd0892018-03-02 20:06:31 -0800245 break;
246 case RotationState::ROTATING_RIGHT:
Neil Balchba9cbba2018-04-06 22:26:38 -0700247 output->left_intake.voltage_rollers = roller_voltage;
248 if (position->right_intake.beam_break) {
249 output->right_intake.voltage_rollers = -roller_voltage * 0.9;
250 } else {
251 output->right_intake.voltage_rollers = -roller_voltage * 0.6;
252 }
Austin Schuh17dd0892018-03-02 20:06:31 -0800253 break;
254 }
255 }
Neil Balchba9cbba2018-04-06 22:26:38 -0700256 } else {
257 rotation_state_ = RotationState::NOT_ROTATING;
258 rotation_count_ = 0;
259 stuck_count_ = 0;
Sabina Davis8d20ca82018-02-19 13:17:45 -0800260 }
Neil Balchba9cbba2018-04-06 22:26:38 -0700261 status->rotation_state = static_cast<uint32_t>(rotation_state_);
Austin Schuh8d5fff42018-05-30 20:44:12 -0700262
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700263 drivetrain_output_fetcher_.Fetch();
Austin Schuh8d5fff42018-05-30 20:44:12 -0700264
Austin Schuh300f2f62019-05-27 13:49:23 -0700265 vision_status_fetcher_.Fetch();
266 monotonic_clock::time_point monotonic_now = event_loop()->monotonic_now();
Austin Schuh8d5fff42018-05-30 20:44:12 -0700267 if (status->estopped) {
268 SendColors(0.5, 0.0, 0.0);
Austin Schuh300f2f62019-05-27 13:49:23 -0700269 } else if (!vision_status_fetcher_.get() ||
270 monotonic_now >
271 vision_status_fetcher_->sent_time + chrono::seconds(1)) {
Austin Schuh8d5fff42018-05-30 20:44:12 -0700272 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);
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700282 } else if (drivetrain_output_fetcher_.get() &&
283 ::std::max(::std::abs(drivetrain_output_fetcher_->left_voltage),
284 ::std::abs(drivetrain_output_fetcher_->right_voltage)) >
285 11.5) {
Austin Schuh8d5fff42018-05-30 20:44:12 -0700286 SendColors(0.5, 0.0, 0.5);
287 } else {
288 SendColors(0.0, 0.0, 0.0);
289 }
290
Neil Balchba9cbba2018-04-06 22:26:38 -0700291 last_box_distance_ = clipped_box_distance;
Sabina Davis8d20ca82018-02-19 13:17:45 -0800292}
293
Austin Schuh01a9f2a2019-05-27 13:36:30 -0700294void Superstructure::SendColors(float red, float green, float blue) {
295 auto new_status_light = status_light_sender_.MakeMessage();
296 new_status_light->red = red;
297 new_status_light->green = green;
298 new_status_light->blue = blue;
299
300 if (!new_status_light.Send()) {
301 LOG(ERROR, "Failed to send lights.\n");
302 }
303}
304
Sabina Davis8d20ca82018-02-19 13:17:45 -0800305} // namespace superstructure
306} // namespace control_loops
307} // namespace y2018