blob: 84bfb6425a74645b54ea01249f171cd415da0eaa [file] [log] [blame]
Brian Silverman4da58072015-01-26 20:18:52 -05001#ifndef FRC971_ENCODER_AND_POTENTIOMETER_H_
2#define FRC971_ENCODER_AND_POTENTIOMETER_H_
3
4#include <atomic>
Parker Schuhd3b7a8872018-02-19 16:42:27 -08005#include <cmath>
Brian Silverman4da58072015-01-26 20:18:52 -05006#include <thread>
7
John Park33858a32018-09-28 23:05:48 -07008#include "aos/macros.h"
James Kuszmaul651fc3f2019-05-15 21:14:25 -07009#include "aos/time/time.h"
Parker Schuhd3b7a8872018-02-19 16:42:27 -080010#include "frc971/wpilib/ahal/AnalogInput.h"
11#include "frc971/wpilib/ahal/Counter.h"
Maxwell Henderson5e7b6e32024-02-20 15:30:33 -080012#include "frc971/wpilib/ahal/DigitalInput.h"
Parker Schuhd3b7a8872018-02-19 16:42:27 -080013#include "frc971/wpilib/ahal/DigitalSource.h"
14#include "frc971/wpilib/ahal/Encoder.h"
Brian Silvermanb5b46ca2016-03-13 01:14:17 -050015#include "frc971/wpilib/dma.h"
Parker Schuhd3b7a8872018-02-19 16:42:27 -080016#include "frc971/wpilib/dma_edge_counting.h"
Brian Silverman4da58072015-01-26 20:18:52 -050017
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -080018namespace frc971::wpilib {
Brian Silverman4da58072015-01-26 20:18:52 -050019
Brian Silverman7cce2d32017-02-19 21:48:48 -080020// Latches values from an encoder on positive edges from another input using
21// DMA.
22class DMAEncoder : public DMASampleHandlerInterface {
Brian Silverman4da58072015-01-26 20:18:52 -050023 public:
Brian Silverman7cce2d32017-02-19 21:48:48 -080024 DMAEncoder() {}
Brian Silverman4da58072015-01-26 20:18:52 -050025
Parker Schuhd3b7a8872018-02-19 16:42:27 -080026 void set_encoder(::std::unique_ptr<frc::Encoder> encoder) {
Brian Silverman4da58072015-01-26 20:18:52 -050027 encoder_ = ::std::move(encoder);
28 }
Parker Schuhd3b7a8872018-02-19 16:42:27 -080029 frc::Encoder *encoder() const { return encoder_.get(); }
Brian Silverman4da58072015-01-26 20:18:52 -050030
Parker Schuhd3b7a8872018-02-19 16:42:27 -080031 void set_index(::std::unique_ptr<frc::DigitalSource> index) {
Brian Silverman4da58072015-01-26 20:18:52 -050032 index_ = ::std::move(index);
33 }
Parker Schuhd3b7a8872018-02-19 16:42:27 -080034 frc::DigitalSource *index() const { return index_.get(); }
Brian Silverman4da58072015-01-26 20:18:52 -050035
Brian Silverman4da58072015-01-26 20:18:52 -050036 // Returns the most recent polled value of the encoder.
37 uint32_t polled_encoder_value() const { return polled_encoder_value_; }
Brian Silverman4da58072015-01-26 20:18:52 -050038
39 // Returns the number of poseges that have happened on the index input.
40 uint32_t index_posedge_count() const { return index_posedge_count_; }
41 // Returns the value of the encoder at the last index posedge.
42 int32_t last_encoder_value() const { return last_encoder_value_; }
Brian Silverman7cce2d32017-02-19 21:48:48 -080043
44 void UpdateFromSample(const DMASample &sample) override {
45 DoUpdateFromSample(sample);
Brian Silverman4da58072015-01-26 20:18:52 -050046 }
47
Brian Silverman7cce2d32017-02-19 21:48:48 -080048 void PollFromSample(const DMASample &sample) override {
Brian Silverman4da58072015-01-26 20:18:52 -050049 polled_encoder_value_ = sample.GetRaw(encoder_.get());
Brian Silverman4da58072015-01-26 20:18:52 -050050 }
51
Brian Silverman7cce2d32017-02-19 21:48:48 -080052 void UpdatePolledValue() override {
Brian Silverman4da58072015-01-26 20:18:52 -050053 polled_encoder_value_ = encoder_->GetRaw();
Brian Silverman4da58072015-01-26 20:18:52 -050054 }
55
Brian Silverman7cce2d32017-02-19 21:48:48 -080056 void AddToDMA(DMA *dma) override {
Brian Silverman4da58072015-01-26 20:18:52 -050057 dma->Add(encoder_.get());
58 dma->Add(index_.get());
Austin Schuhc6cc4102015-02-15 23:19:53 -080059 dma->SetExternalTrigger(index_.get(), true, true);
Brian Silverman4da58072015-01-26 20:18:52 -050060 }
61
Brian Silverman7cce2d32017-02-19 21:48:48 -080062 protected:
63 // The same as UpdateFromSample except also returns true if this sample is a
64 // new edge on the index.
65 bool DoUpdateFromSample(const DMASample &sample);
66
Brian Silverman4da58072015-01-26 20:18:52 -050067 private:
Parker Schuhd3b7a8872018-02-19 16:42:27 -080068 ::std::unique_ptr<frc::Encoder> encoder_;
69 ::std::unique_ptr<frc::DigitalSource> index_;
Brian Silverman4da58072015-01-26 20:18:52 -050070
71 int32_t polled_encoder_value_ = 0;
Brian Silverman4da58072015-01-26 20:18:52 -050072
73 int32_t last_encoder_value_ = 0;
Brian Silverman4da58072015-01-26 20:18:52 -050074
75 uint32_t index_posedge_count_ = 0;
76
77 // Whether or not it was triggered in the last sample.
78 bool index_last_value_ = false;
79
Brian Silverman7cce2d32017-02-19 21:48:48 -080080 DISALLOW_COPY_AND_ASSIGN(DMAEncoder);
81};
82
83// Latches values from an encoder and potentiometer on positive edges from
84// another input using DMA.
85class DMAEncoderAndPotentiometer : public DMAEncoder {
86 public:
87 DMAEncoderAndPotentiometer() {}
88
Parker Schuhd3b7a8872018-02-19 16:42:27 -080089 void set_potentiometer(::std::unique_ptr<frc::AnalogInput> potentiometer) {
Brian Silverman7cce2d32017-02-19 21:48:48 -080090 potentiometer_ = ::std::move(potentiometer);
91 }
Parker Schuhd3b7a8872018-02-19 16:42:27 -080092 frc::AnalogInput *potentiometer() const { return potentiometer_.get(); }
Brian Silverman7cce2d32017-02-19 21:48:48 -080093
94 // Returns the most recent polled voltage of the potentiometer.
95 float polled_potentiometer_voltage() const {
96 return polled_potentiometer_voltage_;
97 }
98
99 // Returns the voltage of the potentiometer at the last index posedge.
100 float last_potentiometer_voltage() const {
101 return last_potentiometer_voltage_;
102 }
103
104 void UpdateFromSample(const DMASample &sample) override {
105 if (DMAEncoder::DoUpdateFromSample(sample)) {
106 last_potentiometer_voltage_ = sample.GetVoltage(potentiometer_.get());
107 }
108 }
109
110 void PollFromSample(const DMASample &sample) override {
111 polled_potentiometer_voltage_ = sample.GetVoltage(potentiometer_.get());
112 DMAEncoder::PollFromSample(sample);
113 }
114
115 void UpdatePolledValue() override {
116 polled_potentiometer_voltage_ = potentiometer_->GetVoltage();
117 DMAEncoder::UpdatePolledValue();
118 }
119
120 void AddToDMA(DMA *dma) override {
121 dma->Add(potentiometer_.get());
122 DMAEncoder::AddToDMA(dma);
123 }
124
125 private:
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800126 ::std::unique_ptr<frc::AnalogInput> potentiometer_;
Brian Silverman7cce2d32017-02-19 21:48:48 -0800127
128 float polled_potentiometer_voltage_ = 0.0f;
129
130 float last_potentiometer_voltage_ = 0.0f;
131
Brian Silverman4da58072015-01-26 20:18:52 -0500132 DISALLOW_COPY_AND_ASSIGN(DMAEncoderAndPotentiometer);
133};
134
Austin Schuh2a3e0632018-02-19 16:24:49 -0800135// Class to read duty cycle of an input. This is tuned for the CTRE encoder's
136// absolute position output.
137class DutyCycleReader {
138 public:
139 // Configure the reader to use the provided digital input.
140 void set_input(::std::unique_ptr<::frc::DigitalInput> input) {
141 high_counter_.reset(new ::frc::Counter(input.get()));
142 high_counter_->SetMaxPeriod(kMaxPeriod);
143 high_counter_->SetSemiPeriodMode(true);
144
145 period_length_counter_.reset(new ::frc::Counter(input.get()));
146 period_length_counter_->SetMaxPeriod(kMaxPeriod);
147 period_length_counter_->SetUpSourceEdge(true, false);
148
149 input_ = ::std::move(input);
150 }
151
152 // Returns the last duty cycle or nan if the signal is stale.
153 double Read() const {
154 const double high_time = high_counter_->GetPeriod();
155 const double period_length = period_length_counter_->GetPeriod();
156 if (!::std::isfinite(high_time) || !::std::isfinite(period_length)) {
157 return ::std::numeric_limits<double>::quiet_NaN();
158 }
159 return high_time / period_length;
160 }
161
162 private:
163 static constexpr ::std::chrono::nanoseconds kNominalPeriod =
164 ::std::chrono::microseconds(4096);
165 static constexpr double kMaxPeriod =
James Kuszmaul651fc3f2019-05-15 21:14:25 -0700166 ::aos::time::DurationInSeconds(kNominalPeriod * 2);
Austin Schuh2a3e0632018-02-19 16:24:49 -0800167
168 ::std::unique_ptr<::frc::Counter> high_counter_, period_length_counter_;
169 ::std::unique_ptr<::frc::DigitalInput> input_;
170};
171
Maxwell Henderson5e7b6e32024-02-20 15:30:33 -0800172class DMAAbsoluteEncoderAndPotentiometer {
173 public:
174 void set_absolute_pwm(::std::unique_ptr<frc::DigitalInput> input) {
175 duty_cycle_input_ = ::std::move(input);
176 duty_cycle_reader_.set_input(duty_cycle_input_.get());
177 }
178
179 void set_encoder(::std::unique_ptr<frc::Encoder> encoder) {
180 encoder_ = ::std::move(encoder);
181 }
182
183 void set_potentiometer(::std::unique_ptr<frc::AnalogInput> potentiometer) {
184 potentiometer_ = ::std::move(potentiometer);
185 }
186
187 double ReadAbsoluteEncoder() const {
188 return duty_cycle_reader_.last_width() / duty_cycle_reader_.last_period();
189 }
190 int32_t ReadRelativeEncoder() const { return encoder_->GetRaw(); }
191 double ReadPotentiometerVoltage() const {
192 return potentiometer_->GetVoltage();
193 }
194
195 DMAPulseWidthReader &reader() { return duty_cycle_reader_; }
196
197 private:
198 DMAPulseWidthReader duty_cycle_reader_;
199 ::std::unique_ptr<::frc::DigitalInput> duty_cycle_input_;
200 ::std::unique_ptr<frc::Encoder> encoder_;
201 ::std::unique_ptr<frc::AnalogInput> potentiometer_;
202};
203
Austin Schuh2a3e0632018-02-19 16:24:49 -0800204// Class to hold a CTRE encoder with absolute angle pwm and potentiometer pair.
205class AbsoluteEncoderAndPotentiometer {
206 public:
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800207 void set_absolute_pwm(::std::unique_ptr<frc::DigitalInput> input) {
Austin Schuh2a3e0632018-02-19 16:24:49 -0800208 duty_cycle_.set_input(::std::move(input));
209 }
210
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800211 void set_encoder(::std::unique_ptr<frc::Encoder> encoder) {
Austin Schuh2a3e0632018-02-19 16:24:49 -0800212 encoder_ = ::std::move(encoder);
213 }
214
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800215 void set_potentiometer(::std::unique_ptr<frc::AnalogInput> potentiometer) {
Austin Schuh2a3e0632018-02-19 16:24:49 -0800216 potentiometer_ = ::std::move(potentiometer);
217 }
218
219 double ReadAbsoluteEncoder() const { return duty_cycle_.Read(); }
220 int32_t ReadRelativeEncoder() const { return encoder_->GetRaw(); }
221 double ReadPotentiometerVoltage() const {
222 return potentiometer_->GetVoltage();
223 }
224
225 private:
226 DutyCycleReader duty_cycle_;
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800227 ::std::unique_ptr<frc::Encoder> encoder_;
228 ::std::unique_ptr<frc::AnalogInput> potentiometer_;
Austin Schuh2a3e0632018-02-19 16:24:49 -0800229};
230
Ravago Jones937587c2020-12-26 17:21:09 -0800231// Class to hold two CTRE encoders, one with both index pulses and absolute
232// angle pwm, and another that can only turn once and only reports absolute
233// angle pwm.
234class AbsoluteAndAbsoluteEncoder {
235 public:
236 void set_single_turn_absolute_pwm(
237 ::std::unique_ptr<frc::DigitalInput> input) {
238 single_turn_duty_cycle_.set_input(::std::move(input));
239 }
240
241 void set_absolute_pwm(::std::unique_ptr<frc::DigitalInput> input) {
242 duty_cycle_.set_input(::std::move(input));
243 }
244
245 void set_encoder(::std::unique_ptr<frc::Encoder> encoder) {
246 encoder_ = ::std::move(encoder);
247 }
248
249 double ReadAbsoluteEncoder() const { return duty_cycle_.Read(); }
250 double ReadSingleTurnAbsoluteEncoder() const {
251 return single_turn_duty_cycle_.Read();
252 }
253 int32_t ReadRelativeEncoder() const { return encoder_->GetRaw(); }
254
255 private:
256 DutyCycleReader duty_cycle_;
257 DutyCycleReader single_turn_duty_cycle_;
258 ::std::unique_ptr<frc::Encoder> encoder_;
259};
260
Sabina Davis8d8ac0a2019-02-06 23:51:07 -0800261class AbsoluteEncoder {
262 public:
263 void set_absolute_pwm(::std::unique_ptr<frc::DigitalInput> input) {
264 duty_cycle_.set_input(::std::move(input));
265 }
266
267 void set_encoder(::std::unique_ptr<frc::Encoder> encoder) {
268 encoder_ = ::std::move(encoder);
269 }
270
271 double ReadAbsoluteEncoder() const { return duty_cycle_.Read(); }
272 int32_t ReadRelativeEncoder() const { return encoder_->GetRaw(); }
273
274 private:
275 DutyCycleReader duty_cycle_;
276 ::std::unique_ptr<frc::Encoder> encoder_;
277};
278
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -0800279} // namespace frc971::wpilib
Brian Silverman4da58072015-01-26 20:18:52 -0500280
281#endif // FRC971_ENCODER_AND_POTENTIOMETER_H_