blob: f5372bf4d37af1c356fc0fd21e39921bd7e3423c [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 <inttypes.h>
4#include <unistd.h>
5
Sabina Davisadc58542019-02-01 22:23:00 -08006#include "aos/init.h"
7#include "aos/util/compiler_memory_barrier.h"
Sabina Davis399dbd82019-02-01 23:06:08 -08008#include "aos/util/phased_loop.h"
Sabina Davisadc58542019-02-01 22:23:00 -08009#include "frc971/wpilib/ahal/DigitalInput.h"
10#include "frc971/wpilib/ahal/Utility.h"
Austin Schuh45a549f2019-02-02 15:43:56 -080011#include "frc971/wpilib/wpilib_interface.h"
Sabina Davisadc58542019-02-01 22:23:00 -080012
13namespace frc971 {
14namespace wpilib {
15
Austin Schuh45a549f2019-02-02 15:43:56 -080016SensorReader::SensorReader() {
17 // Set some defaults. We don't tend to exceed these, so old robots should
18 // just work with them.
19 UpdateFastEncoderFilterHz(500000);
20 UpdateMediumEncoderFilterHz(100000);
21}
22
23void SensorReader::UpdateFastEncoderFilterHz(int hz) {
24 fast_encoder_filter_.SetPeriodHz(::std::max(hz, 100000));
25}
26
27void SensorReader::UpdateMediumEncoderFilterHz(int hz) {
28 medium_encoder_filter_.SetPeriodHz(::std::max(hz, 50000));
29}
Sabina Davisadc58542019-02-01 22:23:00 -080030
Sabina Davisb6317b72019-02-01 22:53:23 -080031void SensorReader::set_drivetrain_left_encoder(
32 ::std::unique_ptr<frc::Encoder> encoder) {
33 fast_encoder_filter_.Add(encoder.get());
34 drivetrain_left_encoder_ = ::std::move(encoder);
Austin Schuh45a549f2019-02-02 15:43:56 -080035 drivetrain_left_encoder_->SetMaxPeriod(0.005);
Sabina Davisb6317b72019-02-01 22:53:23 -080036}
37
38void SensorReader::set_drivetrain_right_encoder(
39 ::std::unique_ptr<frc::Encoder> encoder) {
40 fast_encoder_filter_.Add(encoder.get());
41 drivetrain_right_encoder_ = ::std::move(encoder);
Austin Schuh45a549f2019-02-02 15:43:56 -080042 drivetrain_right_encoder_->SetMaxPeriod(0.005);
Sabina Davisb6317b72019-02-01 22:53:23 -080043}
44
Sabina Davisadc58542019-02-01 22:23:00 -080045void SensorReader::set_pwm_trigger(
46 ::std::unique_ptr<frc::DigitalInput> pwm_trigger) {
Austin Schuh2c2cc2e2019-02-02 20:19:45 -080047 fast_encoder_filter_.Add(pwm_trigger.get());
Sabina Davisadc58542019-02-01 22:23:00 -080048 pwm_trigger_ = ::std::move(pwm_trigger);
49}
50
51void SensorReader::RunPWMDetecter() {
52 ::aos::SetCurrentThreadRealtimePriority(41);
53
54 pwm_trigger_->RequestInterrupts();
55 // Rising edge only.
56 pwm_trigger_->SetUpSourceEdge(true, false);
57
58 monotonic_clock::time_point last_posedge_monotonic =
59 monotonic_clock::min_time;
60
61 while (run_) {
62 auto ret = pwm_trigger_->WaitForInterrupt(1.0, true);
63 if (ret == frc::InterruptableSensorBase::WaitResult::kRisingEdge) {
64 // Grab all the clocks.
65 const double pwm_fpga_time = pwm_trigger_->ReadRisingTimestamp();
66
67 aos_compiler_memory_barrier();
68 const double fpga_time_before = frc::GetFPGATime() * 1e-6;
69 aos_compiler_memory_barrier();
70 const monotonic_clock::time_point monotonic_now = monotonic_clock::now();
71 aos_compiler_memory_barrier();
72 const double fpga_time_after = frc::GetFPGATime() * 1e-6;
73 aos_compiler_memory_barrier();
74
75 const double fpga_offset =
76 (fpga_time_after + fpga_time_before) / 2.0 - pwm_fpga_time;
77
78 // Compute when the edge was.
79 const monotonic_clock::time_point monotonic_edge =
80 monotonic_now - chrono::duration_cast<chrono::nanoseconds>(
81 chrono::duration<double>(fpga_offset));
82
83 LOG(DEBUG, "Got PWM pulse %f spread, %f offset, %lld trigger\n",
84 fpga_time_after - fpga_time_before, fpga_offset,
85 monotonic_edge.time_since_epoch().count());
86
87 // Compute bounds on the timestep and sampling times.
88 const double fpga_sample_length = fpga_time_after - fpga_time_before;
89 const chrono::nanoseconds elapsed_time =
90 monotonic_edge - last_posedge_monotonic;
91
92 last_posedge_monotonic = monotonic_edge;
93
94 // Verify that the values are sane.
95 if (fpga_sample_length > 2e-5 || fpga_sample_length < 0) {
96 continue;
97 }
98 if (fpga_offset < 0 || fpga_offset > 0.00015) {
99 continue;
100 }
101 if (elapsed_time > chrono::microseconds(5050) + chrono::microseconds(4) ||
102 elapsed_time < chrono::microseconds(5050) - chrono::microseconds(4)) {
103 continue;
104 }
105 // Good edge!
106 {
107 ::std::unique_lock<::aos::stl_mutex> locker(tick_time_mutex_);
108 last_tick_time_monotonic_timepoint_ = last_posedge_monotonic;
109 last_period_ = elapsed_time;
110 }
111 } else {
112 LOG(INFO, "PWM triggered %d\n", ret);
113 }
114 }
115 pwm_trigger_->CancelInterrupts();
116}
117
Sabina Davis399dbd82019-02-01 23:06:08 -0800118void SensorReader::operator()() {
119 ::aos::SetCurrentThreadName("SensorReader");
120
Austin Schuh45a549f2019-02-02 15:43:56 -0800121 int32_t my_pid = getpid();
Sabina Davis399dbd82019-02-01 23:06:08 -0800122
Austin Schuh2c2cc2e2019-02-02 20:19:45 -0800123 Start();
Sabina Davis6292bec2019-02-06 22:53:14 -0800124 if (dma_synchronizer_) {
125 dma_synchronizer_->Start();
126 }
Austin Schuh2c2cc2e2019-02-02 20:19:45 -0800127
Austin Schuh45a549f2019-02-02 15:43:56 -0800128 if (pwm_trigger_) {
129 last_period_ = chrono::microseconds(5050);
130 LOG(INFO, "Using PWM trigger and a 5.05 ms period\n");
131 } else {
132 LOG(INFO, "Defaulting to open loop pwm synchronization\n");
133 last_period_ = chrono::microseconds(5000);
134 }
135 ::aos::time::PhasedLoop phased_loop(
136 last_period_,
137 pwm_trigger_ ? ::std::chrono::milliseconds(3) : chrono::milliseconds(4));
Sabina Davis399dbd82019-02-01 23:06:08 -0800138
Austin Schuh45a549f2019-02-02 15:43:56 -0800139 ::std::thread pwm_detecter_thread;
140 if (pwm_trigger_) {
141 pwm_detecter_thread =
142 ::std::thread(::std::bind(&SensorReader::RunPWMDetecter, this));
143 }
Sabina Davis399dbd82019-02-01 23:06:08 -0800144
145 ::aos::SetCurrentThreadRealtimePriority(40);
146 while (run_) {
147 {
148 const int iterations = phased_loop.SleepUntilNext();
149 if (iterations != 1) {
150 LOG(WARNING, "SensorReader skipped %d iterations\n", iterations - 1);
151 }
152 }
Austin Schuh45a549f2019-02-02 15:43:56 -0800153
154 ::frc971::wpilib::SendRobotState(my_pid);
Sabina Davis399dbd82019-02-01 23:06:08 -0800155 RunIteration();
Sabina Davis6292bec2019-02-06 22:53:14 -0800156 if (dma_synchronizer_) {
157 dma_synchronizer_->RunIteration();
158 RunDmaIteration();
159 }
Sabina Davis399dbd82019-02-01 23:06:08 -0800160
Austin Schuh45a549f2019-02-02 15:43:56 -0800161 if (pwm_trigger_) {
162 monotonic_clock::time_point last_tick_timepoint;
163 chrono::nanoseconds period;
164 {
165 ::std::unique_lock<::aos::stl_mutex> locker(tick_time_mutex_);
166 last_tick_timepoint = last_tick_time_monotonic_timepoint_;
167 period = last_period_;
168 }
169
170 if (last_tick_timepoint == monotonic_clock::min_time) {
171 continue;
172 }
173 chrono::nanoseconds new_offset = phased_loop.OffsetFromIntervalAndTime(
174 period, last_tick_timepoint + chrono::microseconds(2050));
175
176 // TODO(austin): If this is the first edge in a while, skip to it (plus
177 // an offset). Otherwise, slowly drift time to line up.
178
179 phased_loop.set_interval_and_offset(period, new_offset);
Sabina Davis399dbd82019-02-01 23:06:08 -0800180 }
Sabina Davis399dbd82019-02-01 23:06:08 -0800181 }
Austin Schuh2c2cc2e2019-02-02 20:19:45 -0800182
Austin Schuh45a549f2019-02-02 15:43:56 -0800183 if (pwm_trigger_) {
184 pwm_detecter_thread.join();
185 }
Sabina Davis399dbd82019-02-01 23:06:08 -0800186}
187
Sabina Davisadc58542019-02-01 22:23:00 -0800188} // namespace wpilib
189} // namespace frc971