Log in

View Full Version : PID Controller Help on Tote Lifting Mechanism


ashaylok
02-03-2015, 20:11
Hello,

My team currently uses an elevator mechanism to raise and stack totes. Earlier we implemented PID and created set points to automatically stack totes for the our drive team. We measured potentiometer values in order to obtain these set points then subtract the bottom potentiometer value from the set points in order to find the difference. This was done in order to allow us to reset the set points, if the potentiometer does shift, each time the elevator trips our bottom limit switch. Currently the elevator correctly cycles through the set points, forwards and backwards, without the totes. The elevator also correctly cycles downwards with the totes on the elevator; however, the elevator cannot cycle upwards while it is holding totes. I believe this is due to the way PID works. PID detects the distance needed to travel, and calculates the necessary speed in order to quickly reach the set point without overshooting. The problem is that totes introduce a second dynamic, weight. The more weight the elevator must move, the greater speed/current is needed to move the elevator arm up. PID however, cannot calculate this. The PID is still calculating a speed based on the distance, though it notices that the distance is not decreasing at the desired speed. The PID does not adapt by increasing the speed; rather it recalculates the speed based on the distance again.




Here is the code we have implemented.


public class ElevatorNextSetpoint extends Command {

public ElevatorNextSetpoint() {
// Use requires() here to declare subsystem dependencies
// eg. requires(chassis);

// BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=REQUIRES
requires(Robot.elevator);

// END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=REQUIRES
}

// Called just before this Command runs the first time
protected void initialize() {
//Go to next setpoint

Robot.elevator.incrementSetpoint();
}

// 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 true;
}

// Called once after isFinished returns true
protected void end() {
}

// Called when another command which requires one or more of the same
// subsystems is scheduled to run
protected void interrupted() {
}


\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\


public static final int POTENTIOMETER_NOISE = 30;

public void incrementSetpoint() {
for (int i = 0; i < setpointArray.length; i++) {
if (setpointArray[i] >= potentiometer.get() + POTENTIOMETER_NOISE) { //setpointArray[] contains our
setSetpoint(setpointArray[i]);
break;
}
}
}


\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\


public void decrementSetpoint() {
for (int i = setpointArray.length - 1; i >= 0; i--) {
if (setpointArray[i] < potentiometer.get() - POTENTIOMETER_NOISE) {
setSetpoint(setpointArray[i]);
break;
}
}
}


\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\


public void resetPotentiometerValues(){
BOTTOM = returnPIDInput();
STAGING_HEIGHT = BOTTOM + STAGING_DIFF_FROM_BOTTOM;
ONE_TOTE_HIGH = STAGING_HEIGHT + ONE_TOTE_DIFF_FROM_STAGING;
TWO_TOTE_HIGH = ONE_TOTE_HIGH + TWO_TOTE_DIFF_FROM_ONE_TOTE;
TOP = TWO_TOTE_HIGH + TOP_DIFF_FROM_TWO_TOTE;
}

TFleig78
02-03-2015, 20:51
The PID does not calculate output based solely on distance to the setpoint(error). The I gain accumulates the error over time and the D gain adds to the output based on the rate of change of the error. Are your I and D gains currently set to 0? If so, you should try giving them a nonzero value and go from there.

dellagd
02-03-2015, 21:21
It seems what you described is not PID control, but more simply just P control, which will most likely not get to a set point on an elevator that would fall by gravity if the motor was sent a zero voltage.

The I value of PID will allow the controller to accumulate the error over time, such that the longer the elevator is away from its set point, the more error that will accumulate, and the harder the controller will consequently drive the motor to get to said setpoint. With more load, the I value will take longer to accumulate the error required, so it probably wouldn't reach the set point as fast, but regardless of weight, it should lift it fully, as long as the elevator is physically capable of it.

As the elevator is at its set point, this I value persists (unless intentionally reset), and will hold your elevator at that point. If you do this though, be careful about it, as you are stalling the motors, which is pretty bad unless you're using something sealed like a CIM (and you're careful about it).


However, more of the code would help, such as for the elevator itself and what class contains the setSetpoint() method so we can all see how you define the PID controller.

loafdog
02-03-2015, 22:01
You can view our code here:

https://code.google.com/p/frc2876/source/browse/#svn%2Ftrunk%2F2015%2F2015%2FRecycleRush2876

TFleig78
02-03-2015, 22:47
super("Elevator", 0.008, 0.0, 0.008);

It looks like you don't have an I value. Try adding adding a value and the cycles up should be better.

dellagd
02-03-2015, 23:08
super("Elevator", 0.008, 0.0, 0.008);

http://cdn.meme.am/instances/500x/59801599.jpg