Arcade Drive

Now that we have our DriveSubsystem and know how to use it, let’s create an ArcadeDriveCommand which will allow us to use the joystick to drive the robot.

Please note that the Driver Station will only check for the presence of a joystick when it is started, so you need to plug in the joystick before launching the Driver Station. Also, if you do not have a joystick available, you can check the Enable Virtual Joystick checkbox and you will be presented with a ‘joystick’ that you can control by clicking and dragging with the mouse:


The first step is to create the new class called ArcadeDriveCommand under the commands folder, copy the ExampleCommand into it and replace ExampleCommand with ArcadeDriveCommand. When you have done this, your file should look like:

Now since this command will once again need to use the DriveSubsystem we will require it in our constructor:

We don’t need to do anything for the initialize() function so we will leave that unchanged.

The execute() function is where we are going to want to set the speed and direction of the motors based on the joystick input. Of course, in order to do that we are going to need to be able to get input from the joystick. Looking at the documentation, we see there is a Joystick class which we can use to do that. The first thing to do is to create a variable for the joystick and initialize it, which we do by adding the following to the top of the class:

Note that the joystick constructor requires an integer which specifies the joystick number. For the Rasbperry Pi, we only support a single joystick, but retain the parameter for compatibility with the FRC libraries.

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:

We don’t want this command to ever end, so we are going to continue to have the isFinished() function always return false.

Your file should now look like:

Now we need to somehow get this command to run. We could do what we did with our DriveForTimeCommand and start it at the beginning of Teleop in our teleopInit() function, but there is a better way. What we want is for the robot to remain under the ArcadeDriveCommand as long as it does not have other commands executing that require the DriveSubsystem. Fortunately, there is a simple way to do this.

If you remember when we created the DriveSubsystem we talked a little about the initDefaultCommand() function, saying that we would address that later. Well now is that later. What we can do in this function is to specify what command is to run when there are no other commands running that need this particular subsystem. We do this by adding the following code to initDefaultCommand().

Your file should now look like:

The final thing we need to do is remove the code from the teleopInit() function of our java class that starts the DriveForTimeCommand since we no longer want that to execute. After doing so, your file should look like:

Now deploy and run your program and enable Teleop. You should be able to drive your robot forward and backward using the joystick.

Now, 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:

Of course, 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:





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 and cubic 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:





Next: Connecting Commands to Joystick Buttons

