Replace SetOutputRange() with SetIntegratorRange()

If users are attempting to use the output range to limit the controller
action, they should use ProfiledPIDController instead. If they actually
intended to clamp the output, they should use std::clamp().
This commit is contained in:
Tyler Veness
2019-08-26 21:40:30 -07:00
committed by Peter Johnson
parent ff8b8f0a8a
commit 9b6ffc201c
11 changed files with 55 additions and 72 deletions

View File

@@ -64,9 +64,10 @@ void PIDController::EnableContinuousInput(double minimumInput,
void PIDController::DisableContinuousInput() { m_continuous = false; }
void PIDController::SetOutputRange(double minimumOutput, double maximumOutput) {
m_minimumOutput = minimumOutput;
m_maximumOutput = maximumOutput;
void PIDController::SetIntegratorRange(double minimumIntegral,
double maximumIntegral) {
m_minimumIntegral = minimumIntegral;
m_maximumIntegral = maximumIntegral;
}
void PIDController::SetTolerance(double positionTolerance,
@@ -89,12 +90,10 @@ double PIDController::Calculate(double measurement) {
if (m_Ki != 0) {
m_totalError =
std::clamp(m_totalError + m_positionError * m_period.to<double>(),
m_minimumOutput / m_Ki, m_maximumOutput / m_Ki);
m_minimumIntegral / m_Ki, m_maximumIntegral / m_Ki);
}
return std::clamp(
m_Kp * m_positionError + m_Ki * m_totalError + m_Kd * m_velocityError,
m_minimumOutput, m_maximumOutput);
return m_Kp * m_positionError + m_Ki * m_totalError + m_Kd * m_velocityError;
}
double PIDController::Calculate(double measurement, double setpoint) {

View File

@@ -69,9 +69,9 @@ void ProfiledPIDController::DisableContinuousInput() {
m_controller.DisableContinuousInput();
}
void ProfiledPIDController::SetOutputRange(double minimumOutput,
double maximumOutput) {
m_controller.SetOutputRange(minimumOutput, maximumOutput);
void ProfiledPIDController::SetIntegratorRange(double minimumIntegral,
double maximumIntegral) {
m_controller.SetIntegratorRange(minimumIntegral, maximumIntegral);
}
void ProfiledPIDController::SetTolerance(double positionTolerance,

View File

@@ -139,12 +139,15 @@ class PIDController : public frc::SendableBase {
void DisableContinuousInput();
/**
* Sets the minimum and maximum values to write.
* Sets the minimum and maximum values for the integrator.
*
* @param minimumOutput the minimum value to write to the output
* @param maximumOutput the maximum value to write to the output
* When the cap is reached, the integrator value is added to the controller
* output rather than the integrator value times the integral gain.
*
* @param minimumIntegral The minimum value of the integrator.
* @param maximumIntegral The maximum value of the integrator.
*/
void SetOutputRange(double minimumOutput, double maximumOutput);
void SetIntegratorRange(double minimumIntegral, double maximumIntegral);
/**
* Sets the error which is considered tolerable for use with AtSetpoint().
@@ -211,11 +214,9 @@ class PIDController : public frc::SendableBase {
// The period (in seconds) of the control loop running this controller
units::second_t m_period;
// |maximum output|
double m_maximumOutput = 1.0;
double m_maximumIntegral = 1.0;
// |minimum output|
double m_minimumOutput = -1.0;
double m_minimumIntegral = -1.0;
// Maximum input - limit setpoint to this
double m_maximumInput = 0;

View File

@@ -168,12 +168,15 @@ class ProfiledPIDController : public SendableBase {
void DisableContinuousInput();
/**
* Sets the minimum and maximum values to write.
* Sets the minimum and maximum values for the integrator.
*
* @param minimumOutput the minimum value to write to the output
* @param maximumOutput the maximum value to write to the output
* When the cap is reached, the integrator value is added to the controller
* output rather than the integrator value times the integral gain.
*
* @param minimumIntegral The minimum value of the integrator.
* @param maximumIntegral The maximum value of the integrator.
*/
void SetOutputRange(double minimumOutput, double maximumOutput);
void SetIntegratorRange(double minimumIntegral, double maximumIntegral);
/**
* Sets the error which is considered tolerable for use with

View File

@@ -17,14 +17,6 @@ class PIDInputOutputTest : public testing::Test {
void TearDown() override { delete controller; }
};
TEST_F(PIDInputOutputTest, OutputRangeTest) {
controller->SetP(1);
controller->SetOutputRange(-50, 50);
EXPECT_DOUBLE_EQ(-50, controller->Calculate(100, 0));
EXPECT_DOUBLE_EQ(50, controller->Calculate(0, 100));
}
TEST_F(PIDInputOutputTest, ContinuousInputTest) {
controller->SetP(1);
controller->EnableContinuousInput(-180, 180);

View File

@@ -141,7 +141,7 @@ TEST_P(MotorEncoderTest, PositionPIDController) {
double goal = 1000;
frc2::PIDController pidController(0.001, 0.01, 0.0);
pidController.SetTolerance(50.0);
pidController.SetOutputRange(-0.2, 0.2);
pidController.SetIntegratorRange(-0.2, 0.2);
pidController.SetSetpoint(goal);
/* 10 seconds should be plenty time to get to the reference */
@@ -167,7 +167,6 @@ TEST_P(MotorEncoderTest, VelocityPIDController) {
frc2::PIDController pidController(1e-5, 0.0, 0.0006);
pidController.SetTolerance(200.0);
pidController.SetOutputRange(-0.3, 0.3);
pidController.SetSetpoint(600);
/* 10 seconds should be plenty time to get to the reference */

View File

@@ -35,11 +35,9 @@ public class PIDController extends SendableBase {
// The period (in seconds) of the loop that calls the controller
private final double m_period;
// |maximum output|
private double m_maximumOutput = 1.0;
private double m_maximumIntegral = 1.0;
// |minimum output|
private double m_minimumOutput = -1.0;
private double m_minimumIntegral = -1.0;
// Maximum input - limit setpoint to this
private double m_maximumInput;
@@ -244,14 +242,17 @@ public class PIDController extends SendableBase {
}
/**
* Sets the minimum and maximum values to write.
* Sets the minimum and maximum values for the integrator.
*
* @param minimumOutput the minimum value to write to the output
* @param maximumOutput the maximum value to write to the output
* <p>When the cap is reached, the integrator value is added to the controller
* output rather than the integrator value times the integral gain.
*
* @param minimumIntegral The minimum value of the integrator.
* @param maximumIntegral The maximum value of the integrator.
*/
public void setOutputRange(double minimumOutput, double maximumOutput) {
m_minimumOutput = minimumOutput;
m_maximumOutput = maximumOutput;
public void setIntegratorRange(double minimumIntegral, double maximumIntegral) {
m_minimumIntegral = minimumIntegral;
m_maximumIntegral = maximumIntegral;
}
/**
@@ -314,12 +315,10 @@ public class PIDController extends SendableBase {
if (m_Ki != 0) {
m_totalError = MathUtils.clamp(m_totalError + m_positionError * m_period,
m_minimumOutput / m_Ki, m_maximumOutput / m_Ki);
m_minimumIntegral / m_Ki, m_maximumIntegral / m_Ki);
}
return MathUtils.clamp(
m_Kp * m_positionError + m_Ki * m_totalError + m_Kd * m_velocityError,
m_minimumOutput, m_maximumOutput);
return m_Kp * m_positionError + m_Ki * m_totalError + m_Kd * m_velocityError;
}
/**

View File

@@ -210,13 +210,16 @@ public class ProfiledPIDController extends SendableBase {
}
/**
* Sets the minimum and maximum values to write.
* Sets the minimum and maximum values for the integrator.
*
* @param minimumOutput the minimum value to write to the output
* @param maximumOutput the maximum value to write to the output
* <p>When the cap is reached, the integrator value is added to the controller
* output rather than the integrator value times the integral gain.
*
* @param minimumIntegral The minimum value of the integrator.
* @param maximumIntegral The maximum value of the integrator.
*/
public void setOutputRange(double minimumOutput, double maximumOutput) {
m_controller.setOutputRange(minimumOutput, maximumOutput);
public void setIntegratorRange(double minimumIntegral, double maximumIntegral) {
m_controller.setIntegratorRange(minimumIntegral, maximumIntegral);
}
/**

View File

@@ -10,7 +10,6 @@ package edu.wpi.first.wpilibj.controller;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -22,17 +21,6 @@ class PIDInputOutputTest {
m_controller = new PIDController(0, 0, 0);
}
@Test
void outputRangeTest() {
m_controller.setP(1);
m_controller.setOutputRange(-50, 50);
assertAll(
() -> assertEquals(-50, m_controller.calculate(100, 0), 1e-5),
() -> assertEquals(50, m_controller.calculate(0, 100), 1e-5)
);
}
@Test
void continuousInputTest() {
m_controller.setP(1);

View File

@@ -178,7 +178,7 @@ public class MotorEncoderTest extends AbstractComsSetup {
public void testPositionPIDController() {
PIDController pidController = new PIDController(0.001, 0.0005, 0);
pidController.setTolerance(50.0);
pidController.setOutputRange(-0.2, 0.2);
pidController.setIntegratorRange(-0.2, 0.2);
pidController.setSetpoint(1000);
Notifier pidRunner = new Notifier(
@@ -201,7 +201,6 @@ public class MotorEncoderTest extends AbstractComsSetup {
LinearFilter filter = LinearFilter.movingAverage(50);
PIDController pidController = new PIDController(1e-5, 0.0, 0.0006);
pidController.setTolerance(200);
pidController.setOutputRange(-0.3, 0.3);
pidController.setSetpoint(600);
Notifier pidRunner =

View File

@@ -45,7 +45,7 @@ public class PIDTest extends AbstractComsSetup {
private SendableBuilderImpl m_builder;
private static final double absoluteTolerance = 50;
private static final double outputRange = 0.25;
private static final double integratorRange = 0.25;
private PIDController m_controller = null;
private static MotorEncoderFixture<?> me = null;
@@ -121,14 +121,14 @@ public class PIDTest extends AbstractComsSetup {
m_controller.setTolerance(absoluteTolerance);
}
private void setupOutputRange() {
m_controller.setOutputRange(-outputRange, outputRange);
private void setupIntegratorRange() {
m_controller.setIntegratorRange(-integratorRange, integratorRange);
}
@Test
public void testInitialSettings() {
setupTolerance();
setupOutputRange();
setupIntegratorRange();
double reference = 2500.0;
m_controller.setSetpoint(reference);
assertEquals("PID.getPositionError() did not start at " + reference,
@@ -144,7 +144,7 @@ public class PIDTest extends AbstractComsSetup {
@Test
public void testSetSetpoint() {
setupTolerance();
setupOutputRange();
setupIntegratorRange();
double reference = 2500.0;
m_controller.setSetpoint(reference);
assertEquals("Did not correctly set reference", reference, m_controller.getSetpoint(), 1e-3);
@@ -153,7 +153,7 @@ public class PIDTest extends AbstractComsSetup {
@Test(timeout = 10000)
public void testRotateToTarget() {
setupTolerance();
setupOutputRange();
setupIntegratorRange();
double reference = 1000.0;
assertEquals(pidData() + "did not start at 0", 0, me.getMotor().get(), 0);
m_controller.setSetpoint(reference);
@@ -178,7 +178,7 @@ public class PIDTest extends AbstractComsSetup {
@Test(expected = RuntimeException.class)
public void testOnTargetNoToleranceSet() {
setupOutputRange();
setupIntegratorRange();
m_controller.atSetpoint();
}
}