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