Stop snapping at full power. Slow down as you approach the target.
Imagine you're trying to park a car exactly 10 feet from a wall. If you drive at full speed until 10 feet then slam the brakes, you'll skid past the line. That's bang-bang control. Instead: the closer you get, the slower you drive. That's proportional control.
error = target − current
If your goal is 1000 motor degrees and you've traveled 200, error = 800. Far from the goal → high error → drive fast. As you approach, error shrinks → motor power shrinks → smooth landing.
// Turn to a target heading using only the P term
void turnTo(double targetHeading) {
const double kP = 0.6; // tune this
while (true) {
double error = targetHeading - Gyro.rotation(degrees);
if (fabs(error) < 1.0) break; // close enough
double power = kP * error; // proportional
if (power > 60) power = 60; // clamp so we don't fly
if (power < -60) power = -60;
LeftMotor.spin(forward, power, percent);
RightMotor.spin(reverse, power, percent);
wait(20, msec);
}
LeftMotor.stop();
RightMotor.stop();
}
Start with kP = 0.1, double it until you see overshoot, then back off slightly. This is the same tuning process pros use.
Write a P-controlled driveTo(distanceInches) that uses the average of the two motor encoders. Test with different kP values. What happens at kP = 5?
Write a P-controlled turn that gets the robot to face exactly 180° from its starting heading without overshooting or oscillating.
Two programs with intentional errors. Spot the bug.
void turnTo(double targetHeading) {
double kP = 5.0;
while (true) {
double error = targetHeading - Gyro.rotation(degrees);
if (fabs(error) < 1.0) break;
double power = kP * error;
LeftMotor.spin(forward, power, percent);
RightMotor.spin(reverse, power, percent);
wait(20, msec);
}
LeftMotor.stop();
RightMotor.stop();
}
void turnTo(double targetHeading) {
double kP = 0.6;
while (true) {
double error = targetHeading - Gyro.rotation(degrees);
if (error < 1.0) break;
double power = kP * error;
LeftMotor.spin(forward, power, percent);
RightMotor.spin(reverse, power, percent);
wait(20, msec);
}
LeftMotor.stop();
RightMotor.stop();
}