TheDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/saquer916/odyssey/llms.txt
Use this file to discover all available pages before exploring further.
Follower is the runtime loop that ties every Odyssey subsystem together. On each call to update(), it queries the localizer for the robot’s current pose, projects that pose onto the path to find the closest point, reads the target velocity from the VelocityProfile, runs two PID controllers to correct translational and heading error, and packages the result into a DriveSignal that MecanumDrive converts into wheel powers.
Follower constructor
Parameter reference
| Parameter | Type | Purpose |
|---|---|---|
path | Path | The pre-built multi-segment Bézier path to follow. |
localizer | Localizer | Provides the current Pose2d (X mm, Y mm, heading rad). |
velocityProfile | VelocityProfile | Pre-computed speed table indexed by arc-length distance. |
pidTranslational | PIDController | Corrects the lateral offset of the robot from the nearest path point. Setpoint is 0; input is −offset.getMagnitude(). |
pidHeading | PIDController | Corrects the angle error between the reference heading and actual heading. Setpoint is 0; input is −normalizeAngle(referenceHeading − poseHeading). |
minDriveSpeed | double | A lower speed floor (mm/s) applied when the profile velocity is very low but the robot is still far from the end. Prevents the robot from stalling on carpet. |
floorCutoff | double | Distance (mm) from the path end within which minDriveSpeed is no longer applied, allowing the robot to decelerate to a true stop. |
Update loop
The follower must be called every loop iteration from inside aLinearOpMode. Always call localizer.update() first so the follower sees a fresh pose.
getDistanceRemaining() returns the cached value from the most recent update() call — it does not trigger an additional getDistanceOnPath() query, so calling it in the loop condition is free.
DriveSignal decomposition
DriveSignal carries five fields that MecanumDrive.drive() unpacks into per-wheel power commands:
MecanumDrive.drive(), the mecanum kinematics mixing is:
k = lX + lY is the sum of the half-wheelbase and half-track width, and f, s, w are the forward velocity, strafe velocity, and turn from the signal.
Voltage compensation
MecanumDrive scales every wheel power by a voltage compensation factor so the robot behaves consistently as the battery drains:
voltageComp ≈ 0.92, reducing power slightly. At 11 V it rises to ≈ 1.09, boosting power to compensate for the sag. The final powers are then normalised so the maximum absolute value does not exceed 1.0.
MecanumDrive constructor
Wire up the drive before constructing theFollower:
MecanumDrive automatically sets all four motors to RUN_WITHOUT_ENCODER mode and BRAKE zero-power behaviour, and reverses the right-side motors to match the standard symmetric FTC chassis wiring.
The translational PID setpoint is always
0 — the target is zero offset from the path. The input passed to getOutput() is the negative magnitude of the position error vector: pidTranslational.getOutput(currentTime, -offset.getMagnitude()). This means a positive PID output pushes the robot toward the path, and the direction is applied separately via the normalised offset vector.