Series: FRC Technical Foundations Unit: 4 — Software and Perception Session length: ~3 hours Prerequisites: Lessons 5 and 7
The rookie approach to autonomous is open-loop: drive forward at 50% for 1.4 seconds, turn right at 40% for 0.7 seconds, stop.
It works perfectly in the shop. At competition it works in the morning and fails in the afternoon, and the reason is instructive: on a full battery the robot goes further in 1.4 seconds than on a depleted one. Carpet friction varies between venues. A slightly tighter bearing changes the deceleration. Every one of these shifts the result, and errors accumulate through the sequence.
The fix is to close the loop — to measure what actually happened and correct.
Rule 8.1 — Never build an autonomous routine on time alone. Time is acceptable as a timeout, never as the primary control.
An encoder measures rotation. Two kinds matter.
Relative (incremental) encoders count changes from wherever they were at power-on. They report zero at boot regardless of physical position. This is what is built into a NEO or a Kraken.
Absolute encoders report true position immediately at power-on. Through-bore encoders and CANcoders are the common examples. Any mechanism whose position you must know at boot — a swerve azimuth, an arm that could start anywhere — needs one.
Configure conversion factors so your code reports metres and radians rather than motor rotations. The arithmetic is trivial and the bugs avoided are not:
wheel metres = motor rotations × (1 / gear ratio) × π × wheel diameter
If your code is full of numbers like 42.7 with no unit, someone will eventually mix a gear-ratio-corrected value with a raw one, and the bug will only appear at high speed.
A relative encoder needs a homing procedure: drive slowly toward a limit switch or hard stop, detect contact, and set zero. Do this on every boot for mechanisms without absolute encoders.
Soft limits then go in software, hard stops in metal — as established in Lesson 4.
A feedback controller computes error — target minus measured — and produces an output from it. Three terms.
Output proportional to current error. Far from target, push hard; close to target, push gently.
P alone leaves steady-state error. As error shrinks, output shrinks, until the output is too small to overcome friction or gravity and the mechanism stops just short. On an arm fighting gravity, P alone will always settle below target.
Too much P causes oscillation: the controller overshoots, error reverses, it overshoots back.
Accumulates error over time. If a small error persists, the integral grows until the output is large enough to eliminate it. This is the term that kills steady-state error.
I is also the term that causes the most trouble. Integral windup happens when the mechanism cannot reach its target — something is jammed, or the motor is saturated — and the integral keeps accumulating. When the obstruction clears, the controller has a huge stored output and slams the mechanism across its range.
Use I sparingly. Most FRC mechanisms need no I term at all, because feedforward handles the job better.
Responds to the rate of change of error. It acts as damping, resisting fast approach and reducing overshoot.
D amplifies noise, because differentiating a noisy signal produces a very noisy result. If your encoder signal is noisy, D will make the motor buzz.
Rule 8.2 — Tune with a plot, not with your eyes. Log setpoint and measured position together and look at the graph. “It looks about right” is not tuning. Use AdvantageScope or the Driver Station plots.
This is the idea that separates teams that tune for three hours from teams that tune for twenty minutes.
Feedback is reactive — it only acts once an error exists. Feedforward is predictive: you model what the mechanism needs and command it directly.
A standard model:
V = kS · sign(velocity) + kG + kV · velocity + kA · acceleration
With a good feedforward, the feedback controller only has to correct the small difference between your model and reality, so P can be gentle and the whole loop is far better behaved.
For an arm, the single highest-value line of code you will write is gravity compensation:
double ff = kG * Math.cos(armAngleRadians);
That alone converts an arm that sags at every angle into one that holds position naturally.
WPILib’s SysId tool determines kS, kV, and kA empirically by running characterisation routines. Use it — it takes twenty minutes and replaces a day of guessing.
Rule 8.3 — Feedforward first, feedback second.
Commanding a mechanism to jump instantly from position A to position B asks for infinite acceleration. The controller saturates, the mechanism lurches, and the structure takes an impact it did not need.
A motion profile generates a smooth sequence of intermediate setpoints respecting maximum velocity and acceleration limits. The mechanism follows a planned ramp rather than chasing a step. WPILib provides TrapezoidProfile and ProfiledPIDController for exactly this.
The mechanical benefit is as large as the control benefit: profiled mechanisms break far less often.
Odometry estimates the robot’s pose — x, y, and heading on the field — by integrating wheel encoders and gyro readings over time.
A few things to be clear about:
Rule 8.4 — Odometry tells you where you probably are. Only an absolute reference tells you where you are.
With pose estimation working, you can follow planned trajectories.
The two tools the community uses are PathPlanner, which offers a graphical editor and an event system for triggering commands mid-path, and Choreo, which computes time-optimal trajectories subject to your drivetrain’s physical constraints. Both support swerve and differential drives, and both integrate with command-based.
What matters pedagogically is that a path is not a guarantee. A path-following controller commands velocities and corrects based on pose error, so the quality of the result depends entirely on the quality of your pose estimate and the accuracy of your drivetrain characterisation. Teams that skip the characterisation step and then blame the path library are extremely common.
Measure repeatability, not accuracy. Run the same path ten times and mark where the robot ends up each time. A robot that stops in the same wrong place every time has a calibration problem you can fix in an afternoon. A robot that stops somewhere different each time has a mechanical or estimation problem, and that is much more serious.
[ANECDOTE SLOT] — An autonomous routine that behaved differently between practice and competition. Carpet differences, battery differences, and field-setup tolerance all make good material here.
Time: 75 minutes. Equipment: An arm or linear-slide test stand with an absolute encoder, a laptop running AdvantageScope or the Driver Station plotter, a known payload.
Evidence of learning: Four labelled plots, a table of steady-state error against configuration, final constants, and a written description of the windup event.
Time: 60 minutes. Equipment: A drivable chassis with encoders and a gyro, tape, a tape measure.
Program a 2 m square path returning to the start. Run it ten times in each of three configurations:
Mark the final position and heading each run.
Evidence of learning: A scatter plot of end positions for all three configurations, mean and standard deviation of position error, and a written explanation of why C beats B and B beats A.
Time: 45 minutes. Equipment: A path-following setup, a fresh battery and a depleted one.
Run the same planned path ten times on a fresh battery, then ten on a depleted one. Then run five more where a team member gently nudges the robot mid-path to simulate a collision.
Evidence of learning: A pose-error map showing all three conditions, and a recommendation for how much positional tolerance your mechanisms need to absorb.
Odometry drifts, and something has to correct it. Lesson 9 — Vision and AprilTags covers how the robot finds out where it actually is, and what it does when the camera lets it down.



