blob: 790868e5cef6946926171320121a6da6814196ad [file] [log] [blame]
Brian Silverman26e4e522015-12-17 01:56:40 -05001/*----------------------------------------------------------------------------*/
2/* Copyright (c) FIRST 2008. All Rights Reserved. */
3/* Open Source Software - may be modified and shared by FRC teams. The code */
4/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
5/*----------------------------------------------------------------------------*/
6
7#include "Encoder.h"
8#include "Resource.h"
9#include "WPIErrors.h"
10#include "LiveWindow/LiveWindow.h"
11
12/**
13 * Common initialization code for Encoders.
14 * This code allocates resources for Encoders and is common to all constructors.
15 *
16 * The counter will start counting immediately.
17 *
18 * @param reverseDirection If true, counts down instead of up (this is all relative)
19 * @param encodingType either k1X, k2X, or k4X to indicate 1X, 2X or 4X decoding. If 4X is
20 * selected, then an encoder FPGA object is used and the returned counts will be 4x the encoder
21 * spec'd value since all rising and falling edges are counted. If 1X or 2X are selected then
22 * a counter object will be used and the returned value will either exactly match the spec'd count
23 * or be double (2x) the spec'd count.
24 */
25void Encoder::InitEncoder(int channelA, int channelB, bool reverseDirection, EncodingType encodingType)
26{
27 m_table = nullptr;
28 this->channelA = channelA;
29 this->channelB = channelB;
30 m_encodingType = encodingType;
31 m_encodingScale = encodingType == k4X ? 4
32 : encodingType == k2X ? 2
33 : 1;
34
35 int32_t index = 0;
36 m_distancePerPulse = 1.0;
37
38 LiveWindow::GetInstance()->AddSensor("Encoder", channelA, this);
39
40 if (channelB < channelA) { // Swap ports
41 int channel = channelB;
42 channelB = channelA;
43 channelA = channel;
44 m_reverseDirection = !reverseDirection;
45 } else {
46 m_reverseDirection = reverseDirection;
47 }
48 char buffer[50];
49 int n = sprintf(buffer, "dio/%d/%d", channelA, channelB);
50 impl = new SimEncoder(buffer);
51 impl->Start();
52}
53
54/**
55 * Encoder constructor.
56 * Construct a Encoder given a and b channels.
57 *
58 * The counter will start counting immediately.
59 *
60 * @param aChannel The a channel digital input channel.
61 * @param bChannel The b channel digital input channel.
62 * @param reverseDirection represents the orientation of the encoder and inverts the output values
63 * if necessary so forward represents positive values.
64 * @param encodingType either k1X, k2X, or k4X to indicate 1X, 2X or 4X decoding. If 4X is
65 * selected, then an encoder FPGA object is used and the returned counts will be 4x the encoder
66 * spec'd value since all rising and falling edges are counted. If 1X or 2X are selected then
67 * a counter object will be used and the returned value will either exactly match the spec'd count
68 * or be double (2x) the spec'd count.
69 */
70Encoder::Encoder(uint32_t aChannel, uint32_t bChannel, bool reverseDirection, EncodingType encodingType)
71{
72 InitEncoder(aChannel, bChannel, reverseDirection, encodingType);
73}
74
75/**
76 * Encoder constructor.
77 * Construct a Encoder given a and b channels as digital inputs. This is used in the case
78 * where the digital inputs are shared. The Encoder class will not allocate the digital inputs
79 * and assume that they already are counted.
80 *
81 * The counter will start counting immediately.
82 *
83 * @param aSource The source that should be used for the a channel.
84 * @param bSource the source that should be used for the b channel.
85 * @param reverseDirection represents the orientation of the encoder and inverts the output values
86 * if necessary so forward represents positive values.
87 * @param encodingType either k1X, k2X, or k4X to indicate 1X, 2X or 4X decoding. If 4X is
88 * selected, then an encoder FPGA object is used and the returned counts will be 4x the encoder
89 * spec'd value since all rising and falling edges are counted. If 1X or 2X are selected then
90 * a counter object will be used and the returned value will either exactly match the spec'd count
91 * or be double (2x) the spec'd count.
92 */
93/* TODO: [Not Supported] Encoder::Encoder(DigitalSource *aSource, DigitalSource *bSource, bool reverseDirection, EncodingType encodingType) :
94 m_encoder(nullptr),
95 m_counter(nullptr)
96{
97 m_aSource = aSource;
98 m_bSource = bSource;
99 m_allocatedASource = false;
100 m_allocatedBSource = false;
101 if (m_aSource == nullptr || m_bSource == nullptr)
102 wpi_setWPIError(NullParameter);
103 else
104 InitEncoder(reverseDirection, encodingType);
105 }*/
106
107/**
108 * Encoder constructor.
109 * Construct a Encoder given a and b channels as digital inputs. This is used in the case
110 * where the digital inputs are shared. The Encoder class will not allocate the digital inputs
111 * and assume that they already are counted.
112 *
113 * The counter will start counting immediately.
114 *
115 * @param aSource The source that should be used for the a channel.
116 * @param bSource the source that should be used for the b channel.
117 * @param reverseDirection represents the orientation of the encoder and inverts the output values
118 * if necessary so forward represents positive values.
119 * @param encodingType either k1X, k2X, or k4X to indicate 1X, 2X or 4X decoding. If 4X is
120 * selected, then an encoder FPGA object is used and the returned counts will be 4x the encoder
121 * spec'd value since all rising and falling edges are counted. If 1X or 2X are selected then
122 * a counter object will be used and the returned value will either exactly match the spec'd count
123 * or be double (2x) the spec'd count.
124 */
125/*// TODO: [Not Supported] Encoder::Encoder(DigitalSource &aSource, DigitalSource &bSource, bool reverseDirection, EncodingType encodingType) :
126 m_encoder(nullptr),
127 m_counter(nullptr)
128{
129 m_aSource = &aSource;
130 m_bSource = &bSource;
131 m_allocatedASource = false;
132 m_allocatedBSource = false;
133 InitEncoder(reverseDirection, encodingType);
134 }*/
135
136/**
137 * Reset the Encoder distance to zero.
138 * Resets the current count to zero on the encoder.
139 */
140void Encoder::Reset()
141{
142 impl->Reset();
143}
144
145/**
146 * Determine if the encoder is stopped.
147 * Using the MaxPeriod value, a boolean is returned that is true if the encoder is considered
148 * stopped and false if it is still moving. A stopped encoder is one where the most recent pulse
149 * width exceeds the MaxPeriod.
150 * @return True if the encoder is considered stopped.
151 */
152bool Encoder::GetStopped() const
153{
154 throw "Simulation doesn't currently support this method.";
155}
156
157/**
158 * The last direction the encoder value changed.
159 * @return The last direction the encoder value changed.
160 */
161bool Encoder::GetDirection() const
162{
163 throw "Simulation doesn't currently support this method.";
164}
165
166/**
167 * The scale needed to convert a raw counter value into a number of encoder pulses.
168 */
169double Encoder::DecodingScaleFactor() const
170{
171 switch (m_encodingType)
172 {
173 case k1X:
174 return 1.0;
175 case k2X:
176 return 0.5;
177 case k4X:
178 return 0.25;
179 default:
180 return 0.0;
181 }
182}
183
184/**
185 * The encoding scale factor 1x, 2x, or 4x, per the requested encodingType.
186 * Used to divide raw edge counts down to spec'd counts.
187 */
188int32_t Encoder::GetEncodingScale() const { return m_encodingScale; }
189
190/**
191 * Gets the raw value from the encoder.
192 * The raw value is the actual count unscaled by the 1x, 2x, or 4x scale
193 * factor.
194 * @return Current raw count from the encoder
195 */
196int32_t Encoder::GetRaw() const
197{
198 throw "Simulation doesn't currently support this method.";
199}
200
201/**
202 * Gets the current count.
203 * Returns the current count on the Encoder.
204 * This method compensates for the decoding type.
205 *
206 * @return Current count from the Encoder adjusted for the 1x, 2x, or 4x scale factor.
207 */
208int32_t Encoder::Get() const
209{
210 throw "Simulation doesn't currently support this method.";
211}
212
213/**
214 * Returns the period of the most recent pulse.
215 * Returns the period of the most recent Encoder pulse in seconds.
216 * This method compenstates for the decoding type.
217 *
218 * @deprecated Use GetRate() in favor of this method. This returns unscaled periods and GetRate() scales using value from SetDistancePerPulse().
219 *
220 * @return Period in seconds of the most recent pulse.
221 */
222double Encoder::GetPeriod() const
223{
224 throw "Simulation doesn't currently support this method.";
225}
226
227/**
228 * Sets the maximum period for stopped detection.
229 * Sets the value that represents the maximum period of the Encoder before it will assume
230 * that the attached device is stopped. This timeout allows users to determine if the wheels or
231 * other shaft has stopped rotating.
232 * This method compensates for the decoding type.
233 *
234 * @deprecated Use SetMinRate() in favor of this method. This takes unscaled periods and SetMinRate() scales using value from SetDistancePerPulse().
235 *
236 * @param maxPeriod The maximum time between rising and falling edges before the FPGA will
237 * report the device stopped. This is expressed in seconds.
238 */
239void Encoder::SetMaxPeriod(double maxPeriod)
240{
241 throw "Simulation doesn't currently support this method.";
242}
243
244/**
245 * Get the distance the robot has driven since the last reset.
246 *
247 * @return The distance driven since the last reset as scaled by the value from SetDistancePerPulse().
248 */
249double Encoder::GetDistance() const
250{
251 return m_distancePerPulse * impl->GetPosition();
252}
253
254/**
255 * Get the current rate of the encoder.
256 * Units are distance per second as scaled by the value from SetDistancePerPulse().
257 *
258 * @return The current rate of the encoder.
259 */
260double Encoder::GetRate() const
261{
262 return m_distancePerPulse * impl->GetVelocity();
263}
264
265/**
266 * Set the minimum rate of the device before the hardware reports it stopped.
267 *
268 * @param minRate The minimum rate. The units are in distance per second as scaled by the value from SetDistancePerPulse().
269 */
270void Encoder::SetMinRate(double minRate)
271{
272 throw "Simulation doesn't currently support this method.";
273}
274
275/**
276 * Set the distance per pulse for this encoder.
277 * This sets the multiplier used to determine the distance driven based on the count value
278 * from the encoder.
279 * Do not include the decoding type in this scale. The library already compensates for the decoding type.
280 * Set this value based on the encoder's rated Pulses per Revolution and
281 * factor in gearing reductions following the encoder shaft.
282 * This distance can be in any units you like, linear or angular.
283 *
284 * @param distancePerPulse The scale factor that will be used to convert pulses to useful units.
285 */
286void Encoder::SetDistancePerPulse(double distancePerPulse)
287{
288 if (m_reverseDirection) {
289 m_distancePerPulse = -distancePerPulse;
290 } else {
291 m_distancePerPulse = distancePerPulse;
292 }
293}
294
295/**
296 * Set the direction sensing for this encoder.
297 * This sets the direction sensing on the encoder so that it could count in the correct
298 * software direction regardless of the mounting.
299 * @param reverseDirection true if the encoder direction should be reversed
300 */
301void Encoder::SetReverseDirection(bool reverseDirection)
302{
303 throw "Simulation doesn't currently support this method.";
304}
305
306/**
307 * Set which parameter of the encoder you are using as a process control variable.
308 *
309 * @param pidSource An enum to select the parameter.
310 */
311void Encoder::SetPIDSourceType(PIDSourceType pidSource)
312{
313 m_pidSource = pidSource;
314}
315
316/**
317 * Implement the PIDSource interface.
318 *
319 * @return The current value of the selected source parameter.
320 */
321double Encoder::PIDGet()
322{
323 switch (m_pidSource)
324 {
325 case PIDSourceType::kDisplacement:
326 return GetDistance();
327 case PIDSourceType::kRate:
328 return GetRate();
329 default:
330 return 0.0;
331 }
332}
333
334void Encoder::UpdateTable() {
335 if (m_table != nullptr) {
336 m_table->PutNumber("Speed", GetRate());
337 m_table->PutNumber("Distance", GetDistance());
338 m_table->PutNumber("Distance per Tick", m_reverseDirection ? -m_distancePerPulse : m_distancePerPulse);
339 }
340}
341
342void Encoder::StartLiveWindowMode() {
343
344}
345
346void Encoder::StopLiveWindowMode() {
347
348}
349
350std::string Encoder::GetSmartDashboardType() const {
351 if (m_encodingType == k4X)
352 return "Quadrature Encoder";
353 else
354 return "Encoder";
355}
356
357void Encoder::InitTable(std::shared_ptr<ITable> subTable) {
358 m_table = subTable;
359 UpdateTable();
360}
361
362std::shared_ptr<ITable> Encoder::GetTable() const {
363 return m_table;
364}