Encoder Navigation - OnBot Java

In the previous section you learned about how to use Elapsed Time to allow your robot to navigate the world around it autonomously. When starting out many of the robot actions can be accomplished by turning on a motor for a specific amount of time. Eventually, these time-based actions may not be accurate or repeatable enough. Environmental factors, such as the state of battery charge during operation and mechanisms wearing in through use, can all affect time-based actions. Fortunately, there is a way to give feedback to the robot about how it is operating by using sensors; devices that are used to collect information about the robot and the environment around it.

With Elapsed Time, in order to get the robot to move to a specific distance, you had to estimate the amount of time and the percentage of duty cycle needed to get from point a to point b. However, the REV motors come with built in encoders, which provide feedback in the form of ticks ( or counts) per revolution of the motor. The information provided by the encoders can be used to move the motor to a target position, or a target distance.

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.

There are two articles in that go through the basics of Encoders. Using Encoders goes through the basics of the different types of motor modes, as well as a few application examples of using these modes in code. In this section we will focus on using RUN_TO_POSITION.

The other article, Encoders, focuses on the general functionality of an encoder.

It is recommended that you review both articles before moving on with this guide.

Basics of Programming with Encoders

Start by creating a basic op mode calledHelloRobot_EncoderAuton.

When creating an op mode a decision needs to be made on whether or not to set it to autonomous mode. For applications under 30 seconds, typically required for competitive game play changing the op mode type to autonomous is recommended. For applications over 30 seconds, setting the code to the autonomous op mode type will limit your autonomous code to 30 seconds of run time. If you plan on exceeding the 30 seconds built into the SDK, keeping the code as a teleoperated op mode type is recommended.

For information on how op modes work please visit the Introduction to Programming section.

For more information on how to change the op mode type check out the Creating an OpMode - OnBot Java section.

The op mode structure below is simplified and only includes the necessary components needed to create the encoder based code.

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 HelloWorld_EncoderAuton 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()){
        
        }
    }
}

As with all drivetrain related navigation, the directionality of one of the motors needs to be reversed in order for both motors to move in the same direction. Since the Class Bot V2 is still being used add the line rightmotor.setDirection(DcMotor.Direction.REVERSE); to the code beneath the rightmotor = hardwareMap.get(DcMotor.class, "rightmotor"); code line.

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

For more information on the directionality of motor check out the Basics of Programming Drivetrains section.

Recall from Using Encoders that using RUN_TO_POSITION mode requires a three step process. The first step is setting target position. To set target position add the lines leftmotor.setTargetPosition(1000); and rightmotor.setTargetPosition(1000); to the op mode after the waitForStart(); command. To get a target position that equates to a target distance requires so calculations, which will be covered later. For now, set target position to 1000 ticks.

waitForStart();

leftmotor.setTargetPosition(1000);
rightmotor.setTargetPosition(1000);

while (opModeIsActive()){
        
        }

The next step is to set both motors to the RUN_TO_POSITIONmode. Add the lines leftmotor.setMode(DcMotor.RunMode.RUN_TO_POSITION);and rightmotor.setMode(DcMotor.RunMode.RUN_TO_POSITION);to your code, beneath the setTargetPosition code lines.

waitForStart();

leftmotor.setTargetPosition(1000);
rightmotor.setTargetPosition(1000);

leftmotor.setMode(DcMotor.RunMode.RUN_TO_POSITION);
rightmotor.setMode(DcMotor.RunMode.RUN_TO_POSITION);

while (opModeIsActive()){
        
        }

The main focus of the three step process is to set a target, tell the robot to move to that target, and at what speed (or velocity) the robot should get to that target. Normally, the recommended next step is to calculate velocity and set a target velocity based on ticks. However, this requires quite a bit of math to find the appropriate velocity. For testing purposes, its more important to make sure that the main part of the code is working before getting too deep into the creation of the code. Since the setPower function was covered in previous sections and will communicate to the system what relative speed (or in this case duty cycle) is needed to get to the target, this can be used in the place of setVelocity for now.

Add the lines to set the power of both motors to 80% of duty cycle.

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()){
        
        }

Now that all three RUN_TO_POSITION steps have been added to the code the code can be tested. However, if you want to wait for the motor to reach its target position before continuing in your program, you can use a while loop that checks if the motor is busy (not yet at its target). For this program lets edit the while (opModeIsActive()){}

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

Edit the while loop to include the leftmotor.isBusy() and righmotor.isBusy()functions. This will check if the left motor and right motor are busy running to a target position. The while loop will stop when either motor reaches the target position.

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

}

Right now the while loop is waiting for the either motor to reach the target. There may be occasions when you want to wait for both motors to reach their target position, in this case the following loop can be used.

while (opModeIsActive() && (leftmotor.isBusy() || rightmotor.isBusy()))

Save and run the op mode two times in a row. Does the robot move as expected the second time?

Try turning the Control Hub off and then back on. How does the robot move?

In the Basic Encoder Concepts section, it is clarified that all encoder ports start at 0 ticks when the Control Hub is turned on. Since you did not turn off the Control Hub in between runs, the second time you ran the op mode the motors were already at, or around, the target position. When you run a code, you want to ensure that certain variables start in a known state. For the encoder ticks, this can be achieved by setting the mode to STOP_AND_RESET_ENCODER . Add this block to the op mode in the initialization section. Each time the op mode is initialized, the encoder ticks will be reset to zero.

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();

For more information on the motor mode STOP_AND_RESET_ENCODERScheck out the STOP_AND_RESET_ENCODERS section of the Using Encoders guide.

Last updated