Lesson 15.2: Controlling a Pedro 3 Follower
Why Use a Path Follower?
Encoder-only autonomous routines often drive to one tick target, stop, turn, and repeat. Wheel slip, battery variation, and contact with field elements make every step start with a little error from the step before it.
Pedro Pathing continuously estimates the robot's field pose and corrects its drivetrain while following a geometric path. Pedro 3 combines localization, drivetrain control, and its Foresight following algorithm inside a Follower.
Use the Pedro Pathing Quickstart or complete the official installation and tuning guides before running these examples. In Pedro 3, your generated Constants.create(hardwareMap) method constructs the correctly configured Follower; new Follower(hardwareMap) is an older API and is not valid Pedro 3 setup.
The Pedro 3 Follower Lifecycle
The important calls are:
- Create:
Constants.create(hardwareMap)assembles the drivetrain, localizer, and algorithm configured for your robot. - Locate:
follower.setPose(startPose)establishes the robot's field pose before it moves. - Follow:
follower.follow(path)begins direct path following. - Update:
follower.update()must run every active loop so localization and motor commands continue to advance. - Observe:
follower.pose()returns the currentPose; usex(),y(), andheading()to read it.
Pedro 3 reports four follower modes through follower.mode(): FOLLOW, HOLD, MANUAL, and IDLE. follower.following() tells you whether it is actively tracking a path. follower.isBusy() is a stricter completion signal that also accounts for the follower's end conditions.
If the plotted path looks right but the robot oscillates or cuts corners, first check odometry mounting, wheel offsets, motor directions, and whether follower.update() runs every cycle.
Poses and PoseFactory
A Pose stores X and Y in inches and heading in radians. Pedro 3 recommends a PoseFactory so headings can be written in degrees and common transformations, such as alliance mirroring, can be applied consistently.
private final PoseFactory poseFactory = PoseFactory.degrees();
private final Pose startPose = poseFactory.of(12, 12, 0);
private final Pose parkPose = poseFactory.of(60, 12, 0);
poseFactory.of(x, y, heading) uses the factory's angle unit. A raw new Pose(x, y, heading) always expects radians.
Is Ivy Required?
No. Pedro can follow a path directly:
follower.follow(parkPath());
while (opModeIsActive() && follower.following()) {
follower.update();
}
That is reasonable for a one-path experiment. For a real autonomous routine, Pedro's documentation recommends a command framework instead of a hand-written state machine. Ivy is the simplest choice because it includes Pedro-aware follow() and hold() commands.
Use this rule of thumb:
| Situation | Good choice |
|---|---|
| One path while learning or tuning | Direct follower.follow(path) |
| Several paths plus mechanisms | Ivy commands |
| Team already uses another command framework | Keep it and write one tested Pedro follow command |
| Existing, reliable state machine | It can remain, but do not start a new one just to sequence Pedro paths |
Ivy is a separate dependency and is not required by the follower itself:
implementation 'com.pedropathing.ivy:pedro:1.1.1'
Annotated Pedro 3 + Ivy Example
package org.firstinspires.ftc.teamcode;
import static com.pedropathing.api.Paths.line;
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_Intro")
public class Pedro3Intro extends LinearOpMode {
private Follower follower;
private final PoseFactory poseFactory = PoseFactory.degrees();
private final Pose startPose = poseFactory.of(12, 12, 0);
private final Pose parkPose = poseFactory.of(60, 12, 0);
private Path parkPath() {
return line(startPose, parkPose).linear(startPose, parkPose);
}
@Override
public void runOpMode() {
Scheduler.reset();
follower = Constants.create(hardwareMap);
follower.setPose(startPose);
follower.update();
waitForStart();
if (isStopRequested()) return;
schedule(follow(follower, parkPath()));
while (opModeIsActive()) {
follower.update();
Scheduler.execute();
telemetry.addData("X", "%.2f", follower.pose().x());
telemetry.addData("Y", "%.2f", follower.pose().y());
telemetry.addData("Mode", follower.mode());
telemetry.update();
}
}
}
The follower and scheduler are separate systems, so both require one update per loop. Ivy's follow() command starts the path and handles its completion condition; the OpMode does not need to poll and advance a custom state variable.
Fill-in-the-Blank Practice
- Pedro 3 creates the configured follower with
Constants.__________(hardwareMap). - The current pose is returned by
follower.__________(). - Ivy is
__________for direct path following but recommended for multi-step autonomous routines.
Show answers
createpose- optional (not required)
Simulator Challenge
Complete the Pedro 3 lifecycle. Create the follower with Constants.create(hardwareMap), create a degree-based PoseFactory, set the starting pose to (8, 60, 0°), call follower.update() before waiting for Start and on every active loop, and report follower.pose().x(), .y(), and .heading().
The simulator remains on the DECODE field so new members can focus on the API without learning a second game layout.
Show answer
PoseFactory poseFactory = PoseFactory.degrees();
follower = Constants.create(hardwareMap);
follower.setPose(poseFactory.of(8, 60, 0));
follower.update();
waitForStart();
while (opModeIsActive()) {
follower.update();
telemetry.addData("X", "%.2f", follower.pose().x());
telemetry.addData("Y", "%.2f", follower.pose().y());
telemetry.addData("Heading", "%.4f", follower.pose().heading());
telemetry.update();
}
The follower is only as good as the localization under it, and that is also a mounting problem.
See Lesson 7.4: Mounting Odometry Pods for Reliable Localization.
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.