@@ -16,6 +16,11 @@ POP_NO_WARNINGS
1616 * */
1717
1818bool Gyro::isPresent (false );
19+ float Gyro::_pitchSamples[WINDOW_SIZE] = {};
20+ float Gyro::_rollSamples[WINDOW_SIZE] = {};
21+ int Gyro::_ringIndex (0 );
22+ int Gyro::_samplesCollected (0 );
23+ unsigned long Gyro::_lastSampleTime (0 );
1924
2025void Gyro::startup ()
2126/* Starts up the MPU-6050 device.
@@ -54,6 +59,16 @@ void Gyro::startup()
5459 Wire.write (6 ); // 5Hz bandwidth (lowest) for smoothing
5560 Wire.endTransmission (true );
5661
62+ // Reset moving average state
63+ for (int i = 0 ; i < WINDOW_SIZE; i++)
64+ {
65+ _pitchSamples[i] = 0 ;
66+ _rollSamples[i] = 0 ;
67+ }
68+ _ringIndex = 0 ;
69+ _samplesCollected = 0 ;
70+ _lastSampleTime = 0 ;
71+
5772 LOG (DEBUG_INFO, " [GYRO]:: Started" );
5873}
5974
@@ -66,45 +81,69 @@ void Gyro::shutdown()
6681 // Nothing to do
6782}
6883
84+ void Gyro::collectSample ()
85+ /* Reads one accelerometer sample and stores it in the circular buffer.
86+ */
87+ {
88+ // Execute 6 byte read from MPU6050_REG_ACCEL_XOUT_H
89+ Wire.beginTransmission (MPU6050_I2C_ADDR);
90+ Wire.write (MPU6050_REG_ACCEL_XOUT_H);
91+ Wire.endTransmission (false );
92+ Wire.requestFrom (MPU6050_I2C_ADDR, 6 , 1 ); // Read 6 registers total, each axis value is stored in 2 registers
93+ int16_t AcX = Wire.read () << 8 | Wire.read (); // X-axis value
94+ int16_t AcY = Wire.read () << 8 | Wire.read (); // Y-axis value
95+ int16_t AcZ = Wire.read () << 8 | Wire.read (); // Z-axis value
96+
97+ // Calculating the Pitch angle (rotation around Y-axis)
98+ _pitchSamples[_ringIndex] = atan2f (-1 .0f * AcX, sqrtf ((float ) AcY * AcY + (float ) AcZ * AcZ)) * 180 .0f / static_cast <float >(PI);
99+ // Calculating the Roll angle (rotation around X-axis)
100+ _rollSamples[_ringIndex] = atan2f (-1 .0f * AcY, sqrtf ((float ) AcX * AcX + (float ) AcZ * AcZ)) * 180 .0f / static_cast <float >(PI);
101+
102+ _ringIndex = (_ringIndex + 1 ) % WINDOW_SIZE;
103+ if (_samplesCollected < WINDOW_SIZE)
104+ {
105+ _samplesCollected++;
106+ }
107+ }
108+
69109angle_t Gyro::getCurrentAngles ()
70110/* Returns roll & tilt angles from MPU-6050 device in angle_t object in degrees.
71- If MPU-6050 is not found then returns {0,0}.
111+ Non-blocking: collects one sample per call if at least SAMPLE_INTERVAL ms
112+ have elapsed since the last sample. Returns the moving average over the
113+ last WINDOW_SIZE samples.
72114*/
73115{
74- const int windowSize = 16 ;
75- // Read the accelerometer data
76- struct angle_t result;
77- result.pitchAngle = 0 ;
78- result.rollAngle = 0 ;
116+ angle_t result;
117+
79118 if (!isPresent)
80- return result; // Gyro is not available
119+ return result;
120+
121+ unsigned long now = millis ();
122+ if (now - _lastSampleTime >= SAMPLE_INTERVAL)
123+ {
124+ _lastSampleTime = now;
125+ collectSample ();
126+ }
81127
82- for (int i = 0 ; i < windowSize; i++)
128+ if (_samplesCollected == 0 )
129+ return result;
130+
131+ float pitchSum = 0 ;
132+ float rollSum = 0 ;
133+ for (int i = 0 ; i < _samplesCollected; i++)
83134 {
84- // Execute 6 byte read from MPU6050_REG_WHO_AM_I
85- Wire.beginTransmission (MPU6050_I2C_ADDR);
86- Wire.write (MPU6050_REG_ACCEL_XOUT_H);
87- Wire.endTransmission (false );
88- Wire.requestFrom (MPU6050_I2C_ADDR, 6 , 1 ); // Read 6 registers total, each axis value is stored in 2 registers
89- int16_t AcX = Wire.read () << 8 | Wire.read (); // X-axis value
90- int16_t AcY = Wire.read () << 8 | Wire.read (); // Y-axis value
91- int16_t AcZ = Wire.read () << 8 | Wire.read (); // Z-axis value
92-
93- // Calculating the Pitch angle (rotation around Y-axis)
94- result.pitchAngle += atan2f (-1 .0f * AcX, sqrtf ((float ) AcY * AcY + (float ) AcZ * AcZ)) * 180 .0f / static_cast <float >(PI);
95- // Calculating the Roll angle (rotation around X-axis)
96- result.rollAngle += atan2f (-1 .0f * AcY, sqrtf ((float ) AcX * AcX + (float ) AcZ * AcZ)) * 180 .0f / static_cast <float >(PI);
97-
98- delay (10 ); // Decorrelate measurements
135+ pitchSum += _pitchSamples[i];
136+ rollSum += _rollSamples[i];
99137 }
138+ result.pitchAngle = pitchSum / _samplesCollected;
139+ result.rollAngle = rollSum / _samplesCollected;
100140
101- result.pitchAngle /= windowSize;
102- result.rollAngle /= windowSize;
103141 #if GYRO_AXIS_SWAP == 1
104142 float temp = result.pitchAngle ;
105143 result.pitchAngle = result.rollAngle ;
106144 result.rollAngle = temp;
107145 #endif
146+
108147 return result;
109148}
110149
0 commit comments