001/*----------------------------------------------------------------------------*/
002/* Copyright (c) 2008-2018 FIRST. All Rights Reserved.                        */
003/* Open Source Software - may be modified and shared by FRC teams. The code   */
004/* must be accompanied by the FIRST BSD license file in the root directory of */
005/* the project.                                                               */
006/*----------------------------------------------------------------------------*/
007
008package edu.wpi.first.wpilibj;
009
010import edu.wpi.first.wpilibj.hal.AnalogGyroJNI;
011import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
012import edu.wpi.first.wpilibj.hal.HAL;
013import edu.wpi.first.wpilibj.interfaces.Gyro;
014
015import static java.util.Objects.requireNonNull;
016
017/**
018 * Use a rate gyro to return the robots heading relative to a starting position. The Gyro class
019 * tracks the robots heading based on the starting position. As the robot rotates the new heading is
020 * computed by integrating the rate of rotation returned by the sensor. When the class is
021 * instantiated, it does a short calibration routine where it samples the gyro while at rest to
022 * determine the default offset. This is subtracted from each sample to determine the heading.
023 *
024 * <p>This class is for gyro sensors that connect to an analog input.
025 */
026public class AnalogGyro extends GyroBase implements Gyro, PIDSource, Sendable {
027  private static final double kDefaultVoltsPerDegreePerSecond = 0.007;
028  protected AnalogInput m_analog;
029  private boolean m_channelAllocated = false;
030
031  private int m_gyroHandle = 0;
032
033  /**
034   * Initialize the gyro. Calibration is handled by calibrate().
035   */
036  public void initGyro() {
037    if (m_gyroHandle == 0) {
038      m_gyroHandle = AnalogGyroJNI.initializeAnalogGyro(m_analog.m_port);
039    }
040
041    AnalogGyroJNI.setupAnalogGyro(m_gyroHandle);
042
043    HAL.report(tResourceType.kResourceType_Gyro, m_analog.getChannel());
044    setName("AnalogGyro", m_analog.getChannel());
045  }
046
047  @Override
048  public void calibrate() {
049    AnalogGyroJNI.calibrateAnalogGyro(m_gyroHandle);
050  }
051
052  /**
053   * Gyro constructor using the channel number.
054   *
055   * @param channel The analog channel the gyro is connected to. Gyros can only be used on on-board
056   *                channels 0-1.
057   */
058  public AnalogGyro(int channel) {
059    this(new AnalogInput(channel));
060    m_channelAllocated = true;
061    addChild(m_analog);
062  }
063
064  /**
065   * Gyro constructor with a precreated analog channel object. Use this constructor when the analog
066   * channel needs to be shared.
067   *
068   * @param channel The AnalogInput object that the gyro is connected to. Gyros can only be used on
069   *                on-board channels 0-1.
070   */
071  public AnalogGyro(AnalogInput channel) {
072    requireNonNull(channel, "AnalogInput supplied to Gyro constructor is null");
073
074    m_analog = channel;
075    initGyro();
076    calibrate();
077  }
078
079  /**
080   * Gyro constructor using the channel number along with parameters for presetting the center and
081   * offset values. Bypasses calibration.
082   *
083   * @param channel The analog channel the gyro is connected to. Gyros can only be used on on-board
084   *                channels 0-1.
085   * @param center  Preset uncalibrated value to use as the accumulator center value.
086   * @param offset  Preset uncalibrated value to use as the gyro offset.
087   */
088  public AnalogGyro(int channel, int center, double offset) {
089    this(new AnalogInput(channel), center, offset);
090    m_channelAllocated = true;
091    addChild(m_analog);
092  }
093
094  /**
095   * Gyro constructor with a precreated analog channel object along with parameters for presetting
096   * the center and offset values. Bypasses calibration.
097   *
098   * @param channel The analog channel the gyro is connected to. Gyros can only be used on on-board
099   *                channels 0-1.
100   * @param center  Preset uncalibrated value to use as the accumulator center value.
101   * @param offset  Preset uncalibrated value to use as the gyro offset.
102   */
103  public AnalogGyro(AnalogInput channel, int center, double offset) {
104    requireNonNull(channel, "AnalogInput supplied to Gyro constructor is null");
105
106    m_analog = channel;
107    initGyro();
108    AnalogGyroJNI.setAnalogGyroParameters(m_gyroHandle, kDefaultVoltsPerDegreePerSecond,
109                                          offset, center);
110    reset();
111  }
112
113  @Override
114  public void reset() {
115    AnalogGyroJNI.resetAnalogGyro(m_gyroHandle);
116  }
117
118  /**
119   * Delete (free) the accumulator and the analog components used for the gyro.
120   */
121  @Override
122  public void free() {
123    super.free();
124    if (m_analog != null && m_channelAllocated) {
125      m_analog.free();
126    }
127    m_analog = null;
128    AnalogGyroJNI.freeAnalogGyro(m_gyroHandle);
129  }
130
131  @Override
132  public double getAngle() {
133    if (m_analog == null) {
134      return 0.0;
135    } else {
136      return AnalogGyroJNI.getAnalogGyroAngle(m_gyroHandle);
137    }
138  }
139
140  @Override
141  public double getRate() {
142    if (m_analog == null) {
143      return 0.0;
144    } else {
145      return AnalogGyroJNI.getAnalogGyroRate(m_gyroHandle);
146    }
147  }
148
149  /**
150   * Return the gyro offset value set during calibration to use as a future preset.
151   *
152   * @return the current offset value
153   */
154  public double getOffset() {
155    return AnalogGyroJNI.getAnalogGyroOffset(m_gyroHandle);
156  }
157
158  /**
159   * Return the gyro center value set during calibration to use as a future preset.
160   *
161   * @return the current center value
162   */
163  public int getCenter() {
164    return AnalogGyroJNI.getAnalogGyroCenter(m_gyroHandle);
165  }
166
167  /**
168   * Set the gyro sensitivity. This takes the number of volts/degree/second sensitivity of the gyro
169   * and uses it in subsequent calculations to allow the code to work with multiple gyros. This
170   * value is typically found in the gyro datasheet.
171   *
172   * @param voltsPerDegreePerSecond The sensitivity in Volts/degree/second.
173   */
174  public void setSensitivity(double voltsPerDegreePerSecond) {
175    AnalogGyroJNI.setAnalogGyroVoltsPerDegreePerSecond(m_gyroHandle,
176                                                       voltsPerDegreePerSecond);
177  }
178
179  /**
180   * Set the size of the neutral zone. Any voltage from the gyro less than this amount from the
181   * center is considered stationary. Setting a deadband will decrease the amount of drift when the
182   * gyro isn't rotating, but will make it less accurate.
183   *
184   * @param volts The size of the deadband in volts
185   */
186  void setDeadband(double volts) {
187    AnalogGyroJNI.setAnalogGyroDeadband(m_gyroHandle, volts);
188  }
189}