POV Drive Programming

Hardware Setup

The hardware for this guide is the same as the hardware for the tank drive programming guide. We will be programming a simple robot driven by two DC Motors, one for the left wheel and one for the right wheel. My robot is using two REV Core Hex Motors that come with the Kit of Parts, but you can use any FTC legal DC Motor.

If you are using Java, this is starting hardware configuration code you will need. Replace “MyOpNodeName” with your OpMode’s name:

import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
import com.qualcomm.robotcore.hardware.DcMotor;

@TeleOp(name="MyOpNodeName")
public class MyOpNodeName extends LinearOpMode {
    DcMotor left;
    DcMotor right;

    @Override
    public void runOpMode() {
        // Put initialization blocks here.
        left = hardwareMap.dcMotor.get("left");
        right = hardwareMap.dcMotor.get("right");
        waitForStart();
        // Put run blocks here.
        while(opModeIsActive()) {
            //Loop code will go here
        }
    }
}

POV Drive

Concept

In the last guide, we wrote a tank drive program to control our robot with. While this is the simplest type of drive program, there are many other different ways we can drive the robot. One of the most popular methods is POV drive, also sometimes called arcade drive.

In tank drive, the driver uses the joysticks to independently control the left and right sides of the robot. However, in POV drive, the driver independently controls the forward-backwards motion of the robot (called the throttle) and the turning motion of the robot (called the steer). The throttle is typically controlled by moving the left joystick up and down (the y-axis) and the steer is typically controlled by moving the right joystick left and right (the x-axis).

POV drive is widely used because the controls are very easy for a driver to understand; one joystick moves the robot forward and backwards, the other joystick turns it. Also, while it involves a bit more code than tank drive, writing a simple POV drive program is not too difficult.  

Direction

Like in the tank drive programming guide, we have to configure the directions of our motors so that each motor has the same “forward”. With the way that the motors are mounted on my robot, I need to reverse the left motor so that both motors have the same direction. So, I add this code to the init section of my program:

left.setDirection(DcMotorSimple.Direction.REVERSE);
If you are using Blocks, the “set direction” block is under Actuators -> DcMotor in the toolbox.

Finding Throttle and Steer

Before we actually control our motors in our loop, we have to figure out what our throttle and steer values are based on the driver inputs. In our code, throttle will be controlled by moving the left joystick up and down (y-axis), and steer will be controlled by moving the right joystick left and right (x-axis). So, we can set store our throttle and steer values into new variables as shown:  

double throttle = -gamepad1.left_stick_y; double steer = gamepad1.right_stick_x;
If you are using Blocks, the variable creator and the “set to” block are under Variables. The gamepad blocks are all under Gamepad. The negate block (negative sign) is under Math.

Notice that we negated the y-axis value in this code by using a negative sign, since the y-axis on joysticks is reversed (as discussed in the tank drive guide).

Driving With Throttle

Now that we have variables containing our throttle and steer values, we can use these values to control the motors. At first, it may seem difficult to figure out how to combine these, so we will just focus on throttle first.

When our throttle variable equals 1, we want the robot to move forward, meaning that both motors will have to move forward at the same speed. To accomplish this, we can simply set each motor’s power to our throttle value. Update the code in your loop to look like this:

double throttle = -gamepad1.left_stick_y;
double steer = gamepad1.right_stick_x;
left.setPower(throttle);
right.setPower(throttle);
If you are using Blocks, the variable values are under Variables.

If you run this code on your robot, moving the left joystick forward should move the robot forward! When the left joystick is pushed forward, the y-axis value is -1. This makes our throttle variable equal 1, since we reverse the y-axis. Then, the throttle variable is used to set both motor powers to 1, which causes our robot to move forward.

If the robot is turning or moving backwards in instead of moving forward, try changing the directions of your motors in your init code.

Adding in Steer

Once you get your forward driving working, we can now add in the steering component.

To add steering to our motor control, we have to figure out if we want to add or subtract the steering variable from each motor. We can figure this out by using the most basic example:

If we want to turn right at full speed, we would move the right joystick to the right. This would result in a value of 1 on the x-axis, meaning that our steer would equal 1. In order to turn the robot right, we would want the left side to move forward (1) and the right side to move backwards (-1). So, to accomplish this, we would add our steer value to the left side and subtract it from the right side.

Now that we figured out whether to add or subtract our steer value in a basic example (turning right) we can write this into our code to apply it to all steering cases (turning left, turning slowly, turning while moving, etc). Modify your loop code so that the steer variable is correctly used to set the motor powers:

double throttle = -gamepad1.left_stick_y;
double steer = gamepad1.right_stick_x;
left.setPower(throttle - steer);
right.setPower(throttle + steer);
If you are using Blocks, the variable values are under Variables.

Notice that in our code, we still have the throttle variable in both of our motor set power statements. This means that, along with the turning functionality, the driving forward and backwards functionality will still work as before.

If you run this updated code on the robot, you should now have full drive functionality on the robot! Not only can you move and turn the robot independently with the joysticks, but you can also move the robot and turn at the same time.

The Full Code

import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
import com.qualcomm.robotcore.hardware.DcMotor;
import com.qualcomm.robotcore.hardware.DcMotorSimple;

@TeleOp(name="MyOpModeName")
public class MyOpModeName extends LinearOpMode {
  private DcMotor left;
  private DcMotor right;

  @Override
  public void runOpMode() {
    left = hardwareMap.dcMotor.get("left");
    right = hardwareMap.dcMotor.get("right");

    // Put initialization blocks here.
    left.setDirection(DcMotorSimple.Direction.REVERSE);
    waitForStart();
    if (opModeIsActive()) {
      // Put run blocks here.
      while (opModeIsActive()) {
        // Put loop blocks here.
        double throttle = -gamepad1.left_stick_y;
        double steer = gamepad1.right_stick_x;
        left.setPower(throttle + steer);
        right.setPower(throttle - steer);
        telemetry.update();
      }
    }
  }
}