PathPlanner: Visual Autonomous Routines

intermediate55 min

What is PathPlanner?

PathPlanner is a motion profile generator and autonomous path planning tool for FRC robots. It allows you to draw paths on a field map, configure robot constraints (max velocity, acceleration), and automatically generate smooth trajectories. It integrates seamlessly with WPILib via PathPlannerLib to follow these paths in code.

The modern workflow uses AutoBuilder, which automatically generates commands to follow paths and trigger event markers (like “Intake” or “Shoot”) defined in the GUI.

Learn more: PathPlanner Documentation | PathPlannerLib API

Key Concepts

Path: A single trajectory from point A to point B, with waypoints and rotation targets. (PathPlannerPath API)

Auto: A full autonomous routine consisting of multiple paths and commands (e.g., “Score -> Taxi -> Balance”).

Event Markers: Triggers placed along a path that execute commands (like running an intake) when the robot reaches that point. (NamedCommands API)

Holonomic Mode: For swerve/mecanum drives, allows the robot to rotate independently of its movement direction.

AutoBuilder: A utility that builds a full “Command” from a PathPlanner file, handling path following, event markers, and telemetry automatically. (AutoBuilder API)

Configuring AutoBuilder

To use PathPlanner, you must configure AutoBuilder in your “RobotContainer” or “Drivetrain” subsystem. This tells PathPlanner how to control your robot and where it is. See AutoBuilder Configuration Documentation.

AutoBuilder Configuration (Swerve)

Current PathPlannerLib uses AutoBuilder.configure() with a PPHolonomicDriveController and a RobotConfig describing the drivetrain’s physical properties. Older guides show configureHolonomic() with HolonomicPathFollowerConfig and ReplanningConfig — those types no longer exist.

import com.pathplanner.lib.auto.AutoBuilder;
import com.pathplanner.lib.config.ModuleConfig;
import com.pathplanner.lib.config.PIDConstants;
import com.pathplanner.lib.config.RobotConfig;
import com.pathplanner.lib.controllers.PPHolonomicDriveController;
import com.pathplanner.lib.pathfinding.Pathfinding;

public class Drive extends SubsystemBase {
    // Physical description of the robot, used for PathPlanner's feedforward
    private static final RobotConfig PP_CONFIG = new RobotConfig(
            PathPlannerConstants.ROBOT_MASS_KG,      // total robot mass, kg
            PathPlannerConstants.ROBOT_MOI,          // moment of inertia, kg*m^2
            new ModuleConfig(
                    TunerConstants.FrontLeft.WheelRadius,
                    TunerConstants.kSpeedAt12Volts.in(MetersPerSecond),
                    PathPlannerConstants.WHEEL_COF,  // wheel coefficient of friction
                    DCMotor.getKrakenX60(1)
                            .withReduction(TunerConstants.FrontLeft.DriveMotorGearRatio),
                    TunerConstants.FrontLeft.SlipCurrent,
                    1),                              // motors per module
            getModuleTranslations());

    public Drive(/* ... */) {
        // ... hardware init ...

        // API: AutoBuilder.configure() - https://pathplanner.dev/api/java/com/pathplanner/lib/auto/AutoBuilder.html
        AutoBuilder.configure(
                this::getPose,           // Supplier<Pose2d> current robot pose
                this::setPose,           // Consumer<Pose2d> reset the pose
                this::getChassisSpeeds,  // Supplier<ChassisSpeeds> robot-relative speeds
                this::runVelocity,       // Consumer<ChassisSpeeds> output for driving
                new PPHolonomicDriveController(
                        new PIDConstants(5.0, 0.0, 0.0),  // Translation PID
                        new PIDConstants(5.0, 0.0, 0.0)), // Rotation PID
                PP_CONFIG,
                // Flip the path for the red alliance. The origin stays on the blue side.
                () -> DriverStation.getAlliance().orElse(Alliance.Blue) == Alliance.Red,
                this // Reference to this subsystem to set requirements
        );
    }
}

Keep RobotConfig honest

RobotConfig is how PathPlanner predicts what the robot will do. Mass, moment of inertia, and wheel coefficient of friction all feed its feedforward.

