blob: 1dd8efd7af921bb8f03c486be07c4fe2c135a35e [file] [log] [blame]
Ariv Diggi0af59c02023-10-07 13:15:39 -07001#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"
Ariv Diggi0af59c02023-10-07 13:15:39 -070027#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/dma.h"
50#include "frc971/wpilib/drivetrain_writer.h"
51#include "frc971/wpilib/encoder_and_potentiometer.h"
52#include "frc971/wpilib/joystick_sender.h"
53#include "frc971/wpilib/logging_generated.h"
54#include "frc971/wpilib/loop_output_handler.h"
55#include "frc971/wpilib/pdp_fetcher.h"
56#include "frc971/wpilib/sensor_reader.h"
57#include "frc971/wpilib/wpilib_robot_base.h"
58#include "y2023_bot3/constants.h"
59#include "y2023_bot3/control_loops/superstructure/led_indicator.h"
60#include "y2023_bot3/control_loops/superstructure/superstructure_output_generated.h"
61#include "y2023_bot3/control_loops/superstructure/superstructure_position_generated.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 ::y2023_bot3::constants::Values;
69namespace superstructure = ::y2023_bot3::control_loops::superstructure;
70namespace drivetrain = ::y2023_bot3::control_loops::drivetrain;
71namespace chrono = ::std::chrono;
72using std::make_unique;
73
Stephan Pleinesf63bde82024-01-13 15:59:33 -080074namespace y2023_bot3::wpilib {
Ariv Diggi0af59c02023-10-07 13:15:39 -070075namespace {
76
77constexpr double kMaxBringupPower = 12.0;
78
79// TODO(Brian): Fix the interpretation of the result of GetRaw here and in the
80// DMA stuff and then removing the * 2.0 in *_translate.
81// The low bit is direction.
82
83double drivetrain_velocity_translate(double in) {
84 return (((1.0 / in) / Values::kDrivetrainCyclesPerRevolution()) *
85 (2.0 * M_PI)) *
86 Values::kDrivetrainEncoderRatio() *
87 control_loops::drivetrain::kWheelRadius;
88}
89
90constexpr double kMaxFastEncoderPulsesPerSecond = std::max({
91 Values::kMaxDrivetrainEncoderPulsesPerSecond(),
92});
93static_assert(kMaxFastEncoderPulsesPerSecond <= 1300000,
94 "fast encoders are too fast");
95
96} // namespace
97
Maxwell Henderson10ed5c32024-01-09 12:40:54 -080098static constexpr int kCANTalonFXCount = 6;
Ariv Diggi0af59c02023-10-07 13:15:39 -070099static constexpr units::frequency::hertz_t kCANUpdateFreqHz = 200_Hz;
100
101class Falcon {
102 public:
103 Falcon(int device_id, std::string canbus,
104 std::vector<ctre::phoenix6::BaseStatusSignal *> *signals)
105 : talon_(device_id, canbus),
106 device_id_(device_id),
107 device_temp_(talon_.GetDeviceTemp()),
108 supply_voltage_(talon_.GetSupplyVoltage()),
109 supply_current_(talon_.GetSupplyCurrent()),
110 torque_current_(talon_.GetTorqueCurrent()),
111 position_(talon_.GetPosition()),
112 duty_cycle_(talon_.GetDutyCycle()) {
113 // device temp is not timesynced so don't add it to the list of signals
114 device_temp_.SetUpdateFrequency(kCANUpdateFreqHz);
115
116 CHECK_NOTNULL(signals);
117
118 supply_voltage_.SetUpdateFrequency(kCANUpdateFreqHz);
119 signals->push_back(&supply_voltage_);
120
121 supply_current_.SetUpdateFrequency(kCANUpdateFreqHz);
122 signals->push_back(&supply_current_);
123
124 torque_current_.SetUpdateFrequency(kCANUpdateFreqHz);
125 signals->push_back(&torque_current_);
126
127 position_.SetUpdateFrequency(kCANUpdateFreqHz);
128 signals->push_back(&position_);
129
130 duty_cycle_.SetUpdateFrequency(kCANUpdateFreqHz);
131 signals->push_back(&duty_cycle_);
132 }
133
134 void PrintConfigs() {
135 ctre::phoenix6::configs::TalonFXConfiguration configuration;
136 ctre::phoenix::StatusCode status =
137 talon_.GetConfigurator().Refresh(configuration);
138 if (!status.IsOK()) {
139 AOS_LOG(ERROR, "Failed to get falcon configuration: %s: %s",
140 status.GetName(), status.GetDescription());
141 }
142 AOS_LOG(INFO, "configuration: %s", configuration.ToString().c_str());
143 }
144
145 void WriteConfigs(ctre::phoenix6::signals::InvertedValue invert) {
146 inverted_ = invert;
147
148 ctre::phoenix6::configs::CurrentLimitsConfigs current_limits;
149 current_limits.StatorCurrentLimit =
150 constants::Values::kDrivetrainStatorCurrentLimit();
151 current_limits.StatorCurrentLimitEnable = true;
152 current_limits.SupplyCurrentLimit =
153 constants::Values::kDrivetrainSupplyCurrentLimit();
154 current_limits.SupplyCurrentLimitEnable = true;
155
156 ctre::phoenix6::configs::MotorOutputConfigs output_configs;
157 output_configs.NeutralMode =
158 ctre::phoenix6::signals::NeutralModeValue::Brake;
159 output_configs.DutyCycleNeutralDeadband = 0;
160
161 output_configs.Inverted = inverted_;
162
163 ctre::phoenix6::configs::TalonFXConfiguration configuration;
164 configuration.CurrentLimits = current_limits;
165 configuration.MotorOutput = output_configs;
166
167 ctre::phoenix::StatusCode status =
168 talon_.GetConfigurator().Apply(configuration);
169 if (!status.IsOK()) {
170 AOS_LOG(ERROR, "Failed to set falcon configuration: %s: %s",
171 status.GetName(), status.GetDescription());
172 }
173
174 PrintConfigs();
175 }
176
177 ctre::phoenix6::hardware::TalonFX *talon() { return &talon_; }
178
Maxwell Henderson10ed5c32024-01-09 12:40:54 -0800179 flatbuffers::Offset<frc971::control_loops::CANTalonFX> WritePosition(
Ariv Diggi0af59c02023-10-07 13:15:39 -0700180 flatbuffers::FlatBufferBuilder *fbb) {
Maxwell Henderson10ed5c32024-01-09 12:40:54 -0800181 frc971::control_loops::CANTalonFX::Builder builder(*fbb);
Ariv Diggi0af59c02023-10-07 13:15:39 -0700182 builder.add_id(device_id_);
183 builder.add_device_temp(device_temp());
184 builder.add_supply_voltage(supply_voltage());
185 builder.add_supply_current(supply_current());
186 builder.add_torque_current(torque_current());
187 builder.add_duty_cycle(duty_cycle());
188
189 double invert =
190 (inverted_ == ctre::phoenix6::signals::InvertedValue::Clockwise_Positive
191 ? 1
192 : -1);
193
194 builder.add_position(
195 constants::Values::DrivetrainCANEncoderToMeters(position()) * invert);
196
197 return builder.Finish();
198 }
199
200 int device_id() const { return device_id_; }
201 float device_temp() const { return device_temp_.GetValue().value(); }
202 float supply_voltage() const { return supply_voltage_.GetValue().value(); }
203 float supply_current() const { return supply_current_.GetValue().value(); }
204 float torque_current() const { return torque_current_.GetValue().value(); }
205 float duty_cycle() const { return duty_cycle_.GetValue().value(); }
206 float position() const { return position_.GetValue().value(); }
207
208 // returns the monotonic timestamp of the latest timesynced reading in the
209 // timebase of the the syncronized CAN bus clock.
210 int64_t GetTimestamp() {
211 std::chrono::nanoseconds latest_timestamp =
212 torque_current_.GetTimestamp().GetTime();
213
214 return latest_timestamp.count();
215 }
216
217 void RefreshNontimesyncedSignals() { device_temp_.Refresh(); };
218
219 private:
220 ctre::phoenix6::hardware::TalonFX talon_;
221 int device_id_;
222
223 ctre::phoenix6::signals::InvertedValue inverted_;
224
225 ctre::phoenix6::StatusSignal<units::temperature::celsius_t> device_temp_;
226 ctre::phoenix6::StatusSignal<units::voltage::volt_t> supply_voltage_;
227 ctre::phoenix6::StatusSignal<units::current::ampere_t> supply_current_,
228 torque_current_;
229 ctre::phoenix6::StatusSignal<units::angle::turn_t> position_;
230 ctre::phoenix6::StatusSignal<units::dimensionless::scalar_t> duty_cycle_;
231};
232
233class CANSensorReader {
234 public:
235 CANSensorReader(
236 aos::EventLoop *event_loop,
237 std::vector<ctre::phoenix6::BaseStatusSignal *> signals_registry)
238 : event_loop_(event_loop),
239 signals_(signals_registry.begin(), signals_registry.end()),
240 can_position_sender_(
241 event_loop
242 ->MakeSender<frc971::control_loops::drivetrain::CANPosition>(
Maxwell Henderson4d4be542023-11-29 18:26:13 -0800243 "/drivetrain")) {
Ariv Diggi0af59c02023-10-07 13:15:39 -0700244 event_loop->SetRuntimeRealtimePriority(40);
245 event_loop->SetRuntimeAffinity(aos::MakeCpusetFromCpus({1}));
246 timer_handler_ = event_loop->AddTimer([this]() { Loop(); });
247 timer_handler_->set_name("CANSensorReader Loop");
248
249 event_loop->OnRun([this]() {
250 timer_handler_->Schedule(event_loop_->monotonic_now(),
251 1 / kCANUpdateFreqHz);
252 });
253 }
254
255 void set_falcons(std::shared_ptr<Falcon> right_front,
Maxwell Henderson9033d712024-01-07 13:05:36 -0800256 std::shared_ptr<Falcon> right_back) {
Ariv Diggi0af59c02023-10-07 13:15:39 -0700257 right_front_ = std::move(right_front);
258 right_back_ = std::move(right_back);
Ariv Diggi0af59c02023-10-07 13:15:39 -0700259 }
260
261 private:
262 void Loop() {
263 ctre::phoenix::StatusCode status =
264 ctre::phoenix6::BaseStatusSignal::WaitForAll(2000_ms, signals_);
265
266 if (!status.IsOK()) {
267 AOS_LOG(ERROR, "Failed to read signals from falcons: %s: %s",
268 status.GetName(), status.GetDescription());
269 }
270
271 auto builder = can_position_sender_.MakeBuilder();
272
Maxwell Henderson9033d712024-01-07 13:05:36 -0800273 for (auto falcon : {right_front_, right_back_}) {
Ariv Diggi0af59c02023-10-07 13:15:39 -0700274 falcon->RefreshNontimesyncedSignals();
275 }
276
Maxwell Henderson10ed5c32024-01-09 12:40:54 -0800277 aos::SizedArray<flatbuffers::Offset<frc971::control_loops::CANTalonFX>,
278 kCANTalonFXCount>
Ariv Diggi0af59c02023-10-07 13:15:39 -0700279 falcons;
280
Maxwell Henderson9033d712024-01-07 13:05:36 -0800281 for (auto falcon : {right_front_, right_back_}) {
Ariv Diggi0af59c02023-10-07 13:15:39 -0700282 falcons.push_back(falcon->WritePosition(builder.fbb()));
283 }
284
285 auto falcons_list =
286 builder.fbb()
287 ->CreateVector<
Maxwell Henderson10ed5c32024-01-09 12:40:54 -0800288 flatbuffers::Offset<frc971::control_loops::CANTalonFX>>(
289 falcons);
Ariv Diggi0af59c02023-10-07 13:15:39 -0700290
291 frc971::control_loops::drivetrain::CANPosition::Builder
292 can_position_builder =
293 builder
294 .MakeBuilder<frc971::control_loops::drivetrain::CANPosition>();
295
Maxwell Henderson10ed5c32024-01-09 12:40:54 -0800296 can_position_builder.add_talonfxs(falcons_list);
Ariv Diggi0af59c02023-10-07 13:15:39 -0700297 can_position_builder.add_status(static_cast<int>(status));
298
299 builder.CheckOk(builder.Send(can_position_builder.Finish()));
300 }
301
302 aos::EventLoop *event_loop_;
303
304 const std::vector<ctre::phoenix6::BaseStatusSignal *> signals_;
305 aos::Sender<frc971::control_loops::drivetrain::CANPosition>
306 can_position_sender_;
307
Maxwell Henderson9033d712024-01-07 13:05:36 -0800308 std::shared_ptr<Falcon> right_front_, right_back_;
Ariv Diggi0af59c02023-10-07 13:15:39 -0700309
310 // Pointer to the timer handler used to modify the wakeup.
311 ::aos::TimerHandler *timer_handler_;
312};
313
314// Class to send position messages with sensor readings to our loops.
315class SensorReader : public ::frc971::wpilib::SensorReader {
316 public:
317 SensorReader(::aos::ShmEventLoop *event_loop,
318 std::shared_ptr<const Values> values,
319 CANSensorReader *can_sensor_reader)
320 : ::frc971::wpilib::SensorReader(event_loop),
321 values_(std::move(values)),
322 auto_mode_sender_(
323 event_loop->MakeSender<::frc971::autonomous::AutonomousMode>(
324 "/autonomous")),
325 superstructure_position_sender_(
326 event_loop->MakeSender<superstructure::Position>(
327 "/superstructure")),
328 drivetrain_position_sender_(
329 event_loop
330 ->MakeSender<::frc971::control_loops::drivetrain::Position>(
331 "/drivetrain")),
332 gyro_sender_(event_loop->MakeSender<::frc971::sensors::GyroReading>(
333 "/drivetrain")),
334 can_sensor_reader_(can_sensor_reader) {
335 // Set to filter out anything shorter than 1/4 of the minimum pulse width
336 // we should ever see.
337 UpdateFastEncoderFilterHz(kMaxFastEncoderPulsesPerSecond);
338 event_loop->SetRuntimeAffinity(aos::MakeCpusetFromCpus({0}));
339 }
340
341 void Start() override { AddToDMA(&imu_yaw_rate_reader_); }
342
343 // Auto mode switches.
344 void set_autonomous_mode(int i, ::std::unique_ptr<frc::DigitalInput> sensor) {
345 autonomous_modes_.at(i) = ::std::move(sensor);
346 }
347
348 void set_yaw_rate_input(::std::unique_ptr<frc::DigitalInput> sensor) {
349 imu_yaw_rate_input_ = ::std::move(sensor);
350 imu_yaw_rate_reader_.set_input(imu_yaw_rate_input_.get());
351 }
352
353 void RunIteration() override {
354 superstructure_reading_->Set(true);
Ariv Diggic892e922023-10-21 15:52:06 -0700355 {
356 auto builder = superstructure_position_sender_.MakeBuilder();
357
Ariv Diggic892e922023-10-21 15:52:06 -0700358 superstructure::Position::Builder position_builder =
359 builder.MakeBuilder<superstructure::Position>();
Ariv Diggic892e922023-10-21 15:52:06 -0700360 builder.CheckOk(builder.Send(position_builder.Finish()));
361 }
Ariv Diggi0af59c02023-10-07 13:15:39 -0700362
363 {
364 auto builder = drivetrain_position_sender_.MakeBuilder();
365 frc971::control_loops::drivetrain::Position::Builder drivetrain_builder =
366 builder.MakeBuilder<frc971::control_loops::drivetrain::Position>();
367 drivetrain_builder.add_left_encoder(
Filip Kujawa35b5aad2023-11-14 21:53:19 -0800368 -constants::Values::DrivetrainEncoderToMeters(
Ariv Diggi0af59c02023-10-07 13:15:39 -0700369 drivetrain_left_encoder_->GetRaw()));
370 drivetrain_builder.add_left_speed(
371 drivetrain_velocity_translate(drivetrain_left_encoder_->GetPeriod()));
372
373 drivetrain_builder.add_right_encoder(
Filip Kujawa35b5aad2023-11-14 21:53:19 -0800374 constants::Values::DrivetrainEncoderToMeters(
Ariv Diggi0af59c02023-10-07 13:15:39 -0700375 drivetrain_right_encoder_->GetRaw()));
376 drivetrain_builder.add_right_speed(-drivetrain_velocity_translate(
377 drivetrain_right_encoder_->GetPeriod()));
378
379 builder.CheckOk(builder.Send(drivetrain_builder.Finish()));
380 }
381
382 {
383 auto builder = gyro_sender_.MakeBuilder();
384 ::frc971::sensors::GyroReading::Builder gyro_reading_builder =
385 builder.MakeBuilder<::frc971::sensors::GyroReading>();
386 // +/- 2000 deg / sec
387 constexpr double kMaxVelocity = 4000; // degrees / second
388 constexpr double kVelocityRadiansPerSecond =
389 kMaxVelocity / 360 * (2.0 * M_PI);
390
391 // Only part of the full range is used to prevent being 100% on or off.
392 constexpr double kScaledRangeLow = 0.1;
393 constexpr double kScaledRangeHigh = 0.9;
394
395 constexpr double kPWMFrequencyHz = 200;
396 double velocity_duty_cycle =
397 imu_yaw_rate_reader_.last_width() * kPWMFrequencyHz;
398
399 constexpr double kDutyCycleScale =
400 1 / (kScaledRangeHigh - kScaledRangeLow);
401 // scale from 0.1 - 0.9 to 0 - 1
402 double rescaled_velocity_duty_cycle =
403 (velocity_duty_cycle - kScaledRangeLow) * kDutyCycleScale;
404
405 if (!std::isnan(rescaled_velocity_duty_cycle)) {
406 gyro_reading_builder.add_velocity((rescaled_velocity_duty_cycle - 0.5) *
407 kVelocityRadiansPerSecond);
408 }
409 builder.CheckOk(builder.Send(gyro_reading_builder.Finish()));
410 }
411
412 {
413 auto builder = auto_mode_sender_.MakeBuilder();
414
415 uint32_t mode = 0;
416 for (size_t i = 0; i < autonomous_modes_.size(); ++i) {
417 if (autonomous_modes_[i] && autonomous_modes_[i]->Get()) {
418 mode |= 1 << i;
419 }
420 }
421
422 auto auto_mode_builder =
423 builder.MakeBuilder<frc971::autonomous::AutonomousMode>();
424
425 auto_mode_builder.add_mode(mode);
426
427 builder.CheckOk(builder.Send(auto_mode_builder.Finish()));
428 }
429 }
430
431 std::shared_ptr<frc::DigitalOutput> superstructure_reading_;
432
433 void set_superstructure_reading(
434 std::shared_ptr<frc::DigitalOutput> superstructure_reading) {
435 superstructure_reading_ = superstructure_reading;
436 }
437
438 private:
439 std::shared_ptr<const Values> values_;
440
441 aos::Sender<frc971::autonomous::AutonomousMode> auto_mode_sender_;
442 aos::Sender<superstructure::Position> superstructure_position_sender_;
443 aos::Sender<frc971::control_loops::drivetrain::Position>
444 drivetrain_position_sender_;
445 ::aos::Sender<::frc971::sensors::GyroReading> gyro_sender_;
446
447 std::array<std::unique_ptr<frc::DigitalInput>, 2> autonomous_modes_;
448
Maxwell Henderson4d4be542023-11-29 18:26:13 -0800449 std::unique_ptr<frc::DigitalInput> imu_yaw_rate_input_;
Ariv Diggi0af59c02023-10-07 13:15:39 -0700450
451 frc971::wpilib::DMAPulseWidthReader imu_yaw_rate_reader_;
452
453 CANSensorReader *can_sensor_reader_;
454};
Ariv Diggi0af59c02023-10-07 13:15:39 -0700455class DrivetrainWriter : public ::frc971::wpilib::LoopOutputHandler<
456 ::frc971::control_loops::drivetrain::Output> {
457 public:
458 DrivetrainWriter(::aos::EventLoop *event_loop)
459 : ::frc971::wpilib::LoopOutputHandler<
460 ::frc971::control_loops::drivetrain::Output>(event_loop,
461 "/drivetrain") {
462 event_loop->SetRuntimeRealtimePriority(
463 constants::Values::kDrivetrainWriterPriority);
464
465 event_loop->OnRun([this]() { WriteConfigs(); });
466 }
467
468 void set_falcons(std::shared_ptr<Falcon> right_front,
Maxwell Henderson9033d712024-01-07 13:05:36 -0800469 std::shared_ptr<Falcon> right_back) {
Ariv Diggi0af59c02023-10-07 13:15:39 -0700470 right_front_ = std::move(right_front);
471 right_back_ = std::move(right_back);
Ariv Diggi0af59c02023-10-07 13:15:39 -0700472 }
473
474 void set_right_inverted(ctre::phoenix6::signals::InvertedValue invert) {
475 right_inverted_ = invert;
476 }
477
Ariv Diggi0af59c02023-10-07 13:15:39 -0700478 void HandleCANConfiguration(const frc971::CANConfiguration &configuration) {
Maxwell Henderson9033d712024-01-07 13:05:36 -0800479 for (auto falcon : {right_front_, right_back_}) {
Ariv Diggi0af59c02023-10-07 13:15:39 -0700480 falcon->PrintConfigs();
481 }
482 if (configuration.reapply()) {
483 WriteConfigs();
484 }
485 }
486
487 private:
488 void WriteConfigs() {
Mirabel Wangf4e42672023-10-14 13:12:49 -0700489 for (auto falcon : {right_front_.get(), right_back_.get()}) {
Ariv Diggi0af59c02023-10-07 13:15:39 -0700490 falcon->WriteConfigs(right_inverted_);
491 }
Ariv Diggi0af59c02023-10-07 13:15:39 -0700492 }
493
494 void Write(
495 const ::frc971::control_loops::drivetrain::Output &output) override {
Ariv Diggi0af59c02023-10-07 13:15:39 -0700496 ctre::phoenix6::controls::DutyCycleOut right_control(
497 SafeSpeed(output.right_voltage()));
498 right_control.UpdateFreqHz = 0_Hz;
499 right_control.EnableFOC = true;
500
Mirabel Wangf4e42672023-10-14 13:12:49 -0700501 for (auto falcon : {right_front_.get(), right_back_.get()}) {
Ariv Diggi0af59c02023-10-07 13:15:39 -0700502 ctre::phoenix::StatusCode status =
503 falcon->talon()->SetControl(right_control);
504
505 if (!status.IsOK()) {
506 AOS_LOG(ERROR, "Failed to write control to falcon: %s: %s",
507 status.GetName(), status.GetDescription());
508 }
509 }
510 }
511
512 void Stop() override {
513 AOS_LOG(WARNING, "drivetrain output too old\n");
514 ctre::phoenix6::controls::DutyCycleOut stop_command(0.0);
515 stop_command.UpdateFreqHz = 0_Hz;
516 stop_command.EnableFOC = true;
517
Maxwell Henderson9033d712024-01-07 13:05:36 -0800518 for (auto falcon : {right_front_.get(), right_back_.get()}) {
Ariv Diggi0af59c02023-10-07 13:15:39 -0700519 falcon->talon()->SetControl(stop_command);
520 }
521 }
522
523 double SafeSpeed(double voltage) {
524 return (::aos::Clip(voltage, -kMaxBringupPower, kMaxBringupPower) / 12.0);
525 }
526
Maxwell Henderson9033d712024-01-07 13:05:36 -0800527 ctre::phoenix6::signals::InvertedValue right_inverted_;
528 std::shared_ptr<Falcon> right_front_, right_back_;
529};
530class PWMDrivetrainWriter : public ::frc971::wpilib::LoopOutputHandler<
531 ::frc971::control_loops::drivetrain::Output> {
532 public:
533 static constexpr double kMaxBringupPower = 12.0;
534
535 PWMDrivetrainWriter(::aos::EventLoop *event_loop)
536 : ::frc971::wpilib::LoopOutputHandler<
537 ::frc971::control_loops::drivetrain::Output>(event_loop,
538 "/drivetrain") {}
539
540 void set_left_controller0(::std::unique_ptr<::frc::PWM> t, bool reversed) {
541 left_controller0_ = ::std::move(t);
542 reversed_left0_ = reversed;
543 }
544
545 void set_left_controller1(::std::unique_ptr<::frc::PWM> t, bool reversed) {
546 left_controller1_ = ::std::move(t);
547 reversed_left1_ = reversed;
548 }
549
550 private:
551 void Write(
552 const ::frc971::control_loops::drivetrain::Output &output) override {
553 left_controller0_->SetSpeed(
554 SafeSpeed(reversed_left0_, output.left_voltage()));
555
556 if (left_controller1_) {
557 left_controller1_->SetSpeed(
558 SafeSpeed(reversed_left1_, output.left_voltage()));
559 }
560 }
561 void Stop() override {
562 AOS_LOG(WARNING, "drivetrain output too old\n");
563 left_controller0_->SetDisabled();
564
565 if (left_controller1_) {
566 left_controller1_->SetDisabled();
567 }
568 }
569
570 double SafeSpeed(bool reversed, double voltage) {
571 return (::aos::Clip((reversed ? -1.0 : 1.0) * voltage, -kMaxBringupPower,
572 kMaxBringupPower) /
573 12.0);
574 }
575
576 ::std::unique_ptr<::frc::PWM> left_controller0_, left_controller1_;
577
578 bool reversed_right0_, reversed_left0_, reversed_right1_, reversed_left1_;
Ariv Diggi0af59c02023-10-07 13:15:39 -0700579};
580
581class WPILibRobot : public ::frc971::wpilib::WPILibRobotBase {
582 public:
583 ::std::unique_ptr<frc::Encoder> make_encoder(int index) {
584 return make_unique<frc::Encoder>(10 + index * 2, 11 + index * 2, false,
585 frc::Encoder::k4X);
586 }
587
588 void Run() override {
589 std::shared_ptr<const Values> values =
590 std::make_shared<const Values>(constants::MakeValues());
591
592 aos::FlatbufferDetachedBuffer<aos::Configuration> config =
593 aos::configuration::ReadConfig("aos_config.json");
594
595 // Thread 1.
596 ::aos::ShmEventLoop joystick_sender_event_loop(&config.message());
597 ::frc971::wpilib::JoystickSender joystick_sender(
598 &joystick_sender_event_loop);
599 AddLoop(&joystick_sender_event_loop);
600
601 // Thread 2.
602 ::aos::ShmEventLoop pdp_fetcher_event_loop(&config.message());
603 ::frc971::wpilib::PDPFetcher pdp_fetcher(&pdp_fetcher_event_loop);
604 AddLoop(&pdp_fetcher_event_loop);
605
606 std::shared_ptr<frc::DigitalOutput> superstructure_reading =
607 make_unique<frc::DigitalOutput>(25);
608
609 std::vector<ctre::phoenix6::BaseStatusSignal *> signals_registry;
610 std::shared_ptr<Falcon> right_front =
611 std::make_shared<Falcon>(1, "Drivetrain Bus", &signals_registry);
612 std::shared_ptr<Falcon> right_back =
Maxwell Henderson3772d282023-11-06 11:07:49 -0800613 std::make_shared<Falcon>(0, "Drivetrain Bus", &signals_registry);
Ariv Diggi0af59c02023-10-07 13:15:39 -0700614
615 // Thread 3.
Maxwell Henderson9033d712024-01-07 13:05:36 -0800616 ::aos::ShmEventLoop output_event_loop(&config.message());
617 PWMDrivetrainWriter drivetrain_writer(&output_event_loop);
618 drivetrain_writer.set_left_controller0(
619 ::std::unique_ptr<::frc::VictorSP>(new ::frc::VictorSP(0)), true);
620
621 AddLoop(&output_event_loop);
622
623 // Thread 4
Ariv Diggi0af59c02023-10-07 13:15:39 -0700624 ::aos::ShmEventLoop can_sensor_reader_event_loop(&config.message());
625 can_sensor_reader_event_loop.set_name("CANSensorReader");
626 CANSensorReader can_sensor_reader(&can_sensor_reader_event_loop,
627 std::move(signals_registry));
Maxwell Henderson9033d712024-01-07 13:05:36 -0800628 can_sensor_reader.set_falcons(right_front, right_back);
Ariv Diggi0af59c02023-10-07 13:15:39 -0700629 AddLoop(&can_sensor_reader_event_loop);
630
Maxwell Henderson9033d712024-01-07 13:05:36 -0800631 // Thread 5.
Ariv Diggi0af59c02023-10-07 13:15:39 -0700632 ::aos::ShmEventLoop sensor_reader_event_loop(&config.message());
633 SensorReader sensor_reader(&sensor_reader_event_loop, values,
634 &can_sensor_reader);
635 sensor_reader.set_pwm_trigger(true);
Maxwell Henderson9033d712024-01-07 13:05:36 -0800636 sensor_reader.set_drivetrain_left_encoder(make_encoder(1));
637 sensor_reader.set_drivetrain_right_encoder(make_encoder(0));
Ariv Diggi0af59c02023-10-07 13:15:39 -0700638 sensor_reader.set_superstructure_reading(superstructure_reading);
Filip Kujawa35b5aad2023-11-14 21:53:19 -0800639 sensor_reader.set_yaw_rate_input(make_unique<frc::DigitalInput>(3));
Maxwell Henderson9435b5c2023-11-06 13:48:51 -0800640
Ariv Diggi0af59c02023-10-07 13:15:39 -0700641 AddLoop(&sensor_reader_event_loop);
642
Maxwell Henderson9033d712024-01-07 13:05:36 -0800643 // Thread 6.
Ariv Diggi0af59c02023-10-07 13:15:39 -0700644 // Set up CAN.
645 if (!FLAGS_ctre_diag_server) {
646 c_Phoenix_Diagnostics_SetSecondsToStart(-1);
647 c_Phoenix_Diagnostics_Dispose();
648 }
649
650 ctre::phoenix::platform::can::CANComm_SetRxSchedPriority(
651 constants::Values::kDrivetrainRxPriority, true, "Drivetrain Bus");
652 ctre::phoenix::platform::can::CANComm_SetTxSchedPriority(
653 constants::Values::kDrivetrainTxPriority, true, "Drivetrain Bus");
654
655 ::aos::ShmEventLoop can_output_event_loop(&config.message());
656 can_output_event_loop.set_name("CANOutputWriter");
Maxwell Henderson9033d712024-01-07 13:05:36 -0800657 DrivetrainWriter can_drivetrain_writer(&can_output_event_loop);
Ariv Diggi0af59c02023-10-07 13:15:39 -0700658
Maxwell Henderson9033d712024-01-07 13:05:36 -0800659 can_drivetrain_writer.set_falcons(right_front, right_back);
660 can_drivetrain_writer.set_right_inverted(
Ariv Diggi0af59c02023-10-07 13:15:39 -0700661 ctre::phoenix6::signals::InvertedValue::CounterClockwise_Positive);
Filip Kujawa35b5aad2023-11-14 21:53:19 -0800662
Ariv Diggi0af59c02023-10-07 13:15:39 -0700663 can_output_event_loop.MakeWatcher(
Maxwell Henderson9033d712024-01-07 13:05:36 -0800664 "/roborio", [&can_drivetrain_writer](
665 const frc971::CANConfiguration &configuration) {
666 can_drivetrain_writer.HandleCANConfiguration(configuration);
Ariv Diggi0af59c02023-10-07 13:15:39 -0700667 });
668
669 AddLoop(&can_output_event_loop);
670
Ariv Diggi0af59c02023-10-07 13:15:39 -0700671 RunLoops();
672 }
673};
674
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800675} // namespace y2023_bot3::wpilib
Ariv Diggi0af59c02023-10-07 13:15:39 -0700676
Maxwell Henderson1c0843c2023-12-22 16:20:59 -0800677AOS_ROBOT_CLASS(::y2023_bot3::wpilib::WPILibRobot);