blob: 5dbe7e7780446e94b27c48faa9e8365ab8ebc339 [file] [log] [blame]
milind-u086d7262022-01-19 20:44:18 -08001#include "y2022/control_loops/superstructure/superstructure.h"
2
3#include "aos/events/event_loop.h"
Ravago Jones3283ce02022-03-09 19:31:29 -08004#include "aos/flatbuffer_merge.h"
James Kuszmaul40526952022-03-13 15:56:38 -07005#include "frc971/zeroing/wrap.h"
Milind Upadhyay225156b2022-02-25 22:42:12 -08006#include "y2022/control_loops/superstructure/collision_avoidance.h"
milind-u086d7262022-01-19 20:44:18 -08007
8namespace y2022 {
9namespace control_loops {
10namespace superstructure {
11
12using frc971::control_loops::AbsoluteEncoderProfiledJointStatus;
13using frc971::control_loops::PotAndAbsoluteEncoderProfiledJointStatus;
Henry Speiser55aa3ba2022-02-21 23:21:12 -080014using frc971::control_loops::RelativeEncoderProfiledJointStatus;
milind-u086d7262022-01-19 20:44:18 -080015
16Superstructure::Superstructure(::aos::EventLoop *event_loop,
Henry Speiser55aa3ba2022-02-21 23:21:12 -080017 std::shared_ptr<const constants::Values> values,
milind-u086d7262022-01-19 20:44:18 -080018 const ::std::string &name)
19 : frc971::controls::ControlLoop<Goal, Position, Status, Output>(event_loop,
Siddhant Kanwar0e37f592022-02-21 19:26:50 -080020 name),
Austin Schuh39f26f62022-02-24 21:34:46 -080021 values_(values),
22 climber_(values_->climber.subsystem_params),
23 intake_front_(values_->intake_front.subsystem_params),
24 intake_back_(values_->intake_back.subsystem_params),
25 turret_(values_->turret.subsystem_params),
Ravago Jones5da06352022-03-04 20:26:24 -080026 catapult_(*values_),
Henry Speiser55aa3ba2022-02-21 23:21:12 -080027 drivetrain_status_fetcher_(
28 event_loop->MakeFetcher<frc971::control_loops::drivetrain::Status>(
Austin Schuh39f26f62022-02-24 21:34:46 -080029 "/drivetrain")),
Ravago Jones5da06352022-03-04 20:26:24 -080030 can_position_fetcher_(
31 event_loop->MakeFetcher<CANPosition>("/superstructure")) {
milind-u086d7262022-01-19 20:44:18 -080032 event_loop->SetRuntimeRealtimePriority(30);
33}
34
35void Superstructure::RunIteration(const Goal *unsafe_goal,
Siddhant Kanwar0e37f592022-02-21 19:26:50 -080036 const Position *position,
milind-u086d7262022-01-19 20:44:18 -080037 aos::Sender<Output>::Builder *output,
38 aos::Sender<Status>::Builder *status) {
39 if (WasReset()) {
40 AOS_LOG(ERROR, "WPILib reset, restarting\n");
Henry Speiser55aa3ba2022-02-21 23:21:12 -080041 intake_front_.Reset();
42 intake_back_.Reset();
43 turret_.Reset();
44 climber_.Reset();
Austin Schuh39f26f62022-02-24 21:34:46 -080045 catapult_.Reset();
Henry Speiser55aa3ba2022-02-21 23:21:12 -080046 }
47
Ravago Jones5da06352022-03-04 20:26:24 -080048 OutputT output_struct;
Milind Upadhyay225156b2022-02-25 22:42:12 -080049
Ravago Jones5da06352022-03-04 20:26:24 -080050 aos::FlatbufferFixedAllocatorArray<
Austin Schuhfce2b602022-03-13 20:05:01 -070051 frc971::control_loops::StaticZeroingSingleDOFProfiledSubsystemGoal, 512>
James Kuszmaul40526952022-03-13 15:56:38 -070052 turret_loading_goal_buffer;
Austin Schuhfce2b602022-03-13 20:05:01 -070053 aos::FlatbufferFixedAllocatorArray<CatapultGoal, 512> catapult_goal_buffer;
Ravago Jones5da06352022-03-04 20:26:24 -080054
55 const aos::monotonic_clock::time_point timestamp =
56 event_loop()->context().monotonic_event_time;
Milind Upadhyay225156b2022-02-25 22:42:12 -080057
Henry Speiser55aa3ba2022-02-21 23:21:12 -080058 drivetrain_status_fetcher_.Fetch();
59 const float velocity = robot_velocity();
60
James Kuszmaul84083f42022-02-27 17:24:38 -080061 const turret::Aimer::Goal *auto_aim_goal = nullptr;
62 if (drivetrain_status_fetcher_.get() != nullptr) {
63 aimer_.Update(drivetrain_status_fetcher_.get(),
64 turret::Aimer::ShotMode::kShootOnTheFly);
65 auto_aim_goal = aimer_.TurretGoal();
66 }
67
Ravago Jones5da06352022-03-04 20:26:24 -080068 const frc971::control_loops::StaticZeroingSingleDOFProfiledSubsystemGoal
69 *turret_goal = nullptr;
Ravago Jones3283ce02022-03-09 19:31:29 -080070 const CatapultGoal *catapult_goal = nullptr;
Ravago Jones5da06352022-03-04 20:26:24 -080071 double roller_speed_compensated_front = 0.0;
72 double roller_speed_compensated_back = 0.0;
Milind Upadhyayb1a74ea2022-03-09 20:34:35 -080073 double transfer_roller_speed_front = 0.0;
74 double transfer_roller_speed_back = 0.0;
Ravago Jones5da06352022-03-04 20:26:24 -080075 double flipper_arms_voltage = 0.0;
James Kuszmaul40526952022-03-13 15:56:38 -070076 bool have_active_intake_request = false;
Henry Speiser55aa3ba2022-02-21 23:21:12 -080077
78 if (unsafe_goal != nullptr) {
79 roller_speed_compensated_front =
80 unsafe_goal->roller_speed_front() +
81 std::max(velocity * unsafe_goal->roller_speed_compensation(), 0.0);
82
83 roller_speed_compensated_back =
84 unsafe_goal->roller_speed_back() -
85 std::min(velocity * unsafe_goal->roller_speed_compensation(), 0.0);
86
Milind Upadhyayb1a74ea2022-03-09 20:34:35 -080087 transfer_roller_speed_front = unsafe_goal->transfer_roller_speed_front();
88 transfer_roller_speed_back = unsafe_goal->transfer_roller_speed_back();
milind-u086d7262022-01-19 20:44:18 -080089
James Kuszmaul84083f42022-02-27 17:24:38 -080090 turret_goal =
91 unsafe_goal->auto_aim() ? auto_aim_goal : unsafe_goal->turret();
Ravago Jones3283ce02022-03-09 19:31:29 -080092
93 catapult_goal = unsafe_goal->catapult();
94
95 constants::Values::ShotParams shot_params;
96 const double distance_to_goal = aimer_.DistanceToGoal();
97 if (unsafe_goal->auto_aim() && values_->shot_interpolation_table.GetInRange(
98 distance_to_goal, &shot_params)) {
Austin Schuhfce2b602022-03-13 20:05:01 -070099 flatbuffers::FlatBufferBuilder *catapult_goal_fbb =
100 catapult_goal_buffer.fbb();
Ravago Jones3283ce02022-03-09 19:31:29 -0800101 std::optional<flatbuffers::Offset<
102 frc971::control_loops::StaticZeroingSingleDOFProfiledSubsystemGoal>>
103 return_position_offset;
104 if (unsafe_goal != nullptr && unsafe_goal->has_catapult() &&
105 unsafe_goal->catapult()->has_return_position()) {
Austin Schuhfce2b602022-03-13 20:05:01 -0700106 return_position_offset = {aos::CopyFlatBuffer(
107 unsafe_goal->catapult()->return_position(), catapult_goal_fbb)};
Ravago Jones3283ce02022-03-09 19:31:29 -0800108 }
Austin Schuhfce2b602022-03-13 20:05:01 -0700109 CatapultGoal::Builder builder(*catapult_goal_fbb);
Ravago Jones3283ce02022-03-09 19:31:29 -0800110 builder.add_shot_position(shot_params.shot_angle);
111 builder.add_shot_velocity(shot_params.shot_velocity);
112 if (return_position_offset.has_value()) {
113 builder.add_return_position(return_position_offset.value());
114 }
115 catapult_goal_buffer.Finish(builder.Finish());
116 catapult_goal = &catapult_goal_buffer.message();
117 }
James Kuszmaul40526952022-03-13 15:56:38 -0700118
119 if (unsafe_goal->has_turret_intake()) {
120 have_active_intake_request = true;
121 }
James Kuszmaul84083f42022-02-27 17:24:38 -0800122 }
Austin Schuh39f26f62022-02-24 21:34:46 -0800123
Milind Upadhyay803bbf02022-03-11 17:56:26 -0800124 // Superstructure state machine:
Ravago Jones5da06352022-03-04 20:26:24 -0800125 // 1. IDLE: Wait until an intake beambreak is triggerred, meaning that a ball
126 // is being intaked. This means that the transfer rollers have a ball. If
127 // we've been waiting here for too long without any beambreak triggered, the
128 // ball got lost, so reset.
129 // 2. TRANSFERRING: Until the turret reaches the loading position where the
130 // ball can be transferred into the catapult, wiggle the ball in place.
131 // Once the turret reaches the loading position, send the ball forward with
132 // the transfer rollers until the turret beambreak is triggered.
133 // If we have been in this state for too long, the ball probably got lost so
134 // reset back to IDLE.
135 // 3. LOADING: To load the ball into the catapult, put the flippers at the
136 // feeding speed. Wait for a timeout, and then wait until the ball has gone
137 // past the turret beambreak and the flippers have stopped moving, meaning
138 // that the ball is fully loaded in the catapult.
139 // 4. LOADED: Wait until the user asks us to fire to transition to the
140 // shooting stage. If asked to cancel the shot, reset back to the IDLE state.
141 // 5. SHOOTING: Open the flippers to get ready for the shot. If they don't
142 // open quickly enough, try reseating the ball and going back to the LOADING
143 // stage, which moves the flippers in the opposite direction first.
144 // Now, hold the flippers open and wait until the turret has reached its
145 // aiming goal. Once the turret is ready, tell the catapult to fire.
146 // If the flippers move back for some reason now, it could damage the
147 // catapult, so estop it. Otherwise, wait until the catapult shoots a ball and
148 // goes back to its return position. We have now finished the shot, so return
149 // to IDLE.
150
Milind Upadhyay803bbf02022-03-11 17:56:26 -0800151 // If we started off preloaded, skip to the loaded state.
152 // Make sure we weren't already there just in case.
153 if (unsafe_goal != nullptr && unsafe_goal->preloaded()) {
154 switch (state_) {
155 case SuperstructureState::IDLE:
156 case SuperstructureState::TRANSFERRING:
157 case SuperstructureState::LOADING:
158 state_ = SuperstructureState::LOADED;
159 loading_timer_ = timestamp;
160 break;
161 case SuperstructureState::LOADED:
162 case SuperstructureState::SHOOTING:
163 break;
164 }
165 }
166
James Kuszmaul40526952022-03-13 15:56:38 -0700167 if (position->intake_beambreak_front()) {
168 front_intake_has_ball_ = true;
169 front_intake_beambreak_timer_ = timestamp;
Ravago Jones5da06352022-03-04 20:26:24 -0800170 }
171
James Kuszmaul40526952022-03-13 15:56:38 -0700172 if (position->intake_beambreak_back()) {
173 back_intake_has_ball_ = true;
174 back_intake_beambreak_timer_ = timestamp;
Milind Upadhyay5dfabef2022-03-06 14:08:15 -0800175 }
176
James Kuszmaul40526952022-03-13 15:56:38 -0700177 // Check if we're either spitting of have lost the ball.
178 if (transfer_roller_speed_front < 0.0 ||
179 timestamp >
180 front_intake_beambreak_timer_ + constants::Values::kBallLostTime()) {
181 front_intake_has_ball_ = false;
182 }
183
184 if (transfer_roller_speed_back < 0.0 ||
185 timestamp >
186 back_intake_beambreak_timer_ + constants::Values::kBallLostTime()) {
187 back_intake_has_ball_ = false;
188 }
189
190 // Wiggle transfer rollers: send the ball back and forth while waiting
191 // for the turret or waiting for another shot to be completed
192 const double wiggle_voltage =
193 constants::Values::kTransferRollerWiggleVoltage();
194 if (front_intake_has_ball_) {
Ravago Jones5da06352022-03-04 20:26:24 -0800195 roller_speed_compensated_front = 0.0;
James Kuszmaul40526952022-03-13 15:56:38 -0700196 if (position->intake_beambreak_front()) {
197 transfer_roller_speed_front = -wiggle_voltage;
Ravago Jones5da06352022-03-04 20:26:24 -0800198 } else {
James Kuszmaul40526952022-03-13 15:56:38 -0700199 transfer_roller_speed_front = wiggle_voltage;
Ravago Jones5da06352022-03-04 20:26:24 -0800200 }
201 }
202
James Kuszmaul40526952022-03-13 15:56:38 -0700203 if (back_intake_has_ball_) {
204 roller_speed_compensated_back = 0.0;
205 if (position->intake_beambreak_back()) {
206 transfer_roller_speed_back = -wiggle_voltage;
207 } else {
208 transfer_roller_speed_back = wiggle_voltage;
Milind Upadhyay918ecf02022-03-12 15:55:46 -0800209 }
210 }
211
James Kuszmaul40526952022-03-13 15:56:38 -0700212 // Create the goal message for putting the turret in its loading position.
213 // This will then get used in the state machine for the states (IDLE and
214 // TRANSFERRING) that use it.
215 double turret_loading_position =
216 (turret_intake_state_ == RequestedIntake::kFront
217 ? constants::Values::kTurretFrontIntakePos()
218 : constants::Values::kTurretBackIntakePos());
219 // Turn to the loading position as close to the current position as
220 // possible.
221 turret_loading_position =
222 turret_.estimated_position() +
223 aos::math::NormalizeAngle(turret_loading_position -
224 turret_.estimated_position());
225 // if out of range, reset back to within +/- pi of zero.
226 if (turret_loading_position > constants::Values::kTurretRange().upper ||
227 turret_loading_position < constants::Values::kTurretRange().lower) {
Milind Upadhyay918ecf02022-03-12 15:55:46 -0800228 turret_loading_position =
James Kuszmaul2a59cf02022-03-17 11:02:02 -0700229 frc971::zeroing::Wrap(constants::Values::kTurretRange().middle_soft(),
James Kuszmaul40526952022-03-13 15:56:38 -0700230 turret_loading_position, 2.0 * M_PI);
Milind Upadhyay918ecf02022-03-12 15:55:46 -0800231 }
232
James Kuszmaul40526952022-03-13 15:56:38 -0700233 turret_loading_goal_buffer.Finish(
234 frc971::control_loops::CreateStaticZeroingSingleDOFProfiledSubsystemGoal(
235 *turret_loading_goal_buffer.fbb(), turret_loading_position));
236
Henry Speiser77747b72022-03-06 17:18:29 -0800237 const bool turret_near_goal =
238 turret_goal != nullptr &&
239 std::abs(turret_goal->unsafe_goal() - turret_.position()) <
240 kTurretGoalThreshold;
241 const bool collided = collision_avoidance_.IsCollided(
242 {.intake_front_position = intake_front_.estimated_position(),
243 .intake_back_position = intake_back_.estimated_position(),
244 .turret_position = turret_.estimated_position(),
245 .shooting = true});
246
Ravago Jones5da06352022-03-04 20:26:24 -0800247 switch (state_) {
248 case SuperstructureState::IDLE: {
James Kuszmaul40526952022-03-13 15:56:38 -0700249 // Only change the turret's goal loading position when idle, to prevent us
250 // spinning the turret around when TRANSFERRING...
Milind Upadhyay90648532022-03-13 20:37:02 -0700251 if (have_active_intake_request) {
252 turret_intake_state_ = unsafe_goal->turret_intake();
253 }
James Kuszmaul40526952022-03-13 15:56:38 -0700254 if (front_intake_has_ball_ != back_intake_has_ball_) {
James Kuszmaul40526952022-03-13 15:56:38 -0700255 turret_intake_state_ = front_intake_has_ball_ ? RequestedIntake::kFront
256 : RequestedIntake::kBack;
257 }
258 // When IDLE with no specific intake button pressed, allow the goal
259 // message to override the intaking stuff.
Austin Schuh92908812022-03-27 14:14:05 -0700260 if (have_active_intake_request || (turret_goal == nullptr)) {
James Kuszmaul40526952022-03-13 15:56:38 -0700261 turret_goal = &turret_loading_goal_buffer.message();
Ravago Jones5da06352022-03-04 20:26:24 -0800262 }
263
James Kuszmaul40526952022-03-13 15:56:38 -0700264 if (!front_intake_has_ball_ && !back_intake_has_ball_) {
Austin Schuh92908812022-03-27 14:14:05 -0700265 last_shot_angle_ = std::nullopt;
Ravago Jones5da06352022-03-04 20:26:24 -0800266 break;
267 }
268
269 state_ = SuperstructureState::TRANSFERRING;
Ravago Jones5da06352022-03-04 20:26:24 -0800270 // Save the side the ball is on for later
271
272 break;
273 }
274 case SuperstructureState::TRANSFERRING: {
James Kuszmaul40526952022-03-13 15:56:38 -0700275 // If we've been transferring for too long, the ball probably got lost.
276 if ((turret_intake_state_ == RequestedIntake::kFront &&
277 !front_intake_has_ball_) ||
278 (turret_intake_state_ == RequestedIntake::kBack &&
279 !back_intake_has_ball_)) {
Ravago Jones5da06352022-03-04 20:26:24 -0800280 state_ = SuperstructureState::IDLE;
281 break;
282 }
283
James Kuszmaul40526952022-03-13 15:56:38 -0700284 turret_goal = &turret_loading_goal_buffer.message();
285
Ravago Jones5da06352022-03-04 20:26:24 -0800286 const bool turret_near_goal =
287 std::abs(turret_.estimated_position() - turret_loading_position) <
288 kTurretGoalThreshold;
289 if (!turret_near_goal) {
290 break; // Wait for turret to reach the chosen intake
291 }
292
293 // Transfer rollers and flipper arm belt on
James Kuszmaul40526952022-03-13 15:56:38 -0700294 if (turret_intake_state_ == RequestedIntake::kFront) {
Milind Upadhyayb1a74ea2022-03-09 20:34:35 -0800295 transfer_roller_speed_front =
296 constants::Values::kTransferRollerVoltage();
Milind Upadhyayb1a74ea2022-03-09 20:34:35 -0800297 } else {
298 transfer_roller_speed_back =
299 constants::Values::kTransferRollerVoltage();
Milind Upadhyayb1a74ea2022-03-09 20:34:35 -0800300 }
Ravago Jones5da06352022-03-04 20:26:24 -0800301 flipper_arms_voltage = constants::Values::kFlipperFeedVoltage();
302
303 // Ball is in catapult
304 if (position->turret_beambreak()) {
James Kuszmaul40526952022-03-13 15:56:38 -0700305 if (turret_intake_state_ == RequestedIntake::kFront) {
306 front_intake_has_ball_ = false;
307 } else {
308 back_intake_has_ball_ = false;
309 }
Ravago Jones5da06352022-03-04 20:26:24 -0800310 state_ = SuperstructureState::LOADING;
311 loading_timer_ = timestamp;
312 }
313 break;
314 }
315 case SuperstructureState::LOADING: {
316 flipper_arms_voltage = constants::Values::kFlipperFeedVoltage();
317
318 // Keep feeding for kExtraLoadingTime
319
Ravago Jones5da06352022-03-04 20:26:24 -0800320 // The ball should go past the turret beambreak to be loaded.
Milind Upadhyay5dfabef2022-03-06 14:08:15 -0800321 // If we got a CAN reading not too long ago, the flippers should have
322 // also stopped.
Milind Upadhyay47e0d032022-03-05 23:06:25 -0800323 if (position->turret_beambreak()) {
324 loading_timer_ = timestamp;
325 } else if (timestamp >
326 loading_timer_ + constants::Values::kExtraLoadingTime()) {
Ravago Jones5da06352022-03-04 20:26:24 -0800327 state_ = SuperstructureState::LOADED;
328 reseating_in_catapult_ = false;
329 }
330 break;
331 }
332 case SuperstructureState::LOADED: {
333 if (unsafe_goal != nullptr) {
Austin Schuh92908812022-03-27 14:14:05 -0700334 if (turret_goal == nullptr) {
335 if (last_shot_angle_) {
336 turret_loading_goal_buffer.mutable_message()->mutate_unsafe_goal(
337 *last_shot_angle_);
338 }
339 turret_goal = &turret_loading_goal_buffer.message();
340 }
Ravago Jones5da06352022-03-04 20:26:24 -0800341 if (unsafe_goal->cancel_shot()) {
342 // Cancel the shot process
343 state_ = SuperstructureState::IDLE;
344 } else if (unsafe_goal->fire()) {
345 // Start if we were asked to and the turret is at goal
346 state_ = SuperstructureState::SHOOTING;
347 prev_shot_count_ = catapult_.shot_count();
348
349 // Reset opening timeout
350 flipper_opening_start_time_ = timestamp;
351 }
352 }
353 break;
354 }
355 case SuperstructureState::SHOOTING: {
Austin Schuh92908812022-03-27 14:14:05 -0700356 if (turret_goal == nullptr) {
357 if (last_shot_angle_) {
358 turret_loading_goal_buffer.mutable_message()->mutate_unsafe_goal(
359 *last_shot_angle_);
360 }
361 turret_goal = &turret_loading_goal_buffer.message();
362 last_shot_angle_ = turret_goal->unsafe_goal();
363 } else {
364 last_shot_angle_ = std::nullopt;
365 }
366 const bool turret_near_goal =
367 turret_goal != nullptr &&
368 std::abs(turret_goal->unsafe_goal() - turret_.position()) <
369 kTurretGoalThreshold;
370
milind-uee3b0012022-03-14 21:19:57 -0700371 // Don't open the flippers until the turret's ready: give them as little
372 // time to get bumped as possible.
373 if (!turret_near_goal || collided) {
374 break;
375 }
376
Ravago Jones5da06352022-03-04 20:26:24 -0800377 // Opening flipper arms could fail, wait until they are open using their
378 // potentiometers (the member below is just named encoder).
379 // Be a little more lenient if the flippers were already open in case of
380 // noise or collisions.
381 const double flipper_open_position =
382 (flippers_open_ ? constants::Values::kReseatFlipperPosition()
383 : constants::Values::kFlipperOpenPosition());
milind-u37dc40b2022-03-08 19:51:27 -0800384
385 // TODO(milind): add left arm back once it's fixed
Ravago Jones5da06352022-03-04 20:26:24 -0800386 flippers_open_ =
Ravago Jones5da06352022-03-04 20:26:24 -0800387 position->flipper_arm_right()->encoder() >= flipper_open_position;
388
389 if (flippers_open_) {
390 // Hold at kFlipperHoldVoltage
391 flipper_arms_voltage = constants::Values::kFlipperHoldVoltage();
392 } else {
393 // Open at kFlipperOpenVoltage
394 flipper_arms_voltage = constants::Values::kFlipperOpenVoltage();
395 }
396
milind-uee3b0012022-03-14 21:19:57 -0700397 // There are two possible failures for the flippers:
398 // 1. They never open on time
399 // 2. They opened and we started firing, but we got bumped or something
400 // and they went back.
401 // If the flippers didn't open in a reasonable amount of time, try
402 // reseating the ball and reversing them.
403 if (!fire_ && !flippers_open_ &&
Ravago Jones5da06352022-03-04 20:26:24 -0800404 timestamp >
405 loading_timer_ + constants::Values::kFlipperOpeningTimeout()) {
406 // Reseat the ball and try again
407 state_ = SuperstructureState::LOADING;
408 loading_timer_ = timestamp;
409 reseating_in_catapult_ = true;
410 break;
411 }
Ravago Jones5da06352022-03-04 20:26:24 -0800412
Henry Speiser28288cc2022-03-09 22:59:24 -0800413 // If the turret reached the aiming goal and the catapult is safe to move
414 // up, fire!
415 if (flippers_open_ && turret_near_goal && !collided) {
Ravago Jones5da06352022-03-04 20:26:24 -0800416 fire_ = true;
417 }
418
Ravago Jones5da06352022-03-04 20:26:24 -0800419 const bool near_return_position =
420 (unsafe_goal != nullptr && unsafe_goal->has_catapult() &&
421 unsafe_goal->catapult()->has_return_position() &&
422 std::abs(unsafe_goal->catapult()->return_position()->unsafe_goal() -
423 catapult_.estimated_position()) < kCatapultGoalThreshold);
424
425 // Once the shot is complete and the catapult is back to its return
426 // position, go back to IDLE
427 if (catapult_.shot_count() > prev_shot_count_ && near_return_position) {
428 prev_shot_count_ = catapult_.shot_count();
429 fire_ = false;
430 state_ = SuperstructureState::IDLE;
431 }
432
433 break;
434 }
435 }
436
437 collision_avoidance_.UpdateGoal(
438 {.intake_front_position = intake_front_.estimated_position(),
439 .intake_back_position = intake_back_.estimated_position(),
Henry Speiser28288cc2022-03-09 22:59:24 -0800440 .turret_position = turret_.estimated_position(),
441 .shooting = state_ == SuperstructureState::SHOOTING},
Ravago Jones5da06352022-03-04 20:26:24 -0800442 turret_goal);
443
444 turret_.set_min_position(collision_avoidance_.min_turret_goal());
445 turret_.set_max_position(collision_avoidance_.max_turret_goal());
446 intake_front_.set_min_position(collision_avoidance_.min_intake_front_goal());
447 intake_front_.set_max_position(collision_avoidance_.max_intake_front_goal());
448 intake_back_.set_min_position(collision_avoidance_.min_intake_back_goal());
449 intake_back_.set_max_position(collision_avoidance_.max_intake_back_goal());
450
James Kuszmaul84083f42022-02-27 17:24:38 -0800451 const flatbuffers::Offset<AimerStatus> aimer_offset =
452 aimer_.PopulateStatus(status->fbb());
453
Milind Upadhyay5dfabef2022-03-06 14:08:15 -0800454 // Disable the catapult if we want to restart to prevent damage with
455 // flippers
Austin Schuh39f26f62022-02-24 21:34:46 -0800456 const flatbuffers::Offset<PotAndAbsoluteEncoderProfiledJointStatus>
Austin Schuh97410d72022-03-12 15:37:23 -0800457 catapult_status_offset = catapult_.Iterate(
Ravago Jones3283ce02022-03-09 19:31:29 -0800458 catapult_goal, position, robot_state().voltage_battery(),
Austin Schuh97410d72022-03-12 15:37:23 -0800459 output != nullptr && !catapult_.estopped()
460 ? &(output_struct.catapult_voltage)
461 : nullptr,
462 fire_, status->fbb());
Siddhant Kanwar0e37f592022-02-21 19:26:50 -0800463
Ravago Jones5da06352022-03-04 20:26:24 -0800464 const flatbuffers::Offset<RelativeEncoderProfiledJointStatus>
Siddhant Kanwar0e37f592022-02-21 19:26:50 -0800465 climber_status_offset = climber_.Iterate(
466 unsafe_goal != nullptr ? unsafe_goal->climber() : nullptr,
Austin Schuh7f120362022-03-05 17:10:11 -0800467 position->climber(),
468 output != nullptr ? &output_struct.climber_voltage : nullptr,
469 status->fbb());
Siddhant Kanwar0e37f592022-02-21 19:26:50 -0800470
Ravago Jones5da06352022-03-04 20:26:24 -0800471 const flatbuffers::Offset<PotAndAbsoluteEncoderProfiledJointStatus>
Henry Speiser55aa3ba2022-02-21 23:21:12 -0800472 intake_status_offset_front = intake_front_.Iterate(
473 unsafe_goal != nullptr ? unsafe_goal->intake_front() : nullptr,
Austin Schuh7f120362022-03-05 17:10:11 -0800474 position->intake_front(),
475 output != nullptr ? &output_struct.intake_voltage_front : nullptr,
Henry Speiser55aa3ba2022-02-21 23:21:12 -0800476 status->fbb());
477
Ravago Jones5da06352022-03-04 20:26:24 -0800478 const flatbuffers::Offset<PotAndAbsoluteEncoderProfiledJointStatus>
Henry Speiser55aa3ba2022-02-21 23:21:12 -0800479 intake_status_offset_back = intake_back_.Iterate(
480 unsafe_goal != nullptr ? unsafe_goal->intake_back() : nullptr,
Austin Schuh7f120362022-03-05 17:10:11 -0800481 position->intake_back(),
482 output != nullptr ? &output_struct.intake_voltage_back : nullptr,
Henry Speiser55aa3ba2022-02-21 23:21:12 -0800483 status->fbb());
484
Ravago Jones5da06352022-03-04 20:26:24 -0800485 const flatbuffers::Offset<PotAndAbsoluteEncoderProfiledJointStatus>
Austin Schuh7f120362022-03-05 17:10:11 -0800486 turret_status_offset = turret_.Iterate(
487 turret_goal, position->turret(),
488 output != nullptr ? &output_struct.turret_voltage : nullptr,
489 status->fbb());
Henry Speiser55aa3ba2022-02-21 23:21:12 -0800490
Siddhant Kanwar0e37f592022-02-21 19:26:50 -0800491 if (output != nullptr) {
Henry Speiser55aa3ba2022-02-21 23:21:12 -0800492 output_struct.roller_voltage_front = roller_speed_compensated_front;
493 output_struct.roller_voltage_back = roller_speed_compensated_back;
Milind Upadhyayb1a74ea2022-03-09 20:34:35 -0800494 output_struct.transfer_roller_voltage_front = transfer_roller_speed_front;
495 output_struct.transfer_roller_voltage_back = transfer_roller_speed_back;
Ravago Jones5da06352022-03-04 20:26:24 -0800496 output_struct.flipper_arms_voltage = flipper_arms_voltage;
Henry Speiser55aa3ba2022-02-21 23:21:12 -0800497
milind-u086d7262022-01-19 20:44:18 -0800498 output->CheckOk(output->Send(Output::Pack(*output->fbb(), &output_struct)));
499 }
500
501 Status::Builder status_builder = status->MakeBuilder<Status>();
502
Henry Speiser55aa3ba2022-02-21 23:21:12 -0800503 const bool zeroed = intake_front_.zeroed() && intake_back_.zeroed() &&
Ravago Jones5da06352022-03-04 20:26:24 -0800504 turret_.zeroed() && climber_.zeroed() &&
505 catapult_.zeroed();
Henry Speiser55aa3ba2022-02-21 23:21:12 -0800506 const bool estopped = intake_front_.estopped() || intake_back_.estopped() ||
Ravago Jones5da06352022-03-04 20:26:24 -0800507 turret_.estopped() || climber_.estopped() ||
508 catapult_.estopped();
Henry Speiser55aa3ba2022-02-21 23:21:12 -0800509
510 status_builder.add_zeroed(zeroed);
511 status_builder.add_estopped(estopped);
512
513 status_builder.add_intake_front(intake_status_offset_front);
514 status_builder.add_intake_back(intake_status_offset_back);
515 status_builder.add_turret(turret_status_offset);
Siddhant Kanwar0e37f592022-02-21 19:26:50 -0800516 status_builder.add_climber(climber_status_offset);
Ravago Jones5da06352022-03-04 20:26:24 -0800517
Austin Schuh39f26f62022-02-24 21:34:46 -0800518 status_builder.add_catapult(catapult_status_offset);
519 status_builder.add_solve_time(catapult_.solve_time());
Austin Schuh80fc2752022-02-25 13:33:56 -0800520 status_builder.add_shot_count(catapult_.shot_count());
Austin Schuh41472552022-03-13 18:09:41 -0700521 status_builder.add_mpc_horizon(catapult_.mpc_horizon());
Ravago Jones3283ce02022-03-09 19:31:29 -0800522 if (catapult_goal != nullptr) {
523 status_builder.add_shot_position(catapult_goal->shot_position());
524 status_builder.add_shot_velocity(catapult_goal->shot_velocity());
525 }
Ravago Jones5da06352022-03-04 20:26:24 -0800526
527 status_builder.add_flippers_open(flippers_open_);
528 status_builder.add_reseating_in_catapult(reseating_in_catapult_);
529 status_builder.add_fire(fire_);
Henry Speiser77747b72022-03-06 17:18:29 -0800530 status_builder.add_ready_to_fire(state_ == SuperstructureState::LOADED &&
531 turret_near_goal && !collided);
Ravago Jones5da06352022-03-04 20:26:24 -0800532 status_builder.add_state(state_);
James Kuszmaul40526952022-03-13 15:56:38 -0700533 if (!front_intake_has_ball_ && !back_intake_has_ball_) {
534 status_builder.add_intake_state(IntakeState::NO_BALL);
535 } else if (front_intake_has_ball_ && back_intake_has_ball_) {
536 status_builder.add_intake_state(turret_intake_state_ ==
537 RequestedIntake::kFront
538 ? IntakeState::INTAKE_FRONT_BALL
539 : IntakeState::INTAKE_BACK_BALL);
540 } else {
541 status_builder.add_intake_state(front_intake_has_ball_
542 ? IntakeState::INTAKE_FRONT_BALL
543 : IntakeState::INTAKE_BACK_BALL);
544 }
545 status_builder.add_front_intake_has_ball(front_intake_has_ball_);
546 status_builder.add_back_intake_has_ball(back_intake_has_ball_);
milind-u086d7262022-01-19 20:44:18 -0800547
James Kuszmaul84083f42022-02-27 17:24:38 -0800548 status_builder.add_aimer(aimer_offset);
549
milind-u086d7262022-01-19 20:44:18 -0800550 (void)status->Send(status_builder.Finish());
551}
552
Henry Speiser55aa3ba2022-02-21 23:21:12 -0800553double Superstructure::robot_velocity() const {
554 return (drivetrain_status_fetcher_.get() != nullptr
555 ? drivetrain_status_fetcher_->robot_speed()
556 : 0.0);
557}
558
milind-u086d7262022-01-19 20:44:18 -0800559} // namespace superstructure
560} // namespace control_loops
561} // namespace y2022