blob: 4ea35886b72df5d59060d781050d7309abb51d88 [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{
jerrym37afdca2013-03-03 01:17:57 +000031 m_table = NULL;
jerrymf1579332013-02-07 01:56:28 +000032 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 */
77Gyro::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 */
91Gyro::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 */
104Gyro::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
118Gyro::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 */
130void Gyro::Reset()
131{
132 m_analog->ResetAccumulator();
133}
134
135/**
136 * Delete (free) the accumulator and the analog components used for the gyro.
137 */
138Gyro::~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 */
155float 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 */
177void 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 */
187double Gyro::PIDGet()
188{
189 return GetAngle();
190}
191
192void Gyro::UpdateTable() {
193 if (m_table != NULL) {
194 m_table->PutNumber("Value", GetAngle());
195 }
196}
197
198void Gyro::StartLiveWindowMode() {
199
200}
201
202void Gyro::StopLiveWindowMode() {
203
204}
205
206std::string Gyro::GetSmartDashboardType() {
207 return "Gyro";
208}
209
210void Gyro::InitTable(ITable *subTable) {
211 m_table = subTable;
212 UpdateTable();
213}
214
215ITable * Gyro::GetTable() {
216 return m_table;
217}
218