Hello CD,
Yet another PID help thread, I apologize, but my team and I were having troubles with implementation of the PID Subsystem to properly work with our elevator lift. Originally we had the lift just stop once it went over a certain setpoint(which worked to some degree) but we now wanted a more accurate and elegant solution.
Setup:
We have two standard CIM motors as the output, and one encoder as the input. There is no CAN, just PWM and regular victors being used.
Issue:
-The implementation of the PID Subsystem results in the motor reaching the desired setpoint; however, oscillates when it reaches it.
-When the Robot is disabled quickly after the fear that the oscillation will break the elevator, when it is re-enabled it continues the PID command right when enabled without any buttons pressed. When the robot code is re-deployed or reset, this does not happen.
Attempted Solutions:
-Followed the GearBots Example, seems to have had some success, except for the oscillation.
-Lower P constant (I and D have remained at 0). Seems to not work, it has went as low as 0.02.
-Change the isFinished() method within the command to instead of detect for onTarget() method to a custom method that implemented our old code of the lift stopping after a certain setpoint. Did not work as well.
-Changed Absolute Tolerance and even tried Percent Tolerance, these were set to 200 ticks for the former and 30% for the latter. Still oscillation.
The Code:
Subsystem
package org.usfirst.frc.team4716.robot.subsystems;
import org.usfirst.frc.team4716.robot.RobotMap;
import edu.wpi.first.wpilibj.DigitalInput;
import edu.wpi.first.wpilibj.Encoder;
import edu.wpi.first.wpilibj.SpeedController;
import edu.wpi.first.wpilibj.CounterBase.EncodingType;
import edu.wpi.first.wpilibj.Victor;
import edu.wpi.first.wpilibj.command.PIDSubsystem;
/**
*
*/
public class PIDElevator extends PIDSubsystem {
private DigitalInput limitSwitch;
private Encoder elevEncoder;
private SpeedController m1,m2;
// Initialize your subsystem here
public PIDElevator() {
super("PIDElevator",0.1,0.0,0.0);
setAbsoluteTolerance(5);
getPIDController().setContinuous(false);
limitSwitch = new DigitalInput(1);
m1 = new Victor(4);
m2 = new Victor(5);
elevEncoder = new Encoder(RobotMap.ELEVATOR_ENCODER_PORT_1, RobotMap.ELEVATOR_ENCDER_PORT_2,
false, EncodingType.k4X);
// Use these to get going:
// setSetpoint() - Sets where the PID controller should move the system
// to
// enable() - Enables the PID controller.
}
public void initDefaultCommand() {
// Set the default command for a subsystem here.
//setDefaultCommand(new MySpecialCommand());
}
protected double returnPIDInput() {
// Return your input value for the PID loop
// e.g. a sensor, like a potentiometer:
// yourPot.getAverageVoltage() / kYourMaxVoltage;
return elevEncoder.pidGet();
}
protected void usePIDOutput(double output) {
// Use output to drive your system, like a motor
// e.g. yourMotor.set(output);
m1.set(-output);
m2.set(-output);
}
public boolean getLimit(){
return limitSwitch.get();
}
public boolean isUp(double setpoint){
return (elevEncoder.get() >= setpoint) ? true:false;
}
public void setMotor(double x){
m1.set(x);
m2.set(x);
}
}
Command
package org.usfirst.frc.team4716.robot.commands;
import org.usfirst.frc.team4716.robot.Robot;
import edu.wpi.first.wpilibj.command.Command;
/**
*
*/
public class SetElevatorSetpoint extends Command {
private double setpoint;
public SetElevatorSetpoint(double setpoint) {
// Use requires() here to declare subsystem dependencies
// eg. requires(chassis);
this.setpoint = setpoint;
requires(Robot.pidelevator);
}
// Called just before this Command runs the first time
protected void initialize() {
Robot.pidelevator.enable();
Robot.pidelevator.setSetpoint(setpoint);
}
// Called repeatedly when this Command is scheduled to run
protected void execute() {
}
// Make this return true when this Command no longer needs to run execute()
protected boolean isFinished() {
return Robot.pidelevator.onTarget();
}
// Called once after isFinished returns true
protected void end() {
Robot.pidelevator.disable();
}
// Called when another command which requires one or more of the same
// subsystems is scheduled to run
protected void interrupted() {
Robot.pidelevator.disable();
}
}
Sorry if the post is a bit lengthy, I just wanted to give as much information as possible to reduce the amount of replies to clarify information.