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 008package edu.wpi.first.wpilibj.command; 009 010import edu.wpi.first.wpilibj.PIDController; 011import edu.wpi.first.wpilibj.PIDOutput; 012import edu.wpi.first.wpilibj.PIDSource; 013import edu.wpi.first.wpilibj.Sendable; 014import 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 */ 025public 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 * @return the {@link PIDController} used by this {@link PIDCommand} 100 */ 101 protected PIDController getPIDController() { 102 return controller; 103 } 104 105 void _initialize() { 106 controller.enable(); 107 } 108 109 void _end() { 110 controller.disable(); 111 } 112 113 void _interrupted() { 114 _end(); 115 } 116 117 /** 118 * Adds the given value to the setpoint. 119 * If {@link PIDCommand#setInputRange(double, double) setInputRange(...)} was used, 120 * then the bounds will still be honored by this method. 121 * @param deltaSetpoint the change in the setpoint 122 */ 123 public void setSetpointRelative(double deltaSetpoint) { 124 setSetpoint(getSetpoint() + deltaSetpoint); 125 } 126 127 /** 128 * Sets the setpoint to the given value. If {@link PIDCommand#setInputRange(double, double) setInputRange(...)} 129 * was called, 130 * then the given setpoint 131 * will be trimmed to fit within the range. 132 * @param setpoint the new setpoint 133 */ 134 protected void setSetpoint(double setpoint) { 135 controller.setSetpoint(setpoint); 136 } 137 138 /** 139 * Returns the setpoint. 140 * @return the setpoint 141 */ 142 protected double getSetpoint() { 143 return controller.getSetpoint(); 144 } 145 146 /** 147 * Returns the current position 148 * @return the current position 149 */ 150 protected double getPosition() { 151 return returnPIDInput(); 152 } 153 154 /** 155 * Sets the maximum and minimum values expected from the input and setpoint. 156 * 157 * @param minimumInput the minimum value expected from the input and setpoint 158 * @param maximumInput the maximum value expected from the input and setpoint 159 */ 160 protected void setInputRange(double minimumInput, double maximumInput) { 161 controller.setInputRange(minimumInput, maximumInput); 162 } 163 164 /** 165 * Returns the input for the pid loop. 166 * 167 * <p>It returns the input for the pid loop, so if this command was based 168 * off of a gyro, then it should return the angle of the gyro</p> 169 * 170 * <p>All subclasses of {@link PIDCommand} must override this method.</p> 171 * 172 * <p>This method will be called in a different thread then the {@link Scheduler} thread.</p> 173 * 174 * @return the value the pid loop should use as input 175 */ 176 protected abstract double returnPIDInput(); 177 178 /** 179 * Uses the value that the pid loop calculated. The calculated value is the "output" parameter. 180 * This method is a good time to set motor values, maybe something along the lines of <code>driveline.tankDrive(output, -output)</code> 181 * 182 * <p>All subclasses of {@link PIDCommand} must override this method.</p> 183 * 184 * <p>This method will be called in a different thread then the {@link Scheduler} thread.</p> 185 * 186 * @param output the value the pid loop calculated 187 */ 188 protected abstract void usePIDOutput(double output); 189 190 public String getSmartDashboardType() { 191 return "PIDCommand"; 192 } 193 public void initTable(ITable table) { 194 controller.initTable(table); 195 super.initTable(table); 196 } 197}