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}