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 org.wpilib.hardware.rotation; 006 007import org.wpilib.hardware.discrete.AnalogInput; 008import org.wpilib.system.RobotController; 009import org.wpilib.util.sendable.Sendable; 010import org.wpilib.util.sendable.SendableBuilder; 011import org.wpilib.util.sendable.SendableRegistry; 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 implements Sendable, AutoCloseable { 019 private AnalogInput m_analogInput; 020 private boolean m_initAnalogInput; 021 private double m_fullRange; 022 private double m_offset; 023 024 /** 025 * AnalogPotentiometer constructor. 026 * 027 * <p>Use the fullRange and offset values so that the output produces meaningful values. I.E: you 028 * have a 270 degree potentiometer, and you want the output to be degrees with the halfway point 029 * as 0 degrees. The fullRange value is 270.0(degrees) and the offset is -135.0 since the halfway 030 * point after scaling is 135 degrees. This will calculate the result from the fullRange times the 031 * fraction of the supply voltage, plus the offset. 032 * 033 * @param channel The SmartIO channel this potentiometer is plugged into. 034 * @param fullRange The scaling to multiply the fraction by to get a meaningful unit. 035 * @param offset The offset to add to the scaled value for controlling the zero value 036 */ 037 @SuppressWarnings("this-escape") 038 public AnalogPotentiometer(final int channel, double fullRange, double offset) { 039 this(new AnalogInput(channel), fullRange, offset); 040 m_initAnalogInput = true; 041 SendableRegistry.addChild(this, 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 049 * as 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 the 051 * fraction of the supply voltage, plus the offset. 052 * 053 * @param input The {@link AnalogInput} this potentiometer is plugged into. 054 * @param fullRange The angular value (in desired units) representing the full 0-3.3V range of the 055 * input. 056 * @param offset The angular value (in desired units) representing the angular output at 0V. 057 */ 058 @SuppressWarnings("this-escape") 059 public AnalogPotentiometer(final AnalogInput input, double fullRange, double offset) { 060 SendableRegistry.add(this, "AnalogPotentiometer", input.getChannel()); 061 m_analogInput = input; 062 m_initAnalogInput = false; 063 064 m_fullRange = fullRange; 065 m_offset = offset; 066 } 067 068 /** 069 * AnalogPotentiometer constructor. 070 * 071 * <p>Use the scale value so that the output produces meaningful values. I.E: you have a 270 072 * degree potentiometer, and you want the output to be degrees with the starting point as 0 073 * degrees. The scale value is 270.0(degrees). 074 * 075 * @param channel The analog input channel this potentiometer is plugged into. 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. 102 */ 103 public AnalogPotentiometer(final int channel) { 104 this(channel, 1, 0); 105 } 106 107 /** 108 * AnalogPotentiometer constructor. 109 * 110 * <p>The potentiometer will return a value between 0 and 1.0. 111 * 112 * @param input The {@link AnalogInput} this potentiometer is plugged into. 113 */ 114 public AnalogPotentiometer(final AnalogInput input) { 115 this(input, 1, 0); 116 } 117 118 /** 119 * Get the current reading of the potentiometer. 120 * 121 * @return The current position of the potentiometer. 122 */ 123 public double get() { 124 if (m_analogInput == null) { 125 return m_offset; 126 } 127 return (m_analogInput.getVoltage() / RobotController.getVoltage3V3()) * m_fullRange + m_offset; 128 } 129 130 @Override 131 public void initSendable(SendableBuilder builder) { 132 if (m_analogInput != null) { 133 builder.setSmartDashboardType("Analog Input"); 134 builder.addDoubleProperty("Value", this::get, null); 135 } 136 } 137 138 @Override 139 public void close() { 140 SendableRegistry.remove(this); 141 if (m_initAnalogInput) { 142 m_analogInput.close(); 143 m_analogInput = null; 144 m_initAnalogInput = false; 145 } 146 } 147}