blob: 757b166004fac5dd7062790cdafb09652c43babb [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"
8#include "y2018/constants.h"
9#include "y2018/control_loops/superstructure/intake/intake.h"
10
11namespace y2018 {
12namespace control_loops {
13namespace superstructure {
14
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
24Superstructure::Superstructure(
25 control_loops::SuperstructureQueue *superstructure_queue)
26 : aos::controls::ControlLoop<control_loops::SuperstructureQueue>(
27 superstructure_queue),
28 intake_left_(constants::GetValues().left_intake.zeroing),
29 intake_right_(constants::GetValues().right_intake.zeroing) {}
30
31void Superstructure::RunIteration(
32 const control_loops::SuperstructureQueue::Goal *unsafe_goal,
33 const control_loops::SuperstructureQueue::Position *position,
34 control_loops::SuperstructureQueue::Output *output,
35 control_loops::SuperstructureQueue::Status *status) {
36 if (WasReset()) {
37 LOG(ERROR, "WPILib reset, restarting\n");
38 intake_left_.Reset();
39 intake_right_.Reset();
Austin Schuhcb091712018-02-21 20:01:55 -080040 arm_.Reset();
Sabina Davis8d20ca82018-02-19 13:17:45 -080041 }
42
Neil Balchba9cbba2018-04-06 22:26:38 -070043 const double clipped_box_distance =
44 ::std::min(1.0, ::std::max(0.0, position->box_distance));
45
46 const double box_velocity =
47 (clipped_box_distance - last_box_distance_) / 0.005;
48
49 constexpr double kFilteredBoxVelocityAlpha = 0.02;
50 filtered_box_velocity_ =
51 box_velocity * kFilteredBoxVelocityAlpha +
52 (1.0 - kFilteredBoxVelocityAlpha) * filtered_box_velocity_;
53 status->filtered_box_velocity = filtered_box_velocity_;
54
55 constexpr double kCenteringAngleGain = 0.0;
56 const double left_intake_goal =
57 ::std::min(
58 arm_.max_intake_override(),
59 (unsafe_goal == nullptr ? 0.0
60 : unsafe_goal->intake.left_intake_angle)) +
61 last_intake_center_error_ * kCenteringAngleGain;
62 const double right_intake_goal =
63 ::std::min(
64 arm_.max_intake_override(),
65 (unsafe_goal == nullptr ? 0.0
66 : unsafe_goal->intake.right_intake_angle)) -
67 last_intake_center_error_ * kCenteringAngleGain;
Austin Schuh83cdd8a2018-03-21 20:49:02 -070068
Austin Schuh96341532018-03-09 21:17:24 -080069 intake_left_.Iterate(unsafe_goal != nullptr ? &(left_intake_goal) : nullptr,
Sabina Daviscfb872f2018-02-25 16:28:20 -080070 &(position->left_intake),
71 output != nullptr ? &(output->left_intake) : nullptr,
Sabina Davis8d20ca82018-02-19 13:17:45 -080072 &(status->left_intake));
73
Austin Schuh96341532018-03-09 21:17:24 -080074 intake_right_.Iterate(unsafe_goal != nullptr ? &(right_intake_goal) : nullptr,
Sabina Daviscfb872f2018-02-25 16:28:20 -080075 &(position->right_intake),
76 output != nullptr ? &(output->right_intake) : nullptr,
Sabina Davis8d20ca82018-02-19 13:17:45 -080077 &(status->right_intake));
78
Neil Balchba9cbba2018-04-06 22:26:38 -070079 const double intake_center_error =
80 intake_right_.output_position() - intake_left_.output_position();
81 last_intake_center_error_ = intake_center_error;
82
Austin Schuh96341532018-03-09 21:17:24 -080083 const bool intake_clear_of_box =
84 intake_left_.clear_of_box() && intake_right_.clear_of_box();
Austin Schuhcb091712018-02-21 20:01:55 -080085 arm_.Iterate(
86 unsafe_goal != nullptr ? &(unsafe_goal->arm_goal_position) : nullptr,
Austin Schuh96341532018-03-09 21:17:24 -080087 unsafe_goal != nullptr ? unsafe_goal->grab_box : false,
Neil Balchba9cbba2018-04-06 22:26:38 -070088 unsafe_goal != nullptr ? unsafe_goal->open_claw : false,
89 unsafe_goal != nullptr ? unsafe_goal->close_claw : false,
90 &(position->arm), position->claw_beambreak_triggered,
Austin Schuh96341532018-03-09 21:17:24 -080091 position->box_back_beambreak_triggered, intake_clear_of_box,
Austin Schuhcb091712018-02-21 20:01:55 -080092 output != nullptr ? &(output->voltage_proximal) : nullptr,
93 output != nullptr ? &(output->voltage_distal) : nullptr,
94 output != nullptr ? &(output->release_arm_brake) : nullptr,
Austin Schuh17e484e2018-03-11 01:11:36 -080095 output != nullptr ? &(output->claw_grabbed) : nullptr, &(status->arm),
96 unsafe_goal != nullptr ? unsafe_goal->voltage_winch > 1.0 : false);
97
98 if (output) {
99 if (unsafe_goal) {
100 output->hook_release = unsafe_goal->hook_release;
101 output->voltage_winch = unsafe_goal->voltage_winch;
102 output->forks_release = unsafe_goal->deploy_fork;
103 } else {
104 output->voltage_winch = 0.0;
105 output->hook_release = false;
106 output->forks_release = false;
107 }
108 }
Austin Schuhcb091712018-02-21 20:01:55 -0800109
110 status->estopped = status->left_intake.estopped ||
111 status->right_intake.estopped || status->arm.estopped;
112
113 status->zeroed = status->left_intake.zeroed && status->right_intake.zeroed &&
114 status->arm.zeroed;
Sabina Davis8d20ca82018-02-19 13:17:45 -0800115
116 if (output && unsafe_goal) {
Austin Schuh96341532018-03-09 21:17:24 -0800117 double roller_voltage = ::std::max(
Sabina Davis8d20ca82018-02-19 13:17:45 -0800118 -kMaxIntakeRollerVoltage, ::std::min(unsafe_goal->intake.roller_voltage,
119 kMaxIntakeRollerVoltage));
Neil Balchba9cbba2018-04-06 22:26:38 -0700120 constexpr int kReverseTime = 14;
121 if (unsafe_goal->intake.roller_voltage < 0.0 ||
122 unsafe_goal->disable_box_correct) {
Sabina Daviscfb872f2018-02-25 16:28:20 -0800123 output->left_intake.voltage_rollers = roller_voltage;
124 output->right_intake.voltage_rollers = roller_voltage;
Austin Schuh17dd0892018-03-02 20:06:31 -0800125 rotation_state_ = RotationState::NOT_ROTATING;
126 rotation_count_ = 0;
Neil Balchba9cbba2018-04-06 22:26:38 -0700127 stuck_count_ = 0;
Austin Schuh17dd0892018-03-02 20:06:31 -0800128 } else {
Neil Balchba9cbba2018-04-06 22:26:38 -0700129 monotonic_clock::time_point monotonic_now = monotonic_clock::now();
130 const bool stuck = position->box_distance < 0.20 &&
131 filtered_box_velocity_ > -0.05 &&
132 !position->box_back_beambreak_triggered;
133 // Make sure we don't declare ourselves re-stuck too quickly. We want to
134 // wait 400 ms before triggering the stuck condition again.
135 if (!stuck) {
136 last_unstuck_time_ = monotonic_now;
137 }
138 if (monotonic_now < last_stuck_time_ + chrono::milliseconds(400)) {
139 last_unstuck_time_ = monotonic_now;
140 }
141
Austin Schuh17dd0892018-03-02 20:06:31 -0800142 switch (rotation_state_) {
143 case RotationState::NOT_ROTATING:
Neil Balchba9cbba2018-04-06 22:26:38 -0700144 if (stuck &&
145 monotonic_now > last_stuck_time_ + chrono::milliseconds(400) &&
146 monotonic_now > last_unstuck_time_ + chrono::milliseconds(100)) {
147 rotation_state_ = RotationState::STUCK;
148 ++stuck_count_;
149 last_stuck_time_ = monotonic_now;
150 } else if (position->left_intake.beam_break) {
Austin Schuh17dd0892018-03-02 20:06:31 -0800151 rotation_state_ = RotationState::ROTATING_RIGHT;
152 rotation_count_ = kReverseTime;
153 break;
Sabina Daviscfb872f2018-02-25 16:28:20 -0800154 } else if (position->right_intake.beam_break) {
Austin Schuh17dd0892018-03-02 20:06:31 -0800155 rotation_state_ = RotationState::ROTATING_LEFT;
156 rotation_count_ = kReverseTime;
157 break;
158 } else {
159 break;
160 }
Neil Balchba9cbba2018-04-06 22:26:38 -0700161 case RotationState::STUCK: {
162 // Latch being stuck for 80 ms so we kick the box out far enough.
163 if (last_stuck_time_ + chrono::milliseconds(80) < monotonic_now) {
164 rotation_state_ = RotationState::NOT_ROTATING;
165 last_unstuck_time_ = monotonic_now;
166 }
167 } break;
Austin Schuh17dd0892018-03-02 20:06:31 -0800168 case RotationState::ROTATING_LEFT:
Sabina Daviscfb872f2018-02-25 16:28:20 -0800169 if (position->right_intake.beam_break) {
Austin Schuh17dd0892018-03-02 20:06:31 -0800170 rotation_count_ = kReverseTime;
171 } else {
172 --rotation_count_;
173 }
174 if (rotation_count_ == 0) {
175 rotation_state_ = RotationState::NOT_ROTATING;
176 }
177 break;
178 case RotationState::ROTATING_RIGHT:
Sabina Daviscfb872f2018-02-25 16:28:20 -0800179 if (position->left_intake.beam_break) {
Austin Schuh17dd0892018-03-02 20:06:31 -0800180 rotation_count_ = kReverseTime;
181 } else {
182 --rotation_count_;
183 }
184 if (rotation_count_ == 0) {
185 rotation_state_ = RotationState::NOT_ROTATING;
186 }
187 break;
188 }
189
Neil Balchba9cbba2018-04-06 22:26:38 -0700190 constexpr double kHoldVoltage = 1.0;
191 constexpr double kStuckVoltage = 10.0;
192
193 if (position->box_back_beambreak_triggered &&
194 roller_voltage > kHoldVoltage) {
195 roller_voltage = kHoldVoltage;
Austin Schuh96341532018-03-09 21:17:24 -0800196 }
Austin Schuh17dd0892018-03-02 20:06:31 -0800197 switch (rotation_state_) {
Neil Balchba9cbba2018-04-06 22:26:38 -0700198 case RotationState::NOT_ROTATING: {
199 double centering_gain = 13.0;
200 if (stuck_count_ > 1) {
201 if ((stuck_count_ - 1) % 2 == 0) {
202 centering_gain = 0.0;
203 }
204 }
205 output->left_intake.voltage_rollers =
206 roller_voltage - intake_center_error * centering_gain;
207 output->right_intake.voltage_rollers =
208 roller_voltage + intake_center_error * centering_gain;
209 } break;
210 case RotationState::STUCK: {
211 if (roller_voltage > kHoldVoltage) {
212 output->left_intake.voltage_rollers = -kStuckVoltage;
213 output->right_intake.voltage_rollers = -kStuckVoltage;
214 }
215 } break;
Austin Schuh17dd0892018-03-02 20:06:31 -0800216 case RotationState::ROTATING_LEFT:
Neil Balchba9cbba2018-04-06 22:26:38 -0700217 if (position->left_intake.beam_break) {
218 output->left_intake.voltage_rollers = -roller_voltage * 0.9;
219 } else {
220 output->left_intake.voltage_rollers = -roller_voltage * 0.6;
221 }
222 output->right_intake.voltage_rollers = roller_voltage;
Austin Schuh17dd0892018-03-02 20:06:31 -0800223 break;
224 case RotationState::ROTATING_RIGHT:
Neil Balchba9cbba2018-04-06 22:26:38 -0700225 output->left_intake.voltage_rollers = roller_voltage;
226 if (position->right_intake.beam_break) {
227 output->right_intake.voltage_rollers = -roller_voltage * 0.9;
228 } else {
229 output->right_intake.voltage_rollers = -roller_voltage * 0.6;
230 }
Austin Schuh17dd0892018-03-02 20:06:31 -0800231 break;
232 }
233 }
Neil Balchba9cbba2018-04-06 22:26:38 -0700234 } else {
235 rotation_state_ = RotationState::NOT_ROTATING;
236 rotation_count_ = 0;
237 stuck_count_ = 0;
Sabina Davis8d20ca82018-02-19 13:17:45 -0800238 }
Neil Balchba9cbba2018-04-06 22:26:38 -0700239 status->rotation_state = static_cast<uint32_t>(rotation_state_);
240 last_box_distance_ = clipped_box_distance;
Sabina Davis8d20ca82018-02-19 13:17:45 -0800241}
242
243} // namespace superstructure
244} // namespace control_loops
245} // namespace y2018