blob: f0748fa2a9cc04a74afb6f9d9d3214403b411f74 [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/logging/logging.h"
Alex Perrycb7da4b2019-08-28 19:35:56 -07006#include "frc971/control_loops/control_loops_generated.h"
7#include "frc971/control_loops/drivetrain/drivetrain_output_generated.h"
Sabina Davis8d20ca82018-02-19 13:17:45 -08008#include "y2018/constants.h"
9#include "y2018/control_loops/superstructure/intake/intake.h"
Alex Perrycb7da4b2019-08-28 19:35:56 -070010#include "y2018/status_light_generated.h"
11#include "y2018/vision/vision_generated.h"
Sabina Davis8d20ca82018-02-19 13:17:45 -080012
Stephan Pleinesf63bde82024-01-13 15:59:33 -080013namespace y2018::control_loops::superstructure {
Sabina Davis8d20ca82018-02-19 13:17:45 -080014
Neil Balchba9cbba2018-04-06 22:26:38 -070015using ::aos::monotonic_clock;
16
17namespace chrono = ::std::chrono;
18
Sabina Davis8d20ca82018-02-19 13:17:45 -080019namespace {
20// The maximum voltage the intake roller will be allowed to use.
21constexpr double kMaxIntakeRollerVoltage = 12.0;
22} // namespace
23
Austin Schuh55a13dc2019-01-27 22:39:03 -080024Superstructure::Superstructure(::aos::EventLoop *event_loop,
25 const ::std::string &name)
James Kuszmaul61750662021-06-21 21:32:33 -070026 : frc971::controls::ControlLoop<Goal, Position, Status, Output>(event_loop,
27 name),
Austin Schuh01a9f2a2019-05-27 13:36:30 -070028 status_light_sender_(
Alex Perrycb7da4b2019-08-28 19:35:56 -070029 event_loop->MakeSender<::y2018::StatusLight>("/superstructure")),
Austin Schuh300f2f62019-05-27 13:49:23 -070030 vision_status_fetcher_(
31 event_loop->MakeFetcher<::y2018::vision::VisionStatus>(
Alex Perrycb7da4b2019-08-28 19:35:56 -070032 "/superstructure")),
Austin Schuhbd0a40f2019-06-30 14:56:31 -070033 drivetrain_output_fetcher_(
Alex Perrycb7da4b2019-08-28 19:35:56 -070034 event_loop->MakeFetcher<::frc971::control_loops::drivetrain::Output>(
35 "/drivetrain")),
Stephan Massalta769ca22019-01-09 05:29:13 +000036 intake_left_(constants::GetValues().left_intake.zeroing,
37 constants::GetValues().left_intake.spring_offset),
38 intake_right_(constants::GetValues().right_intake.zeroing,
39 constants::GetValues().right_intake.spring_offset) {}
Sabina Davis8d20ca82018-02-19 13:17:45 -080040
Alex Perrycb7da4b2019-08-28 19:35:56 -070041void Superstructure::RunIteration(const Goal *unsafe_goal,
42 const Position *position,
43 aos::Sender<Output>::Builder *output,
44 aos::Sender<Status>::Builder *status) {
Austin Schuh20177c92019-07-07 20:48:24 -070045 const monotonic_clock::time_point monotonic_now =
46 event_loop()->monotonic_now();
Sabina Davis8d20ca82018-02-19 13:17:45 -080047 if (WasReset()) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070048 AOS_LOG(ERROR, "WPILib reset, restarting\n");
Sabina Davis8d20ca82018-02-19 13:17:45 -080049 intake_left_.Reset();
50 intake_right_.Reset();
Austin Schuhcb091712018-02-21 20:01:55 -080051 arm_.Reset();
Sabina Davis8d20ca82018-02-19 13:17:45 -080052 }
53
Neil Balchba9cbba2018-04-06 22:26:38 -070054 const double clipped_box_distance =
Alex Perrycb7da4b2019-08-28 19:35:56 -070055 ::std::min(1.0, ::std::max(0.0, position->box_distance()));
Neil Balchba9cbba2018-04-06 22:26:38 -070056
57 const double box_velocity =
58 (clipped_box_distance - last_box_distance_) / 0.005;
59
60 constexpr double kFilteredBoxVelocityAlpha = 0.02;
61 filtered_box_velocity_ =
62 box_velocity * kFilteredBoxVelocityAlpha +
63 (1.0 - kFilteredBoxVelocityAlpha) * filtered_box_velocity_;
Neil Balchba9cbba2018-04-06 22:26:38 -070064
65 constexpr double kCenteringAngleGain = 0.0;
66 const double left_intake_goal =
Alex Perrycb7da4b2019-08-28 19:35:56 -070067 ::std::min(arm_.max_intake_override(),
68 (unsafe_goal == nullptr || !unsafe_goal->has_intake()
69 ? 0.0
70 : unsafe_goal->intake()->left_intake_angle())) +
Neil Balchba9cbba2018-04-06 22:26:38 -070071 last_intake_center_error_ * kCenteringAngleGain;
72 const double right_intake_goal =
Alex Perrycb7da4b2019-08-28 19:35:56 -070073 ::std::min(arm_.max_intake_override(),
74 (unsafe_goal == nullptr || !unsafe_goal->has_intake()
75 ? 0.0
76 : unsafe_goal->intake()->right_intake_angle())) -
Neil Balchba9cbba2018-04-06 22:26:38 -070077 last_intake_center_error_ * kCenteringAngleGain;
Austin Schuh83cdd8a2018-03-21 20:49:02 -070078
Alex Perrycb7da4b2019-08-28 19:35:56 -070079 IntakeVoltageT left_intake_output;
80 flatbuffers::Offset<superstructure::IntakeSideStatus> left_status_offset =
81 intake_left_.Iterate(
82 unsafe_goal != nullptr ? &(left_intake_goal) : nullptr,
83 position->left_intake(),
84 output != nullptr ? &(left_intake_output) : nullptr, status->fbb());
Sabina Davis8d20ca82018-02-19 13:17:45 -080085
Alex Perrycb7da4b2019-08-28 19:35:56 -070086 IntakeVoltageT right_intake_output;
87 flatbuffers::Offset<superstructure::IntakeSideStatus> right_status_offset =
88 intake_right_.Iterate(
89 unsafe_goal != nullptr ? &(right_intake_goal) : nullptr,
90 position->right_intake(),
91 output != nullptr ? &(right_intake_output) : nullptr, status->fbb());
Sabina Davis8d20ca82018-02-19 13:17:45 -080092
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
Alex Perrycb7da4b2019-08-28 19:35:56 -0700100 bool open_claw = unsafe_goal != nullptr ? unsafe_goal->open_claw() : false;
Austin Schuhd76546a2018-07-08 16:05:14 -0700101 if (unsafe_goal) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700102 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()) {
Austin Schuhd76546a2018-07-08 16:05:14 -0700105 open_claw = false;
106 }
107 }
108 }
Austin Schuh17e484e2018-03-11 01:11:36 -0800109
Alex Perrycb7da4b2019-08-28 19:35:56 -0700110 const uint32_t arm_goal_position =
111 unsafe_goal != nullptr ? unsafe_goal->arm_goal_position() : 0u;
112
113 double voltage_proximal_output = 0.0;
114 double voltage_distal_output = 0.0;
115 bool release_arm_brake_output = false;
116 bool claw_grabbed_output = false;
117 flatbuffers::Offset<superstructure::ArmStatus> arm_status_offset =
118 arm_.Iterate(
119 monotonic_now,
120 unsafe_goal != nullptr ? &(arm_goal_position) : nullptr,
121 unsafe_goal != nullptr ? unsafe_goal->grab_box() : false, open_claw,
122 unsafe_goal != nullptr ? unsafe_goal->close_claw() : false,
123 position->arm(), position->claw_beambreak_triggered(),
124 position->box_back_beambreak_triggered(), intake_clear_of_box,
125 unsafe_goal != nullptr ? unsafe_goal->voltage_winch() > 1.0 : false,
126 unsafe_goal != nullptr ? unsafe_goal->trajectory_override() : false,
127 output != nullptr ? &voltage_proximal_output : nullptr,
128 output != nullptr ? &voltage_distal_output : nullptr,
129 output != nullptr ? &release_arm_brake_output : nullptr,
130 output != nullptr ? &claw_grabbed_output : nullptr, status->fbb());
131
Alex Perrycb7da4b2019-08-28 19:35:56 -0700132 bool hook_release_output = false;
133 bool forks_release_output = false;
134 double voltage_winch_output = 0.0;
Austin Schuh17e484e2018-03-11 01:11:36 -0800135 if (output) {
136 if (unsafe_goal) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700137 hook_release_output = unsafe_goal->hook_release();
138 voltage_winch_output = unsafe_goal->voltage_winch();
139 forks_release_output = unsafe_goal->deploy_fork();
Austin Schuh17e484e2018-03-11 01:11:36 -0800140 }
141 }
Austin Schuhcb091712018-02-21 20:01:55 -0800142
Alex Perrycb7da4b2019-08-28 19:35:56 -0700143 Status::Builder status_builder = status->MakeBuilder<Status>();
Austin Schuhcb091712018-02-21 20:01:55 -0800144
Alex Perrycb7da4b2019-08-28 19:35:56 -0700145 status_builder.add_left_intake(left_status_offset);
146 status_builder.add_right_intake(right_status_offset);
147 status_builder.add_arm(arm_status_offset);
148
149 status_builder.add_filtered_box_velocity(filtered_box_velocity_);
150 const bool estopped =
151 intake_left_.estopped() || intake_right_.estopped() || arm_.estopped();
152 status_builder.add_estopped(estopped);
153
154 status_builder.add_zeroed(intake_left_.zeroed() && intake_right_.zeroed() &&
155 arm_.zeroed());
Sabina Davis8d20ca82018-02-19 13:17:45 -0800156
157 if (output && unsafe_goal) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700158 double roller_voltage =
159 ::std::max(-kMaxIntakeRollerVoltage,
160 ::std::min(unsafe_goal->intake()->roller_voltage(),
161 kMaxIntakeRollerVoltage));
Neil Balchba9cbba2018-04-06 22:26:38 -0700162 constexpr int kReverseTime = 14;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700163 if (unsafe_goal->intake()->roller_voltage() < 0.0 ||
164 unsafe_goal->disable_box_correct()) {
165 left_intake_output.voltage_rollers = roller_voltage;
166 right_intake_output.voltage_rollers = roller_voltage;
Austin Schuh17dd0892018-03-02 20:06:31 -0800167 rotation_state_ = RotationState::NOT_ROTATING;
168 rotation_count_ = 0;
Neil Balchba9cbba2018-04-06 22:26:38 -0700169 stuck_count_ = 0;
Austin Schuh17dd0892018-03-02 20:06:31 -0800170 } else {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700171 const bool stuck = position->box_distance() < 0.20 &&
172 filtered_box_velocity_ > -0.05 &&
173 !position->box_back_beambreak_triggered();
Neil Balchba9cbba2018-04-06 22:26:38 -0700174 // Make sure we don't declare ourselves re-stuck too quickly. We want to
175 // wait 400 ms before triggering the stuck condition again.
176 if (!stuck) {
177 last_unstuck_time_ = monotonic_now;
178 }
179 if (monotonic_now < last_stuck_time_ + chrono::milliseconds(400)) {
180 last_unstuck_time_ = monotonic_now;
181 }
182
Austin Schuh17dd0892018-03-02 20:06:31 -0800183 switch (rotation_state_) {
184 case RotationState::NOT_ROTATING:
Neil Balchba9cbba2018-04-06 22:26:38 -0700185 if (stuck &&
186 monotonic_now > last_stuck_time_ + chrono::milliseconds(400) &&
187 monotonic_now > last_unstuck_time_ + chrono::milliseconds(100)) {
188 rotation_state_ = RotationState::STUCK;
189 ++stuck_count_;
190 last_stuck_time_ = monotonic_now;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700191 } else if (position->left_intake()->beam_break()) {
Austin Schuh17dd0892018-03-02 20:06:31 -0800192 rotation_state_ = RotationState::ROTATING_RIGHT;
193 rotation_count_ = kReverseTime;
194 break;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700195 } else if (position->right_intake()->beam_break()) {
Austin Schuh17dd0892018-03-02 20:06:31 -0800196 rotation_state_ = RotationState::ROTATING_LEFT;
197 rotation_count_ = kReverseTime;
198 break;
Austin Schuh17dd0892018-03-02 20:06:31 -0800199 }
Vinay Siva86f568e2021-07-11 11:20:02 -0700200 [[fallthrough]];
Neil Balchba9cbba2018-04-06 22:26:38 -0700201 case RotationState::STUCK: {
202 // Latch being stuck for 80 ms so we kick the box out far enough.
203 if (last_stuck_time_ + chrono::milliseconds(80) < monotonic_now) {
204 rotation_state_ = RotationState::NOT_ROTATING;
205 last_unstuck_time_ = monotonic_now;
206 }
207 } break;
Austin Schuh17dd0892018-03-02 20:06:31 -0800208 case RotationState::ROTATING_LEFT:
Alex Perrycb7da4b2019-08-28 19:35:56 -0700209 if (position->right_intake()->beam_break()) {
Austin Schuh17dd0892018-03-02 20:06:31 -0800210 rotation_count_ = kReverseTime;
211 } else {
212 --rotation_count_;
213 }
214 if (rotation_count_ == 0) {
215 rotation_state_ = RotationState::NOT_ROTATING;
216 }
217 break;
218 case RotationState::ROTATING_RIGHT:
Alex Perrycb7da4b2019-08-28 19:35:56 -0700219 if (position->left_intake()->beam_break()) {
Austin Schuh17dd0892018-03-02 20:06:31 -0800220 rotation_count_ = kReverseTime;
221 } else {
222 --rotation_count_;
223 }
224 if (rotation_count_ == 0) {
225 rotation_state_ = RotationState::NOT_ROTATING;
226 }
227 break;
228 }
229
Neil Balchba9cbba2018-04-06 22:26:38 -0700230 constexpr double kHoldVoltage = 1.0;
231 constexpr double kStuckVoltage = 10.0;
232
Alex Perrycb7da4b2019-08-28 19:35:56 -0700233 if (position->box_back_beambreak_triggered() &&
Neil Balchba9cbba2018-04-06 22:26:38 -0700234 roller_voltage > kHoldVoltage) {
235 roller_voltage = kHoldVoltage;
Austin Schuh96341532018-03-09 21:17:24 -0800236 }
Austin Schuh17dd0892018-03-02 20:06:31 -0800237 switch (rotation_state_) {
Neil Balchba9cbba2018-04-06 22:26:38 -0700238 case RotationState::NOT_ROTATING: {
239 double centering_gain = 13.0;
240 if (stuck_count_ > 1) {
241 if ((stuck_count_ - 1) % 2 == 0) {
242 centering_gain = 0.0;
243 }
244 }
Alex Perrycb7da4b2019-08-28 19:35:56 -0700245 left_intake_output.voltage_rollers =
Neil Balchba9cbba2018-04-06 22:26:38 -0700246 roller_voltage - intake_center_error * centering_gain;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700247 right_intake_output.voltage_rollers =
Neil Balchba9cbba2018-04-06 22:26:38 -0700248 roller_voltage + intake_center_error * centering_gain;
249 } break;
250 case RotationState::STUCK: {
251 if (roller_voltage > kHoldVoltage) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700252 left_intake_output.voltage_rollers = -kStuckVoltage;
253 right_intake_output.voltage_rollers = -kStuckVoltage;
Neil Balchba9cbba2018-04-06 22:26:38 -0700254 }
255 } break;
Austin Schuh17dd0892018-03-02 20:06:31 -0800256 case RotationState::ROTATING_LEFT:
Alex Perrycb7da4b2019-08-28 19:35:56 -0700257 if (position->left_intake()->beam_break()) {
258 left_intake_output.voltage_rollers = -roller_voltage * 0.9;
Neil Balchba9cbba2018-04-06 22:26:38 -0700259 } else {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700260 left_intake_output.voltage_rollers = -roller_voltage * 0.6;
Neil Balchba9cbba2018-04-06 22:26:38 -0700261 }
Alex Perrycb7da4b2019-08-28 19:35:56 -0700262 right_intake_output.voltage_rollers = roller_voltage;
Austin Schuh17dd0892018-03-02 20:06:31 -0800263 break;
264 case RotationState::ROTATING_RIGHT:
Alex Perrycb7da4b2019-08-28 19:35:56 -0700265 left_intake_output.voltage_rollers = roller_voltage;
266 if (position->right_intake()->beam_break()) {
267 right_intake_output.voltage_rollers = -roller_voltage * 0.9;
Neil Balchba9cbba2018-04-06 22:26:38 -0700268 } else {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700269 right_intake_output.voltage_rollers = -roller_voltage * 0.6;
Neil Balchba9cbba2018-04-06 22:26:38 -0700270 }
Austin Schuh17dd0892018-03-02 20:06:31 -0800271 break;
272 }
273 }
Neil Balchba9cbba2018-04-06 22:26:38 -0700274 } else {
275 rotation_state_ = RotationState::NOT_ROTATING;
276 rotation_count_ = 0;
277 stuck_count_ = 0;
Sabina Davis8d20ca82018-02-19 13:17:45 -0800278 }
Alex Perrycb7da4b2019-08-28 19:35:56 -0700279 status_builder.add_rotation_state(static_cast<uint32_t>(rotation_state_));
Austin Schuh8d5fff42018-05-30 20:44:12 -0700280
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700281 drivetrain_output_fetcher_.Fetch();
Austin Schuh8d5fff42018-05-30 20:44:12 -0700282
Austin Schuh300f2f62019-05-27 13:49:23 -0700283 vision_status_fetcher_.Fetch();
Alex Perrycb7da4b2019-08-28 19:35:56 -0700284 if (estopped) {
Austin Schuh8d5fff42018-05-30 20:44:12 -0700285 SendColors(0.5, 0.0, 0.0);
Austin Schuh300f2f62019-05-27 13:49:23 -0700286 } else if (!vision_status_fetcher_.get() ||
287 monotonic_now >
Austin Schuhad154822019-12-27 15:45:13 -0800288 vision_status_fetcher_.context().monotonic_event_time +
Alex Perrycb7da4b2019-08-28 19:35:56 -0700289 chrono::seconds(1)) {
Austin Schuh8d5fff42018-05-30 20:44:12 -0700290 SendColors(0.5, 0.5, 0.0);
291 } else if (rotation_state_ == RotationState::ROTATING_LEFT ||
292 rotation_state_ == RotationState::ROTATING_RIGHT) {
293 SendColors(0.5, 0.20, 0.0);
294 } else if (rotation_state_ == RotationState::STUCK) {
295 SendColors(0.5, 0.0, 0.5);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700296 } else if (position->box_back_beambreak_triggered()) {
Austin Schuh8d5fff42018-05-30 20:44:12 -0700297 SendColors(0.0, 0.0, 0.5);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700298 } else if (position->box_distance() < 0.2) {
Austin Schuh8d5fff42018-05-30 20:44:12 -0700299 SendColors(0.0, 0.5, 0.0);
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700300 } else if (drivetrain_output_fetcher_.get() &&
Alex Perrycb7da4b2019-08-28 19:35:56 -0700301 ::std::max(
302 ::std::abs(drivetrain_output_fetcher_->left_voltage()),
303 ::std::abs(drivetrain_output_fetcher_->right_voltage())) >
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700304 11.5) {
Austin Schuh8d5fff42018-05-30 20:44:12 -0700305 SendColors(0.5, 0.0, 0.5);
306 } else {
307 SendColors(0.0, 0.0, 0.0);
308 }
309
Neil Balchba9cbba2018-04-06 22:26:38 -0700310 last_box_distance_ = clipped_box_distance;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700311
312 if (output) {
313 flatbuffers::Offset<IntakeVoltage> left_intake_offset =
314 IntakeVoltage::Pack(*output->fbb(), &left_intake_output);
315 flatbuffers::Offset<IntakeVoltage> right_intake_offset =
316 IntakeVoltage::Pack(*output->fbb(), &right_intake_output);
317
318 Output::Builder output_builder = output->MakeBuilder<Output>();
319 output_builder.add_left_intake(left_intake_offset);
320 output_builder.add_right_intake(right_intake_offset);
321 output_builder.add_voltage_proximal(voltage_proximal_output);
322 output_builder.add_voltage_distal(voltage_distal_output);
323 output_builder.add_release_arm_brake(release_arm_brake_output);
324 output_builder.add_claw_grabbed(claw_grabbed_output);
325
326 output_builder.add_hook_release(hook_release_output);
327 output_builder.add_forks_release(forks_release_output);
328 output_builder.add_voltage_winch(voltage_winch_output);
329
milind1f1dca32021-07-03 13:50:07 -0700330 output->CheckOk(output->Send(output_builder.Finish()));
Alex Perrycb7da4b2019-08-28 19:35:56 -0700331 }
332
milind1f1dca32021-07-03 13:50:07 -0700333 (void)status->Send(status_builder.Finish());
Sabina Davis8d20ca82018-02-19 13:17:45 -0800334}
335
Austin Schuh01a9f2a2019-05-27 13:36:30 -0700336void Superstructure::SendColors(float red, float green, float blue) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700337 auto builder = status_light_sender_.MakeBuilder();
338 StatusLight::Builder status_light_builder =
339 builder.MakeBuilder<StatusLight>();
Austin Schuh01a9f2a2019-05-27 13:36:30 -0700340
Alex Perrycb7da4b2019-08-28 19:35:56 -0700341 status_light_builder.add_red(red);
342 status_light_builder.add_green(green);
343 status_light_builder.add_blue(blue);
344
milind1f1dca32021-07-03 13:50:07 -0700345 if (builder.Send(status_light_builder.Finish()) !=
346 aos::RawSender::Error::kOk) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700347 AOS_LOG(ERROR, "Failed to send lights.\n");
Austin Schuh01a9f2a2019-05-27 13:36:30 -0700348 }
349}
350
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800351} // namespace y2018::control_loops::superstructure