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 static edu.wpi.first.util.ErrorMessages.requireNonNullParam; 008 009import edu.wpi.first.hal.HAL; 010import edu.wpi.first.util.sendable.Sendable; 011import edu.wpi.first.util.sendable.SendableBuilder; 012import edu.wpi.first.util.sendable.SendableRegistry; 013 014/** 015 * Handle operation of an analog accelerometer. The accelerometer reads acceleration directly 016 * through the sensor. Many sensors have multiple axis and can be treated as multiple devices. Each 017 * is calibrated by finding the center value over a period of time. 018 */ 019public class AnalogAccelerometer implements Sendable, AutoCloseable { 020 private AnalogInput m_analogChannel; 021 private double m_voltsPerG = 1.0; 022 private double m_zeroGVoltage = 2.5; 023 private final boolean m_allocatedChannel; 024 025 /** Common initialization. */ 026 private void initAccelerometer() { 027 HAL.reportUsage("IO", m_analogChannel.getChannel(), "Accelerometer"); 028 SendableRegistry.add(this, "Accelerometer", m_analogChannel.getChannel()); 029 } 030 031 /** 032 * Create a new instance of an accelerometer. 033 * 034 * <p>The constructor allocates desired analog channel. 035 * 036 * @param channel The channel number for the analog input the accelerometer is connected to 037 */ 038 @SuppressWarnings("this-escape") 039 public AnalogAccelerometer(final int channel) { 040 this(new AnalogInput(channel), true); 041 SendableRegistry.addChild(this, m_analogChannel); 042 } 043 044 /** 045 * Create a new instance of Accelerometer from an existing AnalogChannel. Make a new instance of 046 * accelerometer given an AnalogChannel. This is particularly useful if the port is going to be 047 * read as an analog channel as well as through the Accelerometer class. 048 * 049 * @param channel The existing AnalogInput object for the analog input the accelerometer is 050 * connected to 051 */ 052 @SuppressWarnings("this-escape") 053 public AnalogAccelerometer(final AnalogInput channel) { 054 this(channel, false); 055 } 056 057 @SuppressWarnings("this-escape") 058 private AnalogAccelerometer(final AnalogInput channel, final boolean allocatedChannel) { 059 requireNonNullParam(channel, "channel", "AnalogAccelerometer"); 060 m_allocatedChannel = allocatedChannel; 061 m_analogChannel = channel; 062 initAccelerometer(); 063 } 064 065 /** Delete the analog components used for the accelerometer. */ 066 @Override 067 public void close() { 068 SendableRegistry.remove(this); 069 if (m_analogChannel != null && m_allocatedChannel) { 070 m_analogChannel.close(); 071 } 072 m_analogChannel = null; 073 } 074 075 /** 076 * Return the acceleration in Gs. 077 * 078 * <p>The acceleration is returned units of Gs. 079 * 080 * @return The current acceleration of the sensor in Gs. 081 */ 082 public double getAcceleration() { 083 if (m_analogChannel == null) { 084 return 0.0; 085 } 086 return (m_analogChannel.getAverageVoltage() - m_zeroGVoltage) / m_voltsPerG; 087 } 088 089 /** 090 * Set the accelerometer sensitivity. 091 * 092 * <p>This sets the sensitivity of the accelerometer used for calculating the acceleration. The 093 * sensitivity varies by accelerometer model. 094 * 095 * @param sensitivity The sensitivity of accelerometer in Volts per G. 096 */ 097 public void setSensitivity(double sensitivity) { 098 m_voltsPerG = sensitivity; 099 } 100 101 /** 102 * Set the voltage that corresponds to 0 G. 103 * 104 * <p>The zero G voltage varies by accelerometer model. 105 * 106 * @param zero The zero G voltage. 107 */ 108 public void setZero(double zero) { 109 m_zeroGVoltage = zero; 110 } 111 112 @Override 113 public void initSendable(SendableBuilder builder) { 114 builder.setSmartDashboardType("Accelerometer"); 115 builder.addDoubleProperty("Value", this::getAcceleration, null); 116 } 117}