blob: ae79e76ff678563495119ec547b6fc9fed80a585 [file] [log] [blame]
Stephan Massaltd021f972020-01-05 20:41:23 -08001#include "y2020/control_loops/superstructure/superstructure.h"
2
milind-u0beb7dc2021-10-16 19:31:33 -07003#include "aos/containers/sized_array.h"
Stephan Massaltd021f972020-01-05 20:41:23 -08004#include "aos/events/event_loop.h"
Austin Schuh01d81c32021-11-06 22:59:56 -07005#include "aos/network/team_number.h"
Stephan Massaltd021f972020-01-05 20:41:23 -08006
7namespace y2020 {
8namespace control_loops {
9namespace superstructure {
10
Ravago Jones937587c2020-12-26 17:21:09 -080011using frc971::control_loops::AbsoluteAndAbsoluteEncoderProfiledJointStatus;
Stephan Massaltd021f972020-01-05 20:41:23 -080012using frc971::control_loops::AbsoluteEncoderProfiledJointStatus;
13using frc971::control_loops::PotAndAbsoluteEncoderProfiledJointStatus;
14
15Superstructure::Superstructure(::aos::EventLoop *event_loop,
16 const ::std::string &name)
James Kuszmaul61750662021-06-21 21:32:33 -070017 : frc971::controls::ControlLoop<Goal, Position, Status, Output>(event_loop,
18 name),
Sabina Davis0f2d38c2020-02-08 17:01:21 -080019 hood_(constants::GetValues().hood),
Kai Tinkessfb460372020-02-08 14:05:48 -080020 intake_joint_(constants::GetValues().intake),
Sabina Davis0f31d3f2020-02-20 20:41:00 -080021 turret_(constants::GetValues().turret.subsystem_params),
James Kuszmaulb1b2d8e2020-02-21 21:11:46 -080022 drivetrain_status_fetcher_(
23 event_loop->MakeFetcher<frc971::control_loops::drivetrain::Status>(
James Kuszmaula53c3ac2020-02-22 19:36:01 -080024 "/drivetrain")),
25 joystick_state_fetcher_(
Austin Schuh01d81c32021-11-06 22:59:56 -070026 event_loop->MakeFetcher<aos::JoystickState>("/aos")),
27 has_turret_(::aos::network::GetTeamNumber() != 9971) {
Sabina Daviscf08b152020-01-31 22:12:09 -080028 event_loop->SetRuntimeRealtimePriority(30);
Stephan Massaltd021f972020-01-05 20:41:23 -080029}
30
milind upadhyayaec1aee2020-10-13 13:44:33 -070031double Superstructure::robot_speed() const {
32 return (drivetrain_status_fetcher_.get() != nullptr
33 ? drivetrain_status_fetcher_->robot_speed()
34 : 0.0);
35}
36
Sabina Daviscf08b152020-01-31 22:12:09 -080037void Superstructure::RunIteration(const Goal *unsafe_goal,
38 const Position *position,
Stephan Massaltd021f972020-01-05 20:41:23 -080039 aos::Sender<Output>::Builder *output,
40 aos::Sender<Status>::Builder *status) {
41 if (WasReset()) {
42 AOS_LOG(ERROR, "WPILib reset, restarting\n");
Sabina Daviscf08b152020-01-31 22:12:09 -080043 hood_.Reset();
Sabina Davis0f2d38c2020-02-08 17:01:21 -080044 intake_joint_.Reset();
Kai Tinkessfb460372020-02-08 14:05:48 -080045 turret_.Reset();
Stephan Massaltd021f972020-01-05 20:41:23 -080046 }
47
Sabina Davis0f31d3f2020-02-20 20:41:00 -080048 const aos::monotonic_clock::time_point position_timestamp =
49 event_loop()->context().monotonic_event_time;
50
James Kuszmaulb1b2d8e2020-02-21 21:11:46 -080051 if (drivetrain_status_fetcher_.Fetch()) {
James Kuszmaula53c3ac2020-02-22 19:36:01 -080052 aos::Alliance alliance = aos::Alliance::kInvalid;
James Kuszmaul519585d2020-03-08 22:32:48 -070053 joystick_state_fetcher_.Fetch();
54 if (joystick_state_fetcher_.get() != nullptr) {
James Kuszmaula53c3ac2020-02-22 19:36:01 -080055 alliance = joystick_state_fetcher_->alliance();
56 }
James Kuszmaul3b393d72020-02-26 19:43:51 -080057 const turret::Aimer::WrapMode mode =
James Kuszmaulb83d6e12020-02-22 20:44:48 -080058 (unsafe_goal != nullptr && unsafe_goal->shooting())
James Kuszmaul3b393d72020-02-26 19:43:51 -080059 ? turret::Aimer::WrapMode::kAvoidWrapping
60 : turret::Aimer::WrapMode::kAvoidEdges;
61 aimer_.Update(drivetrain_status_fetcher_.get(), alliance, mode,
62 turret::Aimer::ShotMode::kShootOnTheFly);
James Kuszmaulb1b2d8e2020-02-21 21:11:46 -080063 }
64
milind upadhyayaec1aee2020-10-13 13:44:33 -070065 const float velocity = robot_speed();
66
James Kuszmaulb1b2d8e2020-02-21 21:11:46 -080067 const flatbuffers::Offset<AimerStatus> aimer_status_offset =
68 aimer_.PopulateStatus(status->fbb());
69
James Kuszmaul98154a22021-04-03 16:09:29 -070070 const double distance_to_goal = aimer_.DistanceToGoal();
71
72 aos::FlatbufferFixedAllocatorArray<
73 frc971::control_loops::StaticZeroingSingleDOFProfiledSubsystemGoal, 64>
74 hood_goal;
75 aos::FlatbufferFixedAllocatorArray<ShooterGoal, 64> shooter_goal;
76
77 constants::Values::ShotParams shot_params;
milind-u0a178a82021-09-28 18:42:09 -070078 constants::Values::FlywheelShotParams flywheel_shot_params;
James Kuszmaul98154a22021-04-03 16:09:29 -070079 if (constants::GetValues().shot_interpolation_table.GetInRange(
milind-u0a178a82021-09-28 18:42:09 -070080 distance_to_goal, &shot_params) &&
81 constants::GetValues().flywheel_shot_interpolation_table.GetInRange(
82 shot_params.velocity_ball, &flywheel_shot_params)) {
James Kuszmaul98154a22021-04-03 16:09:29 -070083 hood_goal.Finish(frc971::control_loops::
84 CreateStaticZeroingSingleDOFProfiledSubsystemGoal(
85 *hood_goal.fbb(), shot_params.hood_angle));
86
milind-u0a178a82021-09-28 18:42:09 -070087 shooter_goal.Finish(CreateShooterGoal(
88 *shooter_goal.fbb(), flywheel_shot_params.velocity_accelerator,
89 flywheel_shot_params.velocity_finisher));
James Kuszmaul98154a22021-04-03 16:09:29 -070090 } else {
91 hood_goal.Finish(
92 frc971::control_loops::
93 CreateStaticZeroingSingleDOFProfiledSubsystemGoal(
94 *hood_goal.fbb(), constants::GetValues().hood.range.upper));
95
96 shooter_goal.Finish(CreateShooterGoal(*shooter_goal.fbb(), 0.0, 0.0));
97 }
98
Sabina Daviscf08b152020-01-31 22:12:09 -080099 OutputT output_struct;
100
Ravago Jones937587c2020-12-26 17:21:09 -0800101 flatbuffers::Offset<AbsoluteAndAbsoluteEncoderProfiledJointStatus>
102 hood_status_offset = hood_.Iterate(
James Kuszmaul98154a22021-04-03 16:09:29 -0700103 unsafe_goal != nullptr
104 ? (unsafe_goal->hood_tracking() ? &hood_goal.message()
105 : unsafe_goal->hood())
106 : nullptr,
Ravago Jones937587c2020-12-26 17:21:09 -0800107 position->hood(),
108 output != nullptr ? &(output_struct.hood_voltage) : nullptr,
109 status->fbb());
Sabina Daviscf08b152020-01-31 22:12:09 -0800110
Austin Schuh13e55522020-02-29 23:11:17 -0800111 if (unsafe_goal != nullptr) {
112 if (unsafe_goal->shooting() &&
113 shooting_start_time_ == aos::monotonic_clock::min_time) {
114 shooting_start_time_ = position_timestamp;
115 }
116
117 if (unsafe_goal->shooting()) {
Austin Schuh93ddcb42021-10-25 21:54:11 -0700118 intake_joint_.set_max_acceleration(30.0);
Austin Schuh13e55522020-02-29 23:11:17 -0800119 constexpr std::chrono::milliseconds kPeriod =
120 std::chrono::milliseconds(250);
121 if ((position_timestamp - shooting_start_time_) % (kPeriod * 2) <
122 kPeriod) {
123 intake_joint_.set_min_position(-0.25);
124 } else {
125 intake_joint_.set_min_position(-0.75);
126 }
127 } else {
Austin Schuh93ddcb42021-10-25 21:54:11 -0700128 intake_joint_.clear_max_acceleration();
Austin Schuh13e55522020-02-29 23:11:17 -0800129 intake_joint_.clear_min_position();
130 }
131
132 if (!unsafe_goal->shooting()) {
133 shooting_start_time_ = aos::monotonic_clock::min_time;
134 }
135 }
136
Sabina Davis0f2d38c2020-02-08 17:01:21 -0800137 flatbuffers::Offset<AbsoluteEncoderProfiledJointStatus> intake_status_offset =
138 intake_joint_.Iterate(
139 unsafe_goal != nullptr ? unsafe_goal->intake() : nullptr,
140 position->intake_joint(),
141 output != nullptr ? &(output_struct.intake_joint_voltage) : nullptr,
142 status->fbb());
143
James Kuszmaulb1b2d8e2020-02-21 21:11:46 -0800144 const frc971::control_loops::StaticZeroingSingleDOFProfiledSubsystemGoal
145 *turret_goal = unsafe_goal != nullptr ? (unsafe_goal->turret_tracking()
146 ? aimer_.TurretGoal()
147 : unsafe_goal->turret())
148 : nullptr;
James Kuszmaul98154a22021-04-03 16:09:29 -0700149
Kai Tinkessfb460372020-02-08 14:05:48 -0800150 flatbuffers::Offset<PotAndAbsoluteEncoderProfiledJointStatus>
151 turret_status_offset = turret_.Iterate(
James Kuszmaulb1b2d8e2020-02-21 21:11:46 -0800152 turret_goal, position->turret(),
Kai Tinkessfb460372020-02-08 14:05:48 -0800153 output != nullptr ? &(output_struct.turret_voltage) : nullptr,
154 status->fbb());
155
Sabina Davis0f31d3f2020-02-20 20:41:00 -0800156 flatbuffers::Offset<ShooterStatus> shooter_status_offset =
157 shooter_.RunIteration(
James Kuszmaul98154a22021-04-03 16:09:29 -0700158 unsafe_goal != nullptr
159 ? (unsafe_goal->shooter_tracking() ? &shooter_goal.message()
160 : unsafe_goal->shooter())
161 : nullptr,
Sabina Davis0f31d3f2020-02-20 20:41:00 -0800162 position->shooter(), status->fbb(),
163 output != nullptr ? &(output_struct) : nullptr, position_timestamp);
164
Ravago Jones937587c2020-12-26 17:21:09 -0800165 const AbsoluteAndAbsoluteEncoderProfiledJointStatus *const hood_status =
Austin Schuh78f0bfd2020-02-29 23:04:21 -0800166 GetMutableTemporaryPointer(*status->fbb(), hood_status_offset);
167
Austin Schuh2fb23642020-02-29 15:10:51 -0800168 const PotAndAbsoluteEncoderProfiledJointStatus *const turret_status =
169 GetMutableTemporaryPointer(*status->fbb(), turret_status_offset);
170
171 if (output != nullptr) {
172 // Friction is a pain and putting a really high burden on the integrator.
James Kuszmaul9cbdb022021-09-19 17:42:29 -0700173 // TODO(james): I'm not sure how helpful this gain is.
James Kuszmaul519585d2020-03-08 22:32:48 -0700174 const double turret_velocity_sign =
175 turret_status->velocity() * kTurretFrictionGain;
Austin Schuh2fb23642020-02-29 15:10:51 -0800176 output_struct.turret_voltage +=
Austin Schuh78f0bfd2020-02-29 23:04:21 -0800177 std::clamp(turret_velocity_sign, -kTurretFrictionVoltageLimit,
Austin Schuh2fb23642020-02-29 15:10:51 -0800178 kTurretFrictionVoltageLimit);
James Kuszmaul9cbdb022021-09-19 17:42:29 -0700179 const double time_sec =
180 aos::time::DurationInSeconds(position_timestamp.time_since_epoch());
181 output_struct.turret_voltage +=
182 kTurretDitherGain * std::sin(2.0 * M_PI * time_sec * 30.0);
James Kuszmaulb7fe49e2020-03-05 08:24:44 -0800183 output_struct.turret_voltage =
184 std::clamp(output_struct.turret_voltage, -turret_.operating_voltage(),
185 turret_.operating_voltage());
Austin Schuh2fb23642020-02-29 15:10:51 -0800186 }
187
Sabina Daviscf08b152020-01-31 22:12:09 -0800188 bool zeroed;
189 bool estopped;
190
Sabina Davis0f2d38c2020-02-08 17:01:21 -0800191 {
Kai Tinkessfb460372020-02-08 14:05:48 -0800192 const AbsoluteEncoderProfiledJointStatus *const intake_status =
Sabina Davis0f2d38c2020-02-08 17:01:21 -0800193 GetMutableTemporaryPointer(*status->fbb(), intake_status_offset);
194
Kai Tinkessfb460372020-02-08 14:05:48 -0800195 zeroed = hood_status->zeroed() && intake_status->zeroed() &&
196 turret_status->zeroed();
197 estopped = hood_status->estopped() || intake_status->estopped() ||
198 turret_status->estopped();
Stephan Massaltd021f972020-01-05 20:41:23 -0800199 }
200
milind-u0beb7dc2021-10-16 19:31:33 -0700201 flatbuffers::Offset<flatbuffers::Vector<Subsystem>>
202 subsystems_not_ready_offset;
203 const bool turret_ready =
Austin Schuh01d81c32021-11-06 22:59:56 -0700204 (std::abs(turret_.goal(0) - turret_.position()) < 0.025) || !has_turret_;
milind-u0beb7dc2021-10-16 19:31:33 -0700205 if (unsafe_goal && unsafe_goal->shooting() &&
206 (!shooter_.ready() || !turret_ready)) {
207 aos::SizedArray<Subsystem, 3> subsystems_not_ready;
208 if (!shooter_.finisher_ready()) {
209 subsystems_not_ready.push_back(Subsystem::FINISHER);
210 }
211 if (!shooter_.accelerator_ready()) {
212 subsystems_not_ready.push_back(Subsystem::ACCELERATOR);
213 }
214 if (!turret_ready) {
215 subsystems_not_ready.push_back(Subsystem::TURRET);
216 }
217
218 subsystems_not_ready_offset =
219 status->fbb()->CreateVector(subsystems_not_ready.backing_array().data(),
220 subsystems_not_ready.size());
221 }
222
Stephan Massaltd021f972020-01-05 20:41:23 -0800223 Status::Builder status_builder = status->MakeBuilder<Status>();
224
Sabina Daviscf08b152020-01-31 22:12:09 -0800225 status_builder.add_zeroed(zeroed);
226 status_builder.add_estopped(estopped);
227
228 status_builder.add_hood(hood_status_offset);
Sabina Davis0f2d38c2020-02-08 17:01:21 -0800229 status_builder.add_intake(intake_status_offset);
Kai Tinkessfb460372020-02-08 14:05:48 -0800230 status_builder.add_turret(turret_status_offset);
Sabina Davis0f31d3f2020-02-20 20:41:00 -0800231 status_builder.add_shooter(shooter_status_offset);
James Kuszmaulb1b2d8e2020-02-21 21:11:46 -0800232 status_builder.add_aimer(aimer_status_offset);
milind-u0beb7dc2021-10-16 19:31:33 -0700233 status_builder.add_subsystems_not_ready(subsystems_not_ready_offset);
Stephan Massaltd021f972020-01-05 20:41:23 -0800234
235 status->Send(status_builder.Finish());
Sabina Davis0f2d38c2020-02-08 17:01:21 -0800236
237 if (output != nullptr) {
Ravago Jonesf8b7bfe2021-10-09 16:25:29 -0700238 output_struct.washing_machine_spinner_voltage = 0.0;
239 output_struct.feeder_voltage = 0.0;
240 output_struct.intake_roller_voltage = 0.0;
Austin Schuh46712f52021-10-24 22:24:45 -0700241 output_struct.climber_voltage = 0.0;
Sabina Davis0f2d38c2020-02-08 17:01:21 -0800242 if (unsafe_goal) {
Austin Schuh46712f52021-10-24 22:24:45 -0700243 if (unsafe_goal->has_turret()) {
244 output_struct.climber_voltage =
245 std::clamp(unsafe_goal->climber_voltage(), -12.0f, 12.0f);
Ravago Jonese92ff112021-10-23 17:27:44 -0700246
Austin Schuh46712f52021-10-24 22:24:45 -0700247 // Make sure the turret is relatively close to the goal before turning
248 // the climber on.
249 CHECK(unsafe_goal->has_turret());
250 if (std::abs(unsafe_goal->turret()->unsafe_goal() -
251 turret_.position()) > 0.1) {
252 output_struct.climber_voltage = 0;
253 }
milind-ud6534142021-10-24 17:42:58 -0700254 }
255
Ravago Jonesac850da2021-10-13 20:38:29 -0700256 if (unsafe_goal->shooting() || unsafe_goal->intake_preloading()) {
257 preloading_timeout_ = position_timestamp + kPreloadingTimeout;
258 }
259
260 if (position_timestamp <= preloading_timeout_ &&
Ravago Jonesf8b7bfe2021-10-09 16:25:29 -0700261 !position->intake_beambreak_triggered()) {
262 output_struct.washing_machine_spinner_voltage = 5.0;
263 output_struct.feeder_voltage = 12.0;
Ravago Jonesac850da2021-10-13 20:38:29 -0700264
265 preloading_backpower_timeout_ =
266 position_timestamp + kPreloadingBackpowerDuration;
267 }
268
269 if (position->intake_beambreak_triggered() &&
270 position_timestamp <= preloading_backpower_timeout_) {
271 output_struct.feeder_voltage = -12.0;
Ravago Jonesf8b7bfe2021-10-09 16:25:29 -0700272 }
273
Austin Schuh43a220f2020-02-26 22:02:34 -0800274 if (unsafe_goal->shooting()) {
Austin Schuh01d81c32021-11-06 22:59:56 -0700275 if ((shooter_.ready() ||
276 (!has_turret_ && shooter_.accelerator_ready())) &&
277 turret_ready) {
Austin Schuh93109a52020-03-04 21:37:33 -0800278 output_struct.feeder_voltage = 12.0;
Austin Schuh13e55522020-02-29 23:11:17 -0800279 }
280 output_struct.washing_machine_spinner_voltage = 5.0;
281 output_struct.intake_roller_voltage = 3.0;
Austin Schuh43a220f2020-02-26 22:02:34 -0800282 } else {
milind upadhyayaec1aee2020-10-13 13:44:33 -0700283 output_struct.intake_roller_voltage =
284 unsafe_goal->roller_voltage() +
285 std::max(velocity * unsafe_goal->roller_speed_compensation(), 0.0f);
Austin Schuh43a220f2020-02-26 22:02:34 -0800286 }
Sabina Davis0f2d38c2020-02-08 17:01:21 -0800287 }
Ravago Jonesf8b7bfe2021-10-09 16:25:29 -0700288
Sabina Davis0f2d38c2020-02-08 17:01:21 -0800289 output->Send(Output::Pack(*output->fbb(), &output_struct));
290 }
Stephan Massaltd021f972020-01-05 20:41:23 -0800291}
292
Sabina Daviscf08b152020-01-31 22:12:09 -0800293} // namespace superstructure
Stephan Massaltd021f972020-01-05 20:41:23 -0800294} // namespace control_loops
295} // namespace y2020