001// Copyright (c) FIRST and other WPILib contributors. 002// Open Source Software; you can modify and/or share it under the terms of 003// the WPILib BSD license file in the root directory of this project. 004 005package edu.wpi.first.wpilibj; 006 007import edu.wpi.first.util.sendable.Sendable; 008import edu.wpi.first.util.sendable.SendableBuilder; 009import edu.wpi.first.util.sendable.SendableRegistry; 010 011/** 012 * Class for reading analog potentiometers. Analog potentiometers read in an analog voltage that 013 * corresponds to a position. The position is in whichever units you choose, by way of the scaling 014 * and offset constants passed to the constructor. 015 */ 016public class AnalogPotentiometer implements Sendable, AutoCloseable { 017 private AnalogInput m_analogInput; 018 private boolean m_initAnalogInput; 019 private double m_fullRange; 020 private double m_offset; 021 022 /** 023 * AnalogPotentiometer constructor. 024 * 025 * <p>Use the fullRange and offset values so that the output produces meaningful values. I.E: you 026 * have a 270 degree potentiometer, and you want the output to be degrees with the halfway point 027 * as 0 degrees. The fullRange value is 270.0(degrees) and the offset is -135.0 since the halfway 028 * point after scaling is 135 degrees. This will calculate the result from the fullRange times the 029 * fraction of the supply voltage, plus the offset. 030 * 031 * @param channel The analog input channel this potentiometer is plugged into. 0-3 are on-board 032 * and 4-7 are on the MXP port. 033 * @param fullRange The scaling to multiply the fraction by to get a meaningful unit. 034 * @param offset The offset to add to the scaled value for controlling the zero value 035 */ 036 @SuppressWarnings("this-escape") 037 public AnalogPotentiometer(final int channel, double fullRange, double offset) { 038 this(new AnalogInput(channel), fullRange, offset); 039 m_initAnalogInput = true; 040 SendableRegistry.addChild(this, m_analogInput); 041 } 042 043 /** 044 * AnalogPotentiometer constructor. 045 * 046 * <p>Use the fullRange and offset values so that the output produces meaningful values. I.E: you 047 * have a 270 degree potentiometer, and you want the output to be degrees with the halfway point 048 * as 0 degrees. The fullRange value is 270.0(degrees) and the offset is -135.0 since the halfway 049 * point after scaling is 135 degrees. This will calculate the result from the fullRange times the 050 * fraction of the supply voltage, plus the offset. 051 * 052 * @param input The {@link AnalogInput} this potentiometer is plugged into. 053 * @param fullRange The angular value (in desired units) representing the full 0-5V range of the 054 * input. 055 * @param offset The angular value (in desired units) representing the angular output at 0V. 056 */ 057 @SuppressWarnings("this-escape") 058 public AnalogPotentiometer(final AnalogInput input, double fullRange, double offset) { 059 SendableRegistry.addLW(this, "AnalogPotentiometer", input.getChannel()); 060 m_analogInput = input; 061 m_initAnalogInput = false; 062 063 m_fullRange = fullRange; 064 m_offset = offset; 065 } 066 067 /** 068 * AnalogPotentiometer constructor. 069 * 070 * <p>Use the scale value so that the output produces meaningful values. I.E: you have a 270 071 * degree potentiometer, and you want the output to be degrees with the starting point as 0 072 * degrees. The scale value is 270.0(degrees). 073 * 074 * @param channel The analog input channel this potentiometer is plugged into. 0-3 are on-board 075 * and 4-7 are on the MXP port. 076 * @param scale The scaling to multiply the voltage by to get a meaningful unit. 077 */ 078 public AnalogPotentiometer(final int channel, double scale) { 079 this(channel, scale, 0); 080 } 081 082 /** 083 * AnalogPotentiometer constructor. 084 * 085 * <p>Use the fullRange and offset values so that the output produces meaningful values. I.E: you 086 * have a 270 degree potentiometer, and you want the output to be degrees with the starting point 087 * as 0 degrees. The scale value is 270.0(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 * <p>The potentiometer will return a value between 0 and 1.0. 100 * 101 * @param channel The analog input channel this potentiometer is plugged into. 0-3 are on-board 102 * and 4-7 are on the MXP port. 103 */ 104 public AnalogPotentiometer(final int channel) { 105 this(channel, 1, 0); 106 } 107 108 /** 109 * AnalogPotentiometer constructor. 110 * 111 * <p>The potentiometer will return a value between 0 and 1.0. 112 * 113 * @param input The {@link AnalogInput} this potentiometer is plugged into. 114 */ 115 public AnalogPotentiometer(final AnalogInput input) { 116 this(input, 1, 0); 117 } 118 119 /** 120 * Get the current reading of the potentiometer. 121 * 122 * @return The current position of the potentiometer. 123 */ 124 public double get() { 125 if (m_analogInput == null) { 126 return m_offset; 127 } 128 return (m_analogInput.getAverageVoltage() / RobotController.getVoltage5V()) * m_fullRange 129 + m_offset; 130 } 131 132 @Override 133 public void initSendable(SendableBuilder builder) { 134 if (m_analogInput != null) { 135 builder.setSmartDashboardType("Analog Input"); 136 builder.addDoubleProperty("Value", this::get, null); 137 } 138 } 139 140 @Override 141 public void close() { 142 SendableRegistry.remove(this); 143 if (m_initAnalogInput) { 144 m_analogInput.close(); 145 m_analogInput = null; 146 m_initAnalogInput = false; 147 } 148 } 149}