001 /*----------------------------------------------------------------------------*/ 002 /* Copyright (c) FIRST 2008-2012. All Rights Reserved. */ 003 /* Open Source Software - may be modified and shared by FRC teams. The code */ 004 /* must be accompanied by the FIRST BSD license file in the root directory of */ 005 /* the project. */ 006 /*----------------------------------------------------------------------------*/ 007 008 package edu.wpi.first.wpilibj.command; 009 010 import edu.wpi.first.wpilibj.PIDController; 011 import edu.wpi.first.wpilibj.PIDOutput; 012 import edu.wpi.first.wpilibj.PIDSource; 013 import edu.wpi.first.wpilibj.Sendable; 014 import edu.wpi.first.wpilibj.tables.ITable; 015 016 /** 017 * This class is designed to handle the case where there is a {@link Subsystem} 018 * which uses a single {@link PIDController} almost constantly (for instance, 019 * an elevator which attempts to stay at a constant height). 020 * 021 * <p>It provides some convenience methods to run an internal {@link PIDController}. 022 * It also allows access to the internal {@link PIDController} in order to give total control 023 * to the programmer.</p> 024 * 025 * @author Joe Grinstead 026 */ 027 public abstract class PIDSubsystem extends Subsystem implements Sendable{ 028 029 /** The internal {@link PIDController} */ 030 private PIDController controller; 031 /** An output which calls {@link PIDCommand#usePIDOutput(double)} */ 032 private PIDOutput output = new PIDOutput() { 033 034 public void pidWrite(double output) { 035 usePIDOutput(output); 036 } 037 }; 038 /** A source which calls {@link PIDCommand#returnPIDInput()} */ 039 private PIDSource source = new PIDSource() { 040 041 public double pidGet() { 042 return returnPIDInput(); 043 } 044 }; 045 046 /** 047 * Instantiates a {@link PIDSubsystem} that will use the given p, i and d values. 048 * @param name the name 049 * @param p the proportional value 050 * @param i the integral value 051 * @param d the derivative value 052 */ 053 public PIDSubsystem(String name, double p, double i, double d) { 054 super(name); 055 controller = new PIDController(p, i, d, source, output); 056 } 057 058 /** 059 * Instantiates a {@link PIDSubsystem} that will use the given p, i and d values. 060 * @param name the name 061 * @param p the proportional value 062 * @param i the integral value 063 * @param d the derivative value 064 * @param f the feed forward value 065 */ 066 public PIDSubsystem(String name, double p, double i, double d, double f) { 067 super(name); 068 controller = new PIDController(p, i, d, f, source, output); 069 } 070 071 /** 072 * Instantiates a {@link PIDSubsystem} that will use the given p, i and d values. It will also space the time 073 * between PID loop calculations to be equal to the given period. 074 * @param name the name 075 * @param p the proportional value 076 * @param i the integral value 077 * @param d the derivative value 078 * @param period the time (in seconds) between calculations 079 */ 080 public PIDSubsystem(String name, double p, double i, double d, double f, double period) { 081 super(name); 082 controller = new PIDController(p, i, d, f, source, output, period); 083 } 084 085 /** 086 * Instantiates a {@link PIDSubsystem} that will use the given p, i and d values. 087 * It will use the class name as its name. 088 * @param p the proportional value 089 * @param i the integral value 090 * @param d the derivative value 091 */ 092 public PIDSubsystem(double p, double i, double d) { 093 controller = new PIDController(p, i, d, source, output); 094 } 095 096 /** 097 * Instantiates a {@link PIDSubsystem} that will use the given p, i and d values. 098 * It will use the class name as its name. 099 * It will also space the time 100 * between PID loop calculations to be equal to the given period. 101 * @param p the proportional value 102 * @param i the integral value 103 * @param d the derivative value 104 * @param f the feed forward coefficient 105 * @param period the time (in seconds) between calculations 106 */ 107 public PIDSubsystem(double p, double i, double d, double period, double f) { 108 controller = new PIDController(p, i, d, f, source, output, period); 109 } 110 111 /** 112 * Instantiates a {@link PIDSubsystem} that will use the given p, i and d values. 113 * It will use the class name as its name. 114 * It will also space the time 115 * between PID loop calculations to be equal to the given period. 116 * @param p the proportional value 117 * @param i the integral value 118 * @param d the derivative value 119 * @param period the time (in seconds) between calculations 120 */ 121 public PIDSubsystem(double p, double i, double d, double period) { 122 controller = new PIDController(p, i, d, source, output, period); 123 } 124 125 /** 126 * Returns the {@link PIDController} used by this {@link PIDSubsystem}. 127 * Use this if you would like to fine tune the pid loop. 128 * 129 * <p>Notice that calling {@link PIDController#setSetpoint(double) setSetpoint(...)} on the controller 130 * will not result in the setpoint being trimmed to be in 131 * the range defined by {@link PIDSubsystem#setSetpointRange(double, double) setSetpointRange(...)}.</p> 132 * 133 * @return the {@link PIDController} used by this {@link PIDSubsystem} 134 */ 135 public PIDController getPIDController() { 136 return controller; 137 } 138 139 140 /** 141 * Adds the given value to the setpoint. 142 * If {@link PIDCommand#setRange(double, double) setRange(...)} was used, 143 * then the bounds will still be honored by this method. 144 * @param deltaSetpoint the change in the setpoint 145 */ 146 public void setSetpointRelative(double deltaSetpoint) { 147 setSetpoint(getPosition() + deltaSetpoint); 148 } 149 150 /** 151 * Sets the setpoint to the given value. If {@link PIDCommand#setRange(double, double) setRange(...)} 152 * was called, 153 * then the given setpoint 154 * will be trimmed to fit within the range. 155 * @param setpoint the new setpoint 156 */ 157 public void setSetpoint(double setpoint) { 158 controller.setSetpoint(setpoint); 159 } 160 161 /** 162 * Returns the setpoint. 163 * @return the setpoint 164 */ 165 public double getSetpoint() { 166 return controller.getSetpoint(); 167 } 168 169 /** 170 * Returns the current position 171 * @return the current position 172 */ 173 public double getPosition() { 174 return returnPIDInput(); 175 } 176 177 /** 178 * Sets the maximum and minimum values expected from the input. 179 * 180 * @param minimumInput the minimum value expected from the input 181 * @param maximumInput the maximum value expected from the output 182 */ 183 public void setInputRange(double minimumInput, double maximumInput) { 184 controller.setInputRange(minimumInput, maximumInput); 185 } 186 187 /** 188 * Set the absolute error which is considered tolerable for use with 189 * OnTarget. The value is in the same range as the PIDInput values. 190 * @param t A PIDController.Tolerance object instance that is for example 191 * AbsoluteTolerance or PercentageTolerance. E.g. setTolerance(new PIDController.AbsoluteTolerance(0.1)) 192 */ 193 public void setAbsoluteTolerance(double t) { 194 controller.setAbsoluteTolerance(t); 195 } 196 197 /** 198 * Set the percentage error which is considered tolerable for use with 199 * OnTarget. (Value of 15.0 == 15 percent) 200 * @param t A PIDController.Tolerance object instance that is for example 201 * AbsoluteTolerance or PercentageTolerance. E.g. setTolerance(new PIDController.AbsoluteTolerance(0.1)) 202 */ 203 public void setPercentTolerance(double p) { 204 controller.setPercentTolerance(p); 205 } 206 207 /** 208 * Return true if the error is within the percentage of the total input range, 209 * determined by setTolerance. This assumes that the maximum and minimum input 210 * were set using setInput. 211 * @return true if the error is less than the tolerance 212 */ 213 public boolean onTarget() { 214 return controller.onTarget(); 215 } 216 217 /** 218 * Returns the input for the pid loop. 219 * 220 * <p>It returns the input for the pid loop, so if this Subsystem was based 221 * off of a gyro, then it should return the angle of the gyro</p> 222 * 223 * <p>All subclasses of {@link PIDSubsystem} must override this method.</p> 224 * 225 * @return the value the pid loop should use as input 226 */ 227 protected abstract double returnPIDInput(); 228 229 /** 230 * Uses the value that the pid loop calculated. The calculated value is the "output" parameter. 231 * This method is a good time to set motor values, maybe something along the lines of <code>driveline.tankDrive(output, -output)</code> 232 * 233 * <p>All subclasses of {@link PIDSubsystem} must override this method.</p> 234 * 235 * @param output the value the pid loop calculated 236 */ 237 protected abstract void usePIDOutput(double output); 238 239 /** 240 * Enables the internal {@link PIDController} 241 */ 242 public void enable() { 243 controller.enable(); 244 } 245 246 /** 247 * Disables the internal {@link PIDController} 248 */ 249 public void disable() { 250 controller.disable(); 251 } 252 253 public String getSmartDashboardType(){ 254 return "PIDSubsystem"; 255 } 256 public void initTable(ITable table){ 257 controller.initTable(table); 258 super.initTable(table); 259 } 260 }