A mass left over from last season’s robot produces consistent tracking error on every path — and it looks exactly like badly tuned PID, so teams often spend a practice session tuning gains to compensate for a wrong number. Update it when the robot’s weight changes.

Warmup and Pathfinding

Two additions worth making once the basics work.

Warmup. The first path of autonomous otherwise pays a one-time class-loading cost while the match clock is running. Schedule the warmup commands at startup to pay it before the match instead:

// In the Robot constructor
FollowPathCommand.warmupCommand().schedule();
PathfindingCommand.warmupCommand().schedule();

Pathfinding with AdvantageKit. PathPlanner’s default pathfinder runs on a background thread, which makes log replay non-deterministic. Teams using AdvantageKit swap in a logged wrapper:

Pathfinding.setPathfinder(new LocalADStarAK());

LocalADStarAK routes the pathfinder’s results through the logger so a replay follows the same path the robot did. It is a single file, published by PathPlanner’s author — see the gist.

You can also log the active path and target pose so they appear in AdvantageScope:

PathPlannerLogging.setLogActivePathCallback(
        (activePath) -> Logger.recordOutput("Odometry/Trajectory", activePath.toArray(new Pose2d[0])));
PathPlannerLogging.setLogTargetPoseCallback(
        (targetPose) -> Logger.recordOutput("Odometry/TrajectorySetpoint", targetPose));

Creating and Running Paths

Once configured, you can load paths or full autos by name. PathPlanner files are deployed to the robot’s “deploy/pathplanner” directory.

Loading Paths

// In RobotContainer.java

// API: AutoBuilder.buildAuto() - https://pathplanner.dev/api/java/com/pathplanner/lib/auto/AutoBuilder.html#buildAuto(java.lang.String)
// Build an auto command from a named "Auto" file in the GUI
Command myAuto = AutoBuilder.buildAuto("My Two Piece Auto");

// API: AutoBuilder.followPath() - https://pathplanner.dev/api/java/com/pathplanner/lib/auto/AutoBuilder.html#followPath(com.pathplanner.lib.path.PathPlannerPath)
// API: PathPlannerPath.fromPathFile() - https://pathplanner.dev/api/java/com/pathplanner/lib/path/PathPlannerPath.html#fromPathFile(java.lang.String)
// Or, follow a single path
Command followPath = AutoBuilder.followPath(PathPlannerPath.fromPathFile("Taxi Path"));

// API: AutoBuilder.buildAutoChooser() - https://pathplanner.dev/api/java/com/pathplanner/lib/auto/AutoBuilder.html#buildAutoChooser()
// Add to SmartDashboard chooser
SendableChooser<Command> autoChooser = AutoBuilder.buildAutoChooser();
SmartDashboard.putData("Auto Chooser", autoChooser);

Event Markers and Named Commands

To use Event Markers, you must register your commands with NamedCommands before building the auto. This maps the string names in the PathPlanner GUI to actual Java commands. See Event Markers Documentation.

Registering Named Commands

import com.pathplanner.lib.auto.NamedCommands;
import edu.wpi.first.wpilibj2.command.InstantCommand;

public class RobotContainer {
    public RobotContainer() {
        // API: NamedCommands.registerCommand() - https://pathplanner.dev/api/java/com/pathplanner/lib/auto/NamedCommands.html#registerCommand(java.lang.String,edu.wpi.first.wpilibj2.command.Command)
        // Register Named Commands
        NamedCommands.registerCommand("intake", new IntakeCommand(m_intake));
        NamedCommands.registerCommand("shoot", new ShootCommand(m_shooter));
        NamedCommands.registerCommand("stop", new InstantCommand(m_intake::stop, m_intake));

        // Now build the auto
        autoChooser = AutoBuilder.buildAutoChooser();
    }
}

PathPlanner Tips

Best practices for success:

  • Always measure your robot’s max velocity and acceleration accurately.
  • Use ‘On-the-fly’ generation for dynamic pathing if needed, but pre-generated paths are safer.
  • Visualize path following in AdvantageScope or Field2d to debug tracking errors.
  • Remember to register NamedCommands before building the auto chooser.
  • Schedule the warmup commands at startup so the first path does not stutter.
  • Keep the robot mass in RobotConfig current.

Resources