VingVing Robot LogoVingVing Robot

Documentation v0.0.3

VingVing Robot Docs

Path Callbacks

Execute actions at specific points along paths without stopping the robot

What Are Callbacks?

Callbacks are functions that execute automatically when the robot reaches specific points along a path. Perfect for coordinating mechanism actions with movement without complex manual timing.

Progress Callbacks

Trigger Actions at Path Percentage:

Path path = new BezierLine(new Point(48, 0, Point.CARTESIAN))
    .setConstantHeadingInterpolation(0)
    .addCallback(0.25, () -> {
        // Execute when 25% complete (12 inches)
        intake.setPower(1.0);
        telemetry.addLine("Starting intake");
    })
    .addCallback(0.5, () -> {
        // Execute when 50% complete (24 inches)
        arm.setTargetPosition(RAISED_POSITION);
    })
    .addCallback(0.75, () -> {
        // Execute when 75% complete (36 inches)
        telemetry.addLine("Almost there!");
    });

Parameters:

  • progress (0.0 - 1.0): Where along path to trigger (0 = start, 0.5 = halfway, 1 = end)
  • callback function: Code to execute (lambda or method reference)
  • Each callback triggers exactly once when progress reaches that point

Path End Callbacks

Path path = new BezierCurve(/* ... */)
    .setTangentHeadingInterpolation()
    .setPathEndCallback(() -> {
        // Execute when path completes (within tolerances)
        intake.setPower(0);
        arm.setTargetPosition(SCORE_POSITION);
        telemetry.addLine("Ready to score!");
    });

// Cleaner than manually checking completion in loop

Practical Examples

Example 1: Intake While Driving

// Start intake as robot approaches game element
Path toPixelStack = new BezierCurve(
    new Point(0, 0, Point.CARTESIAN),
    new Point(0, 0, Point.CARTESIAN),
    new Point(20, 10, Point.CARTESIAN),
    new Point(35, 20, Point.CARTESIAN),
    new Point(48, 24, Point.CARTESIAN)
).setTangentHeadingInterpolation()
    .addCallback(0.7, () -> {
        // 70% there - start intake early
        intake.setPower(1.0);
    })
    .setPathEndCallback(() -> {
        // Arrived - give intake time to grab
        sleep(500);
        intake.setPower(0);
    });

Example 2: Multi-Stage Mechanism Sequence

Path complexPath = new BezierLine(new Point(60, 0, Point.CARTESIAN))
    .setConstantHeadingInterpolation(0)
    .addCallback(0.2, () -> {
        // Early: Raise arm while moving
        arm.setTargetPosition(TRAVEL_HEIGHT);
    })
    .addCallback(0.5, () -> {
        // Midway: Rotate wrist to scoring position
        wrist.setPosition(SCORE_ANGLE);
    })
    .addCallback(0.8, () -> {
        // Near end: Final arm position
        arm.setTargetPosition(SCORE_HEIGHT);
    })
    .setPathEndCallback(() -> {
        // Arrived: Release game element
        claw.open();
    });

// All mechanism movements coordinated with path automatically

Example 3: Dynamic Path Adjustment

Path adaptivePath = new BezierCurve(/* ... */)
    .setTangentHeadingInterpolation()
    .addCallback(0.4, () -> {
        // Check vision midway through path
        if (aprilTagDetected()) {
            // Adjust follower based on vision
            Point correction = getAprilTagCorrection();
            follower.adjustTargetPoint(correction);
        }
    })
    .addCallback(0.6, () -> {
        // Decision point based on game state
        if (alliancePixelDetected()) {
            queueNextPath(PATH_TO_ALLIANCE_PIXEL);
        } else {
            queueNextPath(PATH_TO_PARK);
        }
    });

Callback Best Practices

✓ Keep Callbacks Fast

Callbacks execute during the path following loop. Long-running code (sleep, loops) will pause path following. Keep actions quick - set targets, not wait for completion.

⚠️ Avoid Blocking Operations

// BAD - blocks path following
.addCallback(0.5, () -> {
    arm.setTargetPosition(1000);
    while (arm.isBusy()) { sleep(10); }  // BLOCKS!
})

// GOOD - non-blocking
.addCallback(0.5, () -> {
    arm.setTargetPosition(1000);  // Set and continue
})

💡 Use Path End for Final Actions

Place final scoring/placement actions in pathEndCallback, not at high progress values like 0.99. Ensures actions happen only when robot is truly stopped.

💡 Test Callback Timing

Use telemetry in callbacks to verify they trigger at expected positions. Adjust progress values based on actual robot behavior.

Complete Example

CallbackDemo.java
@Autonomous
public class CallbackDemo extends LinearOpMode {
    @Override
    public void runOpMode() {
        Robot robot = new Robot(hardwareMap, RobotConfig.class);
        robot.initializeLocalizer(hardwareMap);
        Follower follower = new Follower(hardwareMap);

        waitForStart();

        // Complex path with multiple callbacks
        follower.followPath(
            new BezierCurve(
                new Point(0, 0, Point.CARTESIAN),
                new Point(0, 0, Point.CARTESIAN),
                new Point(24, 12, Point.CARTESIAN),
                new Point(36, 36, Point.CARTESIAN),
                new Point(48, 48, Point.CARTESIAN)
            ).setLinearHeadingInterpolation(Math.toRadians(90))
                .addCallback(0.3, () -> {
                    telemetry.addLine("30% - Starting intake");
                    intake.setPower(1.0);
                })
                .addCallback(0.5, () -> {
                    telemetry.addLine("50% - Raising arm");
                    arm.setTargetPosition(SCORE_HEIGHT);
                })
                .addCallback(0.7, () -> {
                    telemetry.addLine("70% - Preparing to score");
                    intake.setPower(0);
                })
                .addCallback(0.9, () -> {
                    telemetry.addLine("90% - Almost there!");
                })
                .setPathEndCallback(() -> {
                    telemetry.addLine("100% - Scoring!");
                    claw.open();
                })
        );

        // Execute path
        while (!follower.isPathComplete() && opModeIsActive()) {
            robot.update();
            follower.update();
            robot.setDrivePowers(follower.getMotorPowers());

            telemetry.addData("Progress", "%.0f%%", follower.getPathProgress() * 100);
            telemetry.update();
        }

        telemetry.addLine("Path complete - all callbacks executed!");
    }
}