blob: ebcbf1b4509ca524240ce4b94ed8cf835501be16 [file] [log] [blame]
Niko Sohmers3860f8a2024-01-12 21:05:19 -08001#include "y2024/control_loops/superstructure/superstructure.h"
2
3#include "aos/events/event_loop.h"
4#include "aos/flatbuffer_merge.h"
5#include "aos/network/team_number.h"
6#include "frc971/shooter_interpolation/interpolation.h"
7#include "frc971/zeroing/wrap.h"
8
9DEFINE_bool(ignore_distance, false,
10 "If true, ignore distance when shooting and obay joystick_reader");
11
Stephan Pleinesf63bde82024-01-13 15:59:33 -080012namespace y2024::control_loops::superstructure {
Niko Sohmers3860f8a2024-01-12 21:05:19 -080013
14using ::aos::monotonic_clock;
15
16using frc971::control_loops::AbsoluteEncoderProfiledJointStatus;
17using frc971::control_loops::PotAndAbsoluteEncoderProfiledJointStatus;
18using frc971::control_loops::RelativeEncoderProfiledJointStatus;
19
20Superstructure::Superstructure(::aos::EventLoop *event_loop,
21 std::shared_ptr<const constants::Values> values,
22 const ::std::string &name)
23 : frc971::controls::ControlLoop<Goal, Position, Status, Output>(event_loop,
24 name),
25 values_(values),
26 constants_fetcher_(event_loop),
Niko Sohmersafc51fe2024-01-29 17:48:35 -080027 robot_constants_(CHECK_NOTNULL(&constants_fetcher_.constants())),
Niko Sohmers3860f8a2024-01-12 21:05:19 -080028 drivetrain_status_fetcher_(
29 event_loop->MakeFetcher<frc971::control_loops::drivetrain::Status>(
30 "/drivetrain")),
31 joystick_state_fetcher_(
Niko Sohmersafc51fe2024-01-29 17:48:35 -080032 event_loop->MakeFetcher<aos::JoystickState>("/aos")),
Niko Sohmerse735fa82024-02-02 16:49:02 -080033 transfer_goal_(TransferRollerGoal::NONE),
Niko Sohmers74b0ad52024-02-03 18:00:31 -080034 intake_pivot_(robot_constants_->common()->intake_pivot(),
35 robot_constants_->robot()->intake_constants()),
Filip Kujawa6d717632024-02-01 11:40:55 -080036 climber_(
37 robot_constants_->common()->climber(),
Niko Sohmersc4d2c502024-02-19 19:35:35 -080038 robot_constants_->robot()->climber_constants()->zeroing_constants()),
39 shooter_(event_loop, robot_constants_) {
Niko Sohmers3860f8a2024-01-12 21:05:19 -080040 event_loop->SetRuntimeRealtimePriority(30);
41}
42
43void Superstructure::RunIteration(const Goal *unsafe_goal,
44 const Position *position,
45 aos::Sender<Output>::Builder *output,
46 aos::Sender<Status>::Builder *status) {
47 const monotonic_clock::time_point timestamp =
48 event_loop()->context().monotonic_event_time;
49
Niko Sohmers3860f8a2024-01-12 21:05:19 -080050 if (WasReset()) {
51 AOS_LOG(ERROR, "WPILib reset, restarting\n");
Niko Sohmersafc51fe2024-01-29 17:48:35 -080052 intake_pivot_.Reset();
Filip Kujawa6d717632024-02-01 11:40:55 -080053 climber_.Reset();
Niko Sohmersc4d2c502024-02-19 19:35:35 -080054 shooter_.Reset();
Niko Sohmers3860f8a2024-01-12 21:05:19 -080055 }
56
57 OutputT output_struct;
Niko Sohmersafc51fe2024-01-29 17:48:35 -080058
59 double intake_pivot_position =
60 robot_constants_->common()->intake_pivot_set_points()->retracted();
61
62 if (unsafe_goal != nullptr &&
63 unsafe_goal->intake_pivot_goal() == IntakePivotGoal::EXTENDED) {
64 intake_pivot_position =
65 robot_constants_->common()->intake_pivot_set_points()->extended();
66 }
67
Filip Kujawa102a9b22024-02-18 09:40:23 -080068 IntakeRollerStatus intake_roller_state = IntakeRollerStatus::NONE;
Niko Sohmersafc51fe2024-01-29 17:48:35 -080069
70 switch (unsafe_goal != nullptr ? unsafe_goal->intake_roller_goal()
71 : IntakeRollerGoal::NONE) {
72 case IntakeRollerGoal::NONE:
73 output_struct.intake_roller_voltage = 0.0;
74 break;
75 case IntakeRollerGoal::SPIT:
Niko Sohmerse735fa82024-02-02 16:49:02 -080076 transfer_goal_ = TransferRollerGoal::TRANSFER_OUT;
Filip Kujawa102a9b22024-02-18 09:40:23 -080077 intake_roller_state = IntakeRollerStatus::SPITTING;
Niko Sohmersafc51fe2024-01-29 17:48:35 -080078 output_struct.intake_roller_voltage =
79 robot_constants_->common()->intake_roller_voltages()->spitting();
80 break;
81 case IntakeRollerGoal::INTAKE:
Niko Sohmerse735fa82024-02-02 16:49:02 -080082 transfer_goal_ = TransferRollerGoal::TRANSFER_IN;
Filip Kujawa102a9b22024-02-18 09:40:23 -080083 intake_roller_state = IntakeRollerStatus::INTAKING;
Niko Sohmersafc51fe2024-01-29 17:48:35 -080084 output_struct.intake_roller_voltage =
85 robot_constants_->common()->intake_roller_voltages()->intaking();
86 break;
87 }
88
Filip Kujawa102a9b22024-02-18 09:40:23 -080089 TransferRollerStatus transfer_roller_state = TransferRollerStatus::NONE;
Niko Sohmerse735fa82024-02-02 16:49:02 -080090
91 switch (unsafe_goal != nullptr ? transfer_goal_ : TransferRollerGoal::NONE) {
92 case TransferRollerGoal::NONE:
93 output_struct.transfer_roller_voltage = 0.0;
94 break;
95 case TransferRollerGoal::TRANSFER_IN:
96 if (position->transfer_beambreak()) {
97 transfer_goal_ = TransferRollerGoal::NONE;
Filip Kujawa102a9b22024-02-18 09:40:23 -080098 transfer_roller_state = TransferRollerStatus::NONE;
Niko Sohmerse735fa82024-02-02 16:49:02 -080099 output_struct.transfer_roller_voltage = 0.0;
100 break;
101 }
Filip Kujawa102a9b22024-02-18 09:40:23 -0800102 transfer_roller_state = TransferRollerStatus::TRANSFERING_IN;
Niko Sohmerse735fa82024-02-02 16:49:02 -0800103 output_struct.transfer_roller_voltage =
104 robot_constants_->common()->transfer_roller_voltages()->transfer_in();
105 break;
106 case TransferRollerGoal::TRANSFER_OUT:
Filip Kujawa102a9b22024-02-18 09:40:23 -0800107 transfer_roller_state = TransferRollerStatus::TRANSFERING_OUT;
Niko Sohmerse735fa82024-02-02 16:49:02 -0800108 output_struct.transfer_roller_voltage = robot_constants_->common()
109 ->transfer_roller_voltages()
110 ->transfer_out();
111 break;
112 }
113
Filip Kujawa6d717632024-02-01 11:40:55 -0800114 double climber_position =
115 robot_constants_->common()->climber_set_points()->retract();
116
117 if (unsafe_goal != nullptr) {
118 switch (unsafe_goal->climber_goal()) {
119 case ClimberGoal::FULL_EXTEND:
120 climber_position =
121 robot_constants_->common()->climber_set_points()->full_extend();
122 break;
123 case ClimberGoal::HALF_EXTEND:
124 climber_position =
125 robot_constants_->common()->climber_set_points()->half_extend();
126 break;
127 case ClimberGoal::RETRACT:
128 climber_position =
129 robot_constants_->common()->climber_set_points()->retract();
130 break;
131 default:
132 break;
133 }
134 }
135
Niko Sohmers3860f8a2024-01-12 21:05:19 -0800136 if (joystick_state_fetcher_.Fetch() &&
137 joystick_state_fetcher_->has_alliance()) {
138 alliance_ = joystick_state_fetcher_->alliance();
139 }
Niko Sohmersafc51fe2024-01-29 17:48:35 -0800140
Niko Sohmers3860f8a2024-01-12 21:05:19 -0800141 drivetrain_status_fetcher_.Fetch();
142
Niko Sohmersac4d8872024-02-23 13:55:47 -0800143 const bool collided = collision_avoidance_.IsCollided(
144 {.intake_pivot_position = intake_pivot_.estimated_position(),
145 .turret_position = shooter_.turret().estimated_position()});
Niko Sohmersafc51fe2024-01-29 17:48:35 -0800146
Filip Kujawa6d717632024-02-01 11:40:55 -0800147 aos::FlatbufferFixedAllocatorArray<
148 frc971::control_loops::StaticZeroingSingleDOFProfiledSubsystemGoal, 512>
149 climber_goal_buffer;
150
151 climber_goal_buffer.Finish(
152 frc971::control_loops::CreateStaticZeroingSingleDOFProfiledSubsystemGoal(
153 *climber_goal_buffer.fbb(), climber_position));
154
155 const frc971::control_loops::StaticZeroingSingleDOFProfiledSubsystemGoal
156 *climber_goal = &climber_goal_buffer.message();
157
158 const flatbuffers::Offset<PotAndAbsoluteEncoderProfiledJointStatus>
159 climber_status_offset = climber_.Iterate(
160 climber_goal, position->climber(),
161 output != nullptr ? &output_struct.climber_voltage : nullptr,
162 status->fbb());
163
Niko Sohmersac4d8872024-02-23 13:55:47 -0800164 double max_intake_pivot_position = 0;
165 double min_intake_pivot_position = 0;
166
167 aos::FlatbufferFixedAllocatorArray<
168 frc971::control_loops::StaticZeroingSingleDOFProfiledSubsystemGoal, 512>
169 intake_pivot_goal_buffer;
170
171 intake_pivot_goal_buffer.Finish(
172 frc971::control_loops::CreateStaticZeroingSingleDOFProfiledSubsystemGoal(
173 *intake_pivot_goal_buffer.fbb(), intake_pivot_position));
174
175 const frc971::control_loops::StaticZeroingSingleDOFProfiledSubsystemGoal
176 *intake_pivot_goal = &intake_pivot_goal_buffer.message();
177
178 double *intake_output =
179 (output != nullptr ? &output_struct.intake_pivot_voltage : nullptr);
180
181 const bool disabled = intake_pivot_.Correct(
182 intake_pivot_goal, position->intake_pivot(), intake_output == nullptr);
183
184 // TODO(max): Change how we handle the collision with the turret and intake to
185 // be clearer
Niko Sohmersc4d2c502024-02-19 19:35:35 -0800186 const flatbuffers::Offset<ShooterStatus> shooter_status_offset =
187 shooter_.Iterate(
188 position,
189 unsafe_goal != nullptr ? unsafe_goal->shooter_goal() : nullptr,
190 output != nullptr ? &output_struct.catapult_voltage : nullptr,
191 output != nullptr ? &output_struct.altitude_voltage : nullptr,
192 output != nullptr ? &output_struct.turret_voltage : nullptr,
193 output != nullptr ? &output_struct.retention_roller_voltage : nullptr,
Niko Sohmersac4d8872024-02-23 13:55:47 -0800194 robot_state().voltage_battery(), timestamp, &collision_avoidance_,
195 intake_pivot_.estimated_position(), &max_intake_pivot_position,
196 &min_intake_pivot_position, status->fbb());
197
198 intake_pivot_.set_min_position(min_intake_pivot_position);
199 intake_pivot_.set_max_position(max_intake_pivot_position);
200
201 // Calculate the loops for a cycle.
202 const double voltage = intake_pivot_.UpdateController(disabled);
203
204 intake_pivot_.UpdateObserver(voltage);
205
206 // Write out all the voltages.
207 if (intake_output) {
208 *intake_output = voltage;
209 }
210
211 const flatbuffers::Offset<AbsoluteEncoderProfiledJointStatus>
212 intake_pivot_status_offset = intake_pivot_.MakeStatus(status->fbb());
Niko Sohmersc4d2c502024-02-19 19:35:35 -0800213
Niko Sohmers3860f8a2024-01-12 21:05:19 -0800214 if (output) {
215 output->CheckOk(output->Send(Output::Pack(*output->fbb(), &output_struct)));
216 }
217
218 Status::Builder status_builder = status->MakeBuilder<Status>();
Niko Sohmersafc51fe2024-01-29 17:48:35 -0800219
Niko Sohmersc4d2c502024-02-19 19:35:35 -0800220 const bool zeroed =
221 intake_pivot_.zeroed() && climber_.zeroed() && shooter_.zeroed();
222 const bool estopped =
223 intake_pivot_.estopped() || climber_.estopped() || shooter_.estopped();
Niko Sohmersafc51fe2024-01-29 17:48:35 -0800224
225 status_builder.add_zeroed(zeroed);
226 status_builder.add_estopped(estopped);
Filip Kujawa102a9b22024-02-18 09:40:23 -0800227 status_builder.add_intake_roller(intake_roller_state);
228 status_builder.add_intake_pivot(intake_pivot_status_offset);
229 status_builder.add_transfer_roller(transfer_roller_state);
230 status_builder.add_climber(climber_status_offset);
Niko Sohmersc4d2c502024-02-19 19:35:35 -0800231 status_builder.add_shooter(shooter_status_offset);
Niko Sohmersac4d8872024-02-23 13:55:47 -0800232 status_builder.add_collided(collided);
Niko Sohmers3860f8a2024-01-12 21:05:19 -0800233
234 (void)status->Send(status_builder.Finish());
235}
236
237double Superstructure::robot_velocity() const {
238 return (drivetrain_status_fetcher_.get() != nullptr
239 ? drivetrain_status_fetcher_->robot_speed()
240 : 0.0);
241}
242
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800243} // namespace y2024::control_loops::superstructure