001/*----------------------------------------------------------------------------*/
002/* Copyright (c) FIRST 2008-2017. 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.livewindow.LiveWindowSendable;
012import edu.wpi.first.wpilibj.tables.ITable;
013
014/**
015 * Class for reading analog potentiometers. Analog potentiometers read in an analog voltage that
016 * corresponds to a position. The position is in whichever units you choose, by way of the scaling
017 * and offset constants passed to the constructor.
018 */
019public class AnalogPotentiometer implements Potentiometer, LiveWindowSendable {
020  private AnalogInput m_analogInput;
021  private boolean m_initAnalogInput;
022  private double m_fullRange;
023  private double m_offset;
024  protected PIDSourceType m_pidSource = PIDSourceType.kDisplacement;
025
026  /**
027   * AnalogPotentiometer constructor.
028   *
029   * <p>Use the fullRange and offset values so that the output produces meaningful values. I.E: you
030   * have a 270 degree potentiometer and you want the output to be degrees with the halfway point as
031   * 0 degrees. The fullRange value is 270.0(degrees) and the offset is -135.0 since the halfway
032   * point after scaling is 135 degrees. This will calculate the result from the fullRange times
033   * the fraction of the supply voltage, plus the offset.
034   *
035   * @param channel   The analog channel this potentiometer is plugged into.
036   * @param fullRange The scaling to multiply the fraction by to get a meaningful unit.
037   * @param offset    The offset to add to the scaled value for controlling the zero value
038   */
039  public AnalogPotentiometer(final int channel, double fullRange, double offset) {
040    this(new AnalogInput(channel), fullRange, offset);
041    m_initAnalogInput = true;
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    m_analogInput = input;
059    m_initAnalogInput = false;
060
061    m_fullRange = fullRange;
062    m_offset = offset;
063  }
064
065  /**
066   * AnalogPotentiometer constructor.
067   *
068   * <p>Use the fullRange and offset values so that the output produces meaningful values. I.E: you
069   * have a 270 degree potentiometer and you want the output to be degrees with the halfway point as
070   * 0 degrees. The fullRange value is 270.0(degrees) and the offset is -135.0 since the halfway
071   * point after scaling is 135 degrees.
072   *
073   * @param channel The analog channel this potentiometer is plugged into.
074   * @param scale   The scaling to multiply the voltage by to get a meaningful unit.
075   */
076  public AnalogPotentiometer(final int channel, double scale) {
077    this(channel, scale, 0);
078  }
079
080  /**
081   * AnalogPotentiometer constructor.
082   *
083   * <p>Use the fullRange and offset values so that the output produces meaningful values. I.E: you
084   * have a 270 degree potentiometer and you want the output to be degrees with the halfway point as
085   * 0 degrees. The fullRange value is 270.0(degrees) and the offset is -135.0 since the halfway
086   * point after scaling is 135 degrees.
087   *
088   * @param input The {@link AnalogInput} this potentiometer is plugged into.
089   * @param scale The scaling to multiply the voltage by to get a meaningful unit.
090   */
091  public AnalogPotentiometer(final AnalogInput input, double scale) {
092    this(input, scale, 0);
093  }
094
095  /**
096   * AnalogPotentiometer constructor.
097   *
098   * @param channel The analog channel this potentiometer is plugged into.
099   */
100  public AnalogPotentiometer(final int channel) {
101    this(channel, 1, 0);
102  }
103
104  /**
105   * AnalogPotentiometer constructor.
106   *
107   * @param input The {@link AnalogInput} this potentiometer is plugged into.
108   */
109  public AnalogPotentiometer(final AnalogInput input) {
110    this(input, 1, 0);
111  }
112
113  /**
114   * Get the current reading of the potentiometer.
115   *
116   * @return The current position of the potentiometer.
117   */
118  @Override
119  public double get() {
120    return (m_analogInput.getVoltage() / ControllerPower.getVoltage5V()) * m_fullRange + m_offset;
121  }
122
123  @Override
124  public void setPIDSourceType(PIDSourceType pidSource) {
125    if (!pidSource.equals(PIDSourceType.kDisplacement)) {
126      throw new IllegalArgumentException("Only displacement PID is allowed for potentiometers.");
127    }
128    m_pidSource = pidSource;
129  }
130
131  @Override
132  public PIDSourceType getPIDSourceType() {
133    return m_pidSource;
134  }
135
136  /**
137   * Implement the PIDSource interface.
138   *
139   * @return The current reading.
140   */
141  @Override
142  public double pidGet() {
143    return get();
144  }
145
146
147  /**
148   * Live Window code, only does anything if live window is activated.
149   */
150  @Override
151  public String getSmartDashboardType() {
152    return "Analog Input";
153  }
154
155  private ITable m_table;
156
157  @Override
158  public void initTable(ITable subtable) {
159    m_table = subtable;
160    updateTable();
161  }
162
163  @Override
164  public void updateTable() {
165    if (m_table != null) {
166      m_table.putNumber("Value", get());
167    }
168  }
169
170  @Override
171  public ITable getTable() {
172    return m_table;
173  }
174
175  /**
176   * Frees this resource.
177   */
178  public void free() {
179    if (m_initAnalogInput) {
180      m_analogInput.free();
181      m_analogInput = null;
182      m_initAnalogInput = false;
183    }
184  }
185
186  /**
187   * Analog Channels don't have to do anything special when entering the LiveWindow. {@inheritDoc}
188   */
189  @Override
190  public void startLiveWindowMode() {
191  }
192
193  /**
194   * Analog Channels don't have to do anything special when exiting the LiveWindow. {@inheritDoc}
195   */
196  @Override
197  public void stopLiveWindowMode() {
198  }
199}