Draw the route. Take the Java.
How this works
Drag the waypoints, or click anywhere on the field to add one. Arrow keys nudge the selection, shift for 5″, delete removes it, space plays and ⌘Z steps back.
x runs right, y runs up the field, heading 0 faces +x and turns counter-clockwise — Pedro’s convention, not the SDK’s. Squares are 24″ tiles.
The clock is an estimate from distance and your speed limit alone. It does not know your motors, your weight or how much traction you have, so a real robot will be slower.
Current robot position
Starting point
Robot
A mecanum robot strafes slower than it drives, so the two speeds are separate. The 3.9s estimate is geometry and these limits only — no traction, weight or heading cost — so a real robot will be slower. Over a 144″ field most legs never reach top speed at all; acceleration is usually what binds.
Click the field to add a point · arrows nudge, shift for 5″ · delete removes · space plays · ⌘Z undoes
Path chains (1)
Each chain becomes its own PathChain, followed in order.
Waypoints (3)
Leg 1 → 2
Obstacles (0)
Anything the robot must not drive through. Checked against the footprint along the whole route.
Import existing Java
Pedro Pathing code
package org.firstinspires.ftc.teamcode.pedroPathing;
import com.pedropathing.follower.Follower;
import com.pedropathing.geometry.BezierCurve;
import com.pedropathing.geometry.BezierLine;
import com.pedropathing.geometry.Pose;
import com.pedropathing.paths.PathChain;
import com.qualcomm.robotcore.eventloop.opmode.Autonomous;
import com.qualcomm.robotcore.eventloop.opmode.OpMode;
@Autonomous(name = "GeneratedPath")
public class GeneratedPath extends OpMode {
private Follower follower;
private PathChain path;
private final Pose startPose = new Pose(9, 60, Math.toRadians(0));
private final Pose scorePose = new Pose(60, 84, Math.toRadians(90));
private final Pose pickupPose = new Pose(108, 60, Math.toRadians(0));
@Override
public void init() {
follower = Constants.createFollower(hardwareMap);
follower.setStartingPose(startPose);
path = follower.pathBuilder()
.addPath(new BezierLine(startPose, scorePose))
.setLinearHeadingInterpolation(startPose.getHeading(), scorePose.getHeading(), 0.8)
.addPath(new BezierCurve(scorePose, new Pose(84, 96), pickupPose))
.setLinearHeadingInterpolation(scorePose.getHeading(), pickupPose.getHeading(), 0.8)
.build();
}
@Override
public void start() {
follower.followPath(path);
}
@Override
public void loop() {
follower.update();
// isBusy() goes false once the follower has finished correcting.
if (!follower.isBusy()) {
telemetry.addLine("Path complete");
}
telemetry.addData("x", follower.getPose().getX());
telemetry.addData("y", follower.getPose().getY());
telemetry.addData("heading (deg)", Math.toDegrees(follower.getPose().getHeading()));
telemetry.update();
}
}