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 analog input channel this potentiometer is plugged into. 0-3 are on-board 034 * and 4-7 are on the MXP port. 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 @SuppressWarnings("this-escape") 039 public AnalogPotentiometer(final int channel, double fullRange, double offset) { 040 this(new AnalogInput(channel), fullRange, offset); 041 m_initAnalogInput = true; 042 SendableRegistry.addChild(this, m_analogInput); 043 } 044 045 /** 046 * AnalogPotentiometer constructor. 047 * 048 * <p>Use the fullRange and offset values so that the output produces meaningful values. I.E: you 049 * have a 270 degree potentiometer, and you want the output to be degrees with the halfway point 050 * as 0 degrees. The fullRange value is 270.0(degrees) and the offset is -135.0 since the halfway 051 * point after scaling is 135 degrees. This will calculate the result from the fullRange times the 052 * fraction of the supply voltage, plus the offset. 053 * 054 * @param input The {@link AnalogInput} this potentiometer is plugged into. 055 * @param fullRange The angular value (in desired units) representing the full 0-3.3V range of the 056 * input. 057 * @param offset The angular value (in desired units) representing the angular output at 0V. 058 */ 059 @SuppressWarnings("this-escape") 060 public AnalogPotentiometer(final AnalogInput input, double fullRange, double offset) { 061 SendableRegistry.add(this, "AnalogPotentiometer", input.getChannel()); 062 m_analogInput = input; 063 m_initAnalogInput = false; 064 065 m_fullRange = fullRange; 066 m_offset = offset; 067 } 068 069 /** 070 * AnalogPotentiometer constructor. 071 * 072 * <p>Use the scale value so that the output produces meaningful values. I.E: you have a 270 073 * degree potentiometer, and you want the output to be degrees with the starting point as 0 074 * degrees. The scale value is 270.0(degrees). 075 * 076 * @param channel The analog input channel this potentiometer is plugged into. 0-3 are on-board 077 * and 4-7 are on the MXP port. 078 * @param scale The scaling to multiply the voltage by to get a meaningful unit. 079 */ 080 public AnalogPotentiometer(final int channel, double scale) { 081 this(channel, scale, 0); 082 } 083 084 /** 085 * AnalogPotentiometer constructor. 086 * 087 * <p>Use the fullRange and offset values so that the output produces meaningful values. I.E: you 088 * have a 270 degree potentiometer, and you want the output to be degrees with the starting point 089 * as 0 degrees. The scale value is 270.0(degrees). 090 * 091 * @param input The {@link AnalogInput} this potentiometer is plugged into. 092 * @param scale The scaling to multiply the voltage by to get a meaningful unit. 093 */ 094 public AnalogPotentiometer(final AnalogInput input, double scale) { 095 this(input, scale, 0); 096 } 097 098 /** 099 * AnalogPotentiometer constructor. 100 * 101 * <p>The potentiometer will return a value between 0 and 1.0. 102 * 103 * @param channel The analog input channel this potentiometer is plugged into. 0-3 are on-board 104 * and 4-7 are on the MXP port. 105 */ 106 public AnalogPotentiometer(final int channel) { 107 this(channel, 1, 0); 108 } 109 110 /** 111 * AnalogPotentiometer constructor. 112 * 113 * <p>The potentiometer will return a value between 0 and 1.0. 114 * 115 * @param input The {@link AnalogInput} this potentiometer is plugged into. 116 */ 117 public AnalogPotentiometer(final AnalogInput input) { 118 this(input, 1, 0); 119 } 120 121 /** 122 * Get the current reading of the potentiometer. 123 * 124 * @return The current position of the potentiometer. 125 */ 126 public double get() { 127 if (m_analogInput == null) { 128 return m_offset; 129 } 130 return (m_analogInput.getVoltage() / RobotController.getVoltage3V3()) * m_fullRange + m_offset; 131 } 132 133 @Override 134 public void initSendable(SendableBuilder builder) { 135 if (m_analogInput != null) { 136 builder.setSmartDashboardType("Analog Input"); 137 builder.addDoubleProperty("Value", this::get, null); 138 } 139 } 140 141 @Override 142 public void close() { 143 SendableRegistry.remove(this); 144 if (m_initAnalogInput) { 145 m_analogInput.close(); 146 m_analogInput = null; 147 m_initAnalogInput = false; 148 } 149 } 150}