Drivetrains

The base of any FTC robot is the drivetrain, which is what enables the robot to move around. Drivetrains can be split into two types: differential and holonomic. tank vs. mecanum

Differential

Differential, or tank, drivetrains typically use traction wheels, and do not possess the ability to strafe. They are usually easier to program, but limit mobility. An example can be seen below:

tank drivetrain

As you can see, the tank drivetrain would not possess the ability to strafe due to the traction and omniwheels used. The above pictured drive would have the ability to move forwards and backwards, and turn.

Lets go ahead and program movement for a tank drivetrain:

@TeleOp
public class DifferentialDrive extends LinearOpMode {
    @Override
    public void runOpMode() throws InterruptedException {
        // declare four motors for each of our wheels
        DcMotor frontLeft = hardwareMap.dcMotor.get("frontLeft");
        DcMotor frontRight = hardwareMap.dcMotor.get("frontRight");
        DcMotor backLeft = hardwareMap.dcMotor.get("backLeft");
        DcMotor backRight = hardwareMap.dcMotor.get("backRight");

        // reverse the right motors
        frontRight.setDirection(DcMotorSimple.Direction.REVERSE);
        backRight.setDirection(DcMotorSimple.Direction.REVERSE)

        waitForStart();

        if(isStopRequested()) return;

        while(opModeIsActive()) {
            frontLeft.setPower(gamepad.left_stick_y);
            backLeft.setPower(gamepad.left_stick_y);
            frontRight.setPower(gamepad.right_stick_y);
            backRight.setPower(gamepad.right_stick_y);
        }
    }
}

Holonomic

Most FTC teams use holonomic drives which allow for strafing.

mecanum drivetrain

The mecanum drive, as pictured above, is commonly used in FTC. This type of drive uses special mecanum wheels whose rollers are tilted at a 45° angle. When the wheels move in a specific arrangement, the drive strafes.

mecanum movement

Now let's write code for our mecanum drivetrain:

@TeleOp
public class MecanumDrive extends LinearOpMode {
    @Override
    public void runOpMode() throws InterruptedException {
        // declare four motors for each of our wheels
        DcMotor frontLeft = hardwareMap.dcMotor.get("frontLeft");
        DcMotor frontRight = hardwareMap.dcMotor.get("frontRight");
        DcMotor backLeft = hardwareMap.dcMotor.get("backLeft");
        DcMotor backRight = hardwareMap.dcMotor.get("backRight");

        // reverse the right motors
        frontRight.setDirection(DcMotorSimple.Direction.REVERSE);
        backRight.setDirection(DcMotorSimple.Direction.REVERSE)

        waitForStart();

        if(isStopRequested()) return;

        while(opModeIsActive()) {
            frontLeft.setPower(gamepad.left_stick_y);
            backLeft.setPower(gamepad.left_stick_y);
            frontRight.setPower(gamepad.right_stick_y);
            backRight.setPower(gamepad.right_stick_y);
            move(gamepad.left_stick_y, gamepad.left_stick_x, gamepad.right_stick_x);
        }

        public void move(double power, double strafe, double turn) {
            double denominator = Math.max(Math.abs(power) + Math.abs(strafe) + Math.abs(turn), 1);
            double frontLeftPower = (power + strafe + turn) / denominator;
            double backLeftPower = (power - strafe + turn) / denominator;
            double frontRightPower = (power - strafe - turn) / denominator;
            double backRightPower = (power + strafe - turn) / denominator;

            setDrivePowers(frontLeftPower, backLeftPower, frontRightPower, backRightPower);
        }

        public void setDrivePowers(double frontLeftPower, double backLeftPower, double frontRightPower, double backRightPower) {
            leftFront.setPower(frontLeftPower);
            leftRear.setPower(backLeftPower);
            rightFront.setPower(frontRightPower);
            rightRear.setPower(backRightPower);
        }
    }
}

The mecanum drivetrain allows for much more freedom of movement, and makes quick manuevers during the teleop period possible.