Lesson 4: Getting Joystick Input

Making a motor spin is great, but we need to be able to link the speed of the motor with a joystick on a controller. For this, we can use the Joystick class.

First, let's declare our Joystick:

Joystick j;

and instantiate it in the robotInit() method:

j = new Joystick(0);

The Joystick constructor takes one parameter: the port the gamepad is mapped to in the Driver Station software. Normally we start counting at 0, so I have assigned my gamepad to port 0.

Getting the actual input from the joystick can be a little tricky. This is due to the Joystick class not giving human names to all of the axes and buttons. Each axis and button on the controller has a special ID. Here are two tables of all the IDs for a Logitech F310 Gamepad, which is the most widely used controller:

Axis ID
Left Stick X 0
Left Stick Y 1
Right Stick X 4
Right Stick Y 5
Left Trigger 2
Right Trigger 3
Button ID
Button A 1
Button B 2
Button X 3
Button Y 4
Left Bumper 5
Right Bumper 6
Back 7
Start 8
Left Stick 9
Right Stick 10

Whew! You may have noticed that the D-pad is missing. We will get to that later. Lets put these IDs into practice. Check out the following code:

boolean isPressed = j.getRawButton(1);
double axisValue = j.getRawAxis(1);

See if you can figure out what is happening here. The value of isPressed will be true if the A button is pressed, and false if it is not pressed. The value of axisValue depends on where the Y axis on the left stick is being pushed. Axis values run from -1 to 1, just like motor controllers do. When the Axis is in the center, getRawAxis() will return 0. This way, we can feed joystick input directly into the set() method of a motor controller. Let's revisit the motor controller code we made in the last lesson:

public class MyRobot extends IterativeRobot {

    Talon left;
    Talon right;

    public void robotInit() {
        left = new Talon(0);
        right = new Talon(1);
    }

    public void teleopPeriodic() {
        left.set(0.2);
        right.set(0.2);
    }
}

Without looking at the next code block, see if you can update this code to use the left and right sticks to control the motors. This is called tank drive.

So, remember how I said you can feed joystick input directly into a motor controller? Here is what it would look like to control the left motor with the Y axis on the left stick:

left.set(j.getRawAxis(1));

Can you complete the tank drive code now? Here is my completed tank drive code:

public class MyRobot extends IterativeRobot {

    Talon left;
    Talon right;
    Joystick j;

    public void robotInit() {
        left = new Talon(0);
        right = new Talon(1);
        j = new Joystick(0);
    }

    public void teleopPeriodic() {
        left.set(j.getRawAxis(1));
        right.set(j.getRawAxis(5));
    }
}

Remember: you may need to add negatives for motors that are mounted backwards.

I said I would save the D-pad for later... well it's later. The WPI Java Library considers the D-pad to be a "POV." The Logitech F310 only has one POV, so the ID of the D-pad is 0. If we had a controller with more POVs, their IDs would be 1, then 2, and so on. In order to get input from the D-pad, we use the getPOV() method.

int dpadDirection = j.getPOV(0);

What? How do I use that? Well, getPOV() returns the angle of the POV in degrees, or -1 if the POV is not pressed. This can be challenging if we are trying to use the D-pad as a simple button. We can interpret this angle to see what button on the D-pad is pressed. Here are some examples:

int direction = j.getPOV(0);

if (direction == 0) { // DPAD UP button is pressed
  // do something
} else if (direction == 180) { // DPAD DOWN button is pressed
  // do something else
}

// You can interpret the D-pad as an axis as well:
double dpadYAxisValue = Math.cos(Math.toRadians(direction));
double dpadXAxisValue = Math.sin(Math.toRadians(direction));

someMotorController.set(dpadYAxisValue);

0° is located at the top of the D-pad, and the angles rotate clockwise like this:

Exercises

You may be thinking to yourself: this Joystick class is dumb! How am I going to remember all of those IDs? And why does the D-pad have to be so weird? Well, I think the exact same thing. That's why I recommend using Code Red's Robot Library. If you are using the Robot Library, go ahead and read the next section. Otherwise, go on to the next lesson.


Using Code Red's Robot Library

Our Robot Library has a very expansive package for getting gamepad input. We are not going to worry about the finer details of this package in this lesson, but I do want to cover the basics as using our library is arguably easier than using the Joystick class.

Our library has a HID class which manages all the controller input. Here is how you can create a HID object.

HID gamepad1 = new HID(0);

Just as in the Joystick class, the constructor takes an integer representing the port that the gamepad is mapped to in the Driver Station software.

In order to hide the arbitrary numbers of the Joystick class, we made several classes that assign human names to these numbers. We have classes for a few different kinds of controllers, including:

Here is how you use the LogitechF310 class to get axis/button input:

HID gamepad1 = new HID(0);

boolean isPressed = gamepad1.button(LogitechF310.A);
double axisValue = gamepad1.axis(LogitechF310.STICK_LEFT_Y);

In the last code snippet, isPressed is true if the A button is pressed and false if it is not pressed. Also, axisValue depends on where the Y axis on the left stick is currently at. This also works for the D-pad:

boolean left = gamepad1.button(LogitechF310.DPAD_LEFT);
boolean right = gamepad1.button(LogitechF310.DPAD_RIGHT);
boolean up = gamepad1.button(LogitechF310.DPAD_UP);
boolean down = gamepad1.button(LogitechF310.DPAD_DOWN);

You should know what that does. For your reference, here is a list of all the button/axis names in our library:

Axes:

Buttons:

Alright, that is enough for now. As I have already mentioned, this is not a comprehensive list of features of our HID class, and we will cover this more later.