001/*----------------------------------------------------------------------------*/
002/* Copyright (c) FIRST 2008-2017. All Rights Reserved.                        */
003/* Open Source Software - may be modified and shared by FRC teams. The code   */
004/* must be accompanied by the FIRST BSD license file in the root directory of */
005/* the project.                                                               */
006/*----------------------------------------------------------------------------*/
007
008package edu.wpi.first.wpilibj;
009
010import edu.wpi.first.wpilibj.hal.EncoderJNI;
011import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
012import edu.wpi.first.wpilibj.hal.HAL;
013import edu.wpi.first.wpilibj.livewindow.LiveWindow;
014import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
015import edu.wpi.first.wpilibj.tables.ITable;
016import edu.wpi.first.wpilibj.util.AllocationException;
017
018/**
019 * Class to read quadrature encoders. Quadrature encoders are devices that count shaft rotation and
020 * can sense direction. The output of the Encoder class is an integer that can count either up or
021 * down, and can go negative for reverse direction counting. When creating Encoders, a direction
022 * can be supplied that inverts the sense of the output to make code more readable if the encoder is
023 * mounted such that forward movement generates negative values. Quadrature encoders have two
024 * digital outputs, an A Channel and a B Channel, that are out of phase with each other for
025 * direction sensing.
026 *
027 * <p>All encoders will immediately start counting - reset() them if you need them to be zeroed
028 * before use.
029 */
030public class Encoder extends SensorBase implements CounterBase, PIDSource, LiveWindowSendable {
031
032  public enum IndexingType {
033    kResetWhileHigh(0), kResetWhileLow(1), kResetOnFallingEdge(2), kResetOnRisingEdge(3);
034
035    @SuppressWarnings("MemberName")
036    public final int value;
037
038    IndexingType(int value) {
039      this.value = value;
040    }
041  }
042
043  /**
044   * The a source.
045   */
046  @SuppressWarnings("MemberName")
047  protected DigitalSource m_aSource; // the A phase of the quad encoder
048  /**
049   * The b source.
050   */
051  @SuppressWarnings("MemberName")
052  protected DigitalSource m_bSource; // the B phase of the quad encoder
053  /**
054   * The index source.
055   */
056  protected DigitalSource m_indexSource = null; // Index on some encoders
057  private boolean m_allocatedA;
058  private boolean m_allocatedB;
059  private boolean m_allocatedI;
060  private PIDSourceType m_pidSource;
061
062  private int m_encoder; // the HAL encoder object
063
064
065  /**
066   * Common initialization code for Encoders. This code allocates resources for Encoders and is
067   * common to all constructors.
068   *
069   * <p>The encoder will start counting immediately.
070   *
071   * @param reverseDirection If true, counts down instead of up (this is all relative)
072   */
073  private void initEncoder(boolean reverseDirection, final EncodingType type) {
074    m_encoder = EncoderJNI.initializeEncoder(m_aSource.getPortHandleForRouting(),
075        m_aSource.getAnalogTriggerTypeForRouting(), m_bSource.getPortHandleForRouting(),
076        m_bSource.getAnalogTriggerTypeForRouting(), reverseDirection, type.value);
077
078    m_pidSource = PIDSourceType.kDisplacement;
079
080    HAL.report(tResourceType.kResourceType_Encoder, getFPGAIndex(), type.value);
081    LiveWindow.addSensor("Encoder", m_aSource.getChannel(), this);
082  }
083
084  /**
085   * Encoder constructor. Construct a Encoder given a and b channels.
086   *
087   * <p>The encoder will start counting immediately.
088   *
089   * @param channelA         The a channel DIO channel. 0-9 are on-board, 10-25 are on the MXP port
090   * @param channelB         The b channel DIO channel. 0-9 are on-board, 10-25 are on the MXP port
091   * @param reverseDirection represents the orientation of the encoder and inverts the output values
092   *                         if necessary so forward represents positive values.
093   */
094  public Encoder(final int channelA, final int channelB, boolean reverseDirection) {
095    m_allocatedA = true;
096    m_allocatedB = true;
097    m_allocatedI = false;
098    m_aSource = new DigitalInput(channelA);
099    m_bSource = new DigitalInput(channelB);
100    initEncoder(reverseDirection, EncodingType.k4X);
101  }
102
103  /**
104   * Encoder constructor. Construct a Encoder given a and b channels.
105   *
106   * <p>The encoder will start counting immediately.
107   *
108   * @param channelA The a channel digital input channel.
109   * @param channelB The b channel digital input channel.
110   */
111  public Encoder(final int channelA, final int channelB) {
112    this(channelA, channelB, false);
113  }
114
115  /**
116   * Encoder constructor. Construct a Encoder given a and b channels.
117   *
118   * <p>The encoder will start counting immediately.
119   *
120   * @param channelA         The a channel digital input channel.
121   * @param channelB         The b channel digital input channel.
122   * @param reverseDirection represents the orientation of the encoder and inverts the output values
123   *                         if necessary so forward represents positive values.
124   * @param encodingType     either k1X, k2X, or k4X to indicate 1X, 2X or 4X decoding. If 4X is
125   *                         selected, then an encoder FPGA object is used and the returned counts
126   *                         will be 4x the encoder spec'd value since all rising and falling edges
127   *                         are counted. If 1X or 2X are selected then a m_counter object will be
128   *                         used and the returned value will either exactly match the spec'd count
129   *                         or be double (2x) the spec'd count.
130   */
131  public Encoder(final int channelA, final int channelB, boolean reverseDirection,
132                 final EncodingType encodingType) {
133    m_allocatedA = true;
134    m_allocatedB = true;
135    m_allocatedI = false;
136    if (encodingType == null) {
137      throw new NullPointerException("Given encoding type was null");
138    }
139    m_aSource = new DigitalInput(channelA);
140    m_bSource = new DigitalInput(channelB);
141    initEncoder(reverseDirection, encodingType);
142  }
143
144  /**
145   * Encoder constructor. Construct a Encoder given a and b channels. Using an index pulse forces 4x
146   * encoding
147   *
148   * <p>The encoder will start counting immediately.
149   *
150   * @param channelA         The a channel digital input channel.
151   * @param channelB         The b channel digital input channel.
152   * @param indexChannel     The index channel digital input channel.
153   * @param reverseDirection represents the orientation of the encoder and inverts the output values
154   *                         if necessary so forward represents positive values.
155   */
156  public Encoder(final int channelA, final int channelB, final int indexChannel,
157                 boolean reverseDirection) {
158    m_allocatedA = true;
159    m_allocatedB = true;
160    m_allocatedI = true;
161    m_aSource = new DigitalInput(channelA);
162    m_bSource = new DigitalInput(channelB);
163    m_indexSource = new DigitalInput(indexChannel);
164    initEncoder(reverseDirection, EncodingType.k4X);
165    setIndexSource(m_indexSource);
166  }
167
168  /**
169   * Encoder constructor. Construct a Encoder given a and b channels. Using an index pulse forces 4x
170   * encoding
171   *
172   * <p>The encoder will start counting immediately.
173   *
174   * @param channelA     The a channel digital input channel.
175   * @param channelB     The b channel digital input channel.
176   * @param indexChannel The index channel digital input channel.
177   */
178  public Encoder(final int channelA, final int channelB, final int indexChannel) {
179    this(channelA, channelB, indexChannel, false);
180  }
181
182  /**
183   * Encoder constructor. Construct a Encoder given a and b channels as digital inputs. This is used
184   * in the case where the digital inputs are shared. The Encoder class will not allocate the
185   * digital inputs and assume that they already are counted.
186   *
187   * <p>The encoder will start counting immediately.
188   *
189   * @param sourceA          The source that should be used for the a channel.
190   * @param sourceB          the source that should be used for the b channel.
191   * @param reverseDirection represents the orientation of the encoder and inverts the output values
192   *                         if necessary so forward represents positive values.
193   */
194  public Encoder(DigitalSource sourceA, DigitalSource sourceB, boolean reverseDirection) {
195    m_allocatedA = false;
196    m_allocatedB = false;
197    m_allocatedI = false;
198    if (sourceA == null) {
199      throw new NullPointerException("Digital Source A was null");
200    }
201    m_aSource = sourceA;
202    if (sourceB == null) {
203      throw new NullPointerException("Digital Source B was null");
204    }
205    m_bSource = sourceB;
206    initEncoder(reverseDirection, EncodingType.k4X);
207  }
208
209  /**
210   * Encoder constructor. Construct a Encoder given a and b channels as digital inputs. This is used
211   * in the case where the digital inputs are shared. The Encoder class will not allocate the
212   * digital inputs and assume that they already are counted.
213   *
214   * <p>The encoder will start counting immediately.
215   *
216   * @param sourceA The source that should be used for the a channel.
217   * @param sourceB the source that should be used for the b channel.
218   */
219  public Encoder(DigitalSource sourceA, DigitalSource sourceB) {
220    this(sourceA, sourceB, false);
221  }
222
223  /**
224   * Encoder constructor. Construct a Encoder given a and b channels as digital inputs. This is used
225   * in the case where the digital inputs are shared. The Encoder class will not allocate the
226   * digital inputs and assume that they already are counted.
227   *
228   * <p>The encoder will start counting immediately.
229   *
230   * @param sourceA          The source that should be used for the a channel.
231   * @param sourceB          the source that should be used for the b channel.
232   * @param reverseDirection represents the orientation of the encoder and inverts the output values
233   *                         if necessary so forward represents positive values.
234   * @param encodingType     either k1X, k2X, or k4X to indicate 1X, 2X or 4X decoding. If 4X is
235   *                         selected, then an encoder FPGA object is used and the returned counts
236   *                         will be 4x the encoder spec'd value since all rising and falling edges
237   *                         are counted. If 1X or 2X are selected then a m_counter object will be
238   *                         used and the returned value will either exactly match the spec'd count
239   *                         or be double (2x) the spec'd count.
240   */
241  public Encoder(DigitalSource sourceA, DigitalSource sourceB, boolean reverseDirection,
242                 final EncodingType encodingType) {
243    m_allocatedA = false;
244    m_allocatedB = false;
245    m_allocatedI = false;
246    if (encodingType == null) {
247      throw new NullPointerException("Given encoding type was null");
248    }
249    if (sourceA == null) {
250      throw new NullPointerException("Digital Source A was null");
251    }
252    m_aSource = sourceA;
253    if (sourceB == null) {
254      throw new NullPointerException("Digital Source B was null");
255    }
256    m_aSource = sourceA;
257    m_bSource = sourceB;
258    initEncoder(reverseDirection, encodingType);
259  }
260
261  /**
262   * Encoder constructor. Construct a Encoder given a, b and index channels as digital inputs. This
263   * is used in the case where the digital inputs are shared. The Encoder class will not allocate
264   * the digital inputs and assume that they already are counted.
265   *
266   * <p>The encoder will start counting immediately.
267   *
268   * @param sourceA          The source that should be used for the a channel.
269   * @param sourceB          the source that should be used for the b channel.
270   * @param indexSource      the source that should be used for the index channel.
271   * @param reverseDirection represents the orientation of the encoder and inverts the output values
272   *                         if necessary so forward represents positive values.
273   */
274  public Encoder(DigitalSource sourceA, DigitalSource sourceB, DigitalSource indexSource,
275                 boolean reverseDirection) {
276    m_allocatedA = false;
277    m_allocatedB = false;
278    m_allocatedI = false;
279    if (sourceB == null) {
280      throw new NullPointerException("Digital Source A was null");
281    }
282    m_aSource = sourceA;
283    if (sourceB == null) {
284      throw new NullPointerException("Digital Source B was null");
285    }
286    m_aSource = sourceA;
287    m_bSource = sourceB;
288    m_indexSource = indexSource;
289    initEncoder(reverseDirection, EncodingType.k4X);
290    setIndexSource(indexSource);
291  }
292
293  /**
294   * Encoder constructor. Construct a Encoder given a, b and index channels as digital inputs. This
295   * is used in the case where the digital inputs are shared. The Encoder class will not allocate
296   * the digital inputs and assume that they already are counted.
297   *
298   * <p>The encoder will start counting immediately.
299   *
300   * @param sourceA     The source that should be used for the a channel.
301   * @param sourceB     the source that should be used for the b channel.
302   * @param indexSource the source that should be used for the index channel.
303   */
304  public Encoder(DigitalSource sourceA, DigitalSource sourceB, DigitalSource indexSource) {
305    this(sourceA, sourceB, indexSource, false);
306  }
307
308  /**
309   * @return The Encoder's FPGA index.
310   */
311  @SuppressWarnings("AbbreviationAsWordInName")
312  public int getFPGAIndex() {
313    return EncoderJNI.getEncoderFPGAIndex(m_encoder);
314  }
315
316  /**
317   * Used to divide raw edge counts down to spec'd counts.
318   *
319   * @return The encoding scale factor 1x, 2x, or 4x, per the requested encoding type.
320   */
321  public int getEncodingScale() {
322    return EncoderJNI.getEncoderEncodingScale(m_encoder);
323  }
324
325  /**
326   * Free the resources used by this object.
327   */
328  public void free() {
329    if (m_aSource != null && m_allocatedA) {
330      m_aSource.free();
331      m_allocatedA = false;
332    }
333    if (m_bSource != null && m_allocatedB) {
334      m_bSource.free();
335      m_allocatedB = false;
336    }
337    if (m_indexSource != null && m_allocatedI) {
338      m_indexSource.free();
339      m_allocatedI = false;
340    }
341
342    m_aSource = null;
343    m_bSource = null;
344    m_indexSource = null;
345    EncoderJNI.freeEncoder(m_encoder);
346    m_encoder = 0;
347  }
348
349  /**
350   * Gets the raw value from the encoder. The raw value is the actual count unscaled by the 1x, 2x,
351   * or 4x scale factor.
352   *
353   * @return Current raw count from the encoder
354   */
355  public int getRaw() {
356    return EncoderJNI.getEncoderRaw(m_encoder);
357  }
358
359  /**
360   * Gets the current count. Returns the current count on the Encoder. This method compensates for
361   * the decoding type.
362   *
363   * @return Current count from the Encoder adjusted for the 1x, 2x, or 4x scale factor.
364   */
365  public int get() {
366    return EncoderJNI.getEncoder(m_encoder);
367  }
368
369  /**
370   * Reset the Encoder distance to zero. Resets the current count to zero on the encoder.
371   */
372  public void reset() {
373    EncoderJNI.resetEncoder(m_encoder);
374  }
375
376  /**
377   * Returns the period of the most recent pulse. Returns the period of the most recent Encoder
378   * pulse in seconds. This method compensates for the decoding type.
379   *
380   * <p><b>Warning:</b> This returns unscaled periods and getRate() scales using value from
381   * setDistancePerPulse().
382   *
383   * @return Period in seconds of the most recent pulse.
384   * @deprecated Use getRate() in favor of this method.
385   */
386  @Deprecated
387  public double getPeriod() {
388    return EncoderJNI.getEncoderPeriod(m_encoder);
389  }
390
391  /**
392   * Sets the maximum period for stopped detection. Sets the value that represents the maximum
393   * period of the Encoder before it will assume that the attached device is stopped. This timeout
394   * allows users to determine if the wheels or other shaft has stopped rotating. This method
395   * compensates for the decoding type.
396   *
397   * @param maxPeriod The maximum time between rising and falling edges before the FPGA will report
398   *                  the device stopped. This is expressed in seconds.
399   */
400  public void setMaxPeriod(double maxPeriod) {
401    EncoderJNI.setEncoderMaxPeriod(m_encoder, maxPeriod);
402  }
403
404  /**
405   * Determine if the encoder is stopped. Using the MaxPeriod value, a boolean is returned that is
406   * true if the encoder is considered stopped and false if it is still moving. A stopped encoder is
407   * one where the most recent pulse width exceeds the MaxPeriod.
408   *
409   * @return True if the encoder is considered stopped.
410   */
411  public boolean getStopped() {
412    return EncoderJNI.getEncoderStopped(m_encoder);
413  }
414
415  /**
416   * The last direction the encoder value changed.
417   *
418   * @return The last direction the encoder value changed.
419   */
420  public boolean getDirection() {
421    return EncoderJNI.getEncoderDirection(m_encoder);
422  }
423
424  /**
425   * Get the distance the robot has driven since the last reset as scaled by the value from {@link
426   * #setDistancePerPulse(double)}.
427   *
428   * @return The distance driven since the last reset
429   */
430  public double getDistance() {
431    return EncoderJNI.getEncoderDistance(m_encoder);
432  }
433
434  /**
435   * Get the current rate of the encoder. Units are distance per second as scaled by the value from
436   * setDistancePerPulse().
437   *
438   * @return The current rate of the encoder.
439   */
440  public double getRate() {
441    return EncoderJNI.getEncoderRate(m_encoder);
442  }
443
444  /**
445   * Set the minimum rate of the device before the hardware reports it stopped.
446   *
447   * @param minRate The minimum rate. The units are in distance per second as scaled by the value
448   *                from setDistancePerPulse().
449   */
450  public void setMinRate(double minRate) {
451    EncoderJNI.setEncoderMinRate(m_encoder, minRate);
452  }
453
454  /**
455   * Set the distance per pulse for this encoder. This sets the multiplier used to determine the
456   * distance driven based on the count value from the encoder. Do not include the decoding type in
457   * this scale. The library already compensates for the decoding type. Set this value based on the
458   * encoder's rated Pulses per Revolution and factor in gearing reductions following the encoder
459   * shaft. This distance can be in any units you like, linear or angular.
460   *
461   * @param distancePerPulse The scale factor that will be used to convert pulses to useful units.
462   */
463  public void setDistancePerPulse(double distancePerPulse) {
464    EncoderJNI.setEncoderDistancePerPulse(m_encoder, distancePerPulse);
465  }
466
467  /**
468   * Set the direction sensing for this encoder. This sets the direction sensing on the encoder so
469   * that it could count in the correct software direction regardless of the mounting.
470   *
471   * @param reverseDirection true if the encoder direction should be reversed
472   */
473  public void setReverseDirection(boolean reverseDirection) {
474    EncoderJNI.setEncoderReverseDirection(m_encoder, reverseDirection);
475  }
476
477  /**
478   * Set the Samples to Average which specifies the number of samples of the timer to average when
479   * calculating the period. Perform averaging to account for mechanical imperfections or as
480   * oversampling to increase resolution.
481   *
482   * @param samplesToAverage The number of samples to average from 1 to 127.
483   */
484  public void setSamplesToAverage(int samplesToAverage) {
485    EncoderJNI.setEncoderSamplesToAverage(m_encoder, samplesToAverage);
486  }
487
488  /**
489   * Get the Samples to Average which specifies the number of samples of the timer to average when
490   * calculating the period. Perform averaging to account for mechanical imperfections or as
491   * oversampling to increase resolution.
492   *
493   * @return SamplesToAverage The number of samples being averaged (from 1 to 127)
494   */
495  public int getSamplesToAverage() {
496    return EncoderJNI.getEncoderSamplesToAverage(m_encoder);
497  }
498
499  /**
500   * Set which parameter of the encoder you are using as a process control variable. The encoder
501   * class supports the rate and distance parameters.
502   *
503   * @param pidSource An enum to select the parameter.
504   */
505  public void setPIDSourceType(PIDSourceType pidSource) {
506    m_pidSource = pidSource;
507  }
508
509  @Override
510  public PIDSourceType getPIDSourceType() {
511    return m_pidSource;
512  }
513
514  /**
515   * Implement the PIDSource interface.
516   *
517   * @return The current value of the selected source parameter.
518   */
519  public double pidGet() {
520    switch (m_pidSource) {
521      case kDisplacement:
522        return getDistance();
523      case kRate:
524        return getRate();
525      default:
526        return 0.0;
527    }
528  }
529
530  /**
531   * Set the index source for the encoder. When this source is activated, the encoder count
532   * automatically resets.
533   *
534   * @param channel A DIO channel to set as the encoder index
535   */
536  public void setIndexSource(int channel) {
537    setIndexSource(channel, IndexingType.kResetOnRisingEdge);
538  }
539
540  /**
541   * Set the index source for the encoder. When this source is activated, the encoder count
542   * automatically resets.
543   *
544   * @param source A digital source to set as the encoder index
545   */
546  public void setIndexSource(DigitalSource source) {
547    setIndexSource(source, IndexingType.kResetOnRisingEdge);
548  }
549
550  /**
551   * Set the index source for the encoder. When this source rises, the encoder count automatically
552   * resets.
553   *
554   * @param channel A DIO channel to set as the encoder index
555   * @param type    The state that will cause the encoder to reset
556   */
557  public void setIndexSource(int channel, IndexingType type) {
558    if (m_allocatedI) {
559      throw new AllocationException("Digital Input for Indexing already allocated");
560    }
561    m_indexSource = new DigitalInput(channel);
562    m_allocatedI = true;
563    setIndexSource(m_indexSource, type);
564  }
565
566  /**
567   * Set the index source for the encoder. When this source rises, the encoder count automatically
568   * resets.
569   *
570   * @param source A digital source to set as the encoder index
571   * @param type   The state that will cause the encoder to reset
572   */
573  public void setIndexSource(DigitalSource source, IndexingType type) {
574    EncoderJNI.setEncoderIndexSource(m_encoder, source.getPortHandleForRouting(),
575        source.getAnalogTriggerTypeForRouting(), type.value);
576  }
577
578  /**
579   * Live Window code, only does anything if live window is activated.
580   */
581  public String getSmartDashboardType() {
582    if (EncoderJNI.getEncoderEncodingType(m_encoder) == EncodingType.k4X.value) {
583      return "Quadrature Encoder";
584    }
585    return "Encoder";
586  }
587
588  private ITable m_table;
589
590  @Override
591  public void initTable(ITable subtable) {
592    m_table = subtable;
593    updateTable();
594  }
595
596  @Override
597  public ITable getTable() {
598    return m_table;
599  }
600
601  @Override
602  public void updateTable() {
603    if (m_table != null) {
604      m_table.putNumber("Speed", getRate());
605      m_table.putNumber("Distance", getDistance());
606      m_table.putNumber("Distance per Tick", EncoderJNI.getEncoderDistancePerPulse(m_encoder));
607    }
608  }
609
610  @Override
611  public void startLiveWindowMode() {
612  }
613
614  @Override
615  public void stopLiveWindowMode() {
616  }
617}