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 defines a {@link Command} which interacts heavily with a PID loop. 018 * 019 * <p>It provides some convenience methods to run an internal {@link PIDController}. 020 * It will also start and stop said {@link PIDController} when the {@link PIDCommand} is 021 * first initialized and ended/interrupted.</p> 022 * 023 * @author Joe Grinstead 024 */ 025 public abstract class PIDCommand extends Command implements Sendable{ 026 027 /** The internal {@link PIDController} */ 028 private PIDController controller; 029 /** An output which calls {@link PIDCommand#usePIDOutput(double)} */ 030 private PIDOutput output = new PIDOutput() { 031 032 public void pidWrite(double output) { 033 usePIDOutput(output); 034 } 035 }; 036 /** A source which calls {@link PIDCommand#returnPIDInput()} */ 037 private PIDSource source = new PIDSource() { 038 039 public double pidGet() { 040 return returnPIDInput(); 041 } 042 }; 043 044 /** 045 * Instantiates a {@link PIDCommand} that will use the given p, i and d values. 046 * @param name the name of the command 047 * @param p the proportional value 048 * @param i the integral value 049 * @param d the derivative value 050 */ 051 public PIDCommand(String name, double p, double i, double d) { 052 super(name); 053 controller = new PIDController(p, i, d, source, output); 054 } 055 056 /** 057 * Instantiates a {@link PIDCommand} that will use the given p, i and d values. It will also space the time 058 * between PID loop calculations to be equal to the given period. 059 * @param name the name 060 * @param p the proportional value 061 * @param i the integral value 062 * @param d the derivative value 063 * @param period the time (in seconds) between calculations 064 */ 065 public PIDCommand(String name, double p, double i, double d, double period) { 066 super(name); 067 controller = new PIDController(p, i, d, source, output, period); 068 } 069 070 /** 071 * Instantiates a {@link PIDCommand} that will use the given p, i and d values. 072 * It will use the class name as its name. 073 * @param p the proportional value 074 * @param i the integral value 075 * @param d the derivative value 076 */ 077 public PIDCommand(double p, double i, double d) { 078 controller = new PIDController(p, i, d, source, output); 079 } 080 081 /** 082 * Instantiates a {@link PIDCommand} that will use the given p, i and d values. 083 * It will use the class name as its name.. 084 * It will also space the time 085 * between PID loop calculations to be equal to the given period. 086 * @param p the proportional value 087 * @param i the integral value 088 * @param d the derivative value 089 * @param period the time (in seconds) between calculations 090 */ 091 public PIDCommand(double p, double i, double d, double period) { 092 controller = new PIDController(p, i, d, source, output, period); 093 } 094 095 /** 096 * Returns the {@link PIDController} used by this {@link PIDCommand}. 097 * Use this if you would like to fine tune the pid loop. 098 * 099 * <p>Notice that calling {@link PIDController#setSetpoint(double) setSetpoint(...)} on the controller 100 * will not result in the setpoint being trimmed to be in 101 * the range defined by {@link PIDCommand#setSetpointRange(double, double) setSetpointRange(...)}.</p> 102 * 103 * @return the {@link PIDController} used by this {@link PIDCommand} 104 */ 105 protected PIDController getPIDController() { 106 return controller; 107 } 108 109 void _initialize() { 110 controller.enable(); 111 } 112 113 void _end() { 114 controller.disable(); 115 } 116 117 void _interrupted() { 118 _end(); 119 } 120 121 /** 122 * Adds the given value to the setpoint. 123 * If {@link PIDCommand#setRange(double, double) setRange(...)} was used, 124 * then the bounds will still be honored by this method. 125 * @param deltaSetpoint the change in the setpoint 126 */ 127 public void setSetpointRelative(double deltaSetpoint) { 128 setSetpoint(getSetpoint() + deltaSetpoint); 129 } 130 131 /** 132 * Sets the setpoint to the given value. If {@link PIDCommand#setRange(double, double) setRange(...)} 133 * was called, 134 * then the given setpoint 135 * will be trimmed to fit within the range. 136 * @param setpoint the new setpoint 137 */ 138 protected void setSetpoint(double setpoint) { 139 controller.setSetpoint(setpoint); 140 } 141 142 /** 143 * Returns the setpoint. 144 * @return the setpoint 145 */ 146 protected double getSetpoint() { 147 return controller.getSetpoint(); 148 } 149 150 /** 151 * Returns the current position 152 * @return the current position 153 */ 154 protected double getPosition() { 155 return returnPIDInput(); 156 } 157 158 /** 159 * Returns the input for the pid loop. 160 * 161 * <p>It returns the input for the pid loop, so if this command was based 162 * off of a gyro, then it should return the angle of the gyro</p> 163 * 164 * <p>All subclasses of {@link PIDCommand} must override this method.</p> 165 * 166 * <p>This method will be called in a different thread then the {@link Scheduler} thread.</p> 167 * 168 * @return the value the pid loop should use as input 169 */ 170 protected abstract double returnPIDInput(); 171 172 /** 173 * Uses the value that the pid loop calculated. The calculated value is the "output" parameter. 174 * This method is a good time to set motor values, maybe something along the lines of <code>driveline.tankDrive(output, -output)</code> 175 * 176 * <p>All subclasses of {@link PIDCommand} must override this method.</p> 177 * 178 * <p>This method will be called in a different thread then the {@link Scheduler} thread.</p> 179 * 180 * @param output the value the pid loop calculated 181 */ 182 protected abstract void usePIDOutput(double output); 183 184 public String getSmartDashboardType(){ 185 return "PIDCommand"; 186 } 187 public void initTable(ITable table){ 188 controller.initTable(table); 189 super.initTable(table); 190 } 191 }