-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsix_axis_comp_filter.cpp
258 lines (226 loc) · 7.85 KB
/
six_axis_comp_filter.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
//*********************************************************************************
// Six Axis Complementary Filter - Platform Independent
//
// Revision: 1.5
//
// Description: Takes gyroscope and accelerometer readings and produces a "fused"
// reading that is more accurate. Relies heavily on floating point arithmetic
// and trigonometry.
//
// This library has been tested to work with the MPU-6050 6 DOF IMU Sensor
// comprising a gyroscope and accelerometer. It should also work with other 6
// DOF IMUs but there are no guarantees. Also, this library should work
// with even 5 DOF IMUs since the gyroscope reading about the Z axis technically
// goes unused with this library at its current revision.
//
// For more info on the theory behind how this filter functions, view
// http://web.mit.edu/~jinstone/Public/filter.pdf
//
// Revisions can be found here:
// https://github.com/tcleg
//
// Copyright (C) 2014 Trent Cleghorn , <[email protected]>
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//*********************************************************************************
//*********************************************************************************
// Headers
//*********************************************************************************
#include <math.h>
#include "six_axis_comp_filter.h"
//*********************************************************************************
// Macros and Globals
//*********************************************************************************
#define PI 3.1415926f
#define HALF_PI 1.5707963f
#define TWO_PI 6.2831853f
#define SQRE(x) ((x)*(x))
//*********************************************************************************
// Public Class Functions
//*********************************************************************************
CompSixAxis::
CompSixAxis(float deltaTime, float tau)
{
// Save value to class
deltaT = deltaTime;
// Calculate weighting factor
alpha = tau/(tau + deltaT);
// Initialize other class variables
compAngleX = 0;
compAngleY = 0;
accelAngleX = 0;
accelAngleY = 0;
Ax = 0;
Ay = 0;
Az = 0;
Gx = 0;
Gy = 0;
Gz = 0;
}
void CompSixAxis::
CompStart()
{
// Calculate accelerometer angles
CompAccelCalculate();
// Initialize filter to accel angles
compAngleX = accelAngleX;
compAngleY = accelAngleY;
}
void CompSixAxis::
CompUpdate()
{
// Calculate the accelerometer angles
CompAccelCalculate();
// Omega is the rotational velocity reported by the gyroscope. Though it seems
// strange, the rotational velocity about the Y axis must be projected back
// onto the X axis and then its sense of direction must be inverted in order to
// acquire positive angles about the X axis. This is shown below with -Gy being
// passed as a parameter.
compAngleX = CompFilterProcess(compAngleX, accelAngleX, -Gy);
// In this case, the rotational velocity about the X axis (Gx) is projected back
// onto the Y axis and its sense of direction is already correct.
compAngleY = CompFilterProcess(compAngleY, accelAngleY, Gx);
}
void CompSixAxis::
CompAnglesGet(float *XAngle, float *YAngle)
{
// Transfer class's updated comp. filter's angles
// Check if valid addresses were passed as well.
if(XAngle)
{
*XAngle = compAngleX;
}
if(YAngle)
{
*YAngle = compAngleY;
}
}
void CompSixAxis::
CompAccelUpdate(float accelX, float accelY, float accelZ)
{
// Save values to class
Ax = accelX;
Ay = accelY;
Az = accelZ;
}
void CompSixAxis::
CompGyroUpdate(float gyroX, float gyroY, float gyroZ)
{
// Save values to class
Gx = gyroX;
Gy = gyroY;
Gz = gyroZ;
}
//*********************************************************************************
// Private Class Functions
//*********************************************************************************
//
// Calculates the angles according to the accelerometer based on the acceleration
// readings
//
void CompSixAxis::
CompAccelCalculate()
{
// Angle made by X axis acceleration vector relative to ground
accelAngleX = atan2f(Ax, sqrtf( SQRE(Ay) + SQRE(Az) ) );
// Angle made by Y axis acceleration vector relative to ground
accelAngleY = atan2f(Ay, sqrtf( SQRE(Ax) + SQRE(Az) ) );
// Format the accel. angles to lie in the range of 0 to 2*pi
accelAngleX = FormatAccelRange(accelAngleX, Az);
accelAngleY = FormatAccelRange(accelAngleY, Az);
}
//
// Check to see which quadrant of the unit circle the angle lies in
// and format the angle to lie in the range of 0 to 2*PI
//
float CompSixAxis::
FormatAccelRange(float accelAngle, float accelZ)
{
if(accelZ < 0.0f)
{
// Angle lies in Quadrant 2 or Quadrant 3 of
// the unit circle
accelAngle = PI - accelAngle;
}
else if(accelZ > 0.0f && accelAngle < 0.0f)
{
// Angle lies in Quadrant 4 of the unit circle
accelAngle = TWO_PI + accelAngle;
}
// If both of the previous conditions were not satisfied, then
// the angle must lie in Quadrant 1 and nothing more needs
// to be done.
return accelAngle;
}
//
// Formats the complimentary filter angle for faster convergence of the filter.
//
float CompSixAxis::
FormatFastConverge(float compAngle, float accAngle)
{
// Work with comp. angles that are closest in distance to the accelerometer angle
// on the unit circle. This allows for significantly faster filter convergence.
if(compAngle > accAngle + PI)
{
compAngle = compAngle - TWO_PI;
}
else if(accAngle > compAngle + PI)
{
compAngle = compAngle + TWO_PI;
}
return compAngle;
}
//
// Formats the complimentary filter angle to always lie within the range of
// 0 to 2*pi
//
float CompSixAxis::
FormatRange0to2PI(float compAngle)
{
while(compAngle >= TWO_PI)
{
compAngle = compAngle - TWO_PI;
}
while(compAngle < 0.0f)
{
compAngle = compAngle + TWO_PI;
}
return compAngle;
}
//
// Complimentary Filter - This is where the magic happens.
//
float CompSixAxis::
CompFilterProcess(float compAngle, float accelAngle, float omega)
{
float gyroAngle;
// Speed up filter convergence
compAngle = FormatFastConverge(compAngle, accelAngle);
// Integrate the gyroscope's angular velocity reading to get an angle
gyroAngle = compAngle + omega*deltaT;
// Weighting is applied to the gyroscope's angular position and
// accelerometer's angular position and they are put together to form one
// angle, the complimentary filter angle.
compAngle = alpha*gyroAngle + (1.0f - alpha)*accelAngle;
// Format the Comp. Angle to lie in the range of 0 to 2*pi
compAngle = FormatRange0to2PI(compAngle);
return compAngle;
}