Estimate Orientation with a Complementary Filter and IMU Data
This example shows how to stream IMU data from an Arduino and estimate orientation using a complementary filter.
Connect Hardware
Connect the SDA, SCL, GND, and VCC pins of the MPU-9250 sensor to the corresponding pins of the Arduino® hardware. This example uses an Arduino® Uno board with the following connections:
SDA - A4
SCL - A5
VCC - +3.3V
GND - GND
Ensure that the connections to the sensors are intact. It is recommended to attach/connect the sensor to a prototype shield to avoid loose connections while the sensor is in motion. Refer theTroubleshooting Sensors(MATLAB Support Package for Arduino Hardware)page to debug the sensor related issues.
Create Sensor Object
Create anarduino
object and anmpu9250
object. Specify the sensor sampling rateFs
and the amount of time to run the loops. Optionally, enable theisVerbose
flag to check if any samples are overrun. By disabling theuseHW
flag, you can also run the example with sensor data saved in the MAT-fileloggedMPU9250Data.mat
.
The data inloggedMPU9250Data.mat
was logged while the IMU was generally facing due South, then rotated:
在z轴+ 90度
-180 degrees around the z-axis
在z轴+ 90度
+90 degrees around the y-axis
-180 degrees around the y-axis
+90 degrees around the y-axis
+90 degrees around the x-axis
-270 degrees around the x-axis
+180 degrees around the x-axis
Notice that the last two rotations around the x-axis are an additional 90 degrees. This was done to flip the device upside-down. The final orientation of the IMU is the same as the initial orientation, due South.
Fs = 100; samplesPerRead = 10; runTime = 20; isVerbose = false; useHW = true;ifuseHW一= arduino; imu = mpu9250(a,'SampleRate', Fs,'OutputFormat','matrix',...'SamplesPerRead', samplesPerRead);elseload('loggedMPU9250Data.mat','allAccel','allGyro','allMag',...'allT','allOverrun',...'numSamplesAccelGyro','numSamplesAccelGyroMag')end
Align Axes of MPU-9250 Sensor with NED Coordinates
The axes of the accelerometer, gyroscope, and magnetometer in the MPU-9250 are not aligned with each other. Specify the index and sign x-, y-, and z-axis of each sensor so that the sensor is aligned with the North-East-Down (NED) coordinate system when it is at rest. In this example, the magnetometer axes are changed while the accelerometer and gyroscope axes remain fixed. For your own applications, change the following parameters as necessary.
% Accelerometer axes parameters.accelXAxisIndex = 1; accelXAxisSign = 1; accelYAxisIndex = 2; accelYAxisSign = 1; accelZAxisIndex = 3; accelZAxisSign = 1;% Gyroscope axes parameters.gyroXAxisIndex = 1; gyroXAxisSign = 1; gyroYAxisIndex = 2; gyroYAxisSign = 1; gyroZAxisIndex = 3; gyroZAxisSign = 1;% Magnetometer axes parameters.magXAxisIndex = 2; magXAxisSign = 1; magYAxisIndex = 1; magYAxisSign = 1; magZAxisIndex = 3; magZAxisSign = -1;% Helper functions used to align sensor data axes.alignAccelAxes = @(in) [accelXAxisSign, accelYAxisSign, accelZAxisSign]....* in(:, [accelXAxisIndex, accelYAxisIndex, accelZAxisIndex]); alignGyroAxes = @(in) [gyroXAxisSign, gyroYAxisSign, gyroZAxisSign]....* in(:, [gyroXAxisIndex, gyroYAxisIndex, gyroZAxisIndex]); alignMagAxes = @(in) [magXAxisSign, magYAxisSign, magZAxisSign]....* in(:, [magXAxisIndex, magYAxisIndex, magZAxisIndex]);
Perform Additional Sensor Calibration
If necessary, you may calibrate the magnetometer to compensate for magnetic distortions. For more details, see the Compensating for Hard Iron Distortions section of theEstimating Orientation Using Inertial Sensor Fusion and MPU-9250example.
Specify Complementary filter Parameters
ThecomplementaryFilter
has two tunable parameters. TheAccelerometerGain
parameter determines how much the accelerometer measurement is trusted over the gyroscope measurement. TheMagnetometerGain
parameter determines how much the magnetometer measurement is trusted over the gyroscope measurement.
compFilt = complementaryFilter('SampleRate', Fs)
compFilt = complementaryFilter with properties: SampleRate: 100 AccelerometerGain: 0.0100 MagnetometerGain: 0.0100 HasMagnetometer: 1 OrientationFormat: 'quaternion'
Estimate Orientation with Accelerometer and Gyroscope
Set theHasMagnetometer
property tofalse
to disable the magnetometer measurement input. In this mode, the filter only takes accelerometer and gyroscope measurements as inputs. Also, the filter assumes the initial orientation of the IMU is aligned with the parent navigation frame. If the IMU is not aligned with the navigation frame initially, there will be a constant offset in the orientation estimation.
compFilt = complementaryFilter('HasMagnetometer', false); tuner = HelperOrientationFilterTuner(compFilt);ifuseHW ticelseidx = 1:samplesPerRead; overrunIdx = 1;endwhiletrueifuseHW [accel, gyro, mag, t, overrun] = imu(); accel = alignAccelAxes(accel); gyro = alignGyroAxes(gyro);elseaccel = allAccel(idx,:); gyro = allGyro(idx,:); mag = allMag(idx,:); t = allT(idx,:); overrun = allOverrun(overrunIdx,:); idx = idx + samplesPerRead; overrunIdx = overrunIdx + 1; pause(samplesPerRead/Fs)endif(isVerbose && overrun > 0) fprintf('%d samples overrun ...\n', overrun);endq = compFilt(accel, gyro); update(tuner, q);ifuseHWiftoc >= runTimebreak;endelseifidx(end) > numSamplesAccelGyrobreak;endendend
Estimate Orientation with Accelerometer, Gyroscope, and Magnetometer
With the default values ofAccelerometerGain
andMagnetometerGain
, the filter trusts more on the gyroscope measurements in the short-term, but trusts more on the accelerometer and magnetometer measurements in the long-term. This allows the filter to be more reactive to quick orientation changes and prevents the orientation estimates from drifting over longer periods of time. For specific IMU sensors and application purposes, you may want to tune the parameters of the filter to improve the orientation estimation accuracy.
compFilt = complementaryFilter('SampleRate', Fs); tuner = HelperOrientationFilterTuner(compFilt);ifuseHW ticendwhiletrueifuseHW [accel, gyro, mag, t, overrun] = imu(); accel = alignAccelAxes(accel); gyro = alignGyroAxes(gyro); mag = alignMagAxes(mag);elseaccel = allAccel(idx,:); gyro = allGyro(idx,:); mag = allMag(idx,:); t = allT(idx,:); overrun = allOverrun(overrunIdx,:); idx = idx + samplesPerRead; overrunIdx = overrunIdx + 1; pause(samplesPerRead/Fs)endif(isVerbose && overrun > 0) fprintf('%d samples overrun ...\n', overrun);endq = compFilt(accel, gyro, mag); update(tuner, q);ifuseHWiftoc >= runTimebreak;endelseifidx(end) > numSamplesAccelGyroMagbreak;endendend
Summary
This example showed how to estimate the orientation of an IMU using data from an Arduino and a complementary filter. This example also showed how to configure the IMU and discussed the effects of tuning the complementary filter parameters.