jerrym | f157933 | 2013-02-07 01:56:28 +0000 | [diff] [blame] | 1 | /*----------------------------------------------------------------------------*/
|
| 2 | /* Copyright (c) FIRST 2008. 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 $(WIND_BASE)/WPILib. */
|
| 5 | /*----------------------------------------------------------------------------*/
|
| 6 |
|
| 7 | #include "Gyro.h"
|
| 8 | #include "AnalogChannel.h"
|
| 9 | #include "AnalogModule.h"
|
| 10 | #include "NetworkCommunication/UsageReporting.h"
|
| 11 | #include "Timer.h"
|
| 12 | #include "WPIErrors.h"
|
| 13 | #include "LiveWindow/LiveWindow.h"
|
| 14 |
|
| 15 | const UINT32 Gyro::kOversampleBits;
|
| 16 | const UINT32 Gyro::kAverageBits;
|
| 17 | const float Gyro::kSamplesPerSecond;
|
| 18 | const float Gyro::kCalibrationSampleTime;
|
| 19 | const float Gyro::kDefaultVoltsPerDegreePerSecond;
|
| 20 |
|
| 21 | /**
|
| 22 | * Initialize the gyro.
|
| 23 | * Calibrate the gyro by running for a number of samples and computing the center value for this
|
| 24 | * part. Then use the center value as the Accumulator center value for subsequent measurements.
|
| 25 | * It's important to make sure that the robot is not moving while the centering calculations are
|
| 26 | * in progress, this is typically done when the robot is first turned on while it's sitting at
|
| 27 | * rest before the competition starts.
|
| 28 | */
|
| 29 | void Gyro::InitGyro()
|
| 30 | {
|
jerrym | 37afdca | 2013-03-03 01:17:57 +0000 | [diff] [blame] | 31 | m_table = NULL;
|
jerrym | f157933 | 2013-02-07 01:56:28 +0000 | [diff] [blame] | 32 | if (!m_analog->IsAccumulatorChannel())
|
| 33 | {
|
| 34 | wpi_setWPIErrorWithContext(ParameterOutOfRange,
|
| 35 | "moduleNumber and/or channel (must be accumulator channel)");
|
| 36 | if (m_channelAllocated)
|
| 37 | {
|
| 38 | delete m_analog;
|
| 39 | m_analog = NULL;
|
| 40 | }
|
| 41 | return;
|
| 42 | }
|
| 43 |
|
| 44 | m_voltsPerDegreePerSecond = kDefaultVoltsPerDegreePerSecond;
|
| 45 | m_analog->SetAverageBits(kAverageBits);
|
| 46 | m_analog->SetOversampleBits(kOversampleBits);
|
| 47 | float sampleRate = kSamplesPerSecond *
|
| 48 | (1 << (kAverageBits + kOversampleBits));
|
| 49 | m_analog->GetModule()->SetSampleRate(sampleRate);
|
| 50 | Wait(1.0);
|
| 51 |
|
| 52 | m_analog->InitAccumulator();
|
| 53 | Wait(kCalibrationSampleTime);
|
| 54 |
|
| 55 | INT64 value;
|
| 56 | UINT32 count;
|
| 57 | m_analog->GetAccumulatorOutput(&value, &count);
|
| 58 |
|
| 59 | UINT32 center = (UINT32)((float)value / (float)count + .5);
|
| 60 |
|
| 61 | m_offset = ((float)value / (float)count) - (float)center;
|
| 62 |
|
| 63 | m_analog->SetAccumulatorCenter(center);
|
| 64 | m_analog->SetAccumulatorDeadband(0); ///< TODO: compute / parameterize this
|
| 65 | m_analog->ResetAccumulator();
|
| 66 |
|
| 67 | nUsageReporting::report(nUsageReporting::kResourceType_Gyro, m_analog->GetChannel(), m_analog->GetModuleNumber() - 1);
|
| 68 | LiveWindow::GetInstance()->AddSensor("Gyro", m_analog->GetModuleNumber(), m_analog->GetChannel(), this);
|
| 69 | }
|
| 70 |
|
| 71 | /**
|
| 72 | * Gyro constructor given a slot and a channel.
|
| 73 | *
|
| 74 | * @param moduleNumber The analog module the gyro is connected to (1).
|
| 75 | * @param channel The analog channel the gyro is connected to (1 or 2).
|
| 76 | */
|
| 77 | Gyro::Gyro(UINT8 moduleNumber, UINT32 channel)
|
| 78 | {
|
| 79 | m_analog = new AnalogChannel(moduleNumber, channel);
|
| 80 | m_channelAllocated = true;
|
| 81 | InitGyro();
|
| 82 | }
|
| 83 |
|
| 84 | /**
|
| 85 | * Gyro constructor with only a channel.
|
| 86 | *
|
| 87 | * Use the default analog module slot.
|
| 88 | *
|
| 89 | * @param channel The analog channel the gyro is connected to.
|
| 90 | */
|
| 91 | Gyro::Gyro(UINT32 channel)
|
| 92 | {
|
| 93 | m_analog = new AnalogChannel(channel);
|
| 94 | m_channelAllocated = true;
|
| 95 | InitGyro();
|
| 96 | }
|
| 97 |
|
| 98 | /**
|
| 99 | * Gyro constructor with a precreated analog channel object.
|
| 100 | * Use this constructor when the analog channel needs to be shared. There
|
| 101 | * is no reference counting when an AnalogChannel is passed to the gyro.
|
| 102 | * @param channel The AnalogChannel object that the gyro is connected to.
|
| 103 | */
|
| 104 | Gyro::Gyro(AnalogChannel *channel)
|
| 105 | {
|
| 106 | m_analog = channel;
|
| 107 | m_channelAllocated = false;
|
| 108 | if (channel == NULL)
|
| 109 | {
|
| 110 | wpi_setWPIError(NullParameter);
|
| 111 | }
|
| 112 | else
|
| 113 | {
|
| 114 | InitGyro();
|
| 115 | }
|
| 116 | }
|
| 117 |
|
| 118 | Gyro::Gyro(AnalogChannel &channel)
|
| 119 | {
|
| 120 | m_analog = &channel;
|
| 121 | m_channelAllocated = false;
|
| 122 | InitGyro();
|
| 123 | }
|
| 124 |
|
| 125 | /**
|
| 126 | * Reset the gyro.
|
| 127 | * Resets the gyro to a heading of zero. This can be used if there is significant
|
| 128 | * drift in the gyro and it needs to be recalibrated after it has been running.
|
| 129 | */
|
| 130 | void Gyro::Reset()
|
| 131 | {
|
| 132 | m_analog->ResetAccumulator();
|
| 133 | }
|
| 134 |
|
| 135 | /**
|
| 136 | * Delete (free) the accumulator and the analog components used for the gyro.
|
| 137 | */
|
| 138 | Gyro::~Gyro()
|
| 139 | {
|
| 140 | if (m_channelAllocated)
|
| 141 | delete m_analog;
|
| 142 | }
|
| 143 |
|
| 144 | /**
|
| 145 | * Return the actual angle in degrees that the robot is currently facing.
|
| 146 | *
|
| 147 | * The angle is based on the current accumulator value corrected by the oversampling rate, the
|
| 148 | * gyro type and the A/D calibration values.
|
| 149 | * The angle is continuous, that is can go beyond 360 degrees. This make algorithms that wouldn't
|
| 150 | * want to see a discontinuity in the gyro output as it sweeps past 0 on the second time around.
|
| 151 | *
|
| 152 | * @return the current heading of the robot in degrees. This heading is based on integration
|
| 153 | * of the returned rate from the gyro.
|
| 154 | */
|
| 155 | float Gyro::GetAngle( void )
|
| 156 | {
|
| 157 | INT64 rawValue;
|
| 158 | UINT32 count;
|
| 159 | m_analog->GetAccumulatorOutput(&rawValue, &count);
|
| 160 |
|
| 161 | INT64 value = rawValue - (INT64)((float)count * m_offset);
|
| 162 |
|
| 163 | double scaledValue = value * 1e-9 * (double)m_analog->GetLSBWeight() * (double)(1 << m_analog->GetAverageBits()) /
|
| 164 | (m_analog->GetModule()->GetSampleRate() * m_voltsPerDegreePerSecond);
|
| 165 |
|
| 166 | return (float)scaledValue;
|
| 167 | }
|
| 168 |
|
| 169 |
|
| 170 | /**
|
| 171 | * Set the gyro type based on the sensitivity.
|
| 172 | * This takes the number of volts/degree/second sensitivity of the gyro and uses it in subsequent
|
| 173 | * calculations to allow the code to work with multiple gyros.
|
| 174 | *
|
| 175 | * @param voltsPerDegreePerSecond The type of gyro specified as the voltage that represents one degree/second.
|
| 176 | */
|
| 177 | void Gyro::SetSensitivity( float voltsPerDegreePerSecond )
|
| 178 | {
|
| 179 | m_voltsPerDegreePerSecond = voltsPerDegreePerSecond;
|
| 180 | }
|
| 181 |
|
| 182 | /**
|
| 183 | * Get the angle in degrees for the PIDSource base object.
|
| 184 | *
|
| 185 | * @return The angle in degrees.
|
| 186 | */
|
| 187 | double Gyro::PIDGet()
|
| 188 | {
|
| 189 | return GetAngle();
|
| 190 | }
|
| 191 |
|
| 192 | void Gyro::UpdateTable() {
|
| 193 | if (m_table != NULL) {
|
| 194 | m_table->PutNumber("Value", GetAngle());
|
| 195 | }
|
| 196 | }
|
| 197 |
|
| 198 | void Gyro::StartLiveWindowMode() {
|
| 199 |
|
| 200 | }
|
| 201 |
|
| 202 | void Gyro::StopLiveWindowMode() {
|
| 203 |
|
| 204 | }
|
| 205 |
|
| 206 | std::string Gyro::GetSmartDashboardType() {
|
| 207 | return "Gyro";
|
| 208 | }
|
| 209 |
|
| 210 | void Gyro::InitTable(ITable *subTable) {
|
| 211 | m_table = subTable;
|
| 212 | UpdateTable();
|
| 213 | }
|
| 214 |
|
| 215 | ITable * Gyro::GetTable() {
|
| 216 | return m_table;
|
| 217 | }
|
| 218 |
|