2020-12-26 14:12:05 -08:00
|
|
|
// Copyright (c) FIRST and other WPILib contributors.
|
|
|
|
|
// Open Source Software; you can modify and/or share it under the terms of
|
|
|
|
|
// the WPILib BSD license file in the root directory of this project.
|
2016-01-02 03:02:34 -08:00
|
|
|
|
2014-06-02 18:05:15 -04:00
|
|
|
package edu.wpi.first.wpilibj;
|
|
|
|
|
|
2018-05-24 00:31:04 -04:00
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.Arrays;
|
|
|
|
|
import java.util.Collection;
|
|
|
|
|
import java.util.logging.Logger;
|
|
|
|
|
|
2014-06-02 18:05:15 -04:00
|
|
|
import org.junit.After;
|
|
|
|
|
import org.junit.AfterClass;
|
|
|
|
|
import org.junit.Before;
|
|
|
|
|
import org.junit.BeforeClass;
|
|
|
|
|
import org.junit.Test;
|
|
|
|
|
import org.junit.runner.RunWith;
|
|
|
|
|
import org.junit.runners.Parameterized;
|
|
|
|
|
import org.junit.runners.Parameterized.Parameters;
|
|
|
|
|
|
2017-08-28 00:32:53 -07:00
|
|
|
import edu.wpi.first.networktables.NetworkTable;
|
|
|
|
|
import edu.wpi.first.networktables.NetworkTableInstance;
|
Add replacement PIDController class (#1300)
Originally, PIDController used PIDSource with its "PIDSourceType" to
determine whether a class should return position or velocity to the
controller. However, the supported languages have changed a lot over 10
years and now support lambdas. Instead of using PIDSource and PIDOutput,
users can pass in doubles to the Calculate() function synchronously.
This makes the controller much more flexible for team's needs as they no
longer have to make a separate PIDSource-inheriting class just to
provide a custom input.
The built-in feedforward was removed. Since PIDController is synchronous
now, they can add their own feedforward on top of what Calculate()
returns.
To facilitate running the controller asynchronously, there is a
PIDControllerRunner class that handles that. By separating the loop from
the control law, PIDController can now be composed with others and be
used to control a drivetrain (a multiple input, multiple output system
that requires summing the results from two controllers) much easier.
Also, motion profiling can be used to set the reference over time.
All the classes related to the old PIDController are now deprecated. The
new classes are in an experimental namespace to avoid name conflicts.
While this is a large change, I think it is a necessary one for growth.
The old PIDController design was created in a time when languages only
supported OOP, and we have more tools at our disposal now to solve
problems. This more versatile implementation can be used in more places
like as a replacement for Pathfinder's "EncoderFollower" class.
There has been hesitation to add lambda support to WPILib for a while
now out of concerns for requiring teams to learn more features of C++ or
Java. In my opinion, this change makes PIDController easier to use, not
harder. The concept of a function is a building block of OOP and should
be learned before classes. The ability to store functions as first-class
objects and invoke them just like variables is rather natural.
Note that PID constants for the new controller will be different from
the old one. The original controller didn't take the discretization
period into account. To fix this, teams should just have to divide their
Ki gain by 0.05 and multiply their Kd gain by 0.05 where 0.05 is the
original default period.
2019-07-07 15:37:13 -07:00
|
|
|
import edu.wpi.first.wpilibj.controller.PIDController;
|
2014-06-02 18:05:15 -04:00
|
|
|
import edu.wpi.first.wpilibj.fixtures.MotorEncoderFixture;
|
2017-12-04 23:28:33 -08:00
|
|
|
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilderImpl;
|
2014-06-02 18:05:15 -04:00
|
|
|
import edu.wpi.first.wpilibj.test.AbstractComsSetup;
|
|
|
|
|
import edu.wpi.first.wpilibj.test.TestBench;
|
|
|
|
|
|
2016-05-20 12:07:40 -04:00
|
|
|
import static org.junit.Assert.assertEquals;
|
|
|
|
|
import static org.junit.Assert.assertFalse;
|
|
|
|
|
import static org.junit.Assert.assertTrue;
|
|
|
|
|
|
2014-06-02 18:05:15 -04:00
|
|
|
|
|
|
|
|
/**
|
2016-05-20 12:07:40 -04:00
|
|
|
* Test that covers the {@link PIDController}.
|
2014-06-02 18:05:15 -04:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
@RunWith(Parameterized.class)
|
|
|
|
|
public class PIDTest extends AbstractComsSetup {
|
2015-06-25 15:07:55 -04:00
|
|
|
private static final Logger logger = Logger.getLogger(PIDTest.class.getName());
|
2016-05-20 12:07:40 -04:00
|
|
|
private NetworkTable m_table;
|
2017-12-04 23:28:33 -08:00
|
|
|
private SendableBuilderImpl m_builder;
|
2015-06-25 15:07:55 -04:00
|
|
|
|
|
|
|
|
private static final double absoluteTolerance = 50;
|
2019-08-26 21:40:30 -07:00
|
|
|
private static final double integratorRange = 0.25;
|
2015-06-25 15:07:55 -04:00
|
|
|
|
2016-05-20 12:07:40 -04:00
|
|
|
private PIDController m_controller = null;
|
2019-09-03 19:44:24 -07:00
|
|
|
private static MotorEncoderFixture<?> me = null;
|
2015-06-25 15:07:55 -04:00
|
|
|
|
2016-05-20 12:07:40 -04:00
|
|
|
@SuppressWarnings({"MemberName", "EmptyLineSeparator", "MultipleVariableDeclarations"})
|
2015-06-25 15:07:55 -04:00
|
|
|
private final Double k_p, k_i, k_d;
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected Logger getClassLogger() {
|
|
|
|
|
return logger;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-05-20 12:07:40 -04:00
|
|
|
@SuppressWarnings({"ParameterName", "JavadocMethod"})
|
2019-09-03 19:44:24 -07:00
|
|
|
public PIDTest(Double p, Double i, Double d, MotorEncoderFixture<?> mef) {
|
2015-06-25 15:07:55 -04:00
|
|
|
logger.fine("Constructor with: " + mef.getType());
|
2016-05-20 12:07:40 -04:00
|
|
|
if (PIDTest.me != null && !PIDTest.me.equals(mef)) {
|
2015-06-25 15:07:55 -04:00
|
|
|
PIDTest.me.teardown();
|
2016-05-20 12:07:40 -04:00
|
|
|
}
|
2015-06-25 15:07:55 -04:00
|
|
|
PIDTest.me = mef;
|
|
|
|
|
this.k_p = p;
|
|
|
|
|
this.k_i = i;
|
|
|
|
|
this.k_d = d;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Parameters
|
|
|
|
|
public static Collection<Object[]> generateData() {
|
|
|
|
|
// logger.fine("Loading the MotorList");
|
|
|
|
|
Collection<Object[]> data = new ArrayList<Object[]>();
|
|
|
|
|
double kp = 0.001;
|
|
|
|
|
double ki = 0.0005;
|
|
|
|
|
double kd = 0.0;
|
|
|
|
|
for (int i = 0; i < 1; i++) {
|
2019-08-04 03:01:11 -04:00
|
|
|
data.addAll(Arrays.asList(new Object[][]{{kp, ki, kd, TestBench.getInstance().getTalonPair()},
|
2015-06-25 15:07:55 -04:00
|
|
|
{kp, ki, kd, TestBench.getInstance().getVictorPair()},
|
|
|
|
|
{kp, ki, kd, TestBench.getInstance().getJaguarPair()}}));
|
|
|
|
|
}
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@BeforeClass
|
2019-08-01 01:19:48 -04:00
|
|
|
public static void setUpBeforeClass() {
|
2016-05-20 12:07:40 -04:00
|
|
|
}
|
2015-06-25 15:07:55 -04:00
|
|
|
|
|
|
|
|
@AfterClass
|
2019-08-01 01:19:48 -04:00
|
|
|
public static void tearDownAfterClass() {
|
2015-06-25 15:07:55 -04:00
|
|
|
logger.fine("TearDownAfterClass: " + me.getType());
|
|
|
|
|
me.teardown();
|
|
|
|
|
me = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Before
|
2019-08-01 01:19:48 -04:00
|
|
|
public void setUp() {
|
2015-06-25 15:07:55 -04:00
|
|
|
logger.fine("Setup: " + me.getType());
|
|
|
|
|
me.setup();
|
2017-08-28 00:32:53 -07:00
|
|
|
m_table = NetworkTableInstance.getDefault().getTable("TEST_PID");
|
2017-12-04 23:28:33 -08:00
|
|
|
m_builder = new SendableBuilderImpl();
|
|
|
|
|
m_builder.setTable(m_table);
|
Add replacement PIDController class (#1300)
Originally, PIDController used PIDSource with its "PIDSourceType" to
determine whether a class should return position or velocity to the
controller. However, the supported languages have changed a lot over 10
years and now support lambdas. Instead of using PIDSource and PIDOutput,
users can pass in doubles to the Calculate() function synchronously.
This makes the controller much more flexible for team's needs as they no
longer have to make a separate PIDSource-inheriting class just to
provide a custom input.
The built-in feedforward was removed. Since PIDController is synchronous
now, they can add their own feedforward on top of what Calculate()
returns.
To facilitate running the controller asynchronously, there is a
PIDControllerRunner class that handles that. By separating the loop from
the control law, PIDController can now be composed with others and be
used to control a drivetrain (a multiple input, multiple output system
that requires summing the results from two controllers) much easier.
Also, motion profiling can be used to set the reference over time.
All the classes related to the old PIDController are now deprecated. The
new classes are in an experimental namespace to avoid name conflicts.
While this is a large change, I think it is a necessary one for growth.
The old PIDController design was created in a time when languages only
supported OOP, and we have more tools at our disposal now to solve
problems. This more versatile implementation can be used in more places
like as a replacement for Pathfinder's "EncoderFollower" class.
There has been hesitation to add lambda support to WPILib for a while
now out of concerns for requiring teams to learn more features of C++ or
Java. In my opinion, this change makes PIDController easier to use, not
harder. The concept of a function is a building block of OOP and should
be learned before classes. The ability to store functions as first-class
objects and invoke them just like variables is rather natural.
Note that PID constants for the new controller will be different from
the old one. The original controller didn't take the discretization
period into account. To fix this, teams should just have to divide their
Ki gain by 0.05 and multiply their Kd gain by 0.05 where 0.05 is the
original default period.
2019-07-07 15:37:13 -07:00
|
|
|
m_controller = new PIDController(k_p, k_i, k_d);
|
2017-12-04 23:28:33 -08:00
|
|
|
m_controller.initSendable(m_builder);
|
2015-06-25 15:07:55 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@After
|
2019-08-01 01:19:48 -04:00
|
|
|
public void tearDown() {
|
2015-06-25 15:07:55 -04:00
|
|
|
logger.fine("Teardown: " + me.getType());
|
2016-05-20 12:07:40 -04:00
|
|
|
m_controller = null;
|
2015-06-25 15:07:55 -04:00
|
|
|
me.reset();
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-25 13:01:51 -07:00
|
|
|
private void setupTolerance() {
|
|
|
|
|
m_controller.setTolerance(absoluteTolerance);
|
2015-06-25 15:07:55 -04:00
|
|
|
}
|
|
|
|
|
|
2019-08-26 21:40:30 -07:00
|
|
|
private void setupIntegratorRange() {
|
|
|
|
|
m_controller.setIntegratorRange(-integratorRange, integratorRange);
|
2015-06-25 15:07:55 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void testInitialSettings() {
|
2019-08-25 13:01:51 -07:00
|
|
|
setupTolerance();
|
2019-08-26 21:40:30 -07:00
|
|
|
setupIntegratorRange();
|
Add replacement PIDController class (#1300)
Originally, PIDController used PIDSource with its "PIDSourceType" to
determine whether a class should return position or velocity to the
controller. However, the supported languages have changed a lot over 10
years and now support lambdas. Instead of using PIDSource and PIDOutput,
users can pass in doubles to the Calculate() function synchronously.
This makes the controller much more flexible for team's needs as they no
longer have to make a separate PIDSource-inheriting class just to
provide a custom input.
The built-in feedforward was removed. Since PIDController is synchronous
now, they can add their own feedforward on top of what Calculate()
returns.
To facilitate running the controller asynchronously, there is a
PIDControllerRunner class that handles that. By separating the loop from
the control law, PIDController can now be composed with others and be
used to control a drivetrain (a multiple input, multiple output system
that requires summing the results from two controllers) much easier.
Also, motion profiling can be used to set the reference over time.
All the classes related to the old PIDController are now deprecated. The
new classes are in an experimental namespace to avoid name conflicts.
While this is a large change, I think it is a necessary one for growth.
The old PIDController design was created in a time when languages only
supported OOP, and we have more tools at our disposal now to solve
problems. This more versatile implementation can be used in more places
like as a replacement for Pathfinder's "EncoderFollower" class.
There has been hesitation to add lambda support to WPILib for a while
now out of concerns for requiring teams to learn more features of C++ or
Java. In my opinion, this change makes PIDController easier to use, not
harder. The concept of a function is a building block of OOP and should
be learned before classes. The ability to store functions as first-class
objects and invoke them just like variables is rather natural.
Note that PID constants for the new controller will be different from
the old one. The original controller didn't take the discretization
period into account. To fix this, teams should just have to divide their
Ki gain by 0.05 and multiply their Kd gain by 0.05 where 0.05 is the
original default period.
2019-07-07 15:37:13 -07:00
|
|
|
double reference = 2500.0;
|
|
|
|
|
m_controller.setSetpoint(reference);
|
2019-08-14 22:17:44 -07:00
|
|
|
assertEquals("PID.getPositionError() did not start at " + reference,
|
|
|
|
|
reference, m_controller.getPositionError(), 0);
|
2017-12-04 23:28:33 -08:00
|
|
|
m_builder.updateTable();
|
Add replacement PIDController class (#1300)
Originally, PIDController used PIDSource with its "PIDSourceType" to
determine whether a class should return position or velocity to the
controller. However, the supported languages have changed a lot over 10
years and now support lambdas. Instead of using PIDSource and PIDOutput,
users can pass in doubles to the Calculate() function synchronously.
This makes the controller much more flexible for team's needs as they no
longer have to make a separate PIDSource-inheriting class just to
provide a custom input.
The built-in feedforward was removed. Since PIDController is synchronous
now, they can add their own feedforward on top of what Calculate()
returns.
To facilitate running the controller asynchronously, there is a
PIDControllerRunner class that handles that. By separating the loop from
the control law, PIDController can now be composed with others and be
used to control a drivetrain (a multiple input, multiple output system
that requires summing the results from two controllers) much easier.
Also, motion profiling can be used to set the reference over time.
All the classes related to the old PIDController are now deprecated. The
new classes are in an experimental namespace to avoid name conflicts.
While this is a large change, I think it is a necessary one for growth.
The old PIDController design was created in a time when languages only
supported OOP, and we have more tools at our disposal now to solve
problems. This more versatile implementation can be used in more places
like as a replacement for Pathfinder's "EncoderFollower" class.
There has been hesitation to add lambda support to WPILib for a while
now out of concerns for requiring teams to learn more features of C++ or
Java. In my opinion, this change makes PIDController easier to use, not
harder. The concept of a function is a building block of OOP and should
be learned before classes. The ability to store functions as first-class
objects and invoke them just like variables is rather natural.
Note that PID constants for the new controller will be different from
the old one. The original controller didn't take the discretization
period into account. To fix this, teams should just have to divide their
Ki gain by 0.05 and multiply their Kd gain by 0.05 where 0.05 is the
original default period.
2019-07-07 15:37:13 -07:00
|
|
|
assertEquals(k_p, m_table.getEntry("Kp").getDouble(9999999), 0);
|
|
|
|
|
assertEquals(k_i, m_table.getEntry("Ki").getDouble(9999999), 0);
|
|
|
|
|
assertEquals(k_d, m_table.getEntry("Kd").getDouble(9999999), 0);
|
|
|
|
|
assertEquals(reference, m_table.getEntry("reference").getDouble(9999999), 0);
|
2017-08-28 00:32:53 -07:00
|
|
|
assertFalse(m_table.getEntry("enabled").getBoolean(true));
|
2015-06-25 15:07:55 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void testSetSetpoint() {
|
2019-08-25 13:01:51 -07:00
|
|
|
setupTolerance();
|
2019-08-26 21:40:30 -07:00
|
|
|
setupIntegratorRange();
|
2019-08-01 01:19:48 -04:00
|
|
|
double reference = 2500.0;
|
Add replacement PIDController class (#1300)
Originally, PIDController used PIDSource with its "PIDSourceType" to
determine whether a class should return position or velocity to the
controller. However, the supported languages have changed a lot over 10
years and now support lambdas. Instead of using PIDSource and PIDOutput,
users can pass in doubles to the Calculate() function synchronously.
This makes the controller much more flexible for team's needs as they no
longer have to make a separate PIDSource-inheriting class just to
provide a custom input.
The built-in feedforward was removed. Since PIDController is synchronous
now, they can add their own feedforward on top of what Calculate()
returns.
To facilitate running the controller asynchronously, there is a
PIDControllerRunner class that handles that. By separating the loop from
the control law, PIDController can now be composed with others and be
used to control a drivetrain (a multiple input, multiple output system
that requires summing the results from two controllers) much easier.
Also, motion profiling can be used to set the reference over time.
All the classes related to the old PIDController are now deprecated. The
new classes are in an experimental namespace to avoid name conflicts.
While this is a large change, I think it is a necessary one for growth.
The old PIDController design was created in a time when languages only
supported OOP, and we have more tools at our disposal now to solve
problems. This more versatile implementation can be used in more places
like as a replacement for Pathfinder's "EncoderFollower" class.
There has been hesitation to add lambda support to WPILib for a while
now out of concerns for requiring teams to learn more features of C++ or
Java. In my opinion, this change makes PIDController easier to use, not
harder. The concept of a function is a building block of OOP and should
be learned before classes. The ability to store functions as first-class
objects and invoke them just like variables is rather natural.
Note that PID constants for the new controller will be different from
the old one. The original controller didn't take the discretization
period into account. To fix this, teams should just have to divide their
Ki gain by 0.05 and multiply their Kd gain by 0.05 where 0.05 is the
original default period.
2019-07-07 15:37:13 -07:00
|
|
|
m_controller.setSetpoint(reference);
|
2019-08-04 03:01:11 -04:00
|
|
|
assertEquals("Did not correctly set reference", reference, m_controller.getSetpoint(), 1e-3);
|
2015-06-25 15:07:55 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test(timeout = 10000)
|
|
|
|
|
public void testRotateToTarget() {
|
2019-08-25 13:01:51 -07:00
|
|
|
setupTolerance();
|
2019-08-26 21:40:30 -07:00
|
|
|
setupIntegratorRange();
|
Add replacement PIDController class (#1300)
Originally, PIDController used PIDSource with its "PIDSourceType" to
determine whether a class should return position or velocity to the
controller. However, the supported languages have changed a lot over 10
years and now support lambdas. Instead of using PIDSource and PIDOutput,
users can pass in doubles to the Calculate() function synchronously.
This makes the controller much more flexible for team's needs as they no
longer have to make a separate PIDSource-inheriting class just to
provide a custom input.
The built-in feedforward was removed. Since PIDController is synchronous
now, they can add their own feedforward on top of what Calculate()
returns.
To facilitate running the controller asynchronously, there is a
PIDControllerRunner class that handles that. By separating the loop from
the control law, PIDController can now be composed with others and be
used to control a drivetrain (a multiple input, multiple output system
that requires summing the results from two controllers) much easier.
Also, motion profiling can be used to set the reference over time.
All the classes related to the old PIDController are now deprecated. The
new classes are in an experimental namespace to avoid name conflicts.
While this is a large change, I think it is a necessary one for growth.
The old PIDController design was created in a time when languages only
supported OOP, and we have more tools at our disposal now to solve
problems. This more versatile implementation can be used in more places
like as a replacement for Pathfinder's "EncoderFollower" class.
There has been hesitation to add lambda support to WPILib for a while
now out of concerns for requiring teams to learn more features of C++ or
Java. In my opinion, this change makes PIDController easier to use, not
harder. The concept of a function is a building block of OOP and should
be learned before classes. The ability to store functions as first-class
objects and invoke them just like variables is rather natural.
Note that PID constants for the new controller will be different from
the old one. The original controller didn't take the discretization
period into account. To fix this, teams should just have to divide their
Ki gain by 0.05 and multiply their Kd gain by 0.05 where 0.05 is the
original default period.
2019-07-07 15:37:13 -07:00
|
|
|
double reference = 1000.0;
|
2019-08-14 22:17:44 -07:00
|
|
|
assertEquals(pidData() + "did not start at 0", 0, me.getMotor().get(), 0);
|
Add replacement PIDController class (#1300)
Originally, PIDController used PIDSource with its "PIDSourceType" to
determine whether a class should return position or velocity to the
controller. However, the supported languages have changed a lot over 10
years and now support lambdas. Instead of using PIDSource and PIDOutput,
users can pass in doubles to the Calculate() function synchronously.
This makes the controller much more flexible for team's needs as they no
longer have to make a separate PIDSource-inheriting class just to
provide a custom input.
The built-in feedforward was removed. Since PIDController is synchronous
now, they can add their own feedforward on top of what Calculate()
returns.
To facilitate running the controller asynchronously, there is a
PIDControllerRunner class that handles that. By separating the loop from
the control law, PIDController can now be composed with others and be
used to control a drivetrain (a multiple input, multiple output system
that requires summing the results from two controllers) much easier.
Also, motion profiling can be used to set the reference over time.
All the classes related to the old PIDController are now deprecated. The
new classes are in an experimental namespace to avoid name conflicts.
While this is a large change, I think it is a necessary one for growth.
The old PIDController design was created in a time when languages only
supported OOP, and we have more tools at our disposal now to solve
problems. This more versatile implementation can be used in more places
like as a replacement for Pathfinder's "EncoderFollower" class.
There has been hesitation to add lambda support to WPILib for a while
now out of concerns for requiring teams to learn more features of C++ or
Java. In my opinion, this change makes PIDController easier to use, not
harder. The concept of a function is a building block of OOP and should
be learned before classes. The ability to store functions as first-class
objects and invoke them just like variables is rather natural.
Note that PID constants for the new controller will be different from
the old one. The original controller didn't take the discretization
period into account. To fix this, teams should just have to divide their
Ki gain by 0.05 and multiply their Kd gain by 0.05 where 0.05 is the
original default period.
2019-07-07 15:37:13 -07:00
|
|
|
m_controller.setSetpoint(reference);
|
|
|
|
|
assertEquals(pidData() + "did not have an error of " + reference, reference,
|
2019-08-14 22:17:44 -07:00
|
|
|
m_controller.getPositionError(), 0);
|
2019-08-04 03:01:11 -04:00
|
|
|
Notifier pidRunner = new Notifier(
|
|
|
|
|
() -> me.getMotor().set(m_controller.calculate(me.getEncoder().getDistance())));
|
|
|
|
|
pidRunner.startPeriodic(m_controller.getPeriod());
|
2015-06-25 15:07:55 -04:00
|
|
|
Timer.delay(5);
|
2019-08-04 03:01:11 -04:00
|
|
|
pidRunner.stop();
|
2019-08-14 22:17:44 -07:00
|
|
|
assertTrue(pidData() + "Was not on Target. Controller Error: "
|
|
|
|
|
+ m_controller.getPositionError(), m_controller.atSetpoint());
|
2019-09-03 19:44:24 -07:00
|
|
|
|
|
|
|
|
pidRunner.close();
|
2015-06-25 15:07:55 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String pidData() {
|
2016-05-20 12:07:40 -04:00
|
|
|
return me.getType() + " PID {P:" + m_controller.getP() + " I:" + m_controller.getI() + " D:"
|
|
|
|
|
+ m_controller.getD() + "} ";
|
2015-06-25 15:07:55 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Test(expected = RuntimeException.class)
|
|
|
|
|
public void testOnTargetNoToleranceSet() {
|
2019-08-26 21:40:30 -07:00
|
|
|
setupIntegratorRange();
|
Add replacement PIDController class (#1300)
Originally, PIDController used PIDSource with its "PIDSourceType" to
determine whether a class should return position or velocity to the
controller. However, the supported languages have changed a lot over 10
years and now support lambdas. Instead of using PIDSource and PIDOutput,
users can pass in doubles to the Calculate() function synchronously.
This makes the controller much more flexible for team's needs as they no
longer have to make a separate PIDSource-inheriting class just to
provide a custom input.
The built-in feedforward was removed. Since PIDController is synchronous
now, they can add their own feedforward on top of what Calculate()
returns.
To facilitate running the controller asynchronously, there is a
PIDControllerRunner class that handles that. By separating the loop from
the control law, PIDController can now be composed with others and be
used to control a drivetrain (a multiple input, multiple output system
that requires summing the results from two controllers) much easier.
Also, motion profiling can be used to set the reference over time.
All the classes related to the old PIDController are now deprecated. The
new classes are in an experimental namespace to avoid name conflicts.
While this is a large change, I think it is a necessary one for growth.
The old PIDController design was created in a time when languages only
supported OOP, and we have more tools at our disposal now to solve
problems. This more versatile implementation can be used in more places
like as a replacement for Pathfinder's "EncoderFollower" class.
There has been hesitation to add lambda support to WPILib for a while
now out of concerns for requiring teams to learn more features of C++ or
Java. In my opinion, this change makes PIDController easier to use, not
harder. The concept of a function is a building block of OOP and should
be learned before classes. The ability to store functions as first-class
objects and invoke them just like variables is rather natural.
Note that PID constants for the new controller will be different from
the old one. The original controller didn't take the discretization
period into account. To fix this, teams should just have to divide their
Ki gain by 0.05 and multiply their Kd gain by 0.05 where 0.05 is the
original default period.
2019-07-07 15:37:13 -07:00
|
|
|
m_controller.atSetpoint();
|
2015-06-25 15:07:55 -04:00
|
|
|
}
|
2014-06-02 18:05:15 -04:00
|
|
|
}
|