📊 Chapter 9: Encoders

Visual Blocks Examples
Reset and set encoder mode
set motor1 .mode to STOP_AND_RESET_ENCODER
set motor1 .targetPosition to 1120
set motor1 .mode to RUN_TO_POSITION
set motor1 .power to 0.5
Wait for encoder to reach target
repeat while motor1.isBusy
telemetry.addData Position motor1.currentPosition
telemetry.update
set motor1 .power to 0
Blocks Guide

Encoder Basics

Encoder Basics

The HD Hex Motor and Core Hex Motor from REV Robotics include a built-in encoder. You may need to check your motor's documentation if following this tutorial with a different vendor's motor.

What is an Encoder?

Encoders are a form of sensor built into some motors that help provide feedback to our robot. There are different kinds of encoders, but we're going to focus on what's called a quadrature encoder for this tutorial. These encoders are able to count the number of revolutions of the motor also sometimes called "ticks".

While quadrature encoders aren't able to tell exact positions, they can still be used to help the motor move to a specified point. This works by specifying first an origin point in our code then a point the motor should move away.

Quadrature vs. Absolute Encoders

You may see the term absolute encoder when referring to something like REV's Through Bore Encoder. Absolute encoders have a set origin allowing exact movements of the motor in comparison.

Here's a hint for how to remember the difference:

  • Quadrature Encoders are like a stopwatch continuously adding up time!
  • Absolute Encoders are more like a clock telling an exact time!
  • Different motors have different numbers of ticks per rotation of the output shaft based on the gear ratio of the motor. When the Control Hub is turned on, all of its encoder ports are at 0 ticks. As a motor moves forward, its encoder value increases. As a motor moves backwards, its encoder value decreases.

    Exploring Motor Modes

    The mode is often established during the initialization process of our code, meaning the motors are ready to go throughout our program, but it is possible to change this for specific use cases as it executes.

    Which mode we need to use largely depends on the intended function of the motor and any attached mechanism.

    STOP_AND_RESET_ENCODER

    When using encoders, it is strongly recommended to first use STOP_AND_RESET_ENCODER during initialization. This will allow you to know what position the motor is starting in, however you will want to plan for a repeatable start up configuration each time!

    A motor can be switched to "STOP_AND_RESET_ENCODER" while a code is executing as well. This is often set up using a button on the gamepad to allow the driver to reset the encoder in the event of a motor misbehaving, such as after the robot's been caught on an obstacle.

    RUN_WITHOUT_ENCODER

    Use this mode when you don't want the Control Hub to attempt to use the encoders to maintain a constant speed. You can still access the encoder values, but your actual motor speed will vary more based on external factors such as battery life and friction. In this mode, you provide a power level in the -1 to 1 range, where -1 is full speed backwards, 0 is stopped, and 1 is full speed forwards. Reducing the power reduces both torque and speed.

    The RUN_WITHOUT_ENCODER motor mode is very straightforward, you simply set a power throughout the program using the "Power" block or, such as for a drivetrain, to be set by the joysticks.

    RUN_USING_ENCODER

    In this mode, the Control Hub will use the encoder to take an active role in managing the motor's speed. Rather than directly applying a percentage of the available power, RUN_USING_ENCODER mode targets a specific velocity (speed). This allows the motor to account for friction, battery voltage, and other factors. You can still provide a power level in RUN_USING_ENCODER mode, but this is not recommended, as it will limit your target speed significantly.

    Setting a velocity from RUN_WITHOUT_ENCODER mode will automatically switch the motor to RUN_USING_ENCODER mode. You should pick a velocity that the motor will be capable of reaching even with a full load and a low battery.

    RUN_TO_POSITION

    In this mode, the Control Hub will target a specific position, rather than a specific velocity. You can still choose to set a velocity, but it is only used as the maximum velocity. The motor will continue to hold its position even after it has reached its target.

    [DANGER] If the motor is unable to reach the determined position the motor will continue to run attempting to reach or maintain that position, which can lead to the motor stalling and overheating.

    To use RUN_TO_POSITION mode, you need to do the following things in this order:

    1. Set a target position (measured in ticks)

    2. Switch to RUN_TO_POSITION mode

    3. Set the maximum velocity (if not determined by a gamepad input)

    Remember it is recommended to always reset the encoder during initialization, however you will need to make sure your robot has been reset physically to the initialization position. For example, an arm may need to be brought back to the start up configuration like for the beginning of a FTC match.

    The motor will continue to hold its position even after it has reached its target, unless you set the velocity or power to zero, or switch to a different motor mode.

    Drivetrain Encoders

    Drivetrain Encoders - Blocks

    Moving the motors to a specific position, using the encoders, removes any potential inaccuracies or inconsistencies from using Elapsed Time. The focus of this section is to move the robot to a target position using encoders.

    Setting up the Drivetrain Encoders

    For this tutorial, our OpMode is named HelloRobot_Encoder!

    Before diving in too far, recall that for certain drivetrains, like the Class Bot V2, one of the motors needs to be reversed as the motors are mirrored. In our example, we are adding the Motor - rightmotorDirection block under the Comment - Put initialization blocks.

    RUN_TO_POSITION

    As introduced in Using Encoders, using RUN_TO_POSITION mode requires a three step process.

    The first step is setting target position. To do so, grab the Dual Motor - set position block and add it under the Comment - Put loop blocks comment. For this example, we are setting our position after pressing Initialize, but before we hit Play on the Driver Hub.

    If we want our robot to travel a specific distance we will need to do a bit of math beforehand to calculate the TargetPosition. But for now let's start simple by setting the target position to 1000 ticks.

    The next step is to set both motors to the RUN_TO_POSITION mode. Place the Dual Motor - set mode to RUNTO block beneath the Dual Motor - target position to 1000 block.

    Order matters! The TargetPosition block must come before RUN_TO_POSITION mode is set or it will result in an error.

    The final step is setting the power. Add the Dual Motor - set to positive block beneath the set mode block. Change the duty cycle (or power) of both motors to 0.8.

    Quick Check!

    Save your OpMode and give it a test. What happens once you press play? What happens if you stop the program then start it again?

    Likely your motors turned on when testing out the code to spin until they've reached the set position.

    Some may have turned off once the position was reached, but you may also experience the motors twitching or making small adjustments in an attempt to reach the position. Then when starting the code again, the motor either continued twitching or did not move at all.

    Recall we may need to reset our encoder to zero before running a program! The motor will continuously try to adjust until it hits the set position, but if it's already there it won't move!

    Adjusting the power may help prevent the motor from overshooting the position and needing to repeatedly adjust.

    STOP_AND_RESET_ENCODERS

    For our demo code we will want to request our motors reset their encoders during the initialization process of the program.

    Setting up the whileLoop

    Let's say we want our program to run only for however long it takes for the motors to reach designated position. Or maybe we intend for the robot to do something else after reaching the destination. For this we will need to edit our whileLoop block!

    Even though we are ending a new exit case for our loop, we must always have our call to check opModeIsActive or our program will instantly timeout!

    Grab a Logic - and block from the logic menu and add it to the while loop. On the left side of the Logic - and block add the Motor - is busy block. On the right side add the Motor - rightmotor is busy block.

    Embed the Combo - left and right are busy in another Logic - and block. Place the Combo - left and right are busy on the right side of the Logic - and block. Our call for the OpMode will go in the lefthand side slot.

    Save your OpMode and give it a try! As soon as the motors hit the desired position the program will end instead of continuously run in the event they do not perfectly hit the position.

    Right now the while loop is waiting for the right and left motors to reach their respective targets. There may be occasions when you want to wait for both motors to reach their target position, in this case the logic - or block can be used.
    Level Up: OnBot Java versions

    Encoder Basics (Java)

    Encoder Basics - OnBot Java

    What is an Encoder?

    Encoders are sensors built into motors that provide feedback to robots. This tutorial focuses on quadrature encoders, which count motor revolutions ("ticks"). While quadrature encoders cannot determine exact positions, they help motors move to specified points by establishing an origin point and target destination in code.

    Quadrature vs. Absolute Encoders: Quadrature encoders continuously accumulate data like a stopwatch, whereas absolute encoders (such as REV's Through Bore Encoder) provide exact positions like a clock.

    Exploring Motor Modes

    Motor modes are typically established during code initialization but can be changed during execution. The appropriate mode depends on the motor's intended function and attached mechanisms.

    STOP_AND_RESET_ENCODER

    This mode is strongly recommended during initialization to establish a known starting position. It can also be triggered via gamepad button during execution to reset encoders after motor misbehavior.

    DcMotorEx motor = hardwareMap.get(DcMotorEx.class, "Motor");
    motor.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);

    RUN_WITHOUT_ENCODER

    Use this mode when encoder-based speed control is unnecessary. Motor speed varies based on battery life and friction. Power ranges from -1 (full reverse) to 1 (full forward), with 0 as stopped.

    DcMotorEx motor = hardwareMap.get(DcMotorEx.class, "Motor");
    motor.setMode(DcMotor.RunMode.RUN_WITHOUT_ENCODER);
    double motorPower = 0.5;
    motor.setPower(motorPower);

    RUN_USING_ENCODER

    The Control Hub actively manages motor speed by targeting specific velocity rather than power percentage. This accounts for friction and battery voltage. Setting velocity automatically switches to this mode.

    DcMotorEx motor = hardwareMap.get(DcMotorEx.class, "Motor");
    motor.setMode(DcMotor.RunMode.RUN_USING_ENCODER);
    double motorVelocity = 200;
    motor.setVelocity(motorVelocity);

    RUN_TO_POSITION

    The Control Hub targets a specific position (measured in ticks). Velocity can be set as maximum velocity only. The motor holds its position after reaching the target.

    [DANGER] If the motor cannot reach the target position, it will continue attempting, potentially causing stalling and overheating.

    Steps to implement:

    1. Set target position (in ticks)

    2. Switch to RUN_TO_POSITION mode

    3. Set maximum velocity

    package org.firstinspires.ftc.teamcode;
    
    @TeleOp
    public class JavaRunToPositionExample extends LinearOpMode {
        DcMotorEx motor;
    
        @Override
        public void runOpMode() {
            motor = hardwareMap.get(DcMotorEx.class, "Motor");
    
            motor.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
    
            waitForStart();
    
            motor.setTargetPosition(300);
            motor.setMode(DcMotor.RunMode.RUN_TO_POSITION);
            motor.setVelocity(200);
    
            while (opModeIsActive()) {
                telemetry.addData("velocity", motor.getVelocity());
                telemetry.addData("position", motor.getCurrentPosition());
                telemetry.addData("is at target", !motor.isBusy());
                telemetry.update();
            }
        }
    }

    Drivetrain Encoders (Java)

    Drivetrain Encoders - OnBot Java

    Moving the motors to a specific position, using the encoders, removes any potential inaccuracies or inconsistencies from using Elapsed Time. The focus of this section is to move the robot to a target position using encoders.

    Setting up the Drivetrain Encoders

    For this tutorial, our OpMode is named HelloRobot_Encoder!

    The OpMode structure below is simplified and only includes the necessary components:

    package org.firstinspires.ftc.teamcode;
    
    import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
    import com.qualcomm.robotcore.eventloop.opmode.Autonomous;
    import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
    import com.qualcomm.robotcore.eventloop.opmode.Disabled;
    import com.qualcomm.robotcore.hardware.DcMotor;
    import com.qualcomm.robotcore.hardware.DcMotorSimple;
    
    @Autonomous //sets the op mode as an autonomous op mode
    
    public class HelloRobot_Encoder extends LinearOpMode {
        private DcMotor leftmotor;
        private DcMotor rightmotor;
    
        @Override
        public void runOpMode() {
            leftmotor = hardwareMap.get(DcMotor.class, "leftmotor");
            rightmotor = hardwareMap.get(DcMotor.class, "rightmotor");
    
            // Wait for the game to start (driver presses PLAY)
            waitForStart();
    
            // run until the end of the match (driver presses STOP)
            while (opModeIsActive()){
    
            }
        }
    }

    Before diving in too far, recall that for certain drivetrains, like the Class Bot V2, one of the motors needs to be reversed as the motors are mirrored:

    public void runOpMode() {
        leftmotor = hardwareMap.get(DcMotor.class, "leftmotor");
        rightmotor = hardwareMap.get(DcMotor.class, "rightmotor");
    
        rightmotor.setDirection(DcMotor.Direction.REVERSE);
    
        waitForStart();

    RUN_TO_POSITION

    As introduced in Using Encoders, using RUN_TO_POSITION mode requires a three step process.

    Step 1 - Set target position:

    waitForStart();
    
    leftmotor.setTargetPosition(1000);
    rightmotor.setTargetPosition(1000);
    
    while (opModeIsActive()){
    
    }

    If we want our robot to travel a specific distance we will need to do a bit of math beforehand to calculate the TargetPosition. But for now let's start simple by setting the target position to 1000 ticks.

    Step 2 - Set both motors to RUN_TO_POSITION mode:

    waitForStart();
    
    leftmotor.setTargetPosition(1000);
    rightmotor.setTargetPosition(1000);
    
    leftmotor.setMode(DcMotor.RunMode.RUN_TO_POSITION);
    rightmotor.setMode(DcMotor.RunMode.RUN_TO_POSITION);
    
    while (opModeIsActive()){
    
    }
    Order matters! The TargetPosition must come before RUN_TO_POSITION mode is set or it will result in an error.

    Step 3 - Set the power (duty cycle) to 80%:

    waitForStart();
    
    leftmotor.setTargetPosition(1000);
    rightmotor.setTargetPosition(1000);
    
    leftmotor.setMode(DcMotor.RunMode.RUN_TO_POSITION);
    rightmotor.setMode(DcMotor.RunMode.RUN_TO_POSITION);
    
    leftmotor.setPower(0.8);
    rightmotor.setPower(0.8);
    
    while (opModeIsActive()){
    
    }

    Quick Check!

    Build your OpMode and give it a test. What happens once you press play? What happens if you stop the program then start it again?

    Likely your motors turned on when testing out the code to spin until they've reached the set position.

    Some may have turned off once the position was reached, but you may also experience the motors twitching or making small adjustments in an attempt to reach the position. Then when starting the code again, the motor either continued twitching or did not move at all.

    Recall we may need to reset our encoder to zero before running a program! The motor will continuously try to adjust until it hits the set position, but if it's already there it won't move!

    STOP_AND_RESET_ENCODERS

    For our demo code we will want to request our motors reset their encoders during the initialization process:

    public void runOpMode() {
        leftmotor = hardwareMap.get(DcMotor.class, "leftmotor");
        rightmotor = hardwareMap.get(DcMotor.class, "rightmotor");
    
        rightmotor.setDirection(DcMotor.Direction.REVERSE);
    
        leftmotor.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
        rightmotor.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
    
        waitForStart();

    Setting up the whileLoop

    Let's say we want our program to run only for however long it takes for the motors to reach designated position.

    Recall that, within a linear OpMode, a whileLoop must always have the opModeIsActive() Boolean as a condition. This condition ensures that the whileLoop will terminate when the stop button is pressed.

    To the whileLoop add the isBusy() functions. This will check if the motors are busy running to a target position:

    while (opModeIsActive() && (leftmotor.isBusy() && rightmotor.isBusy())) {
    
    }

    As soon as the motors hit the desired position the program will end instead of continuously running.

    Right now the whileLoop is waiting for either motor to reach the target. There may be occasions when y

    [... guide continues at REV docs ...]

    ← 🤖 Autonomous & Timing🎯 Advanced Topics →