Documentation 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 Odyssey’s main runtime class. Each call to update() queries the localizer for the current robot pose, projects it onto the path to find where the robot is, reads the target velocity from the profile, applies PID corrections, and returns a DriveSignal ready to be passed to MecanumDrive.drive().
Package: org.firstinspires.ftc.teamcode.odyssey.follower
Constructor
The cubic Bézier
Path to follow. Follower queries it for point positions, tangent vectors, curvature, and centripetal vectors on every update() call.A
Localizer implementation that provides the current robot Pose2d. Follower calls localizer.getPose() on every update() — you must call localizer.update() yourself each loop before calling follower.update().Pre-computed trapezoidal velocity profile for the path.
Follower calls getTargetVelocity() and getTargetTangentialAcceleration() to obtain the commanded speed and tangential feedforward at the current path distance.Corrects lateral offset from the path. The setpoint should be
0; the input passed at runtime is the negative magnitude of the vector from the robot’s position to the nearest path point (-offset.getMagnitude()). The output is added to the drive vector in world-frame before the robot-frame rotation is applied.Corrects heading error. The setpoint should be
0; the input passed at runtime is the negative normalized angle difference between the reference heading and the robot heading (-normalizeAngle(referenceHeading - poseHeading)). The output is forwarded as the turn component of the returned DriveSignal.Minimum drive speed in mm/s. When the velocity profile returns a speed lower than this value,
minDriveSpeed is used instead — keeping the robot moving when the profile speed is very low near the start of the path. This floor is disabled once distanceRemaining falls below floorCutoff.Distance remaining in mm below which
minDriveSpeed ceases to apply. Setting this to a small positive value (e.g. 50.0) lets the robot decelerate naturally to a full stop near the end of the path rather than being held at minimum speed.Methods
update(double currentTime) → DriveSignal
localizer.update(). Pass the current elapsed time in seconds — both PID controllers use this value to derive dt for derivative and integral calculations.
A
DriveSignal containing the robot-frame forward velocity, strafe velocity, forward acceleration feedforward, strafe acceleration feedforward, and heading correction. Pass it directly to MecanumDrive.drive().update() does — step by step:
- Get pose — calls
localizer.getPose()to read the currentPose2d. - Project onto path — calls
path.getDistanceOnPath(pose.getPosition())to find the arc-length distance of the closest point on the path. - Get reference pose — calls
path.getPointOnPath(distance)to obtain the target position and heading at that arc-length. - Compute commanded speed — calls
velocityProfile.getTargetVelocity(distance); ifdistanceRemaining > floorCutoff, clamps the result to at leastminDriveSpeedviaMath.max(profileSpeed, minDriveSpeed). - Compute translational PID correction — subtracts the robot position from the reference position to get an offset vector, then feeds its negative magnitude into
pidTranslational.getOutput(). The normalized offset direction is scaled by this output to produce a correction vector. - Compute drive vector — normalizes the path tangent at the current distance and scales it by the commanded speed.
- Compute heading PID correction — normalizes the angle difference between the reference heading and the robot heading, feeds its negative into
pidHeading.getOutput(), and stores the result as theturncomponent. - Compose robot-frame velocity vector — sums the translational correction and the drive vector, then rotates the result by
-pose.getHeading()to convert from world frame to robot frame. - Compute acceleration feedforward — combines a centripetal vector (
v² × κin the centripetal direction) and a tangential vector (getTargetTangentialAcceleration()along the tangent), then rotates the sum into robot frame. - Return
DriveSignal— packages(velocityVector.x, velocityVector.y, accelVector.x, accelVector.y, heading)into a newDriveSignal.
getDistanceRemaining() → double
update() call — it reuses the getDistanceOnPath() result already computed that iteration so no duplicate projection is performed.
Remaining path distance in mm. Valid only after at least one call to
update().