Lesson 15.3: Creating Pedro 3 Paths with Bézier Curves
Why Curves Beat Stop–Turn–Drive
A stop–turn–drive routine throws away momentum at every corner. A smooth Bézier path can carry speed through a direction change while Pedro continuously corrects tracking error. Actual performance still depends on localization, tuning, curvature, and endpoint constraints.
Pedro 3's Paths API
Pedro 3 replaced the old Point, BezierLine, BezierCurve, PathChain, and follower.pathBuilder() lesson API with static helpers from com.pedropathing.api.Paths:
import static com.pedropathing.api.Paths.*;
line(start, end)creates a straightPathbetween twoPoses.curve(start, control..., end)creates a BézierPath.path(first, second, ...)combines paths into one compoundPath.through(pose...)creates a Bézier curve that passes through all supplied poses.
A Bézier curve passes through its first and last poses. Intermediate poses are control poses: they pull the curve without normally lying on it.
The embedded Pedro Pathing Visualizer generates the same PoseFactory, line(), curve(), and path() API shown here. Prefer returning paths from methods, which is also the format generated by the visualizer.
Heading Is Separate from Geometry
The curve describes where the robot travels. Heading interpolation describes which way it faces while moving.
line(startPose, scorePose).linear(startPose, scorePose);
curve(scorePose, controlPose, pickupPose).constant(pickupPose);
Common Pedro 3 heading choices include:
.linear(startPose, endPose): smoothly rotate between two headings..constant(pose): keep one heading for the path..tangent(): face along the direction of travel..facingPoint(targetPose): continuously face a field point.
Compound Paths Replace PathChain
Use path() when several geometric segments should behave as one path:
private Path scoringRoutine() {
return path(
line(startPose, scorePose).linear(startPose, scorePose),
curve(scorePose, controlPose, pickupPose)
.linear(scorePose, pickupPose)
);
}
The follower receives the compound path through the same Pedro 3 method as any other path:
follower.follow(scoringRoutine());
With Ivy, use follow(follower, scoringRoutine()) inside a command group instead.
Annotated Code
package org.firstinspires.ftc.teamcode;
import static com.pedropathing.api.Paths.*;
import static com.pedropathing.ivy.Scheduler.schedule;
import static com.pedropathing.ivy.pedro.PedroCommands.follow;
import com.pedropathing.api.PoseFactory;
import com.pedropathing.follower.Follower;
import com.pedropathing.ivy.Scheduler;
import com.pedropathing.math.Pose;
import com.pedropathing.paths.Path;
import com.qualcomm.robotcore.eventloop.opmode.Autonomous;
import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
import org.firstinspires.ftc.teamcode.pedro.Constants;
@Autonomous(name="Pedro_3_Bezier")
public class Pedro3Bezier extends LinearOpMode {
private Follower follower;
private final PoseFactory poseFactory = PoseFactory.degrees();
private final Pose startPose = poseFactory.of(12, 12, 0);
private final Pose scorePose = poseFactory.of(108, 12, 0);
private final Pose controlPose = poseFactory.of(120, 60, 45);
private final Pose pickupPose = poseFactory.of(108, 108, 90);
private Path scoringRoutine() {
return path(
line(startPose, scorePose).linear(startPose, scorePose),
curve(scorePose, controlPose, pickupPose)
.linear(scorePose, pickupPose)
);
}
@Override
public void runOpMode() {
Scheduler.reset();
follower = Constants.create(hardwareMap);
follower.setPose(startPose);
follower.update();
waitForStart();
if (isStopRequested()) return;
schedule(follow(follower, scoringRoutine()));
while (opModeIsActive()) {
follower.update();
Scheduler.execute();
telemetry.addData("X", "%.1f", follower.pose().x());
telemetry.addData("Y", "%.1f", follower.pose().y());
telemetry.addData("Segment", follower.pathIndex());
telemetry.update();
}
}
}
Fill-in-the-Blank Practice
- Pedro 3 creates a straight path with
__________(startPose, endPose). - Multiple paths become one compound path with
__________(first, second). - A path's geometry and heading
__________are configured separately.
Show answers
linepath- interpolation
Simulator Challenge
Create a compound Path named scoringRoutine. Start at (0, 0, 0°), drive in a straight line to (60, 0, 0°), then follow a quadratic Bézier curve through the control pose (80, 30, 45°) to (60, 60, 90°). Use PoseFactory.degrees() and the Pedro 3 path(line(...), curve(...)) API.
The path preview and robot animation remain on the DECODE field. The embedded official visualizer can be opened beside the editor for creating coordinates and comparing its generated Java.
Show answer
PoseFactory poseFactory = PoseFactory.degrees();
Pose start = poseFactory.of(0, 0, 0);
Pose join = poseFactory.of(60, 0, 0);
Pose control = poseFactory.of(80, 30, 45);
Pose end = poseFactory.of(60, 60, 90);
Path scoringRoutine = path(
line(start, join).linear(start, join),
curve(join, control, end).linear(join, end)
);
Ready to move on?
Only mark complete if you genuinely understand the material. Your progress will be saved in this browser.
Stuck on this lesson?
Ask about anything on this page. It can see which lesson you have open and which part you are reading.