== Encoders [[Image(Encoder-Working-Principle.gif,right,350px,margin=10)]] In the [wiki://ControlSystems/SoftwareTeam/Training/GettingStarted/DCMotor previous example], we controlled the amount of power we were giving the motor (-1.0=full reverse 0=none, 1.0=full forward), but that doesn't tell us how fast or far the wheel is turning. Just like a car or a bicycle, for a given amount of power, the speed will vary with how heavy the robot is, whether it's going up a hill or down a hill, how good the traction is, etc. To determine how fast a wheel is turning or how much it has turned, we use encoders. An encoder is a device attached to the motor or wheel shaft that generates a pulse with each partial rotation (e.g. every 1-degree or 5-degrees of rotation, another pulse is generated). By counting these pulses, we can tell how fast the wheel is turning or what position it is in. We can use this information to do things like make a robot travel a fixed distance or at a set speed. You can read more about encoders on [https://wpilib.screenstepslive.com/s/currentCS/m/java/l/599717-encoders-measuring-rotation-of-a-wheel-or-other-shaft ScreenStepsLive]. We connect encoders either directly to !RoboRio DIO ports or to an intelligent motor controller such as the TalonSRX. Intelligent motor controllers can use encoder data to offload work from the RoboRIO (e.g. to keep a wheel spinning at a set speed); in general, if you have smart motor controllers, the encoders should connect to them. We'll provide examples both ways: === Encoder connected to RoboRIO DIO (Macademia) Create another program using the !TimedRobot java template and name it !EncoderTest. Modify the generated code as follows: * Add an import for the [https://first.wpi.edu/FRC/roborio/beta/docs/java/edu/wpi/first/wpilibj/Encoder.html Encoder] class: {{{ import edu.wpi.first.wpilibj.Encoder; }}} * Declare a variable for the Encoder in the Robot class {{{ private Encoder leftEncoder; }}} * • In robotInit() instantiate the Encoder object and reset it {{{ // Quadrature encoder has A and B channels connected to DIO0, DIO1 leftEncoder = new Encoder(0, 1); // Peanut wheels are 7.5" in diameter // Encoders provide 1 count per degree of rotation leftEncoder.setDistancePerPulse((3.141592*7.5)/360); // reset encoder counts to 0 leftEncoder.reset(); }}} * In robotPeriodic() read and display the encoder value {{{ int encoderValue = leftEncoder.getRaw(); double distance = leftEncoder.getDistance(); SmartDashboard.putNumber("Encoder Value", encoderValue); SmartDashboard.putNumber("Encoder Distance", distance); }}} For more information and examples of using an encoder connected to DIOs, see the [https://mililanirobotics.gitbooks.io/frc-electrical-bible/content/Sensors/opticalencoder.html FRC Electrical Bible] === Encoder connected to a TalonSRX smart motor controller (Hazelnut, Almond) Create another program using the !TimedRobot java template and name it SRXencoderTest. Add the CTRE-Phoenix library to the project as done previously. Modify the generated code as follows: * Add the following imports: {{{ import com.ctre.phoenix.motorcontrol.can.*; import com.ctre.phoenix.motorcontrol.FeedbackDevice; }}} * Declare a variable for the smart motor controller with connected encoder in the Robot class {{{ private WPI_TalonSRX m_Left; }}} * • In robotInit() instantiate the motor controller object and reset it {{{ // TalonSRX is configured with CAN bus address 3 m_Left = new WPI_TalonSRX(3); // Clear any non default configuration/settings m_Left.configFactoryDefault(); // A quadrature encoder is connected to the TalonSRX m_Left.configSelectedFeedbackSensor(FeedbackDevice.QuadEncoder); // Reset encoder count to 0 m_Left.setSelectedSensorPosition(0); }}} * In robotPeriodic() read and display the encoder value {{{ SmartDashboard.putNumber("Encoder value", m_Left.getSelectedSensorPosition()); }}} For the complete Robot.java see [wiki:ControlSystems/SoftwareTeam/Training/GettingStarted/Encoders/CANCode here] Note: you'll need to manually turn the left wheel forward and backward to see the Encoder values change. Try turning the wheel 360 degrees to see what value is equivalent to a full revolution of the wheel. === Quadrature Encoders [[Image(encAB.gif,left,250px,margin=10)]][[Image(quadEncoder2.gif,right,250px,margin=10)]]Notice that the raw count reports 2x360=720 counts per rotation. This is because the encoders used are quadrature encoders which have two channels: A, B and the sum of both A and B channels are reported. A quadrature encoder works like the optical encoder shown above, but with two rows of slits in the disk, each slightly offset from the other (overlapping) and each with its own light source/detector. This allows you to determine not just distance and speed but also direction. The light detectors are labeled A and B; because the slots overlap, the sequence of detected light as the wheel rotates forward is: A, AB, B, off, A, AB, etc. When the wheel rotates backwards, the sequence is B, AB, A, off, B, AB, A, off. You can read more about quadrature encoders [https://robu.in/quadrature-encoder/ here] There are many types of encoders; the ones shown here use light, but there are magnetic, capacitive, and other detection mechanisms. Encoders can have a single channel (A) to determine speed and distance traveled, two channels (A,B) to determine speed, distance, and direction, and many encoders have a third channel (A, B, Z) where the Z (index) channel only provides a single pulse per full rotation of the wheel. This can be useful if you need to move the motor to a precise position. === Extra credit === 1. Ask a mentor to get an oscilloscope so you can see the pulses generated by the encoder as the wheel rotates. 1. Try to make the robot rotate 90-degrees to the right by spinning one wheel in one direction and the other the same amount in the other direction.