Skip to main content

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.

VelocityProfile pre-computes a physically realizable speed schedule for a Path that simultaneously respects maximum velocity, acceleration, braking, and centripetal acceleration limits. The profile is built entirely at construction time by sampling the path at a fixed distance step, applying a curvature-based speed cap, running a forward acceleration pass, and then a backward braking pass. The result is a dense array of (distance, velocity) pairs that getTargetVelocity and getTargetTangentialAcceleration can query in O(1) via index arithmetic and v²-linear interpolation. Package: org.firstinspires.ftc.teamcode.odyssey.path

Constructor

VelocityProfile(Path path, double maxVelocity, double maxAcceleration,
                double maxBrake, double maxCentripetalAccel, double step)
path
Path
required
The path to profile. The constructor calls path.getTotalLength() and path.getCurvatureFromPathDistance() once per sample, so path must be fully constructed before being passed here.
maxVelocity
double
required
Absolute speed cap in mm/s. No sample in the profile will exceed this value.
maxAcceleration
double
required
Maximum forward (tangential) acceleration in mm/s². Applied during the forward pass: v[i] ≤ sqrt(v[i-1]² + 2 · maxAcceleration · Δs).
maxBrake
double
required
Maximum deceleration magnitude in mm/s². Applied during the backward pass: v[i] ≤ sqrt(v[i+1]² + 2 · maxBrake · Δs). Can differ from maxAcceleration to model asymmetric drivetrains or conservative stopping behaviour.
maxCentripetalAccel
double
required
Centripetal acceleration limit in mm/s². At any sample with curvature κ, the speed is capped at sqrt(maxCentripetalAccel / κ) before the forward/backward passes. Samples where κ < 1e-4 (effectively straight) are treated as unconstrained and receive the full maxVelocity cap instead.
step
double
required
Distance between consecutive profile samples in mm. Smaller values produce a finer-grained profile at the cost of more memory and a longer construction time. Typical values range from 1.0 mm (high precision) to 10.0 mm (fast builds for long paths).
The entire profile array is allocated and filled during the constructor call — there is no lazy evaluation. For a 3 000 mm path with step = 5 this allocates ~601 samples and calls getCurvatureFromPathDistance 601 times. Construct VelocityProfile during OpMode initialisation, not inside the control loop.
The profile is guaranteed to start and end at rest: velocities[0] and velocities[arraySize - 1] are forced to 0 before the forward and backward passes respectively, so the robot always begins and ends stationary regardless of the other limits.

Methods

getTargetVelocity

public double getTargetVelocity(double distance)
Returns the interpolated target speed at a given arc-length distance from the path start.
distance
double
required
Distance from path start in mm.
return
double
Target speed in mm/s. The interpolation is v²-linear (linear in v²) between the two bracketing samples, which matches the physics of constant-acceleration motion: v = sqrt(v1² + (d − d1) · (v2² − v1²) / (d2 − d1)). Values for distance ≤ 0 return velocities[0] (always 0); values beyond the profile end return velocities[last] (always 0).

getTargetTangentialAcceleration

public double getTargetTangentialAcceleration(double distance)
Returns the tangential acceleration for feedforward at a given arc-length distance. The value is derived directly from the slope of the v² profile between the two bracketing samples.
distance
double
required
Distance from path start in mm.
return
double
Tangential acceleration in mm/s², computed as (vf² − v0²) / (2 · Δs) over the bracketing interval. Positive values indicate the robot should be accelerating; negative values indicate braking. Returns 0 for queries outside the profile range.
Feed getTargetTangentialAcceleration into your drivetrain’s voltage feedforward term (multiply by robot mass or an empirical constant) to reduce steady-state velocity error on acceleration and braking phases.

Implementation Notes

The profile is built in three sequential passes over the sample array:
  1. Curvature cap — each sample i is initialised to min(maxVelocity, sqrt(maxCentripetalAccel / κ)). Samples with κ < 1e-4 receive maxVelocity directly.
  2. Forward acceleration pass — iterates from index 1 to end, clamping each sample to sqrt(v[i-1]² + 2 · maxAcceleration · Δs). The first sample is pinned to 0 before this pass.
  3. Backward braking pass — iterates from end−1 back to 0, clamping each sample to sqrt(v[i+1]² + 2 · maxBrake · Δs). The last sample is pinned to 0 before this pass.
The minimum of all three constraints is taken at each sample, producing the tightest physically realizable profile.

Example

import org.firstinspires.ftc.teamcode.odyssey.path.Path;
import org.firstinspires.ftc.teamcode.odyssey.path.VelocityProfile;

// Assumes `path` is a fully constructed Path object
VelocityProfile vp = new VelocityProfile(
    path,
    1200,  // mm/s   — max speed
    800,   // mm/s²  — max acceleration
    800,   // mm/s²  — max braking deceleration
    600,   // mm/s²  — max centripetal acceleration
    5.0    // mm     — profile sample spacing
);

// Query speed and feedforward acceleration at 500 mm from path start
double v = vp.getTargetVelocity(500.0);
double a = vp.getTargetTangentialAcceleration(500.0);

// Use in a control loop alongside robot distance tracking
double robotDist = path.getDistanceOnPath(robotPose.getPosition());
double targetSpeed = vp.getTargetVelocity(robotDist);
double ffAccel     = vp.getTargetTangentialAcceleration(robotDist);
Asymmetric acceleration and braking are common in FTC drivetrains. Setting maxBrake higher than maxAcceleration allows the robot to decelerate more aggressively into tight manoeuvres while still ramping up smoothly from rest.

Build docs developers (and LLMs) love