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}