blob: 3efe122e9a7844a60293e66c09a737ebbd627106 [file] [log] [blame]
Sabina Davisadc58542019-02-01 22:23:00 -08001#include "frc971/wpilib/sensor_reader.h"
2
Sabina Davis399dbd82019-02-01 23:06:08 -08003#include <unistd.h>
4
Tyler Chatowbf0609c2021-07-31 16:13:27 -07005#include <cinttypes>
6
Austin Schuh99f7c6a2024-06-25 22:07:44 -07007#include "absl/flags/flag.h"
8
Sabina Davisadc58542019-02-01 22:23:00 -08009#include "aos/init.h"
Austin Schuha0c41ba2020-09-10 22:59:14 -070010#include "aos/logging/logging.h"
Austin Schuh719d6802021-11-05 23:46:20 -070011#include "aos/realtime.h"
Sabina Davisadc58542019-02-01 22:23:00 -080012#include "aos/util/compiler_memory_barrier.h"
13#include "frc971/wpilib/ahal/DigitalInput.h"
Austin Schuh3b010bc2019-02-24 17:25:37 -080014#include "frc971/wpilib/ahal/DriverStation.h"
Brian Silverman7be68ba2020-01-08 22:08:40 -080015#include "frc971/wpilib/fpga_time_conversion.h"
Austin Schuh45a549f2019-02-02 15:43:56 -080016#include "frc971/wpilib/wpilib_interface.h"
Austin Schuh3b010bc2019-02-24 17:25:37 -080017#include "hal/PWM.h"
Sabina Davisadc58542019-02-01 22:23:00 -080018
Austin Schuh99f7c6a2024-06-25 22:07:44 -070019ABSL_FLAG(int32_t, pwm_offset, 5050 / 2,
20 "Offset of reading the sensors from the start of the PWM cycle");
Austin Schuh028d81d2022-03-26 15:11:42 -070021
Stephan Pleinesf63bde82024-01-13 15:59:33 -080022namespace frc971::wpilib {
Sabina Davisadc58542019-02-01 22:23:00 -080023
Austin Schuh217a9782019-12-21 23:02:50 -080024SensorReader::SensorReader(::aos::ShmEventLoop *event_loop)
Austin Schuhdf6cbb12019-02-02 13:46:52 -080025 : event_loop_(event_loop),
Austin Schuh217a9782019-12-21 23:02:50 -080026 robot_state_sender_(event_loop_->MakeSender<::aos::RobotState>("/aos")),
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070027 my_pid_(getpid()) {
Austin Schuh45a549f2019-02-02 15:43:56 -080028 // Set some defaults. We don't tend to exceed these, so old robots should
29 // just work with them.
30 UpdateFastEncoderFilterHz(500000);
31 UpdateMediumEncoderFilterHz(100000);
Austin Schuh3b010bc2019-02-24 17:25:37 -080032 ds_ = &::frc::DriverStation::GetInstance();
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070033
34 event_loop->SetRuntimeRealtimePriority(40);
Austin Schuh719d6802021-11-05 23:46:20 -070035 // The timer interrupt fires on CPU1. Since nothing else is pinned, it will
36 // be cheapest to pin this there so it transitions directly and doesn't
37 // need to ever migrate.
38 event_loop->SetRuntimeAffinity(aos::MakeCpusetFromCpus({1}));
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070039
40 // Fill in the no pwm trigger defaults.
milind-u61227f22021-08-29 15:58:33 -070041 timer_handler_ = event_loop_->AddTimer([this]() { Loop(); });
42 timer_handler_->set_name("SensorReader Loop");
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070043
44 event_loop->set_name("SensorReader");
45 event_loop->OnRun([this]() { DoStart(); });
Austin Schuh45a549f2019-02-02 15:43:56 -080046}
47
48void SensorReader::UpdateFastEncoderFilterHz(int hz) {
49 fast_encoder_filter_.SetPeriodHz(::std::max(hz, 100000));
50}
51
52void SensorReader::UpdateMediumEncoderFilterHz(int hz) {
53 medium_encoder_filter_.SetPeriodHz(::std::max(hz, 50000));
54}
Sabina Davisadc58542019-02-01 22:23:00 -080055
Sabina Davisb6317b72019-02-01 22:53:23 -080056void SensorReader::set_drivetrain_left_encoder(
57 ::std::unique_ptr<frc::Encoder> encoder) {
58 fast_encoder_filter_.Add(encoder.get());
59 drivetrain_left_encoder_ = ::std::move(encoder);
Austin Schuh45a549f2019-02-02 15:43:56 -080060 drivetrain_left_encoder_->SetMaxPeriod(0.005);
Sabina Davisb6317b72019-02-01 22:53:23 -080061}
62
63void SensorReader::set_drivetrain_right_encoder(
64 ::std::unique_ptr<frc::Encoder> encoder) {
65 fast_encoder_filter_.Add(encoder.get());
66 drivetrain_right_encoder_ = ::std::move(encoder);
Austin Schuh45a549f2019-02-02 15:43:56 -080067 drivetrain_right_encoder_->SetMaxPeriod(0.005);
Sabina Davisb6317b72019-02-01 22:53:23 -080068}
69
Austin Schuh3b010bc2019-02-24 17:25:37 -080070monotonic_clock::time_point SensorReader::GetPWMStartTime() {
71 int32_t status = 0;
Brian Silverman7be68ba2020-01-08 22:08:40 -080072 const auto new_fpga_time =
73 hal::fpga_clock::duration(HAL_GetPWMCycleStartTime(&status));
Sabina Davisadc58542019-02-01 22:23:00 -080074
Brian Silverman7be68ba2020-01-08 22:08:40 -080075 if (!ds_->IsSysActive()) {
Austin Schuh3b010bc2019-02-24 17:25:37 -080076 return monotonic_clock::min_time;
Sabina Davisadc58542019-02-01 22:23:00 -080077 }
Brian Silverman7be68ba2020-01-08 22:08:40 -080078
79 const auto fpga_offset = CalculateFpgaOffset();
80 // If we failed to sample the offset, just ignore this reading.
81 if (!fpga_offset) {
82 return monotonic_clock::min_time;
83 }
84
85 return monotonic_clock::epoch() + (new_fpga_time + *fpga_offset);
Sabina Davisadc58542019-02-01 22:23:00 -080086}
87
Maxwell Hendersond5ae85b2024-01-08 16:14:28 -080088void SensorReader::SendDrivetrainPosition(
Maxwell Hendersonf382b4b2024-01-14 12:31:41 -080089 aos::Sender<control_loops::drivetrain::PositionStatic>::StaticBuilder
90 builder,
Maxwell Hendersond5ae85b2024-01-08 16:14:28 -080091 std::function<double(double input)> velocity_translate,
92 std::function<double(double input)> encoder_to_meters, bool left_inverted,
93 bool right_inverted) {
Maxwell Hendersonf382b4b2024-01-14 12:31:41 -080094 builder->set_left_encoder(
Maxwell Hendersond5ae85b2024-01-08 16:14:28 -080095 (left_inverted ? -1.0 : 1.0) *
96 encoder_to_meters(drivetrain_left_encoder_->GetRaw()));
Maxwell Hendersonf382b4b2024-01-14 12:31:41 -080097 builder->set_left_speed(
Maxwell Hendersond5ae85b2024-01-08 16:14:28 -080098 (left_inverted ? -1.0 : 1.0) *
99 velocity_translate(drivetrain_left_encoder_->GetPeriod()));
100
Maxwell Hendersonf382b4b2024-01-14 12:31:41 -0800101 builder->set_right_encoder(
Maxwell Hendersond5ae85b2024-01-08 16:14:28 -0800102 (right_inverted ? -1.0 : 1.0) *
103 encoder_to_meters(drivetrain_right_encoder_->GetRaw()));
Maxwell Hendersonf382b4b2024-01-14 12:31:41 -0800104 builder->set_right_speed(
Maxwell Hendersond5ae85b2024-01-08 16:14:28 -0800105 (right_inverted ? -1.0 : 1.0) *
106 velocity_translate(drivetrain_right_encoder_->GetPeriod()));
107
Maxwell Hendersonf382b4b2024-01-14 12:31:41 -0800108 builder.CheckOk(builder.Send());
Maxwell Hendersond5ae85b2024-01-08 16:14:28 -0800109}
110
Austin Schuhbd1fe9c2019-06-29 16:35:48 -0700111void SensorReader::DoStart() {
Austin Schuh2c2cc2e2019-02-02 20:19:45 -0800112 Start();
Sabina Davis6292bec2019-02-06 22:53:14 -0800113 if (dma_synchronizer_) {
114 dma_synchronizer_->Start();
115 }
Austin Schuh2c2cc2e2019-02-02 20:19:45 -0800116
Austin Schuhbd1fe9c2019-06-29 16:35:48 -0700117 period_ =
Austin Schuh3b010bc2019-02-24 17:25:37 -0800118 pwm_trigger_ ? chrono::microseconds(5050) : chrono::microseconds(5000);
Austin Schuh45a549f2019-02-02 15:43:56 -0800119 if (pwm_trigger_) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700120 AOS_LOG(INFO, "Using PWM trigger and a 5.05 ms period\n");
Austin Schuh45a549f2019-02-02 15:43:56 -0800121 } else {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700122 AOS_LOG(INFO, "Defaulting to open loop pwm synchronization\n");
Austin Schuh45a549f2019-02-02 15:43:56 -0800123 }
Austin Schuhbd1fe9c2019-06-29 16:35:48 -0700124
Austin Schuh8ba6c5c2024-03-17 16:01:45 -0700125 if (pwm_trigger_) {
126 // Now that we are configured, actually fill in the defaults.
127 timer_handler_->Schedule(
128 event_loop_->monotonic_now() +
129 (pwm_trigger_ ? chrono::milliseconds(3) : chrono::milliseconds(4)),
130 period_);
131 } else {
132 // Synchronous CAN wakes up at round multiples of the clock. Use a phased
133 // loop to calculate it.
134 aos::time::PhasedLoop phased_loop(period_, monotonic_clock::now());
135 timer_handler_->Schedule(phased_loop.sleep_time(), period_);
136 }
Sabina Davis399dbd82019-02-01 23:06:08 -0800137
Austin Schuhbd1fe9c2019-06-29 16:35:48 -0700138 last_monotonic_now_ = monotonic_clock::now();
139}
Austin Schuh45a549f2019-02-02 15:43:56 -0800140
milind-u61227f22021-08-29 15:58:33 -0700141void SensorReader::Loop() {
Austin Schuhbd1fe9c2019-06-29 16:35:48 -0700142 const monotonic_clock::time_point monotonic_now =
143 event_loop_->monotonic_now();
144
145 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700146 auto builder = robot_state_sender_.MakeBuilder();
milind1f1dca32021-07-03 13:50:07 -0700147 (void)builder.Send(::frc971::wpilib::PopulateRobotState(&builder, my_pid_));
Austin Schuhbd1fe9c2019-06-29 16:35:48 -0700148 }
149 RunIteration();
150 if (dma_synchronizer_) {
151 dma_synchronizer_->RunIteration();
152 RunDmaIteration();
153 }
154
155 if (pwm_trigger_) {
James Kuszmaul1bce5772020-03-08 22:13:50 -0700156 // TODO(austin): Put this in a status message.
157 VLOG(1) << "PWM wakeup delta: "
158 << (monotonic_now - last_monotonic_now_).count();
Austin Schuhbd1fe9c2019-06-29 16:35:48 -0700159 last_monotonic_now_ = monotonic_now;
160
161 monotonic_clock::time_point last_tick_timepoint = GetPWMStartTime();
Philipp Schrader790cb542023-07-05 21:06:52 -0700162 VLOG(1) << "Start time " << last_tick_timepoint << " period "
163 << period_.count();
Austin Schuhbd1fe9c2019-06-29 16:35:48 -0700164 if (last_tick_timepoint == monotonic_clock::min_time) {
165 return;
Sabina Davis6292bec2019-02-06 22:53:14 -0800166 }
Sabina Davis399dbd82019-02-01 23:06:08 -0800167
Austin Schuhbd1fe9c2019-06-29 16:35:48 -0700168 last_tick_timepoint +=
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700169 ((monotonic_now -
170 chrono::microseconds(absl::GetFlag(FLAGS_pwm_offset)) -
Austin Schuh028d81d2022-03-26 15:11:42 -0700171 last_tick_timepoint) /
172 period_) *
Philipp Schrader790cb542023-07-05 21:06:52 -0700173 period_ +
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700174 chrono::microseconds(absl::GetFlag(FLAGS_pwm_offset));
Austin Schuh028d81d2022-03-26 15:11:42 -0700175 VLOG(1) << "Now " << monotonic_now << " tick " << last_tick_timepoint;
Austin Schuhbd1fe9c2019-06-29 16:35:48 -0700176 // If it's over 1/2 of a period back in time, that's wrong. Move it
177 // forwards to now.
178 if (last_tick_timepoint - monotonic_now < -period_ / 2) {
179 last_tick_timepoint += period_;
Sabina Davis399dbd82019-02-01 23:06:08 -0800180 }
Austin Schuhbd1fe9c2019-06-29 16:35:48 -0700181
182 // We should be sampling our sensors to kick off the control cycle 50 uS
183 // after the falling edge. This gives us a little bit of buffer for
184 // errors in waking up. The PWM cycle starts at the falling edge of the
185 // PWM pulse.
Philipp Schrader790cb542023-07-05 21:06:52 -0700186 const auto next_time = last_tick_timepoint + period_;
Austin Schuhbd1fe9c2019-06-29 16:35:48 -0700187
Philipp Schradera6712522023-07-05 20:25:11 -0700188 timer_handler_->Schedule(next_time, period_);
Sabina Davis399dbd82019-02-01 23:06:08 -0800189 }
Sabina Davis399dbd82019-02-01 23:06:08 -0800190}
191
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800192} // namespace frc971::wpilib