001/*----------------------------------------------------------------------------*/
002/* Copyright (c) 2008-2018 FIRST. 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;
009
010import edu.wpi.first.wpilibj.interfaces.Potentiometer;
011import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
012
013/**
014 * Class for reading analog potentiometers. Analog potentiometers read in an analog voltage that
015 * corresponds to a position. The position is in whichever units you choose, by way of the scaling
016 * and offset constants passed to the constructor.
017 */
018public class AnalogPotentiometer extends SensorBase implements Potentiometer, Sendable {
019  private AnalogInput m_analogInput;
020  private boolean m_initAnalogInput;
021  private double m_fullRange;
022  private double m_offset;
023  protected PIDSourceType m_pidSource = PIDSourceType.kDisplacement;
024
025  /**
026   * AnalogPotentiometer constructor.
027   *
028   * <p>Use the fullRange and offset values so that the output produces meaningful values. I.E: you
029   * have a 270 degree potentiometer and you want the output to be degrees with the halfway point as
030   * 0 degrees. The fullRange value is 270.0(degrees) and the offset is -135.0 since the halfway
031   * point after scaling is 135 degrees. This will calculate the result from the fullRange times
032   * the fraction of the supply voltage, plus the offset.
033   *
034   * @param channel   The analog channel this potentiometer is plugged into.
035   * @param fullRange The scaling to multiply the fraction by to get a meaningful unit.
036   * @param offset    The offset to add to the scaled value for controlling the zero value
037   */
038  public AnalogPotentiometer(final int channel, double fullRange, double offset) {
039    this(new AnalogInput(channel), fullRange, offset);
040    m_initAnalogInput = true;
041    addChild(m_analogInput);
042  }
043
044  /**
045   * AnalogPotentiometer constructor.
046   *
047   * <p>Use the fullRange and offset values so that the output produces meaningful values. I.E: you
048   * have a 270 degree potentiometer and you want the output to be degrees with the halfway point as
049   * 0 degrees. The fullRange value is 270.0(degrees) and the offset is -135.0 since the halfway
050   * point after scaling is 135 degrees. This will calculate the result from the fullRange times
051   * the fraction of the supply voltage, plus the offset.
052   *
053   * @param input     The {@link AnalogInput} this potentiometer is plugged into.
054   * @param fullRange The scaling to multiply the fraction by to get a meaningful unit.
055   * @param offset    The offset to add to the scaled value for controlling the zero value
056   */
057  public AnalogPotentiometer(final AnalogInput input, double fullRange, double offset) {
058    setName("AnalogPotentiometer", input.getChannel());
059    m_analogInput = input;
060    m_initAnalogInput = false;
061
062    m_fullRange = fullRange;
063    m_offset = offset;
064  }
065
066  /**
067   * AnalogPotentiometer constructor.
068   *
069   * <p>Use the fullRange and offset values so that the output produces meaningful values. I.E: you
070   * have a 270 degree potentiometer and you want the output to be degrees with the halfway point as
071   * 0 degrees. The fullRange value is 270.0(degrees) and the offset is -135.0 since the halfway
072   * point after scaling is 135 degrees.
073   *
074   * @param channel The analog channel this potentiometer is plugged into.
075   * @param scale   The scaling to multiply the voltage by to get a meaningful unit.
076   */
077  public AnalogPotentiometer(final int channel, double scale) {
078    this(channel, scale, 0);
079  }
080
081  /**
082   * AnalogPotentiometer constructor.
083   *
084   * <p>Use the fullRange and offset values so that the output produces meaningful values. I.E: you
085   * have a 270 degree potentiometer and you want the output to be degrees with the halfway point as
086   * 0 degrees. The fullRange value is 270.0(degrees) and the offset is -135.0 since the halfway
087   * point after scaling is 135 degrees.
088   *
089   * @param input The {@link AnalogInput} this potentiometer is plugged into.
090   * @param scale The scaling to multiply the voltage by to get a meaningful unit.
091   */
092  public AnalogPotentiometer(final AnalogInput input, double scale) {
093    this(input, scale, 0);
094  }
095
096  /**
097   * AnalogPotentiometer constructor.
098   *
099   * @param channel The analog channel this potentiometer is plugged into.
100   */
101  public AnalogPotentiometer(final int channel) {
102    this(channel, 1, 0);
103  }
104
105  /**
106   * AnalogPotentiometer constructor.
107   *
108   * @param input The {@link AnalogInput} this potentiometer is plugged into.
109   */
110  public AnalogPotentiometer(final AnalogInput input) {
111    this(input, 1, 0);
112  }
113
114  /**
115   * Get the current reading of the potentiometer.
116   *
117   * @return The current position of the potentiometer.
118   */
119  @Override
120  public double get() {
121    if (m_analogInput == null) {
122      return m_offset;
123    }
124    return (m_analogInput.getVoltage() / RobotController.getVoltage5V()) * m_fullRange + m_offset;
125  }
126
127  @Override
128  public void setPIDSourceType(PIDSourceType pidSource) {
129    if (!pidSource.equals(PIDSourceType.kDisplacement)) {
130      throw new IllegalArgumentException("Only displacement PID is allowed for potentiometers.");
131    }
132    m_pidSource = pidSource;
133  }
134
135  @Override
136  public PIDSourceType getPIDSourceType() {
137    return m_pidSource;
138  }
139
140  /**
141   * Implement the PIDSource interface.
142   *
143   * @return The current reading.
144   */
145  @Override
146  public double pidGet() {
147    return get();
148  }
149
150  @Override
151  public void initSendable(SendableBuilder builder) {
152    if (m_analogInput != null) {
153      m_analogInput.initSendable(builder);
154    }
155  }
156
157  /**
158   * Frees this resource.
159   */
160  @Override
161  public void free() {
162    super.free();
163    if (m_initAnalogInput) {
164      m_analogInput.free();
165      m_analogInput = null;
166      m_initAnalogInput = false;
167    }
168  }
169}