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.

Odyssey represents robot trajectories as sequences of cubic Bézier curves chained together into a Path. Each BezierCurve is defined by four Vector2d control points and a heading interpolator. Because the path geometry is stored independently of kinematic limits, you can redesign a trajectory’s speed profile at any time without touching the control points.

FTC field coordinate system

The FTC field is 3657.5 mm × 3657.5 mm. Odyssey works entirely in millimetres — every Vector2d you pass to a BezierCurve should use mm values. The origin is typically at one corner of the field; X increases toward the opposing wall and Y increases toward the far wall. Heading is in radians, measured counter-clockwise from the positive X axis.

Anatomy of a BezierCurve

public BezierCurve(Vector2d p0, Vector2d p1, Vector2d p2, Vector2d p3,
                   HeadingInterpolator headingInterpolator)
ParameterRole
p0Start point (curve passes through this)
p1First handle (curve is pulled toward this)
p2Second handle (curve is pulled toward this)
p3End point (curve passes through this)
headingInterpolatorControls robot heading along the segment
The robot travels through p0 and p3 exactly. The handles p1 and p2 never lie on the curve — they act as magnets that shape it.

Heading interpolators

Odyssey ships four interpolators that implement the HeadingInterpolator interface:

LinearInterpolator

Sweeps the heading linearly from startHeading to endHeading as t goes from 0 to 1. Ideal for segments where you want the robot to rotate a known amount.
new LinearInterpolator(0, Math.PI / 2)

ConstantInterpolator

Holds a fixed heading for the entire segment. Good for backing away while pointing at a target.
new ConstantInterpolator(Math.PI / 2)

TangentInterpolator

Aligns the robot’s heading with the curve’s tangent direction at every point. Produces natural, forward-facing motion along the curve.
new TangentInterpolator()

FaceTargetInterpolator

Continuously rotates the robot to face a fixed field point throughout the segment. Useful for keeping a camera or intake aimed at a game element.
new FaceTargetInterpolator(new Vector2d(1800, 1800))

Building a multi-segment path

A common FTC autonomous routine sweeps from the starting tile into a scoring zone, then backs away. Below, two BezierCurve segments are chained into a single Path:
// Segment 1: sweep from starting position into scoring zone
BezierCurve toScore = new BezierCurve(
    new Vector2d(300, 300),      // start
    new Vector2d(300, 1200),     // handle 1 — pulls curve toward +Y early
    new Vector2d(1200, 1800),    // handle 2 — pulls curve toward +X late
    new Vector2d(1800, 1800),    // end
    new LinearInterpolator(0, Math.PI / 2)   // rotate 90° over the segment
);

// Segment 2: back away while holding heading
BezierCurve backAway = new BezierCurve(
    new Vector2d(1800, 1800),
    new Vector2d(1800, 1200),
    new Vector2d(1200, 900),
    new Vector2d(900, 900),
    new ConstantInterpolator(Math.PI / 2)
);

Path fullPath = new Path(toScore, backAway);
Path accepts any number of BezierCurve arguments via varargs and caches each segment’s arc length at construction time, so subsequent queries are fast.

Control point placement tips

1

Gentle sweeping curve

Place handles far from the endpoints — roughly one-third of the total segment length away. The curve bows out smoothly and the robot has time to accelerate and decelerate.
2

Tight corner

Place handles close to the endpoints. The curve approaches the corner more steeply and the heading change is concentrated near p3.
3

S-curve

Place p1 on the same side as p0 and p2 on the opposite side relative to the chord. The curve inflects in the middle.
4

Straight line

Collinear handles: put p1 one-third of the way from p0 to p3 and p2 two-thirds of the way. The curve is geometrically straight even though it is parameterised as a cubic.

Heading continuity at segment seams

When chaining segments, the robot’s heading at the end of segment N must equal its heading at the start of segment N+1, otherwise the follower will see a sudden heading discontinuity and issue a large corrective turn command.
  • If segment N uses LinearInterpolator(start, end), make segment N+1 start with LinearInterpolator(end, ...) or ConstantInterpolator(end).
  • If segment N uses TangentInterpolator, compute curve.getTangentAngle(1.0) and use that value as the start heading of the next interpolator.
Use the odyssey-gui path editor to drag control points on a live field image before translating coordinates to code. Once you are happy with the shape, read off the handle positions and paste them directly into new Vector2d(x, y) calls.
VelocityProfile is constructed after the Path, not inside it. This means you can swap in a different set of kinematic limits — maxVelocity, maxAcceleration, maxBrake, maxCentripetalAccel — and regenerate the speed profile without re-specifying any control points.
VelocityProfile profile = new VelocityProfile(
    fullPath,
    1500.0,   // maxVelocity mm/s
    2000.0,   // maxAcceleration mm/s²
    2500.0,   // maxBrake mm/s²
    3000.0,   // maxCentripetalAccel mm/s²
    10.0      // step mm (resolution of the pre-computed table)
);

Build docs developers (and LLMs) love