blob: 7ee85e1107a45fb8e10aa808d4a49bbb3d3fdf4d [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"
12#include "frc971/wpilib/ahal/DigitalSource.h"
13#include "frc971/wpilib/ahal/Encoder.h"
Brian Silvermanb5b46ca2016-03-13 01:14:17 -050014#include "frc971/wpilib/dma.h"
Parker Schuhd3b7a8872018-02-19 16:42:27 -080015#include "frc971/wpilib/dma_edge_counting.h"
Brian Silverman4da58072015-01-26 20:18:52 -050016
17namespace frc971 {
18namespace wpilib {
19
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
172// Class to hold a CTRE encoder with absolute angle pwm and potentiometer pair.
173class AbsoluteEncoderAndPotentiometer {
174 public:
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800175 void set_absolute_pwm(::std::unique_ptr<frc::DigitalInput> input) {
Austin Schuh2a3e0632018-02-19 16:24:49 -0800176 duty_cycle_.set_input(::std::move(input));
177 }
178
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800179 void set_encoder(::std::unique_ptr<frc::Encoder> encoder) {
Austin Schuh2a3e0632018-02-19 16:24:49 -0800180 encoder_ = ::std::move(encoder);
181 }
182
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800183 void set_potentiometer(::std::unique_ptr<frc::AnalogInput> potentiometer) {
Austin Schuh2a3e0632018-02-19 16:24:49 -0800184 potentiometer_ = ::std::move(potentiometer);
185 }
186
187 double ReadAbsoluteEncoder() const { return duty_cycle_.Read(); }
188 int32_t ReadRelativeEncoder() const { return encoder_->GetRaw(); }
189 double ReadPotentiometerVoltage() const {
190 return potentiometer_->GetVoltage();
191 }
192
193 private:
194 DutyCycleReader duty_cycle_;
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800195 ::std::unique_ptr<frc::Encoder> encoder_;
196 ::std::unique_ptr<frc::AnalogInput> potentiometer_;
Austin Schuh2a3e0632018-02-19 16:24:49 -0800197};
198
Ravago Jones937587c2020-12-26 17:21:09 -0800199// Class to hold two CTRE encoders, one with both index pulses and absolute
200// angle pwm, and another that can only turn once and only reports absolute
201// angle pwm.
202class AbsoluteAndAbsoluteEncoder {
203 public:
204 void set_single_turn_absolute_pwm(
205 ::std::unique_ptr<frc::DigitalInput> input) {
206 single_turn_duty_cycle_.set_input(::std::move(input));
207 }
208
209 void set_absolute_pwm(::std::unique_ptr<frc::DigitalInput> input) {
210 duty_cycle_.set_input(::std::move(input));
211 }
212
213 void set_encoder(::std::unique_ptr<frc::Encoder> encoder) {
214 encoder_ = ::std::move(encoder);
215 }
216
217 double ReadAbsoluteEncoder() const { return duty_cycle_.Read(); }
218 double ReadSingleTurnAbsoluteEncoder() const {
219 return single_turn_duty_cycle_.Read();
220 }
221 int32_t ReadRelativeEncoder() const { return encoder_->GetRaw(); }
222
223 private:
224 DutyCycleReader duty_cycle_;
225 DutyCycleReader single_turn_duty_cycle_;
226 ::std::unique_ptr<frc::Encoder> encoder_;
227};
228
Sabina Davis8d8ac0a2019-02-06 23:51:07 -0800229class AbsoluteEncoder {
230 public:
231 void set_absolute_pwm(::std::unique_ptr<frc::DigitalInput> input) {
232 duty_cycle_.set_input(::std::move(input));
233 }
234
235 void set_encoder(::std::unique_ptr<frc::Encoder> encoder) {
236 encoder_ = ::std::move(encoder);
237 }
238
239 double ReadAbsoluteEncoder() const { return duty_cycle_.Read(); }
240 int32_t ReadRelativeEncoder() const { return encoder_->GetRaw(); }
241
242 private:
243 DutyCycleReader duty_cycle_;
244 ::std::unique_ptr<frc::Encoder> encoder_;
245};
246
Brian Silverman4da58072015-01-26 20:18:52 -0500247} // namespace wpilib
248} // namespace frc971
249
250#endif // FRC971_ENCODER_AND_POTENTIOMETER_H_