###### tags: `程式組教程`
# Encoder
## What is an Encoder?
On its basis, an encoder is a device that is able to convert between different types of data. For example, an encoder would be able to convert physical movement (analog data) into electric signal transfering bytes (digital data).
In FRC, the main function of encoders is to record and monitor motors' movement. For example, an encoder would be able to return the motor's speed, the motor's total moved distance, etc.
These encoders that we use essentially work by spining itself along with the motor. During this process, its internal gears will turn, and the amount of movement will be recorded by the detector inside (usually magnetic or mechanical).
A few important words to remember:
* CPR (Cycle per Rotation): The way that the movement is recorded is by electrical "cycles." When each "tooth" of the gear passes the detector, an electrical cycle will happen. CPR means how many cycles will happen for each rotation, which is equal to the number of teeth of the gear. For example, 2048 CPR means that for each rotation there's 2048 cycles (which is quite precise).
* Encoder Resolution: how precise the encoder is, mainly measured in CPR
A few of the most important application of encoders are PID control and odometry, which we'll talk about later.
## Common Types of Encoders
There are two major types of encoder that you need to know:
* external encoder: this kind of encoder is applied by attaching an additional device to the motor that uses a different port to transfer data. Therefore, this encoder can be used seperately from the motor (having its own object instance)
* in-built encoder: the encoder is included in the motor itself and can be retrieved using the motor controller. (e.g. leftMotor.getDistance()) Most motor controllers will have available functions in its library that supports retrieving data of the in-built encoder, but be mindful that not every motor has in-built encoder. For instance, Falcon 500 has 2048 CPR in-built encoder that can be easily retrieved by TalonFX or TalonSRX motor controller
## Using Encoder
### External Encoder
When using an external encoder, generally we use the Encoder class of the WPILib.
```java=
Encoder encoder = new Encoder(0, 1);
// ports 0, 1 are the two pins
```
After instantiating the encoder, we can then set up some basic attributes.
```java=
encoder.setDistancePerPulse(4./256.);
// set up the distance that the wheel of the motor passes after one encoder pulse/cycle.
// This usually goes with the equation of DistancePerPulse = WheelPerimeter * GearRatio / CPR
encoder.setReverseDirection(true);
//reverse the encoder reading. If the motor is inverted, its encoder need to do so too.
//(Optional Configurations)
encoder.setSamplesToAverage(5);
// Configures an encoder to average its period measurement over 5 samples
// Can be between 1 and 127 samples
encoder.setMaxPeriod(.1);
// Configures the encoder to consider itself stopped after .1 seconds
encoder.setMinRate(10);
// Configures the encoder to consider itself stopped when its rate is below 10
```
Now we can start retrieving value from the encoder
```java=
encoder.getDistance(); // get total distance moved by the motor
encoder.getRate(); //get the current speed of the motor
encoder.reset();
//sometimes we want to start counting from zero, then we reset the encoder when necessary
```
### In-Built Encoder
One important advantage of in-built encoder is the fact that no additional object is needed. However, for the same reason, some functions might be more complicated to use. Moreover, these in-built encoder may be controlled quite differently depending on the manufacturer.
Let's look at an example using Falcon500's encoder with TalonSRX motor controller.
```java=
WPI_TalonSRX motor = new WPI_TalonSRX(1);
motor.getSelectedSensorPosition(); // returns the current distance/position
motor.getSelectedSensorVelocity(); // return the velocity of the motor\
```
The problem with using in-built encoder is that you need to add the distance per impulse by yourself since hte returned values are in raw sensor units (cycles). The equation goes like this:
distancePerPulse = gearRatio * wheelPerimeter / EncoderCPR
distance = motor.getSelectedSensorPosition() * positionConstant
velocity = motor.getSelectedSensorVelocity() * distancePerPulse
Also, sometimes some advanced WPILib usage will need the Encoder object to use, which requires special solutions when using in-bulit encoders. We'll talk about those later.