Skip to content
FRC Article 12 min read

Choreo vs PathPlanner: Planning FRC Autonomous Trajectories

Compare Choreo and PathPlanner for FRC autonomous trajectories: how Choreo's time-optimal solver differs from PathPlanner's GUI paths, and when to use each.

to read
12 min

to read

words
2,529

words

sections
8

sections

Every FRC match starts with fifteen seconds where nobody touches a controller. Those autonomous seconds decide a shocking number of matches, and almost all of that scoring comes down to one thing: can your robot drive a planned route accurately and repeatably without a human in the loop? That is the job of a trajectory — a time-parameterized plan of where the robot should be, how fast it should be moving, and which way it should be facing at every instant.

Two tools dominate how modern FRC teams build those trajectories: PathPlanner and Choreo. They solve the same end problem — get a swerve (or tank) drive to follow a smooth, physically achievable route — but they get there from opposite directions. PathPlanner hands you a GUI where you draw waypoints and tune constraints. Choreo asks for your robot's physical limits and a few guide points, then mathematically solves for the fastest trajectory that respects them. This guide breaks down how each works, how they plug into WPILib command-based code and swerve odometry, and how to decide which one (or both) belongs in your codebase.

What "following a trajectory" actually means

A trajectory is not just a line on the field. It is a schedule. At t = 0.42 s the robot should be at (3.1 m, 5.4 m), traveling 2.8 m/s at heading 120°, and so on for the whole path. Following it well requires three things working together:

  • A trajectory file — the sampled sequence of states, generated offline by PathPlanner or Choreo.
  • Odometry / pose estimation — the robot's live estimate of where it actually is, fused from wheel encoders, the gyro, and often vision. If your pose estimate drifts, even a perfect trajectory follows badly. See pose estimation for the underlying math.
  • A closed-loop controller — usually a holonomic drive controller that compares the desired state against the measured pose each loop and nudges the drivetrain to close the error.

The trajectory tells the robot where it should be; odometry tells it where it is; the controller drives the difference to zero. Weakness in any of the three shows up as a robot that misses its mark. A great trajectory cannot rescue bad odometry.

Both tools generate the file. Both lean on WPILib for the controller. The interesting differences are in how the file gets made and how much of the following logic each tool wraps for you.

PathPlanner: draw it, mark it, build it

PathPlanner, created by Michael Jansen of FRC team 3015, is a standalone GUI plus a vendor library (PathPlannerLib). You place Bezier waypoints on a field image, drag control handles to shape the curve, and set per-path or per-waypoint constraints — max velocity, max acceleration, max angular velocity, and (for swerve) an independent target heading at each point. It supports both holonomic (swerve) and differential (tank) drivetrains.

Three features make it the default choice for many teams:

  • AutoBuilder — one-time configuration that wires PathPlannerLib to your drivetrain so it can build follow commands and full autos for you.
  • Event markers — points along a path that trigger commands (spin up a shooter, drop an intake) while the robot keeps driving.
  • Named commands — you register commands by string name in code; the GUI references those names on markers and in autos, so non-programmers can assemble routines visually.

Wiring PathPlanner into command-based code

You configure AutoBuilder once, typically in RobotContainer after subsystems exist, and register any named commands before any auto or path is loaded. This snippet is current for PathPlannerLib 2026:

public RobotContainer() {
  // Register named commands BEFORE building any autos/paths.
  NamedCommands.registerCommand("shoot", shooter.shootCommand());
  NamedCommands.registerCommand("intake", intake.deployCommand());

  AutoBuilder.configure(
      drivetrain::getPose,                 // Supplier<Pose2d> from odometry
      drivetrain::resetPose,               // Consumer<Pose2d> to seed odometry
      drivetrain::getRobotRelativeSpeeds,  // Supplier<ChassisSpeeds>
      (speeds, feedforwards) -> drivetrain.driveRobotRelative(speeds),
      new PPHolonomicDriveController(       // holonomic controller for swerve
          new PIDConstants(5.0, 0.0, 0.0),  // translation PID
          new PIDConstants(5.0, 0.0, 0.0)), // rotation PID
      RobotConfig.fromGUISettings(),        // mass, MOI, module config from GUI
      () -> DriverStation.getAlliance()     // mirror path for red alliance
          .orElse(Alliance.Blue) == Alliance.Red,
      drivetrain);

  // Build a chooser populated with every auto in the project.
  autoChooser = AutoBuilder.buildAutoChooser();
  SmartDashboard.putData("Auto", autoChooser);
}

From there, new PathPlannerAuto("My Auto") returns a ready-to-schedule command built from a .auto file you assembled in the GUI, and autoChooser.getSelected() gives you the dashboard-selected routine to return from getAutonomousCommand(). Note that RobotConfig.fromGUISettings() pulls your robot's mass, moment of inertia, and module geometry straight from the GUI's settings, so PathPlannerLib can respect swerve dynamics at follow time.

Load paths and autos at startup, not inside getAutonomousCommand(). Reading and deserializing trajectory files is a blocking operation, and doing it as the match begins can cost you real time on the field.

On-the-fly pathfinding

