Arcade Drive

Now that we know how to create commands, let’s do something a little more useful. In this chapter we are going to create a command which will allow us to control the drive motors using a joystick.

The first step is to create the new class called ArcadeDriveCommand under the commands folder. Like we did with the DriveSubsystem, copy the ExampleCommand (make sure the copy is in the commands folder). Then change the name of the copy to ArcadeDriveCommand.java and in that file search and replace all instances of ExampleCommand with ArcadeDriveCommand. Also, since this command will be using the DriveSubsystem, replace all instances of ExampleSubsystem with DriveSubsystem. After you have done that you ArcadeDriveCommand.java file should look like:

Now since we are going to control the robot with the joystick, we are going to need access to the CommandJoystick class. We have already created an instance in the RobotContainer and we do not want to create a second instance here so we will pass in the CommandJoystick instance via the constructor:

Just like when we added a CommandJoystick reference in RobotContainer, add the import line for it using the “hover” trick.

Also, as we are doing with the DriveSubsystem parameter we have created a member variable m_joystick and initialized it in the constructor with the joystick argument so that we will have access to the CommandJoystick class for the life of this object.

Your code should look like this:

Now in the execute() function we need to read the joystick and set the power on the motors. Let’s start by just reading the value from the joystick, and make the robot drive forward and backwards using this value. The function to get the position of the joystick is getY() and we note that it returns a number from -1.0 to +1.0. Since the motors take their power setting in the same range, we can simply pass this on to the setPower(…) function of our DriveSubsystem class:

Your ArcadeDriveCommand.java file should now look like this:

To have the robot respond to joystick “stick” input, we don’t want to connect this command to a button like we did with the DriveForTimeCommand. We want this command to always run – to always look for input from “stick” – whenever no other command that requires the DriveSubsystem is running. To do this we add a setDefaultCommand(…) call to the constructor of our RobotContainer class:

Here we are creating an instance of our ArcadeDriveCommand class and setting it as the default command for the DriveSubsystem. With this set, the ArcadeDriveCommand will run whenever no other command that requires the DriveSubsystem is running. For example, if we were to now press the B1 button the ArcadeDriveCommand would be interrupted and the DriveForTimeCommand would execute. Once the DriveForTimeCommand ends, the ArcadeDriveCommand would be restarted and the robot would once again be under joystick control.

Your RobotContainer.java file should now look like:

Now run your program and you should be able to use the joystick to move the robot forward and backwards.

Of course, we are going to want to be able to turn our robot. How are we going to do that? To make the robot turn right, we want to run the left motor forward and the right motor backwards. To turn left we need to do the opposite. If we are going to use the X value from the joystick, we might accomplish this by changing the execute() function of our ArcadeDriveCommand class as follows:

Now this will enable the robot to turn, but it will no longer drive forward and backward. See if you can figure out how to change the execute() function to accomplish both driving forward and backward and turning. When you have your solution, compare it to the one below:

Don’t scroll down until you have tried to find your own solution!

.

.

.

You might find that controlling the robot, especially at low speeds is a bit tricky. There is a simple way that we can improve it. Right now if we were to graph the power we apply to the motors vs the X or Y of the joystick, we would just see a straight line. What we would like to do is curve the relationship so that we have more control over the lower speeds. We can do this by cubing the and Y values. Compare the linear (red) and cubic (blue) curves:

Notice that in both cases, we can still get full power out of the robot by pushing the joystick full over in one direction or another (this is because 1.0 * 1.0 * 1.0 is still equal to 1.0). However for joystick positions less than 1.0, we see that the power output increases much more slowly than the linear case, allowing for better control at the lower speeds. We can implement this change in our execute() function as follows:

Try it out and see if you don’t have better control over the robot.

Note that we could also just square the inputs which would result in a less drastic flattening of the curve. However if we wanted to use the square, we would need to take care to make sure that the sign was correct when X or Y becomes negative (remember that -1.0 * -1.0 is equal to +1.0). As an exercise, why don’t you see if you can come up with a solution that squares the inputs but still preserves the sign. You can then compare your solution to the one below:

.

.

.

.

As a final note, there is another way this may be accomplished by using the Math.abs function which returns the absolute value of a number.

By taking the absolute value and multiplying it by itself, we square the value but retain the sign. While this involves less typing it may or may be less intuitive.

Finally you can also do this using the Math.signum function which returns +1 if the number is positive and -1 if the number is negative.

These show that there are many correct ways to solve a problem given the tools Java provides…and in general!

Next: Wheel Encoders