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.math.geometry.Rotation2d; 011import edu.wpi.first.util.sendable.Sendable; 012import edu.wpi.first.util.sendable.SendableBuilder; 013import edu.wpi.first.util.sendable.SendableRegistry; 014 015/** 016 * Use a rate gyro to return the robots heading relative to a starting position. The Gyro class 017 * tracks the robots heading based on the starting position. As the robot rotates the new heading is 018 * computed by integrating the rate of rotation returned by the sensor. When the class is 019 * instantiated, it does a short calibration routine where it samples the gyro while at rest to 020 * determine the default offset. This is subtracted from each sample to determine the heading. 021 * 022 * <p>This class is for gyro sensors that connect to an analog input. 023 */ 024public class AnalogGyro implements Sendable, AutoCloseable { 025 private AnalogInput m_analog; 026 private boolean m_channelAllocated; 027 028 /** Initialize the gyro. Calibration is handled by calibrate(). */ 029 private void initGyro() { 030 HAL.reportUsage("AnalogGyro", m_analog.getChannel(), ""); 031 SendableRegistry.add(this, "AnalogGyro", m_analog.getChannel()); 032 } 033 034 /** 035 * Calibrate the gyro by running for a number of samples and computing the center value. Then use 036 * the center value as the Accumulator center value for subsequent measurements. 037 * 038 * <p>It's important to make sure that the robot is not moving while the centering calculations 039 * are in progress, this is typically done when the robot is first turned on while it's sitting at 040 * rest before the competition starts. 041 */ 042 public void calibrate() {} 043 044 /** 045 * Return the heading of the robot as a {@link edu.wpi.first.math.geometry.Rotation2d}. 046 * 047 * <p>The angle is continuous, that is it will continue from 360 to 361 degrees. This allows 048 * algorithms that wouldn't want to see a discontinuity in the gyro output as it sweeps past from 049 * 360 to 0 on the second time around. 050 * 051 * <p>The angle is expected to increase as the gyro turns counterclockwise when looked at from the 052 * top. It needs to follow the NWU axis convention. 053 * 054 * <p>This heading is based on integration of the returned rate from the gyro. 055 * 056 * @return the current heading of the robot as a {@link edu.wpi.first.math.geometry.Rotation2d}. 057 */ 058 public Rotation2d getRotation2d() { 059 return Rotation2d.fromDegrees(-getAngle()); 060 } 061 062 /** 063 * Gyro constructor using the channel number. 064 * 065 * @param channel The analog channel the gyro is connected to. Gyros can only be used on on-board 066 * channels 0-1. 067 */ 068 @SuppressWarnings("this-escape") 069 public AnalogGyro(int channel) { 070 this(new AnalogInput(channel)); 071 m_channelAllocated = true; 072 SendableRegistry.addChild(this, m_analog); 073 } 074 075 /** 076 * Gyro constructor with a precreated analog channel object. Use this constructor when the analog 077 * channel needs to be shared. 078 * 079 * @param channel The AnalogInput object that the gyro is connected to. Gyros can only be used on 080 * on-board channels 0-1. 081 */ 082 @SuppressWarnings("this-escape") 083 public AnalogGyro(AnalogInput channel) { 084 requireNonNullParam(channel, "channel", "AnalogGyro"); 085 086 m_analog = channel; 087 initGyro(); 088 calibrate(); 089 } 090 091 /** 092 * Gyro constructor using the channel number along with parameters for presetting the center and 093 * offset values. Bypasses calibration. 094 * 095 * @param channel The analog channel the gyro is connected to. Gyros can only be used on on-board 096 * channels 0-1. 097 * @param center Preset uncalibrated value to use as the accumulator center value. 098 * @param offset Preset uncalibrated value to use as the gyro offset. 099 */ 100 @SuppressWarnings("this-escape") 101 public AnalogGyro(int channel, int center, double offset) { 102 this(new AnalogInput(channel), center, offset); 103 m_channelAllocated = true; 104 SendableRegistry.addChild(this, m_analog); 105 } 106 107 /** 108 * Gyro constructor with a precreated analog channel object along with parameters for presetting 109 * the center and offset values. Bypasses calibration. 110 * 111 * @param channel The analog channel the gyro is connected to. Gyros can only be used on on-board 112 * channels 0-1. 113 * @param center Preset uncalibrated value to use as the accumulator center value. 114 * @param offset Preset uncalibrated value to use as the gyro offset. 115 */ 116 @SuppressWarnings({"this-escape", "PMD.UnusedFormalParameter"}) 117 public AnalogGyro(AnalogInput channel, int center, double offset) { 118 requireNonNullParam(channel, "channel", "AnalogGyro"); 119 120 m_analog = channel; 121 initGyro(); 122 reset(); 123 } 124 125 /** 126 * Reset the gyro. 127 * 128 * <p>Resets the gyro to a heading of zero. This can be used if there is significant drift in the 129 * gyro, and it needs to be recalibrated after it has been running. 130 */ 131 public void reset() {} 132 133 /** Delete (free) the accumulator and the analog components used for the gyro. */ 134 @Override 135 public void close() { 136 SendableRegistry.remove(this); 137 if (m_analog != null && m_channelAllocated) { 138 m_analog.close(); 139 } 140 m_analog = null; 141 } 142 143 /** 144 * Return the heading of the robot in degrees. 145 * 146 * <p>The angle is continuous, that is it will continue from 360 to 361 degrees. This allows 147 * algorithms that wouldn't want to see a discontinuity in the gyro output as it sweeps past from 148 * 360 to 0 on the second time around. 149 * 150 * <p>The angle is expected to increase as the gyro turns clockwise when looked at from the top. 151 * It needs to follow the NED axis convention. 152 * 153 * <p>This heading is based on integration of the returned rate from the gyro. 154 * 155 * @return the current heading of the robot in degrees. 156 */ 157 public double getAngle() { 158 return 0.0; 159 } 160 161 /** 162 * Return the rate of rotation of the gyro. 163 * 164 * <p>The rate is based on the most recent reading of the gyro analog value 165 * 166 * <p>The rate is expected to be positive as the gyro turns clockwise when looked at from the top. 167 * It needs to follow the NED axis convention. 168 * 169 * @return the current rate in degrees per second 170 */ 171 public double getRate() { 172 return 0.0; 173 } 174 175 /** 176 * Return the gyro offset value set during calibration to use as a future preset. 177 * 178 * @return the current offset value 179 */ 180 public double getOffset() { 181 return 0.0; 182 } 183 184 /** 185 * Return the gyro center value set during calibration to use as a future preset. 186 * 187 * @return the current center value 188 */ 189 public int getCenter() { 190 return 0; 191 } 192 193 /** 194 * Set the gyro sensitivity. This takes the number of volts/degree/second sensitivity of the gyro 195 * and uses it in subsequent calculations to allow the code to work with multiple gyros. This 196 * value is typically found in the gyro datasheet. 197 * 198 * @param voltsPerDegreePerSecond The sensitivity in Volts/degree/second. 199 */ 200 public void setSensitivity(double voltsPerDegreePerSecond) {} 201 202 /** 203 * Set the size of the neutral zone. Any voltage from the gyro less than this amount from the 204 * center is considered stationary. Setting a deadband will decrease the amount of drift when the 205 * gyro isn't rotating, but will make it less accurate. 206 * 207 * @param volts The size of the deadband in volts 208 */ 209 public void setDeadband(double volts) {} 210 211 /** 212 * Gets the analog input for the gyro. 213 * 214 * @return AnalogInput 215 */ 216 public AnalogInput getAnalogInput() { 217 return m_analog; 218 } 219 220 @Override 221 public void initSendable(SendableBuilder builder) { 222 builder.setSmartDashboardType("Gyro"); 223 builder.addDoubleProperty("Value", this::getAngle, null); 224 } 225}