blob: 7cecb2137617bc9f37281f78053b775fec1ab02c [file] [log] [blame]
Maxwell Hendersonc3d063a2023-12-26 17:37:22 -08001#include <unistd.h>
2
3#include <array>
4#include <chrono>
5#include <cinttypes>
6#include <cmath>
7#include <cstdio>
8#include <cstring>
9#include <functional>
10#include <memory>
11#include <mutex>
12#include <thread>
13
14#include "ctre/phoenix/CANifier.h"
15
16#include "frc971/wpilib/ahal/AnalogInput.h"
17#include "frc971/wpilib/ahal/Counter.h"
18#include "frc971/wpilib/ahal/DigitalGlitchFilter.h"
19#include "frc971/wpilib/ahal/DriverStation.h"
20#include "frc971/wpilib/ahal/Encoder.h"
21#include "frc971/wpilib/ahal/Servo.h"
22#include "frc971/wpilib/ahal/TalonFX.h"
23#include "frc971/wpilib/ahal/VictorSP.h"
24#undef ERROR
25
26#include "ctre/phoenix/cci/Diagnostics_CCI.h"
27#include "ctre/phoenix6/TalonFX.hpp"
28
29#include "aos/commonmath.h"
30#include "aos/containers/sized_array.h"
31#include "aos/events/event_loop.h"
32#include "aos/events/shm_event_loop.h"
33#include "aos/init.h"
34#include "aos/logging/logging.h"
35#include "aos/realtime.h"
36#include "aos/time/time.h"
37#include "aos/util/log_interval.h"
38#include "aos/util/phased_loop.h"
39#include "aos/util/wrapping_counter.h"
40#include "frc971/autonomous/auto_mode_generated.h"
41#include "frc971/can_configuration_generated.h"
42#include "frc971/control_loops/drivetrain/drivetrain_can_position_generated.h"
43#include "frc971/control_loops/drivetrain/drivetrain_position_generated.h"
44#include "frc971/input/robot_state_generated.h"
45#include "frc971/queues/gyro_generated.h"
46#include "frc971/wpilib/ADIS16448.h"
47#include "frc971/wpilib/buffered_pcm.h"
48#include "frc971/wpilib/buffered_solenoid.h"
49#include "frc971/wpilib/can_drivetrain_writer.h"
50#include "frc971/wpilib/can_sensor_reader.h"
51#include "frc971/wpilib/dma.h"
52#include "frc971/wpilib/drivetrain_writer.h"
53#include "frc971/wpilib/encoder_and_potentiometer.h"
54#include "frc971/wpilib/falcon.h"
55#include "frc971/wpilib/joystick_sender.h"
56#include "frc971/wpilib/logging_generated.h"
57#include "frc971/wpilib/loop_output_handler.h"
58#include "frc971/wpilib/pdp_fetcher.h"
59#include "frc971/wpilib/sensor_reader.h"
60#include "frc971/wpilib/wpilib_robot_base.h"
61#include "y2024_defense/constants.h"
62
63DEFINE_bool(ctre_diag_server, false,
64 "If true, enable the diagnostics server for interacting with "
65 "devices on the CAN bus using Phoenix Tuner");
66
67using ::aos::monotonic_clock;
68using ::frc971::CANConfiguration;
69using ::y2024_defense::constants::Values;
70
71using frc971::control_loops::drivetrain::CANPosition;
72using frc971::wpilib::Falcon;
73
74using std::make_unique;
75
76namespace y2024_defense {
77namespace wpilib {
78namespace {
79
80constexpr double kMaxBringupPower = 12.0;
81
82double drivetrain_velocity_translate(double in) {
83 return (((1.0 / in) / Values::kDrivetrainCyclesPerRevolution()) *
84 (2.0 * M_PI)) *
85 Values::kDrivetrainEncoderRatio() *
86 control_loops::drivetrain::kWheelRadius;
87}
88
89constexpr double kMaxFastEncoderPulsesPerSecond = std::max({
90 Values::kMaxDrivetrainEncoderPulsesPerSecond(),
91});
92static_assert(kMaxFastEncoderPulsesPerSecond <= 1300000,
93 "fast encoders are too fast");
94
95} // namespace
96
97// Class to send position messages with sensor readings to our loops.
98class SensorReader : public ::frc971::wpilib::SensorReader {
99 public:
100 SensorReader(::aos::ShmEventLoop *event_loop,
101 std::shared_ptr<const Values> values)
102 : ::frc971::wpilib::SensorReader(event_loop),
103 values_(std::move(values)),
104 auto_mode_sender_(
105 event_loop->MakeSender<::frc971::autonomous::AutonomousMode>(
106 "/autonomous")),
107 drivetrain_position_sender_(
108 event_loop
109 ->MakeSender<::frc971::control_loops::drivetrain::Position>(
110 "/drivetrain")),
111 gyro_sender_(event_loop->MakeSender<::frc971::sensors::GyroReading>(
112 "/drivetrain")) {
113 // Set to filter out anything shorter than 1/4 of the minimum pulse width
114 // we should ever see.
115 UpdateFastEncoderFilterHz(kMaxFastEncoderPulsesPerSecond);
116 event_loop->SetRuntimeAffinity(aos::MakeCpusetFromCpus({0}));
117 }
118
119 void Start() override { AddToDMA(&imu_yaw_rate_reader_); }
120
121 // Auto mode switches.
122 void set_autonomous_mode(int i, ::std::unique_ptr<frc::DigitalInput> sensor) {
123 autonomous_modes_.at(i) = ::std::move(sensor);
124 }
125
126 void set_yaw_rate_input(::std::unique_ptr<frc::DigitalInput> sensor) {
127 imu_yaw_rate_input_ = ::std::move(sensor);
128 imu_yaw_rate_reader_.set_input(imu_yaw_rate_input_.get());
129 }
130
131 void RunIteration() override {
132 superstructure_reading_->Set(true);
133 {
134 {
135 auto builder = drivetrain_position_sender_.MakeBuilder();
136 frc971::control_loops::drivetrain::Position::Builder
137 drivetrain_builder =
138 builder
139 .MakeBuilder<frc971::control_loops::drivetrain::Position>();
140 drivetrain_builder.add_left_encoder(
141 constants::Values::DrivetrainEncoderToMeters(
142 drivetrain_left_encoder_->GetRaw()));
143 drivetrain_builder.add_left_speed(drivetrain_velocity_translate(
144 drivetrain_left_encoder_->GetPeriod()));
145
146 drivetrain_builder.add_right_encoder(
147 -constants::Values::DrivetrainEncoderToMeters(
148 drivetrain_right_encoder_->GetRaw()));
149 drivetrain_builder.add_right_speed(-drivetrain_velocity_translate(
150 drivetrain_right_encoder_->GetPeriod()));
151
152 builder.CheckOk(builder.Send(drivetrain_builder.Finish()));
153 }
154
155 {
156 auto builder = gyro_sender_.MakeBuilder();
157 ::frc971::sensors::GyroReading::Builder gyro_reading_builder =
158 builder.MakeBuilder<::frc971::sensors::GyroReading>();
159 // +/- 2000 deg / sec
160 constexpr double kMaxVelocity = 4000; // degrees / second
161 constexpr double kVelocityRadiansPerSecond =
162 kMaxVelocity / 360 * (2.0 * M_PI);
163
164 // Only part of the full range is used to prevent being 100% on or off.
165 constexpr double kScaledRangeLow = 0.1;
166 constexpr double kScaledRangeHigh = 0.9;
167
168 constexpr double kPWMFrequencyHz = 200;
169 double velocity_duty_cycle =
170 imu_yaw_rate_reader_.last_width() * kPWMFrequencyHz;
171
172 constexpr double kDutyCycleScale =
173 1 / (kScaledRangeHigh - kScaledRangeLow);
174 // scale from 0.1 - 0.9 to 0 - 1
175 double rescaled_velocity_duty_cycle =
176 (velocity_duty_cycle - kScaledRangeLow) * kDutyCycleScale;
177
178 if (!std::isnan(rescaled_velocity_duty_cycle)) {
179 gyro_reading_builder.add_velocity(
180 (rescaled_velocity_duty_cycle - 0.5) * kVelocityRadiansPerSecond);
181 }
182 builder.CheckOk(builder.Send(gyro_reading_builder.Finish()));
183 }
184
185 {
186 auto builder = auto_mode_sender_.MakeBuilder();
187
188 uint32_t mode = 0;
189 for (size_t i = 0; i < autonomous_modes_.size(); ++i) {
190 if (autonomous_modes_[i] && autonomous_modes_[i]->Get()) {
191 mode |= 1 << i;
192 }
193 }
194
195 auto auto_mode_builder =
196 builder.MakeBuilder<frc971::autonomous::AutonomousMode>();
197
198 auto_mode_builder.add_mode(mode);
199
200 builder.CheckOk(builder.Send(auto_mode_builder.Finish()));
201 }
202 }
203 }
204
205 std::shared_ptr<frc::DigitalOutput> superstructure_reading_;
206
207 void set_superstructure_reading(
208 std::shared_ptr<frc::DigitalOutput> superstructure_reading) {
209 superstructure_reading_ = superstructure_reading;
210 }
211
212 private:
213 std::shared_ptr<const Values> values_;
214
215 aos::Sender<frc971::autonomous::AutonomousMode> auto_mode_sender_;
216 aos::Sender<frc971::control_loops::drivetrain::Position>
217 drivetrain_position_sender_;
218 ::aos::Sender<::frc971::sensors::GyroReading> gyro_sender_;
219
220 std::array<std::unique_ptr<frc::DigitalInput>, 2> autonomous_modes_;
221
222 std::unique_ptr<frc::DigitalInput> imu_yaw_rate_input_;
223
224 frc971::wpilib::DMAPulseWidthReader imu_yaw_rate_reader_;
225};
226
227class WPILibRobot : public ::frc971::wpilib::WPILibRobotBase {
228 public:
229 ::std::unique_ptr<frc::Encoder> make_encoder(int index) {
230 return make_unique<frc::Encoder>(10 + index * 2, 11 + index * 2, false,
231 frc::Encoder::k4X);
232 }
233
234 void Run() override {
235 std::shared_ptr<const Values> values =
236 std::make_shared<const Values>(constants::MakeValues());
237
238 aos::FlatbufferDetachedBuffer<aos::Configuration> config =
239 aos::configuration::ReadConfig("aos_config.json");
240
241 // Thread 1.
242 ::aos::ShmEventLoop joystick_sender_event_loop(&config.message());
243 ::frc971::wpilib::JoystickSender joystick_sender(
244 &joystick_sender_event_loop);
245 AddLoop(&joystick_sender_event_loop);
246
247 // Thread 2.
248 ::aos::ShmEventLoop pdp_fetcher_event_loop(&config.message());
249 ::frc971::wpilib::PDPFetcher pdp_fetcher(&pdp_fetcher_event_loop);
250 AddLoop(&pdp_fetcher_event_loop);
251
252 // Thread 3.
253 ::aos::ShmEventLoop sensor_reader_event_loop(&config.message());
254 SensorReader sensor_reader(&sensor_reader_event_loop, values);
255 std::shared_ptr<frc::DigitalOutput> superstructure_reading =
256 make_unique<frc::DigitalOutput>(25);
257
258 sensor_reader.set_pwm_trigger(true);
259 sensor_reader.set_drivetrain_left_encoder(make_encoder(1));
260 sensor_reader.set_drivetrain_right_encoder(make_encoder(0));
261 sensor_reader.set_superstructure_reading(superstructure_reading);
262 sensor_reader.set_yaw_rate_input(make_unique<frc::DigitalInput>(0));
263
264 AddLoop(&sensor_reader_event_loop);
265
266 // Thread 4.
267 std::vector<ctre::phoenix6::BaseStatusSignal *> signals_registry;
268
269 std::shared_ptr<Falcon> right_front = std::make_shared<Falcon>(
270 1, true, "Drivetrain Bus", &signals_registry,
271 constants::Values::kDrivetrainStatorCurrentLimit(),
272 constants::Values::kDrivetrainSupplyCurrentLimit());
273 std::shared_ptr<Falcon> right_back = std::make_shared<Falcon>(
274 2, true, "Drivetrain Bus", &signals_registry,
275 constants::Values::kDrivetrainStatorCurrentLimit(),
276 constants::Values::kDrivetrainSupplyCurrentLimit());
277 std::shared_ptr<Falcon> right_under = std::make_shared<Falcon>(
278 3, true, "Drivetrain Bus", &signals_registry,
279 constants::Values::kDrivetrainStatorCurrentLimit(),
280 constants::Values::kDrivetrainSupplyCurrentLimit());
281 std::shared_ptr<Falcon> left_front = std::make_shared<Falcon>(
282 4, false, "Drivetrain Bus", &signals_registry,
283 constants::Values::kDrivetrainStatorCurrentLimit(),
284 constants::Values::kDrivetrainSupplyCurrentLimit());
285 std::shared_ptr<Falcon> left_back = std::make_shared<Falcon>(
286 5, false, "Drivetrain Bus", &signals_registry,
287 constants::Values::kDrivetrainStatorCurrentLimit(),
288 constants::Values::kDrivetrainSupplyCurrentLimit());
289 std::shared_ptr<Falcon> left_under = std::make_shared<Falcon>(
290 6, false, "Drivetrain Bus", &signals_registry,
291 constants::Values::kDrivetrainStatorCurrentLimit(),
292 constants::Values::kDrivetrainSupplyCurrentLimit());
293
294 // Setting up CAN.
295 if (!FLAGS_ctre_diag_server) {
296 c_Phoenix_Diagnostics_SetSecondsToStart(-1);
297 c_Phoenix_Diagnostics_Dispose();
298 }
299
300 // Creating list of falcons for CANSensorReader
301 std::vector<std::shared_ptr<Falcon>> falcons;
302 for (auto falcon : {right_front, right_back, right_under, left_front,
303 left_back, left_under}) {
304 falcons.push_back(falcon);
305 }
306
307 ctre::phoenix::platform::can::CANComm_SetRxSchedPriority(
308 constants::Values::kDrivetrainRxPriority, true, "Drivetrain Bus");
309 ctre::phoenix::platform::can::CANComm_SetTxSchedPriority(
310 constants::Values::kDrivetrainTxPriority, true, "Drivetrain Bus");
311
312 ::aos::ShmEventLoop can_sensor_reader_event_loop(&config.message());
313 can_sensor_reader_event_loop.set_name("CANSensorReader");
314
315 aos::Sender<CANPosition> can_position_sender =
316 can_sensor_reader_event_loop.MakeSender<CANPosition>("/drivetrain");
317
318 frc971::wpilib::CANSensorReader can_sensor_reader(
319 &can_sensor_reader_event_loop, std::move(signals_registry), falcons,
320 [falcons, &can_position_sender](ctre::phoenix::StatusCode status) {
321 auto builder = can_position_sender.MakeBuilder();
322 aos::SizedArray<flatbuffers::Offset<frc971::control_loops::CANFalcon>,
323 6>
324 flatbuffer_falcons;
325
326 for (auto falcon : falcons) {
327 falcon->SerializePosition(
328 builder.fbb(), control_loops::drivetrain::kHighOutputRatio);
329 std::optional<flatbuffers::Offset<frc971::control_loops::CANFalcon>>
330 falcon_offset = falcon->TakeOffset();
331
332 CHECK(falcon_offset.has_value());
333
334 flatbuffer_falcons.push_back(falcon_offset.value());
335 }
336
337 auto falcons_list =
338 builder.fbb()
339 ->CreateVector<
340 flatbuffers::Offset<frc971::control_loops::CANFalcon>>(
341 flatbuffer_falcons);
342
343 frc971::control_loops::drivetrain::CANPosition::Builder
344 can_position_builder = builder.MakeBuilder<
345 frc971::control_loops::drivetrain::CANPosition>();
346
347 can_position_builder.add_falcons(falcons_list);
348 can_position_builder.add_timestamp(falcons.front()->GetTimestamp());
349 can_position_builder.add_status(static_cast<int>(status));
350
351 builder.CheckOk(builder.Send(can_position_builder.Finish()));
352 });
353
354 AddLoop(&can_sensor_reader_event_loop);
355
356 // Thread 5.
357 ::aos::ShmEventLoop can_drivetrain_writer_event_loop(&config.message());
358 can_drivetrain_writer_event_loop.set_name("CANDrivetrainWriter");
359
360 frc971::wpilib::CANDrivetrainWriter can_drivetrain_writer(
361 &can_drivetrain_writer_event_loop);
362
363 can_drivetrain_writer.set_falcons({right_front, right_back, right_under},
364 {left_front, left_back, left_under});
365
366 can_drivetrain_writer_event_loop.MakeWatcher(
367 "/roborio", [&can_drivetrain_writer](
368 const frc971::CANConfiguration &configuration) {
369 can_drivetrain_writer.HandleCANConfiguration(configuration);
370 });
371
372 AddLoop(&can_drivetrain_writer_event_loop);
373
374 RunLoops();
375 }
376};
377
378} // namespace wpilib
379} // namespace y2024_defense
380
381AOS_ROBOT_CLASS(::y2024_defense::wpilib::WPILibRobot);