PID
Constructors
PID()
Creates a PID object with constants. Everything past kP has a default starting value, so you can just put kP.
p kP
i kI
d kD
start_i i will start when error is within this
name a string for the name of the PID
- Prototype
- Example
ez::PID liftPID{1, 0.003, 4, 100, "Lift"};
PID(double p, double i = 0, double d = 0, double start_i = 0, std::string name = "");
Functions
compute()
Computes PID.
current the current sensor value for the subsystem
- Prototype
- Example
ez::PID liftPID{1, 0.003, 4, 100, "Lift"};
pros::Motor lift_motor(1);
void opcontrol() {
while (true) {
if (master.get_digital(DIGITAL_L1)) {
liftPID.target_set(500);
}
else if (master.get_digital(DIGITAL_L2)) {
liftPID.target_set(0);
}
lift_motor.move(liftPID.compute(lift_motor.get_position()));
pros::delay(ez::util::DELAY_TIME);
}
}
double compute(double current);
compute_error()
Computes PID based on error. This function ignores target entirely and the user has to calculate error.
err the target minus current, you calculate this yourself
current the current sensor value for the subsystem
- Prototype
- Example
ez::PID liftPID{1, 0.003, 4, 100, "Lift"};
pros::Motor lift_motor(1);
void opcontrol() {
double target = 0.0;
double error = 0.0;
while (true) {
if (master.get_digital(DIGITAL_L1)) {
target = 500.0;
}
else if (master.get_digital(DIGITAL_L2)) {
target = 0.0;
}
error = target - lift_motor.get_position();
lift_motor.move(liftPID.compute_error(error, lift_motor.get_position()));
pros::delay(ez::util::DELAY_TIME);
}
}
double compute_error(double err, double current);
Setters
constants_set()
Sets PID constants.
p kP
i kI
d kD
p_start_i i will start when error is within this
- Prototype
- Example
ez::PID liftPID;
void initialize() {
liftPID.constants_set(1, 0, 4);
}
void constants_set(double p, double i = 0, double d = 0, double p_start_i = 0);
target_set()
Sets PID target.
input the goal position for your subsystem
- Prototype
- Example
ez::PID liftPID{1, 0.003, 4, 100, "Lift"};
pros::Motor lift_motor(1);
void opcontrol() {
while (true) {
if (master.get_digital(DIGITAL_L1)) {
liftPID.target_set(500);
}
else if (master.get_digital(DIGITAL_L2)) {
liftPID.target_set(0);
}
lift_motor.move(liftPID.compute(lift_motor.get_position()));
pros::delay(ez::util::DELAY_TIME);
}
}
void target_set(double input);
exit_condition_set()
Sets the exit condition constants. To disable one of the conditions, set the constants relating to it to 0.
p_small_exit_time time, in ms, before exiting p_small_error
p_small_error small error threshold
p_big_exit_time time, in ms, before exiting p_big_error
p_big_error big error threshold
p_velocity_exit_time time, in ms, for velocity to be 0 after the robot has moved (or after 1 second if it never moves)
p_mA_timeout time, in ms, for is_over_current to be true
- Prototype
- Example
ez::PID liftPID{1, 0.003, 4, 100, "Lift"};
void initialize() {
liftPID.exit_condition_set(100, 3, 500, 7, 500, 500);
}
void exit_condition_set(int p_small_exit_time, double p_small_error, int p_big_exit_time = 0, double p_big_error = 0, int p_velocity_exit_time = 0, int p_mA_timeout = 0);
velocity_sensor_secondary_toggle_set()
Enables / disables the use of the second sensor. True enables this and uses the secondary sensor in velocity exits, false disables.
toggle true uses the secondary sensor in velocity exits, false does not
- Prototype
- Example
ez::PID liftPID;
void initialize() {
liftPID.velocity_sensor_secondary_toggle_set(true); // Enable the secondary sensor
}
void velocity_sensor_secondary_toggle_set(bool toggle);
velocity_sensor_secondary_set()
This sets the velocity (or acceleration) reading for the secondary sensor. The secondary sensor is used in addition to the main sensor for determining velocity exits, if enabled.
secondary_sensor the secondary sensor's current velocity or acceleration reading, not its position. It counts as stopped while the absolute value of this is at or below velocity_sensor_secondary_exit_get(). EZ-Template passes the IMU acceleration magnitude.
- Prototype
- Example
ez::PID liftPID;
pros::Imu imu(5);
void autonomous() {
liftPID.velocity_sensor_secondary_toggle_set(true); // Enable the secondary sensor
liftPID.velocity_sensor_secondary_set(imu.get_gyro_rate().z); // Degrees per second, near 0 when the imu is still
}
void velocity_sensor_secondary_set(double secondary_sensor);
velocity_sensor_main_exit_set()
Sets a threshold for the main sensors velocity. The velocity timer will start increasing when the main sensor is within this value, once the robot has moved faster than this at least once (or after 1 second if it never moves). This is defaulted to 0.05.
zero double, a small threshold
- Prototype
- Example
ez::PID liftPID;
void initialize() {
liftPID.velocity_sensor_main_exit_set(0.1); // The main sensor counts as stopped within 0.1
}
void velocity_sensor_main_exit_set(double zero);
velocity_sensor_secondary_exit_set()
Sets a threshold for the secondary sensors velocity. The velocity timer will start increasing when the secondary sensor is within this value. This is defaulted to 0.075. This is only used when the secondary sensor is enabled. The velocity timer also waits until the robot has moved, see velocity_sensor_main_exit_set(), or 1 second if it never moves.
zero double, a small threshold
- Prototype
- Example
ez::PID liftPID;
void initialize() {
liftPID.velocity_sensor_secondary_toggle_set(true); // Enable the secondary sensor
liftPID.velocity_sensor_secondary_exit_set(0.1); // The secondary sensor counts as stopped within 0.1
}
void velocity_sensor_secondary_exit_set(double zero);
name_set()
A string that prints when exit conditions are met. When you have multiple mechanisms using exit conditions and you're debugging, seeing which exit condition is doing what can be useful.
name a string for the name of the PID
- Prototype
- Example
ez::PID liftPID{1, 0.003, 4, 100};
void initialize() {
liftPID.name_set("Lift");
}
void name_set(std::string name);
Getters
target_get()
Returns the PID target.
- Prototype
- Example
ez::PID liftPID{1, 0.003, 4, 100, "Lift"};
pros::Motor lift_motor(1);
void opcontrol() {
while (true) {
if (master.get_digital(DIGITAL_L1)) {
liftPID.target_set(500);
printf("%.2f\n", liftPID.target_get()); // This prints 500
}
else if (master.get_digital(DIGITAL_L2)) {
liftPID.target_set(0);
printf("%.2f\n", liftPID.target_get()); // This prints 0
}
lift_motor.move(liftPID.compute(lift_motor.get_position()));
pros::delay(ez::util::DELAY_TIME);
}
}
double target_get();
name_get()
Returns the name of the PID, the string that prints when exit conditions are met.
- Prototype
- Example
ez::PID liftPID{1, 0.003, 4, 100};
void initialize() {
liftPID.name_set("Lift");
printf("%s\n", liftPID.name_get().c_str()); // This prints Lift
}
std::string name_get();
velocity_sensor_secondary_toggle_get()
Returns if the secondary sensor is enabled for velocity exits. True means it is in use, false means it is not.
- Prototype
- Example
ez::PID liftPID;
void initialize() {
printf("%i\n",liftPID.velocity_sensor_secondary_toggle_get()); // This prints 0
liftPID.velocity_sensor_secondary_toggle_set(true); // Enable the secondary sensor
printf("%i\n",liftPID.velocity_sensor_secondary_toggle_get()); // This prints 1
}
bool velocity_sensor_secondary_toggle_get();
velocity_sensor_main_exit_get()
Gets a threshold for the main sensors velocity. The velocity timer will start increasing when the main sensor is within this value, once the robot has moved faster than this at least once (or after 1 second if it never moves). This is defaulted to 0.05.
- Prototype
- Example
ez::PID liftPID;
void initialize() {
liftPID.velocity_sensor_secondary_toggle_set(true); // Enable the secondary sensor
printf("%.2f\n",liftPID.velocity_sensor_main_exit_get()); // This prints 0.05
}
double velocity_sensor_main_exit_get();
velocity_sensor_secondary_exit_get()
Gets a threshold for the secondary sensors velocity. The velocity timer will start increasing when the secondary sensor is within this value. This is defaulted to 0.075. This is only used when the secondary sensor is enabled. The velocity timer also waits until the robot has moved, see velocity_sensor_main_exit_set(), or 1 second if it never moves.
- Prototype
- Example
ez::PID liftPID;
void initialize() {
liftPID.velocity_sensor_secondary_toggle_set(true); // Enable the secondary sensor
printf("%.3f\n",liftPID.velocity_sensor_secondary_exit_get()); // This prints 0.075
}
double velocity_sensor_secondary_exit_get();
velocity_sensor_secondary_get()
Returns the last value given to velocity_sensor_secondary_set().
- Prototype
- Example
ez::PID liftPID;
void initialize() {
liftPID.velocity_sensor_secondary_set(0.0);
printf("%.2f\n", liftPID.velocity_sensor_secondary_get()); // This prints 0.00
}
double velocity_sensor_secondary_get();
Exit Conditions
Exit conditions are a series of things that need to happen for you to know your subsystem has arrived at the desired target.
exit_output
The .exit_condition() function can return any of the following variables depending on what triggered it to exit.
enum exit_output { RUNNING = 1,
SMALL_EXIT = 2,
BIG_EXIT = 3,
VELOCITY_EXIT = 4,
mA_EXIT = 5,
ERROR_NO_CONSTANTS = 6 };
No Motor
Exit conditions without a motor will check if the error is small for X amount of time, if error is a little bigger for Y amount of time, or if velocity is 0 for Z amount of time (after the robot has moved), if you have constants enabled for them in exit_condition_set().
Outputs one of the exit_output states. This exit condition checks small_error, big_error and velocity if they are enabled.
- Prototype
- Example
ez::PID liftPID{1, 0.003, 4, 100, "Lift"};
pros::Motor lift_motor(1);
void initialize() {
liftPID.exit_condition_set(100, 3, 500, 7, 500, 500);
}
void autonomous() {
liftPID.target_set(500);
while (liftPID.exit_condition(true) == ez::RUNNING) {
lift_motor.move(liftPID.compute(lift_motor.get_position()));
pros::delay(ez::util::DELAY_TIME);
}
liftPID.target_set(0);
while (liftPID.exit_condition(true) == ez::RUNNING) {
lift_motor.move(liftPID.compute(lift_motor.get_position()));
pros::delay(ez::util::DELAY_TIME);
}
}
ez::exit_output exit_condition(bool print = false);
One Motor
Exit conditions with a motor will check if the error is small for X amount of time, if error is a little bigger for Y amount of time, if velocity is 0 for Z amount of time (after the robot has moved), then they will check if the motor is pulling too many amps for A amount of time, only if you have constants enabled for them in exit_condition_set().
Outputs one of the exit_output states. This exit condition checks small_error, big_error, velocity and mA if they are enabled.
- Prototype
- Example
ez::PID liftPID{1, 0.003, 4, 100, "Lift"};
pros::Motor lift_motor(1);
void initialize() {
liftPID.exit_condition_set(100, 3, 500, 7, 500, 500);
}
void autonomous() {
liftPID.target_set(500);
while (liftPID.exit_condition(lift_motor, true) == ez::RUNNING) {
lift_motor.move(liftPID.compute(lift_motor.get_position()));
pros::delay(ez::util::DELAY_TIME);
}
liftPID.target_set(0);
while (liftPID.exit_condition(lift_motor, true) == ez::RUNNING) {
lift_motor.move(liftPID.compute(lift_motor.get_position()));
pros::delay(ez::util::DELAY_TIME);
}
}
ez::exit_output exit_condition(pros::Motor sensor, bool print = false);
Multiple Motors
This checks the same thing as one motor, except it will check through multiple motors instead of 1. If any of the motors are pulling too many amps the function will start the timer for mA.
Outputs one of the exit_output states. This exit condition checks small_error, big_error, velocity and mA if they are enabled. When any of the motors trip mA, it returns mA_EXIT.
- Prototype
- Example
ez::PID liftPID{1, 0.003, 4, 100, "Lift"};
pros::Motor l_lift_motor(1);
pros::Motor r_lift_motor(2, true);
void set_lift(int input) {
l_lift_motor.move(input);
r_lift_motor.move(input);
}
void initialize() {
liftPID.exit_condition_set(100, 3, 500, 7, 500, 500);
}
void autonomous() {
liftPID.target_set(500);
while (liftPID.exit_condition({r_lift_motor, l_lift_motor}, true) == ez::RUNNING) {
set_lift(liftPID.compute(l_lift_motor.get_position()));
pros::delay(ez::util::DELAY_TIME);
}
liftPID.target_set(0);
while (liftPID.exit_condition({r_lift_motor, l_lift_motor}, true) == ez::RUNNING) {
set_lift(liftPID.compute(l_lift_motor.get_position()));
pros::delay(ez::util::DELAY_TIME);
}
}
ez::exit_output exit_condition(const std::vector<pros::Motor>& sensor, bool print = false);
ez::exit_output exit_condition(const pros::MotorGroup& sensor, bool print = false);
timers_reset()
Resets all timers for exit conditions.
- Prototype
- Example
ez::PID liftPID{1, 0.003, 4, 100, "Lift"};
pros::Motor lift_motor(1);
void opcontrol() {
while (true) {
if (master.get_digital(DIGITAL_L1)) {
liftPID.timers_reset();
liftPID.target_set(500);
}
else if (master.get_digital(DIGITAL_L2)) {
liftPID.timers_reset();
liftPID.target_set(0);
}
lift_motor.move(liftPID.compute(lift_motor.get_position()));
pros::delay(ez::util::DELAY_TIME);
}
}
void timers_reset();
motion_reset()
Resets the parts of the PID that shouldn't carry over from one motion to the next. It clears the integral and primes the derivative, so the first compute() of a new motion doesn't see a spike from where the last motion ended. Call it when you reuse one PID for several targets, alongside timers_reset().
current the sensor value the next compute() will be given
- Prototype
- Example
ez::PID liftPID{1, 0.003, 4, 100, "Lift"};
pros::Motor lift_motor(1);
void opcontrol() {
while (true) {
if (master.get_digital(DIGITAL_L1)) {
liftPID.motion_reset(lift_motor.get_position()); // Start fresh from where the lift is now
liftPID.timers_reset();
liftPID.target_set(500);
}
else if (master.get_digital(DIGITAL_L2)) {
liftPID.motion_reset(lift_motor.get_position());
liftPID.timers_reset();
liftPID.target_set(0);
}
lift_motor.move(liftPID.compute(lift_motor.get_position()));
pros::delay(ez::util::DELAY_TIME);
}
}
void motion_reset(double current);