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