PathPlanner's standout runtime feature is pathfinding: AutoBuilder.pathfindToPose(...) generates a path to an arbitrary target pose during the match, routing around a set of navigation obstacles using an implementation of the AD* (LocalADStar) search algorithm. This is what powers "drive to the nearest scoring location" style commands where you cannot pre-plan the exact start. Choreo cannot do this — its solver runs offline only.

PathPlanner also ships a version of FRC team 254's SwerveSetpointGenerator, which constrains commanded module setpoints to what the motors can physically deliver given available torque — useful whether or not you use PathPlanner's trajectories.

For a deeper walk-through of the PathPlanner GUI and autos, see the PathPlanner autonomous guide.

Choreo: solve for the fastest physically possible path

Choreo, from the SleipnirGroup, takes a fundamentally different stance. Instead of you drawing a path and hoping the robot can follow it, you specify the robot's physical characteristics — mass, moment of inertia, wheel radius, max motor speed and torque, track dimensions — plus a handful of waypoints and constraints (be at this pose, keep velocity under this value here, stop at the end). Choreo then runs a numerical trajectory optimization (built on the Sleipnir solver) to compute the time-optimal trajectory: the mathematically fastest route that never asks a module to exceed its real limits.

The practical payoff: because the output already respects your drivetrain's dynamics, the robot can usually follow a fresh Choreo trajectory accurately on the first try, with far less of the "generate, test, tweak, repeat" loop that hand-drawn paths often require. Choreo is bundled with the WPILib installer (look for the "Choreo" app in your WPILib Tools folder), so you likely already have it.

ChoreoLib: loading and following

The runtime side is ChoreoLib, added as a vendor dependency. For the current season that JSON URL is https://choreo.autos/lib/ChoreoLib2026.json. Choreo deliberately leaves the how you follow a sample step to you — it hands you SwerveSample (or DifferentialSample) objects describing the desired state at each timestep, and you apply them with your own controller. That openness lets you add telemetry hooks or vendor features like CTRE's wheel-force feedforwards.

ChoreoLib's higher-level Java API is the AutoFactory / AutoRoutine system, which layers triggers and command composition on top of trajectory following. You build an AutoFactory once (giving it your pose supplier, an odometry-reset consumer, your follow function, an alliance-mirror flag, and the drive subsystem), then compose routines:

AutoRoutine routine = factory.newRoutine("FourPiece");
AutoTrajectory startToNote = routine.trajectory("StartToNote");

// Reset odometry to the trajectory's start, then drive it.
routine.active().onTrue(
    Commands.sequence(startToNote.resetOdometry(), startToNote.cmd()));

// Trigger a command at a named event marker inside the trajectory.
startToNote.atTime("intake").onTrue(intake.deployCommand());

// Chain the next trajectory when this one finishes.
startToNote.done().onTrue(routine.trajectory("NoteToShoot").cmd());

Key AutoTrajectory triggers are active() (while running), done() (one cycle after it finishes), and atTime("marker") / atTime(seconds) for event markers — Choreo's equivalent of PathPlanner's markers. The exact AutoFactory constructor and a couple of helper names have shifted across seasons, so check the ChoreoLib docs for the version you have installed before copying a constructor call.

Load every trajectory at robot startup, not when auto begins. On a roboRIO, deserializing a large trajectory can take multiple seconds — enough to eat much of your autonomous window if you defer it.

Because you write the follow function yourself, Choreo integrates cleanly with whatever command-based structure and pose estimator you already run. Your followTrajectory(SwerveSample sample) typically reads the sample's target pose and field-relative speeds, adds a WPILib PIDController correction per axis against your live pose, and hands the resulting ChassisSpeeds to the drivetrain.

Head-to-head comparison

DimensionPathPlannerChoreo
Core approachYou draw the path; the tool profiles itYou give constraints; the solver computes the path
Editing modelBezier waypoints, drag handles, per-point headingsGuide waypoints + explicit physical/kinematic constraints
OptimizationRespects swerve dynamics, but not guaranteed time-optimalTrue time-optimal solve for the given constraints
Runtime generationYes — on-the-fly pathfinding (AD*) to any poseNo — offline generation only
Event handlingEvent markers + registered named commandsatTime triggers + bind on the AutoFactory
WPILib integrationAutoBuilder wraps most follow logic for youYou implement the follow step (more control)
DrivetrainsHolonomic (swerve) and differentialHolonomic (swerve) and differential
Learning curveGentle; very visual; great for newer teamsSteeper; requires accurate robot characterization

The single sharpest distinction: PathPlanner gives you control, Choreo gives you optimality. With PathPlanner you can draw a path your robot physically cannot follow, then spend practice time discovering that. With Choreo you cannot draw an impossible path — the solver simply won't produce one — but you also give up the fine-grained "make it go exactly here in exactly this shape" control, and you must feed it an honest model of your robot.

A telling data point from the community: FRC 3015, the team that created PathPlanner, has publicly said they run Choreo for their own trajectories. That is not a knock on PathPlanner — it reflects that once you trust your robot model, time-optimal paths are hard to beat.

When to use which

