blob: d8377d82dfd8d881155d92de755eb811031ab018 [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
Sabina Davisadc58542019-02-01 22:23:00 -08007#include "aos/init.h"
Austin Schuha0c41ba2020-09-10 22:59:14 -07008#include "aos/logging/logging.h"
Sabina Davisadc58542019-02-01 22:23:00 -08009#include "aos/util/compiler_memory_barrier.h"
Sabina Davis399dbd82019-02-01 23:06:08 -080010#include "aos/util/phased_loop.h"
Sabina Davisadc58542019-02-01 22:23:00 -080011#include "frc971/wpilib/ahal/DigitalInput.h"
Austin Schuh3b010bc2019-02-24 17:25:37 -080012#include "frc971/wpilib/ahal/DriverStation.h"
Sabina Davisadc58542019-02-01 22:23:00 -080013#include "frc971/wpilib/ahal/Utility.h"
Brian Silverman7be68ba2020-01-08 22:08:40 -080014#include "frc971/wpilib/fpga_time_conversion.h"
Austin Schuh45a549f2019-02-02 15:43:56 -080015#include "frc971/wpilib/wpilib_interface.h"
Austin Schuh3b010bc2019-02-24 17:25:37 -080016#include "hal/PWM.h"
Sabina Davisadc58542019-02-01 22:23:00 -080017
18namespace frc971 {
19namespace wpilib {
20
Austin Schuh217a9782019-12-21 23:02:50 -080021SensorReader::SensorReader(::aos::ShmEventLoop *event_loop)
Austin Schuhdf6cbb12019-02-02 13:46:52 -080022 : event_loop_(event_loop),
Austin Schuh217a9782019-12-21 23:02:50 -080023 robot_state_sender_(event_loop_->MakeSender<::aos::RobotState>("/aos")),
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070024 my_pid_(getpid()) {
Austin Schuh45a549f2019-02-02 15:43:56 -080025 // Set some defaults. We don't tend to exceed these, so old robots should
26 // just work with them.
27 UpdateFastEncoderFilterHz(500000);
28 UpdateMediumEncoderFilterHz(100000);
Austin Schuh3b010bc2019-02-24 17:25:37 -080029 ds_ = &::frc::DriverStation::GetInstance();
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070030
31 event_loop->SetRuntimeRealtimePriority(40);
32
33 // Fill in the no pwm trigger defaults.
34 phased_loop_handler_ =
35 event_loop_->AddPhasedLoop([this](int iterations) { Loop(iterations); },
36 period_, chrono::milliseconds(4));
37
38 event_loop->set_name("SensorReader");
39 event_loop->OnRun([this]() { DoStart(); });
Austin Schuh45a549f2019-02-02 15:43:56 -080040}
41
42void SensorReader::UpdateFastEncoderFilterHz(int hz) {
43 fast_encoder_filter_.SetPeriodHz(::std::max(hz, 100000));
44}
45
46void SensorReader::UpdateMediumEncoderFilterHz(int hz) {
47 medium_encoder_filter_.SetPeriodHz(::std::max(hz, 50000));
48}
Sabina Davisadc58542019-02-01 22:23:00 -080049
Sabina Davisb6317b72019-02-01 22:53:23 -080050void SensorReader::set_drivetrain_left_encoder(
51 ::std::unique_ptr<frc::Encoder> encoder) {
52 fast_encoder_filter_.Add(encoder.get());
53 drivetrain_left_encoder_ = ::std::move(encoder);
Austin Schuh45a549f2019-02-02 15:43:56 -080054 drivetrain_left_encoder_->SetMaxPeriod(0.005);
Sabina Davisb6317b72019-02-01 22:53:23 -080055}
56
57void SensorReader::set_drivetrain_right_encoder(
58 ::std::unique_ptr<frc::Encoder> encoder) {
59 fast_encoder_filter_.Add(encoder.get());
60 drivetrain_right_encoder_ = ::std::move(encoder);
Austin Schuh45a549f2019-02-02 15:43:56 -080061 drivetrain_right_encoder_->SetMaxPeriod(0.005);
Sabina Davisb6317b72019-02-01 22:53:23 -080062}
63
Austin Schuh3b010bc2019-02-24 17:25:37 -080064monotonic_clock::time_point SensorReader::GetPWMStartTime() {
65 int32_t status = 0;
Brian Silverman7be68ba2020-01-08 22:08:40 -080066 const auto new_fpga_time =
67 hal::fpga_clock::duration(HAL_GetPWMCycleStartTime(&status));
Sabina Davisadc58542019-02-01 22:23:00 -080068
Brian Silverman7be68ba2020-01-08 22:08:40 -080069 if (!ds_->IsSysActive()) {
Austin Schuh3b010bc2019-02-24 17:25:37 -080070 return monotonic_clock::min_time;
Sabina Davisadc58542019-02-01 22:23:00 -080071 }
Brian Silverman7be68ba2020-01-08 22:08:40 -080072
73 const auto fpga_offset = CalculateFpgaOffset();
74 // If we failed to sample the offset, just ignore this reading.
75 if (!fpga_offset) {
76 return monotonic_clock::min_time;
77 }
78
79 return monotonic_clock::epoch() + (new_fpga_time + *fpga_offset);
Sabina Davisadc58542019-02-01 22:23:00 -080080}
81
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070082void SensorReader::DoStart() {
Austin Schuh2c2cc2e2019-02-02 20:19:45 -080083 Start();
Sabina Davis6292bec2019-02-06 22:53:14 -080084 if (dma_synchronizer_) {
85 dma_synchronizer_->Start();
86 }
Austin Schuh2c2cc2e2019-02-02 20:19:45 -080087
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070088 period_ =
Austin Schuh3b010bc2019-02-24 17:25:37 -080089 pwm_trigger_ ? chrono::microseconds(5050) : chrono::microseconds(5000);
Austin Schuh45a549f2019-02-02 15:43:56 -080090 if (pwm_trigger_) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070091 AOS_LOG(INFO, "Using PWM trigger and a 5.05 ms period\n");
Austin Schuh45a549f2019-02-02 15:43:56 -080092 } else {
Austin Schuhf257f3c2019-10-27 21:00:43 -070093 AOS_LOG(INFO, "Defaulting to open loop pwm synchronization\n");
Austin Schuh45a549f2019-02-02 15:43:56 -080094 }
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070095
96 // Now that we are configured, actually fill in the defaults.
97 phased_loop_handler_->set_interval_and_offset(
98 period_,
Austin Schuh45a549f2019-02-02 15:43:56 -080099 pwm_trigger_ ? ::std::chrono::milliseconds(3) : chrono::milliseconds(4));
Sabina Davis399dbd82019-02-01 23:06:08 -0800100
Austin Schuhbd1fe9c2019-06-29 16:35:48 -0700101 last_monotonic_now_ = monotonic_clock::now();
102}
Austin Schuh45a549f2019-02-02 15:43:56 -0800103
Austin Schuhbd1fe9c2019-06-29 16:35:48 -0700104void SensorReader::Loop(const int iterations) {
105 if (iterations != 1) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700106 AOS_LOG(WARNING, "SensorReader skipped %d iterations\n", iterations - 1);
Austin Schuhbd1fe9c2019-06-29 16:35:48 -0700107 }
108
109 const monotonic_clock::time_point monotonic_now =
110 event_loop_->monotonic_now();
111
112 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700113 auto builder = robot_state_sender_.MakeBuilder();
114 builder.Send(::frc971::wpilib::PopulateRobotState(&builder, my_pid_));
Austin Schuhbd1fe9c2019-06-29 16:35:48 -0700115 }
116 RunIteration();
117 if (dma_synchronizer_) {
118 dma_synchronizer_->RunIteration();
119 RunDmaIteration();
120 }
121
122 if (pwm_trigger_) {
James Kuszmaul1bce5772020-03-08 22:13:50 -0700123 // TODO(austin): Put this in a status message.
124 VLOG(1) << "PWM wakeup delta: "
125 << (monotonic_now - last_monotonic_now_).count();
Austin Schuhbd1fe9c2019-06-29 16:35:48 -0700126 last_monotonic_now_ = monotonic_now;
127
128 monotonic_clock::time_point last_tick_timepoint = GetPWMStartTime();
129 if (last_tick_timepoint == monotonic_clock::min_time) {
130 return;
Sabina Davis6292bec2019-02-06 22:53:14 -0800131 }
Sabina Davis399dbd82019-02-01 23:06:08 -0800132
Austin Schuhbd1fe9c2019-06-29 16:35:48 -0700133 last_tick_timepoint +=
134 ((monotonic_now - last_tick_timepoint) / period_) * period_;
135 // If it's over 1/2 of a period back in time, that's wrong. Move it
136 // forwards to now.
137 if (last_tick_timepoint - monotonic_now < -period_ / 2) {
138 last_tick_timepoint += period_;
Sabina Davis399dbd82019-02-01 23:06:08 -0800139 }
Austin Schuhbd1fe9c2019-06-29 16:35:48 -0700140
141 // We should be sampling our sensors to kick off the control cycle 50 uS
142 // after the falling edge. This gives us a little bit of buffer for
143 // errors in waking up. The PWM cycle starts at the falling edge of the
144 // PWM pulse.
145 chrono::nanoseconds new_offset =
146 ::aos::time::PhasedLoop::OffsetFromIntervalAndTime(
147 period_, last_tick_timepoint + chrono::microseconds(50));
148
149 phased_loop_handler_->set_interval_and_offset(period_, new_offset);
Sabina Davis399dbd82019-02-01 23:06:08 -0800150 }
Sabina Davis399dbd82019-02-01 23:06:08 -0800151}
152
Sabina Davisadc58542019-02-01 22:23:00 -0800153} // namespace wpilib
154} // namespace frc971