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.

Before running an autonomous path, Odyssey needs four feedforward constants (kS, kV, kA) and two PID controllers tuned to your specific robot. The constants live in MecanumDrive; the PID gains are passed to the Follower constructor. Follow the steps below in order — each step builds on the results of the previous one.
1

Tune kS — static friction coefficient

kS is the minimum normalised motor power required to overcome static friction and begin moving. MecanumDrive adds kS * Math.signum(velocity) to every wheel before scaling by kV and kA, ensuring the motors always have enough power to break away from rest.Procedure — use StaticCoefficientOpMode:The StaticCoefficientOpMode TeleOp ramps power from 0.0 to 0.4 in 0.1 increments. At each step it drives all four wheels for 2 000 ms, reads the forward velocity from the Pinpoint localizer (localizer.getVelX(DistanceUnit.MM)), logs the result, then rests for 2 000 ms before moving to the next step.
  1. Deploy the OpMode and run it on a flat surface.
  2. Watch the telemetry log. You will see lines like:
    power: 0.1000 | velo: 0.0000
    power: 0.2000 | velo: 345.2000
    
  3. Find the first power level at which the velocity is non-zero — that is your kS. In the example above, kS ≈ 0.2.
Run this test on the same carpet surface you will use for the match. Static friction is higher on carpet than on smooth tile.
2

Tune kV — velocity feedforward

kV converts a target wheel velocity (mm/s) into a normalised motor power. It is defined as the reciprocal of the robot’s steady-state velocity at full power:
kV = 1 / v_max
Procedure:
  1. Run the robot in a straight line at full motor power (1.0) for at least 2 000 mm.
  2. Read the steady-state forward velocity from PinpointLocalizer telemetry once acceleration has plateaued.
  3. Divide 1 by that velocity.
For example, if the robot reaches 1 250 mm/s at full power:
kV = 1 / 1250 ≈ 0.0008
Typical FTC mecanum values fall in the range 0.0008 – 0.002 depending on gearing and wheel diameter. A correctly tuned kV means the robot reaches the path’s target velocity without the translational PID needing to compensate for a persistent speed error.
3

Tune kA — acceleration feedforward

kA scales the tangential and centripetal acceleration components from the VelocityProfile into additional motor power. Start at kA = 0 and increase incrementally.Signs of under-tuned kA (too low):
  • The robot lags behind the profile at the start of the path and takes time to reach target velocity.
  • The robot coasts past the endpoint because braking power is insufficient.
Signs of over-tuned kA (too high):
  • The robot jerks at path start or oscillates as acceleration commands change sign.
  • Wheel slip on carpet.
Increase kA by 0.0001 at a time and re-run a straight-line path until the robot accelerates and decelerates crisply without overshoot.
4

Tune the translational PID

The translational PIDController corrects the robot’s lateral offset from the nearest point on the path. Its setpoint is always 0; the input is the negative magnitude of the position error vector.Start with kI = 0 throughout. Integral gain is rarely needed for path following and causes wind-up if the robot is held off the path at the start.
new PIDController(0, kP_trans, 0, kD_trans)
Procedure:
  1. Set kD_trans = 0. Increase kP_trans from 0 until the robot tracks the path cleanly without significant overshoot.
  2. If the robot oscillates around the path, add a small kD_trans (start at kP_trans / 10) to damp the oscillation.
  3. Re-run until lateral error is consistently less than ~15 mm on a sweeping curve.
PIDController exposes setOutputLimits(min, max) and setMaxIntegral(value). If you do enable kI, always call setMaxIntegral() to prevent the integral term from winding up during a long stall at path start.
5

Tune the heading PID

The heading PIDController corrects the angle error between the reference heading (from the HeadingInterpolator) and the robot’s actual heading. Setpoint is 0; error is −normalizeAngle(referenceHeading − poseHeading).
new PIDController(0, kP_head, 0, kD_head)
Procedure:
  1. Run a path with LinearInterpolator so the robot must rotate while driving.
  2. Set kD_head = 0. Increase kP_head until the robot reaches its target heading quickly without overshooting.
  3. If the robot oscillates through the target heading, add kD_head.
Heading errors are in radians, so PID outputs tend to be smaller numbers than translational gains. A typical starting range is kP_head = 1.0 – 3.0.

Common issues

The translational PID gain is too aggressive relative to the feedforward. Try lowering kP_trans by 20 % or adding kD_trans if not already set. Also verify that kV is correct — a persistent velocity error forces the translational PID to do extra work.
The braking profile is not matched to the robot’s actual deceleration capability. Increase maxBrake in the VelocityProfile constructor to command stronger deceleration, which gives the profile more headroom to stop in time. If the robot still overshoots, kA may be too high — reduce it slightly.
VelocityProfile profile = new VelocityProfile(
    path,
    1500.0,   // maxVelocity
    2000.0,   // maxAcceleration
    3000.0,   // maxBrake ← increase this
    3000.0,   // maxCentripetalAccel
    10.0      // step
);
The right-side motor direction is incorrect. MecanumDrive sets rightFront and rightBack to Direction.REVERSE by default for a standard symmetric FTC chassis. If your chassis mounts the right-side motors the other way, change those two motors to Direction.FORWARD in your MecanumDrive constructor call.
The VelocityProfile ramps up from zero, and at very low profile velocities the feedforward alone may not overcome static friction. Increase minDriveSpeed in the Follower constructor — for example from 50.0 to 80.0 mm/s — to add a speed floor while the robot is still far from the end. Make sure kS is also correctly tuned so the static friction term is applied.
Centripetal acceleration feedforward is handled automatically by the Follower using path.getCurvatureFromPathDistance() and path.getCentripetalVectorPath(). If the robot still drifts outward, try increasing maxCentripetalAccel in the VelocityProfile so the profile slows down more aggressively before tight curves.

Build docs developers (and LLMs) love