Project 2 — Deploy a Real Arcade-Drive Program
Write, deploy, and drive a TimedRobot arcade-drive program on an AM14U6 chassis using an Xbox controller.
Sign in to track progress, earn XP, and save lessons.
Now we give the robot a brain. This is the canonical WPILib drivetrain example, the same pattern in the official Zero-to-Robot guide, adapted to PWM SPARK MAX outputs so it works on any KitBot wiring.
Create a new project in WPILib VS Code (Ctrl+Shift+P -> 'WPILib: Create a new project' -> Example -> java -> Getting Started). Replace Robot.java with:
package frc.robot;
import edu.wpi.first.wpilibj.TimedRobot;
import edu.wpi.first.wpilibj.XboxController;
import edu.wpi.first.wpilibj.drive.DifferentialDrive;
import edu.wpi.first.wpilibj.motorcontrol.PWMSparkMax;
public class Robot extends TimedRobot {
private final PWMSparkMax m_leftDrive = new PWMSparkMax(0);
private final PWMSparkMax m_rightDrive = new PWMSparkMax(1);
private final DifferentialDrive m_robotDrive =
new DifferentialDrive(m_leftDrive::set, m_rightDrive::set);
private final XboxController m_controller = new XboxController(0);
public Robot() {
m_rightDrive.setInverted(true); // right side spins opposite
}
@Override
public void teleopPeriodic() {
// left stick Y = forward/back, right stick X = turn
m_robotDrive.arcadeDrive(-m_controller.getLeftY(),
-m_controller.getRightX());
}
}
The modern DifferentialDrive constructor takes two DoubleConsumer outputs, so m_leftDrive::set and m_rightDrive::set (method references) are exactly what it expects.
Why the negatives? On an Xbox controller, pushing the stick forward returns a negative Y value. Negating it makes 'stick forward' equal 'robot forward'. arcadeDrive(xSpeed, zRotation) takes forward speed and rotation, both on [-1, 1].
Why setInverted(true) on the right? The two gearboxes face opposite directions, so a positive command would drive them apart. Inverting the right side makes both sides push forward together. If your robot spins in place instead of driving straight, this flag is almost always the culprit.
Deploy: Connect to the robot radio over Wi-Fi (or USB to the roboRIO), then Ctrl+Shift+P -> 'WPILib: Deploy Robot Code'. Watch the RioLog — you want to see 'Robot program starting'. Open the Driver Station, enable Teleop, and drive. Note that DifferentialDrive has Motor Safety enabled, so you must call arcadeDrive every loop or the motors will time out and stop.
A safety habit: test on blocks first (wheels off the ground). Start at low stick deflection. Map a 'slow mode' later by multiplying the inputs by 0.5 when a bumper is held. This single example — two motor controllers, one DifferentialDrive, one controller — is the foundation every drivetrain builds on.
Key takeaways
- arcadeDrive(xSpeed, zRotation) takes forward speed and rotation, each on [-1, 1]
- Negate Xbox stick Y because forward returns negative; invert one drive side so both push forward
- DifferentialDrive uses Motor Safety — call arcadeDrive every loop, test on blocks, and watch the RioLog for 'Robot program starting'
Go deeper
Lesson quiz
RequiredAnswer all 3 questions correctly to complete this lesson.
1.In WPILib's DifferentialDrive.arcadeDrive(xSpeed, zRotation), what do the two arguments represent?
2.Why is a joystick's Y-axis value typically negated before being passed to arcadeDrive?
3.To avoid a Motor Safety timeout that stops your drivetrain, how must arcadeDrive be called?
Answer every question to submit.