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