用 Tank Drive 和 Joystick 操控机器人

A common use case is to have a joystick that should drive some actuators that are part of a subsystem. The problem is that the joystick is created in the RobotContainer class and the motors to be controlled are in the subsystem. The idea is to create a command that, when scheduled, reads input from the joystick and calls a method that is created on the subsystem that drives the motors.

在这个例子中,一个底盘子系统在一个用一对操纵杆的 tank drive 被运行。

建造一个 Drive Train Subsystem 。

../../../../../_images/driving-with-joysticks-subsystem.png

Create a subsystem called Drive Train. Its responsibility will be to handle the driving for the robot base.

../../../../../_images/driving-with-joysticks-differential-drive.png

Inside the Drive Train create a Differential Drive object for a two motor drive. There is a left motor and right motor as part of the Differential Drive class.

../../../../../_images/driving-with-joysticks-speed-controller-group.png

Since we want to use more then two motors to drive the robot, inside the Differential Drive, create two Speed Controller Groups. These will group multiple speed controllers so they can be used with Differential Drive.

../../../../../_images/driving-with-joysticks-speed-controller.png

Finally, create two Speed Controllers in each Speed Controller Group.

将 Joystick 添加到 Operator Interface。

../../../../../_images/driving-with-joysticks-joysticks.png

将两个操纵杆添加到 Operator Interface。其中一个为左杆,另一个为右杆。两个操纵杆的y轴是用来让机器人左右移动的。

注解

注意在继续下一步前用 C++ 或 Java 输出程序。

建造一个 Method 来在 Subsystem 中 Write the Motor。

public class Drivetrain extends SubsystemBase {

    // BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=DECLARATIONS
private PWMVictorSPX left1;
private PWMVictorSPX left2;
private SpeedControllerGroup leftMotor;
private PWMVictorSPX right1;
private PWMVictorSPX right2;
private SpeedControllerGroup rightMotor;
private DifferentialDrive drive;

    // END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=DECLARATIONS

    public Drivetrain() {
        // BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=CONSTRUCTORS
left1 = new PWMVictorSPX(0);
 addChild("left1",left1);
 left1.setInverted(false);

left2 = new PWMVictorSPX(1);
 addChild("left2",left2);
 left2.setInverted(false);

SpeedControllerGroup leftMotor = new SpeedControllerGroup(left1, left2  );
 addChild("Left Motor",leftMotor);


right1 = new PWMVictorSPX(5);
 addChild("right1",right1);
 right1.setInverted(false);

right2 = new PWMVictorSPX(6);
 addChild("right2",right2);
 right2.setInverted(false);

SpeedControllerGroup rightMotor = new SpeedControllerGroup(right1, right2  );
 addChild("Right Motor",rightMotor);


drive = new DifferentialDrive(leftMotor, left1);
 addChild("Drive",drive);
 drive.setSafetyEnabled(true);
drive.setExpiration(0.1);
drive.setMaxOutput(1.0);

    // END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=CONSTRUCTORS
    }

    // Put methods for controlling this subsystem
    // here. Call these from Commands.

    public void drive(double left, double right) {
        drive.tankDrive(left, right);
    }
}

创造一个可以获取操纵杆输入值的方法,在这个情况下是左和右操纵杆。这些值被传给 RobotDrive object ,然后用这些操纵杆值执行 tank steering 。并且创造一个名叫 stop() 的方法来使机器人停止行驶,这个之后迟早有用。

注解

Some RobotBuilder output has been removed for this example for clarity

读取 Joystick Values 和 Call the Subsystem Methods 。

../../../../../_images/driving-with-joysticks-command.png

Create a command, in this case called Tank Drive. Its purpose will be to read the joystick values and send them to the Drive Base subsystem. Notice that this command Requires the Drive Train subsystem. This will cause it to stop running whenever anything else tries to use the Drive Train.

注解

注意在继续下一步前用 C++ 或 Java 输出程序。

把这个代码加入到 Driving 中。

public class TankDrive extends CommandBase {

    // BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=VARIABLE_DECLARATIONS
        private final Drivetrain m_drivetrain;

    // END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=VARIABLE_DECLARATIONS

    private Joystick leftJoystick = RobotContainer.getInstance().getJoystick1();
    private Joystick rightJoystick = RobotContainer.getInstance().getJoystick2();

    // BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=CONSTRUCTORS


    public TankDrive(Drivetrain subsystem) {


    // END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=CONSTRUCTORS
        // BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=VARIABLE_SETTING

    // END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=VARIABLE_SETTING
        // BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=REQUIRES

        m_drivetrain = subsystem;
        addRequirements(m_drivetrain);

    // END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=REQUIRES
    }

    // Called when the command is initially scheduled.
    @Override
    public void initialize() {
    }

    // Called every time the scheduler runs while the command is scheduled.
    @Override
    public void execute() {
        m_drivetrain.drive(leftJoystick.getY(), rightJoystick.getY());
    }

    // Called once the command ends or is interrupted.
    @Override
    public void end(boolean interrupted) {
        m_drivetrain.drive(0.0, 0.0);
    }

    // Returns true when the command should end.
    @Override
    public boolean isFinished() {
        return false;
    }

    @Override
    public boolean runsWhenDisabled() {
        // BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=DISABLED
        return false;

    // END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=DISABLED
    }
}

把代码加入到执行方法中来真正执行运行。这只需要获取左右操纵杆的 Joystick object 然后传输给 Drive Train subsystem 。这个子系统只会将它们用于 RobotDrive object 中的 tank steering method 。然后我们就得到了 tank steering 。

We also filled in the end() method so that when this command is interrupted or stopped, the motors will be stopped as a safety precaution.

创建 Default Command 。

../../../../../_images/driving-with-joysticks-default-command.png

The last step is to make the Tank Drive command be the “Default Command” for the Drive Train subsystem. This means that whenever no other command is using the Drive Train, the Joysticks will be in control. This is probably the desirable behavior. When the autonomous code is running, it will also require the drive train and interrupt the Tank Drive command. When the autonomous code is finished, the DriveWithJoysticks command will restart automatically (because it is the default command), and the operators will be back in control. If you write any code that does teleop automatic driving, those commands should also “require” the DriveTrain so that they too will interrupt the Tank Drive command and have full control.

注解

确保在继续前把你的程序导出到 C++ 或 Java。