Help setting up two joystick tank drive in Command Based


#1

So I only know arcade and tank drive in Timed base but since my team is adding pneumatic system to our robot, I wanted to organize more in my code so I made a command based project. However, the plan for driving the robot is using two flight sticks to move so the two left motors is connected to joystick 1 and two right motors connected to joystick 2. Here is what I have so far:

In OI, I set up my two joysticks which is set up at RobotMap.joystickPort0 in RobotMap.
OI.java

In RobotMap, I also set up the PMWs and USB.
RobotMap.java

In Robot.java, there’s nothing really set up yet except declaring the DriveSubsystem.
Robot.java

In DriveSubsystem, I did differential drive but stop cause I don’t know what to do next.
DriveSubsystem.java

I stopped at drivesubsystem since I do not know where to go on next. Could anyone help me, first time coding this year.

NOTE: Don’t mind everything set up on public, I thought putting it on public was good but it defeats the purpose of command base so just pretend that it’s private (which is already is in VSCode).


#2

You should attempt to make a drive command which uses methods from DriveSubsystem.java in order to control the robot via joysticks.
First, create a method in DriveSubsystem.java that is public and has two parameters – A forward/backward (drive), and a turn (rotate).
Pass those values onto the drive object.
Next, create the command and call that method in the execute(). Make sure isFinished() is always false.
Once you’ve created the command you’ll want to set it as the default command for the DriveSubsystem subsystem (you’ll probably only want to do this in this specific case, normally you want to avoid the initDefaultCommand() at all costs imo).

I’m assuming you have read WPILIB, however, if someone stumbles across this I’ll leave the link for them below. I’ll also shamelessly plug my teams GitHub

https://wpilib.screenstepslive.com/s/currentCS/m/java/l/599737-creating-simple-commands


(2017 code is decent-ish)


#3

Why do you say that? I almost always have some default command, like a “hold current position” for PID subsystems, or even just a “stop all motors” command. I find it’s easier to reason about what a subsystem is doing if I know there’s always exactly one command running. (modulo command group issues)

As for my two cents, I will shamelessly plug HYPERLib. That makes it easy to make a “drive command” right in the subsystem like this:

/** 
 * Method which returns a command that drives using the joysticks.
 */
public Command userDriveCmd() {
    return QuickCommand.continuous(() -> {
        drive.tankDrive(Robot.m_oi.flightStick1.getY(),
                        Robot.m_oi.flightStick2.getY());
    });
}

Then set it as default with setDefaultCommand(userDriveCmd()). The continuous method takes a function to run during execute, and makes a command which runs indefinitely.

If you don’t like the tight coupling you get from referencing the joysticks in the drive subsystem, you can make a “generic drive command” which takes DoubleSupplier's for the left and right parameters. Then you can pass different parameters to turn it into a “drive with joysticks” command, or a “drive at a constant rate command”, or even a “track vision targets” command. This is closer in spirit to what Kenny suggested, but imo is cleaner:

public Command driveCmd(DoubleSupplier left, DoubleSupplier right) {
    return QuickCommand.continuous(() -> {
        drive.tankDrive(left.getAsDouble(), right.getAsDouble());
    });
}

Then to get a “drive with joysticks” command, you pass in Robot.m_oi.flightStick1::getY and Robot.m_oi.flightStick2::getY.