###### tags: `程式組教程` # Chassis Controller Mode(X) :::danger The DifferentialDrive class contains three different default modes of driving your robot’s motors. - **Tank Drive** ➨ which controls the left and right side independently. - **Arcade Drive** ➨ which controls a forward and turn speed. - ==**Curvature Drive**== ➨ a handle which control the velocity of the robot ,and another handle makes you follow a curved path turning. ::: ## TankDrive Basically, Tank Drive is a method which controled by two different Axis independently on a joystick. And the difference of velocity outputs on each side can make robot move forward and turn. Below begin with a example code which is not totally wrong. :::spoiler Example Code ```java= if(js1.getRawAxis(1) > 0 || js1.getRawAxis(1) < 0){ leftFront.set(ControlMode.PercentOutput, js1.getRawAxis(1)); //Motor.set(mode, value); //leftFront the motor's velocity will according to the axisY leftBack.set(ControlMode.PercentOutput, js1.getRawAxis(1)); //leftFront the motor's velocity will according to the percentagemovement of axisY }else{ //If the detection result of the Y-axis does not move leftFront.set(ControlMode.PercentOutput, 0 ); leftBack.set(ControlMode.PercentOutput, 0 ); //then set the vel of leftFront and leftBack as 0 } if(js1.getRawAxis(5) > 0 || js1.getRawAxis(5) < 0){ rightFront.set(ControlMode.PercentOutput, js1.getRawAxis(5)); rightBack.set(ControlMode.PercentOutput, js1.getRawAxis(5)); }else{ rightFront.set(ControlMode.PercentOutput, 0 ); rightBack.set(ControlMode.PercentOutput, 0 ); } ``` ::: </br> Alought the code above is exactly wrong, but it's too hard to read and understand. So it'll be much better after you rewrite in the way below. :::spoiler Better Code ```java= if(js1.getRawAxis(leftstick_Y) > 0 || js1.getRawAxis(leftstick_Y) < 0){ leftFront.set(ControlMode.PercentOutput, js1.getRawAxis(leftstick_Y)); leftBack.set(ControlMode.PercentOutput, js1.getRawAxis(leftstick_Y)); }else{ leftFront.set(ControlMode.PercentOutput, 0 ); leftBack.set(ControlMode.PercentOutput, 0 ); } if(js1.getRawAxis(rightstick_Y) > 0 || js1.getRawAxis(rightstick_Y) < 0){ rightFront.set(ControlMode.PercentOutput, js1.getRawAxis(rightstick_Y)); rightBack.set(ControlMode.PercentOutput, js1.getRawAxis(rightstick_Y)); }else{ rightFront.set(ControlMode.PercentOutput, 0 ); rightBack.set(ControlMode.PercentOutput, 0 ); } ``` ::: </br> what if we change into the method below it is much much more comfortable to program and even read and understand. ```java= if(js1.getRawAxis(leftstick_Y)){ leftFront.set(ControlMode.PercentOutput, js1.getRawAxis(leftstick_Y)); leftBack.set(ControlMode.PercentOutput, js1.getRawAxis(leftstick_Y)); } if(js1.getRawAxis(rightstick_Y)){ rightFront.set(ControlMode.PercentOutput, js1.getRawAxis(rightstick_Y)); rightBack.set(ControlMode.PercentOutput, js1.getRawAxis(rightstick_Y)); } ``` Alought we can just use the program above, in order to increase the programming speed we often use the function in WPILib just like below. ```java= // Tank drive with a given left and right rates Drive.tankDrive(js1.getRawAxis(leftstick_Y)*0.8, js1.getRawAxis(rightstick_Y)*0.8); //前面取DifferentialDrive的名字.tankDrive(leftSpeed, rightSpeed); ``` ## arcadeDrive using one joysick to control the robot,import the wpi function directly。 > The Arcade Drive mode is used to control the drivetrain using speed/throttle and rotation rate. This is typically used either with two axes from a single joystick, or split across joysticks (often on a single gamepad) with the throttle coming from one stick and the rotation from another. This example shows how to use a single joystick with the Arcade mode. ```java= // Arcade drive with a given forward and turn rate Drive.arcadeDrive(js1.getRawAxis(leftStick_Y)*0.8,js1.getRawAxis(rightStick_X)*0.8); //前面取DifferentialDrive的名字.arcadeDrive(Speed, Rotation); ``` ## curvatureDrive we won't use this ```java // Curvature drive with a given forward and turn rate, as well as a quick-turn button myDrive.curvatureDrive(-driveStick.getY(), driveStick.getX(), driveStick.getButton(1)); ``` > Curvature Drive mode is used to control the drivetrain using speed/throttle and rotation rate. The difference is that the rotation control input controls the radius of curvature instead of rate of heading change, much like the steering wheel of a car. This mode also supports turning in place, which is enabled when the third boolean parameter is true. ## mecanumDrive theory: Use the forward and reverse rotation of the four wheels to control the direction of movement ![](https://i.imgur.com/hFXkSTL.jpg) ![](https://i.imgur.com/OwBVdXl.jpg) > MecanumDrive is a method provided for the control of holonomic drivetrains with Mecanum wheels, such as the Kit of Parts chassis with the mecanum drive upgrade kit, as shown above. :::spoiler the code ``` java package frc.robot; import com.ctre.phoenix.motorcontrol.can.WPI_TalonSRX; import edu.wpi.first.wpilibj.Joystick; import edu.wpi.first.wpilibj.SpeedController; import edu.wpi.first.wpilibj.SpeedControllerGroup; import edu.wpi.first.wpilibj.TimedRobot; import edu.wpi.first.wpilibj.drive.DifferentialDrive; import edu.wpi.first.wpilibj.drive.MecanumDrive; import edu.wpi.first.wpilibj.smartdashboard.SendableChooser; import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; public class Robot extends TimedRobot { private static final String kDefaultAuto = "Default"; private static final String kCustomAuto = "My Auto"; private String m_autoSelected; private final SendableChooser<String> m_chooser = new SendableChooser<>(); public final int kFrontLeftChannel = 3; public final int kRearLeftChannel = 4; public final int kFrontRightChannel = 1; public final int kRearRightChannel = 2; public final int leftStick_X = 0; public final int leftStick_Y = 1; public final int rightStick_X = 4; public final int rightStick_Y = 5; public final int trigger_L = 2; public final int trigger_R = 3; public final int Btn_A = 1; public final int Btn_B = 2; public final int Btn_X = 3; public final int Btn_Y = 4; public final int Btn_LB = 5; public final int Btn_RB = 6; public final int Btn_LS = 9; public final int Btn_RS = 10; double ySpeed; double xSpeed; double zRotation; WPI_TalonSRX LeftFront = new WPI_TalonSRX(kFrontLeftChannel); WPI_TalonSRX LeftRear = new WPI_TalonSRX(kRearLeftChannel); WPI_TalonSRX RightFront = new WPI_TalonSRX(kFrontRightChannel); WPI_TalonSRX RightRear = new WPI_TalonSRX(kRearRightChannel); Joystick joystick = new Joystick(0); @Override public void robotInit() { RightFront.setInverted(true); RightRear.setInverted(true); LeftFront.setInverted(false); LeftRear.setInverted(false); } @Override public void robotPeriodic() { } @Override public void autonomousInit() { } @Override public void autonomousPeriodic() { } @Override public void teleopInit() { } @Override public void teleopPeriodic() { ySpeed = -joystick.getRawAxis(leftStick_Y) * -0.5; xSpeed = joystick.getRawAxis(leftStick_X)* -0.5; zRotation = joystick.getRawAxis(rightStick_X)* 0.5; LeftFront.set(ySpeed + xSpeed + zRotation); RightFront.set(ySpeed - xSpeed - zRotation); LeftRear.set(ySpeed - xSpeed + zRotation); RightRear.set(ySpeed + xSpeed - zRotation); } @Override public void disabledInit() { } @Override public void disabledPeriodic() { } @Override public void testInit() { } @Override public void testPeriodic() { } } ``` ::: :::spoiler using official function ```java= package frc.robot; import com.ctre.phoenix.motorcontrol.can.WPI_TalonSRX; import edu.wpi.first.wpilibj.Joystick; import edu.wpi.first.wpilibj.SpeedController; import edu.wpi.first.wpilibj.SpeedControllerGroup; import edu.wpi.first.wpilibj.TimedRobot; import edu.wpi.first.wpilibj.drive.MecanumDrive; import edu.wpi.first.wpilibj.smartdashboard.SendableChooser; import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; public class Robot extends TimedRobot { private static final String kDefaultAuto = "Default"; private static final String kCustomAuto = "My Auto"; private String m_autoSelected; private final SendableChooser<String> m_chooser = new SendableChooser<>(); public final int kFrontLeftChannel = 3; public final int kRearLeftChannel = 4; public final int kFrontRightChannel = 1; public final int kRearRightChannel = 2; public final int leftStick_X = 0; public final int leftStick_Y = 1; public final int rightStick_X = 4; public final int rightStick_Y = 5; public final int trigger_L = 2; public final int trigger_R = 3; public final int Btn_A = 1; public final int Btn_B = 2; public final int Btn_X = 3; public final int Btn_Y = 4; public final int Btn_LB = 5; public final int Btn_RB = 6; public final int Btn_LS = 9; public final int Btn_RS = 10; public MecanumDrive m_Drive; double ySpeed; double xSpeed; double zRotation; double chassisPower; WPI_TalonSRX m_frontLeft = new WPI_TalonSRX(kFrontLeftChannel); WPI_TalonSRX m_rearLeft = new WPI_TalonSRX(kRearLeftChannel); WPI_TalonSRX m_frontRight = new WPI_TalonSRX(kFrontRightChannel); WPI_TalonSRX m_rearRight = new WPI_TalonSRX(kRearRightChannel); Joystick joystick = new Joystick(0); WPI_TalonSRX LeftFront = new WPI_TalonSRX(0); WPI_TalonSRX LeftRear = new WPI_TalonSRX(1); SpeedControllerGroup LeftMotor = new SpeedControllerGroup(LeftFront, LeftRear); WPI_TalonSRX RightFront = new WPI_TalonSRX(2); WPI_TalonSRX RightRear = new WPI_TalonSRX(3); SpeedControllerGroup RightMotor = new SpeedControllerGroup(RightFront, RightRear); @Override public void robotInit() { double chassisPower = 0.5; m_Drive = new MecanumDrive(LeftFront, LeftRear, RightFront, RightRear); } @Override public void robotPeriodic() { } @Override public void autonomousInit() { } @Override public void autonomousPeriodic() { } @Override public void teleopInit() { } @Override public void teleopPeriodic() { if (joystick.getRawButton(6) || joystick.getRawButton(5)){ chassisPower = 1; } else { chassisPower = 0.5; } ySpeed = -joystick.getRawAxis(leftStick_Y) * chassisPower; xSpeed = joystick.getRawAxis(leftStick_X) * chassisPower; zRotation = joystick.getRawAxis(rightStick_X) * chassisPower; m_Drive.driveCartesian(ySpeed, -xSpeed, zRotation); } @Override public void disabledInit() { } @Override public void disabledPeriodic() { } @Override public void testInit() { } @Override public void testPeriodic() { } } ``` ::: 資料來源:https://docs.wpilib.org/en/stable/docs/software/actuators/wpi-drive-classes.html