1 /*----------------------------------------------------------------------------*/
2 /* Copyright (c) FIRST 2008-2012. All Rights Reserved. */
3 /* Open Source Software - may be modified and shared by FRC teams. The code */
4 /* must be accompanied by the FIRST BSD license file in the root directory of */
6 /*----------------------------------------------------------------------------*/
7 package edu.wpi.first.wpilibj;
9 import edu.wpi.first.wpilibj.communication.FRCNetworkCommunicationsLibrary.tResourceType;
10 import edu.wpi.first.wpilibj.communication.UsageReporting;
11 import edu.wpi.first.wpilibj.livewindow.LiveWindow;
12 import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
13 import edu.wpi.first.wpilibj.tables.ITable;
14 import edu.wpi.first.wpilibj.util.BoundaryException;
17 * Use a rate gyro to return the robots heading relative to a starting position.
18 * The Gyro class tracks the robots heading based on the starting position. As
19 * the robot rotates the new heading is computed by integrating the rate of
20 * rotation returned by the sensor. When the class is instantiated, it does a
21 * short calibration routine where it samples the gyro while at rest to
22 * determine the default offset. This is subtracted from each sample to
23 * determine the heading.
25 public class Gyro extends SensorBase implements PIDSource, LiveWindowSendable {
27 static final int kOversampleBits = 10;
28 static final int kAverageBits = 0;
29 static final double kSamplesPerSecond = 50.0;
30 static final double kCalibrationSampleTime = 5.0;
31 static final double kDefaultVoltsPerDegreePerSecond = 0.007;
32 protected AnalogInput m_analog;
33 double m_voltsPerDegreePerSecond;
36 boolean m_channelAllocated = false;
37 AccumulatorResult result;
38 private PIDSourceParameter m_pidSource;
41 * Initialize the gyro. Calibrate the gyro by running for a number of
42 * samples and computing the center value. Then use the center
43 * value as the Accumulator center value for subsequent measurements. It's
44 * important to make sure that the robot is not moving while the centering
45 * calculations are in progress, this is typically done when the robot is
46 * first turned on while it's sitting at rest before the competition starts.
48 public void initGyro() {
49 result = new AccumulatorResult();
50 if (m_analog == null) {
51 System.out.println("Null m_analog");
53 m_voltsPerDegreePerSecond = kDefaultVoltsPerDegreePerSecond;
54 m_analog.setAverageBits(kAverageBits);
55 m_analog.setOversampleBits(kOversampleBits);
56 double sampleRate = kSamplesPerSecond
57 * (1 << (kAverageBits + kOversampleBits));
58 AnalogInput.setGlobalSampleRate(sampleRate);
61 m_analog.initAccumulator();
62 m_analog.resetAccumulator();
64 Timer.delay(kCalibrationSampleTime);
66 m_analog.getAccumulatorOutput(result);
68 m_center = (int) ((double) result.value / (double) result.count + .5);
70 m_offset = ((double) result.value / (double) result.count)
73 m_analog.setAccumulatorCenter(m_center);
74 m_analog.resetAccumulator();
78 setPIDSourceParameter(PIDSourceParameter.kAngle);
80 UsageReporting.report(tResourceType.kResourceType_Gyro, m_analog.getChannel());
81 LiveWindow.addSensor("Gyro", m_analog.getChannel(), this);
85 * Gyro constructor using the channel number
88 * The analog channel the gyro is connected to. Gyros can only
89 be used on on-board channels 0-1.
91 public Gyro(int channel) {
92 this(new AnalogInput(channel));
93 m_channelAllocated = true;
97 * Gyro constructor with a precreated analog channel object. Use this
98 * constructor when the analog channel needs to be shared.
101 * The AnalogInput object that the gyro is connected to. Gyros
102 can only be used on on-board channels 0-1.
104 public Gyro(AnalogInput channel) {
106 if (m_analog == null) {
107 throw new NullPointerException("AnalogInput supplied to Gyro constructor is null");
113 * Reset the gyro. Resets the gyro to a heading of zero. This can be used if
114 * there is significant drift in the gyro and it needs to be recalibrated
115 * after it has been running.
117 public void reset() {
118 if (m_analog != null) {
119 m_analog.resetAccumulator();
124 * Delete (free) the accumulator and the analog components used for the
129 if (m_analog != null && m_channelAllocated) {
136 * Return the actual angle in degrees that the robot is currently facing.
138 * The angle is based on the current accumulator value corrected by the
139 * oversampling rate, the gyro type and the A/D calibration values. The
140 * angle is continuous, that is it will continue from 360 to 361 degrees. This allows
141 * algorithms that wouldn't want to see a discontinuity in the gyro output
142 * as it sweeps past from 360 to 0 on the second time around.
144 * @return the current heading of the robot in degrees. This heading is
145 * based on integration of the returned rate from the gyro.
147 public double getAngle() {
148 if (m_analog == null) {
151 m_analog.getAccumulatorOutput(result);
153 long value = result.value - (long) (result.count * m_offset);
155 double scaledValue = value
157 * m_analog.getLSBWeight()
158 * (1 << m_analog.getAverageBits())
159 / (AnalogInput.getGlobalSampleRate() * m_voltsPerDegreePerSecond);
166 * Return the rate of rotation of the gyro
168 * The rate is based on the most recent reading of the gyro analog value
170 * @return the current rate in degrees per second
172 public double getRate() {
173 if (m_analog == null) {
176 return (m_analog.getAverageValue() - (m_center + m_offset))
178 * m_analog.getLSBWeight()
179 / ((1 << m_analog.getOversampleBits()) * m_voltsPerDegreePerSecond);
184 * Set the gyro sensitivity. This takes the number of
185 * volts/degree/second sensitivity of the gyro and uses it in subsequent
186 * calculations to allow the code to work with multiple gyros. This value
187 * is typically found in the gyro datasheet.
189 * @param voltsPerDegreePerSecond
190 * The sensitivity in Volts/degree/second.
192 public void setSensitivity(double voltsPerDegreePerSecond) {
193 m_voltsPerDegreePerSecond = voltsPerDegreePerSecond;
197 * Set the size of the neutral zone. Any voltage from the gyro less than
198 * this amount from the center is considered stationary. Setting a
199 * deadband will decrease the amount of drift when the gyro isn't rotating,
200 * but will make it less accurate.
202 * @param volts The size of the deadband in volts
204 void setDeadband(double volts) {
205 int deadband = (int)(volts * 1e9 / m_analog.getLSBWeight() * (1 << m_analog.getOversampleBits()));
206 m_analog.setAccumulatorDeadband(deadband);
210 * Set which parameter of the gyro you are using as a process control
211 * variable. The Gyro class supports the rate and angle parameters
214 * An enum to select the parameter.
216 public void setPIDSourceParameter(PIDSourceParameter pidSource) {
217 BoundaryException.assertWithinBounds(pidSource.value, 1, 2);
218 m_pidSource = pidSource;
222 * Get the output of the gyro for use with PIDControllers.
223 * May be the angle or rate depending on the set PIDSourceParameter
225 * @return the output according to the gyro
228 public double pidGet() {
229 switch (m_pidSource.value) {
230 case PIDSourceParameter.kRate_val:
232 case PIDSourceParameter.kAngle_val:
240 * Live Window code, only does anything if live window is activated.
243 public String getSmartDashboardType() {
247 private ITable m_table;
253 public void initTable(ITable subtable) {
262 public ITable getTable() {
270 public void updateTable() {
271 if (m_table != null) {
272 m_table.putNumber("Value", getAngle());
280 public void startLiveWindowMode() {
287 public void stopLiveWindowMode() {