Reach for PathPlanner when:

  • You are a newer team and want a fast, visual, forgiving path to a working autonomous.
  • You need runtime pathfinding — drive-to-pose, dynamic obstacle avoidance, or auto-align that can't be pre-planned.
  • You want the library to handle the follow loop, auto chooser, and named-command wiring with minimal code.

Reach for Choreo when:

  • Autonomous cycle time is a competitive priority and every tenth of a second matters.
  • You have characterized your robot well (accurate mass, MOI, and module data) and can trust the model.
  • You want trajectories that just work on the first run, minimizing on-field tuning.

For many teams the honest answer early in the season is PathPlanner (to move fast), then Choreo once the robot is characterized and you're squeezing out cycle time.

Using them together

You do not have to pick one forever. PathPlanner explicitly supports Choreo interop: you can generate a time-optimal trajectory in Choreo and load it into PathPlannerLib as a path, then follow it with all of AutoBuilder's plumbing and markers. The API is PathPlannerPath.fromChoreoTrajectory("Trajectory Name"), with an overload that takes a split index for Choreo trajectories broken into segments:

PathPlannerPath choreoPath =
    PathPlannerPath.fromChoreoTrajectory("SprintToStage");
PathPlannerPath choreoSegment =
    PathPlannerPath.fromChoreoTrajectory("SprintToStage", 1); // split index

This is a genuinely nice hybrid: Choreo does the hard optimization for the long, speed-critical drives, while PathPlanner handles auto assembly, event markers, the dashboard chooser, and runtime pathfinding for the align-and-score moments. A common pattern is Choreo for the pre-planned scoring runs and PathPlanner pathfindToPose for the reactive endgame.

Integration with swerve and odometry

Whichever tool you pick, the following loop is only as good as your pose estimate. Both PathPlanner and Choreo assume you feed them a trustworthy pose each cycle and expect to reset odometry to the trajectory's starting pose at the beginning of a routine (resetPose / resetOdometry above). Practical must-dos:

  • Seed pose at auto start. Reset odometry to the trajectory's initial pose so the controller isn't fighting a large initial error. Both tools expose a first-action reset for exactly this.
  • Handle alliance mirroring once. Both provide an alliance-flip flag so a single blue-side trajectory mirrors correctly on red. Wire it in one place and let the library flip.
  • Fuse vision carefully. If you add AprilTag vision to your estimator, add measurements with sane standard deviations so a noisy frame doesn't yank the robot mid-path. The trajectory follower will chase whatever pose you give it.
  • Match units and conventions. WPILib uses meters and a field coordinate frame with counter-clockwise-positive rotation. Both tools follow this; mixing in degrees or a flipped axis is the classic "robot drives into the wall" bug.

You can validate almost all of this before the robot exists on the field by running it in WPILib simulation — watch the commanded trajectory and the simulated pose track together in the sim GUI, and you'll catch reset, mirroring, and unit bugs on your laptop instead of on the practice field.

Frequently asked questions

Is Choreo better than PathPlanner?

Neither is universally better — they optimize for different things. Choreo produces time-optimal trajectories that follow well on the first try, while PathPlanner offers visual editing, runtime pathfinding, and a fuller library that wraps the follow loop for you. Many strong teams use both.

Can I use Choreo trajectories inside PathPlanner?

Yes. PathPlannerLib provides PathPlannerPath.fromChoreoTrajectory("name") (with a split-index overload) to load a Choreo-generated trajectory as a PathPlanner path, so you get Choreo's optimization plus PathPlanner's AutoBuilder, event markers, and chooser.

Does Choreo or PathPlanner work with tank drive?

Both support differential (tank) drivetrains as well as holonomic swerve. ChoreoLib exposes DifferentialSample and PathPlanner supports differential path following, though the ecosystem's momentum and most examples center on swerve.

Why does my robot follow the path poorly even though the trajectory looks right?

Almost always odometry, not the trajectory. If your pose estimate drifts or starts at the wrong place, the follower chases a bad reference. Verify you reset odometry to the start pose, that your gyro and encoder conversions are correct, and that vision measurements aren't destabilizing the estimate.

Do I need to characterize my robot for Choreo?

Yes — that's the point. Choreo's solver needs accurate mass, moment of inertia, wheel radius, and motor limits to compute a trajectory your robot can actually execute. Garbage in, garbage out: a wrong model yields a trajectory that looks optimal but the robot can't follow.

Which one should a rookie team start with?

PathPlanner is usually the gentler on-ramp: it's visual, forgiving, and its AutoBuilder writes most of the following code for you. Once your drivetrain is dialed in and characterized, adding Choreo for your speed-critical paths is a natural next step.

Both tools are free, actively maintained, and bundled with or installable alongside WPILib, so there's little cost to trying each on your own robot. Start with whichever matches your team's current strengths — visual control or optimized speed — get one clean autonomous working end to end, and expand from there. For more on the pieces that make autonomous work, browse the rest of the LearnFRC guides.

Spot an error or something out of date?Create a free account to suggest an edit

Keep reading

More from the pit

Start learning FRC — free

Structured lessons and quizzes across every department. Create a free account to save your progress, track your team, and earn a certificate.

394lessons
11departments
100%free