Getting Started With Inertial Measurement Units | Exploring Degrees Of Freedom

Updated 19 July 2023

In this guide, we'll be learning about sensors that measure inertial movement, how they work, how to choose the right sensor type, and how to get the most out of their readings.

Hardware mentioned in this guide:

Contents:


Introduction

Inertial Measurement Units (IMUs for short) are sensors that detect and measure their own movement and are useful in scenarios where a device needs to keep track of changes to its physical orientation in 3D space. They are commonly used in drones and robots, smartphones, game console controllers, and even smart TV remotes.

IMUs are most commonly comprised of a combination of the following three sensors: Accelerometer, Gyrometer, and Magnetometer.

An Accelerometer measures acceleration or changes in the velocity of an object along the 3 axes of 3D space.

They work by using a small mass connected to a series of fixed capacitors, which are arranged in a particular pattern using micro-electromechanical systems (MEMS) technology.

When the sensor experiences acceleration or changes its velocity in a particular direction, the small mass inside the accelerometer also moves relative to the fixed capacitors. This changes the distance between the mass and capacitors, which in turn changes the capacitance of the system. The change in capacitance is detected by an electronic circuit, which converts it into a digital signal.

Accelerometers are commonly used in smartphones, wearables, and other electronic devices to measure motion, detect orientation, and enable features such as step tracking, screen rotation, and gaming controls.

In addition to detecting movement, a fundamental feature of physics - gravity - enables us to use an accelerometer to measure tilt as well. We'll discuss that in more detail in the section '3 Degrees of Freedom: Accelerometers'.

A Gyrometer (or gyro for short) is a sensor that measures the rate of rotation or angular velocity of an object around the 3 axes of 3D space.

They work by using a tiny vibrating element, typically a MEMS resonator, which vibrates at a particular frequency range.

When the gyro experiences angular motion, the Coriolis force acts on the resonator, which is then detected by sensors placed all around the resonator. These tiny sensors determine the rate and direction of angular motion, which is detected by an electronic circuit, which converts it into a digital signal.

Gyros are commonly used in applications such as smartphones, gaming controllers, and drones, which require high accuracy and fast response for motion tracking and orientation control.

A Magnetometer is a sensor that measures the strength of its surrounding magnetic field along the 3 axes of 3D space.

They work by using a MEMS device containing a tiny silicon structure that is sensitive to magnetic fields.

When the sensor is exposed to a magnetic field the silicon structure moves, which is detected by capacitive or resistive elements within the MEMS device. The change in capacitance/resistance is detected by an electronic circuit, which converts it into a digital signal.

Magnetometers are commonly used in smartphones, navigation systems, and digital compasses to detect magnetic north direction or measure the strength of magnetic fields.

Stand-alone use of a Magnetometer is outside the scope of this guide, but if you're interested check out our guide on the PiicoDev Magnetometer.


Degrees Of Freedom

IMUs are categorised by how many Degrees of Freedom (DoF for short) they are able to sense. Degrees of Freedom are how many different ways something can move in 3D space.

Imagine a basketball, you can move (translate) the basketball up/down, left/right, and forwards/backwards - these are the 3 degrees of freedom of translation.

You can also rotate the same basketball left/right, forwards/backward, or spin it on your finger - these are the 3 degrees of freedom of rotation.

Combined with the 3 DoF of translation, we find that the basketball has a total of 6 degrees of freedom.

Finally, you can also track the direction of those movements relative to Earth - north/south, east/west, and up/down - these are the 3 degrees of freedom of direction

All added up, we now have a total of 9 degrees of freedom.

3 Degrees of Freedom of Translation3 Degrees of Freedom of Translation
3 Degrees of Freedom of Translation
3 Degrees of Freedom of Rotation3 Degrees of Freedom of Rotation
3 Degrees of Freedom of Rotation
3 Degrees of Freedom of Direction in Relation To Earth3 Degrees of Freedom of Direction in Relation To Earth
3 Degrees of Freedom of Direction in Relation To Earth

But how are the first 3 DoF of movements different from the last 3 DoF relative to Earth, I hear you ask?

Well, imagine you have a friend that lives on the opposite side of the world.

You and your friend, who are on other sides of the Earth, both hold a basketball and lift it straight upwards.

To each of you individually, the basketball has moved upwards, but in 3D space, they have actually moved in opposite directions.

The first 3 DoF of movement have no reference system, so movement by an object can only really be understood by the object itself. The last 3 DoF of direction gives us a reference system, which makes the movement of one object understandable to other objects by sharing the same reference system - assuming they're all on or near Earth that is!

In the previous section, we looked at the three common sensor types used in IMUs - Accelerometer, Gyro, and Magnetometer - and the forces that each sensor measures.

Can you guess which category of Degrees of Freedom - translation, rotation, or direction - each of these sensors measures?

In case you're not sure, they are:

  • Accelerometer: 3 DoF of Translation
  • Gyro: 3 DoF of Rotation
  • Magnetometer: 3 DoF of Direction

IMUs incorporate one, two, or all three of these sensors to measure 3, 6, or 9 Degrees of Freedom. For example, we can use an Accelerometer to achieve 3 DoF, we can add in a Gyro to achieve 6 DoF, and finally, add the Magnetometer to achieve the full 9 DoF.


Sensor Fusion

The more Degrees of Freedom (translation, rotation, and direction) we can measure, the more accurately we can determine the orientation of an object and track it in 3D space.

That's great in theory, but in reality, IMUs usually output raw readings from each of their sensors in different units and scales. To obtain orientation information in a format we can easily use, we first need to combine all the different raw readings using complex algorithms in a process called Sensor Fusion.

Fortunately for us, those complex algorithms have already been solved and made public, and are available as a package/library for every microcontroller platform, such as the Raspberry Pi Pico using the micropython-fusion library. Some of the more sophisticated IMUs even perform their own sensor fusion onboard and provide the results along with the raw sensor readings - so you don't even have to do it yourself!

Sensor Fusion combines the raw readings from individual sensors and outputs the resulting orientation as Roll, Pitch, and Heading (or Yaw) - which you might be familiar with if you are interested in aeroplanes or aviation. These three angles are also known as Euler Angles, and are usually output by the sensor fusion algorithm in Radians rather than Degrees.

Roll, Pitch, and Heading define the rotation of an object around the three axes of 3D Space, which are referred to as the X, Y, and Z axes:

  • Roll defines the rotation of an object around the X-Axis, and if you were to do a cartwheel, you would be changing your Roll.
  • Pitch defines the rotation of an object around the Y-Axis, and if you were to do a front flip, you would be changing your Pitch.
  • Heading defines the rotation of an object around the Z-Axis, and if you were to spin on the tip of your toes, you would be changing your Heading.
Image Source: Wikipedia

Another common sensor fusion output format is Quaternions, which is an alternate way to represent orientation and has some benefits over using Euler Angles.

However, they can be a lot more complicated to understand, so to keep things as simple as possible, we're only going to be using Euler Angles in this guide.

To perform sensor fusion we need readings from at least two separate sensors for a minimum of 6 DoF, and to perform full sensor fusion we need all three sensors with all 9 DoF.

We'll discuss 6 and 9 DoF Sensor Fusion in more detail in the 6 DoF and 9 DoF sections below.


3 Degrees of Freedom: Accelerometer

The simplest of the bunch, 3 DoF IMUs can only sense one of either translation, rotation, or direction. The most common maker-level type of 3 DoF IMU senses translation using an Accelerometer.

While they might be the 'simplest', Accelerometers are still very useful devices on their own. Accelerometers can be used to detect tapping and shaking, and can actually be used to measure rotation, thanks to the Earth's gravity asserting a constant measurable acceleration in a single direction. As you rotate an accelerometer, the acceleration force of gravity acts against each axis, enabling us to use some trigonometry to calculate the rotation of the accelerometer.

Check out our guide on the PiicoDev Accelerometer to see how to detect tapping/shaking and rotation using an accelerometer.

So if an Accelerometer can be used to measure both translation and rotation, doesn't that mean it has 6 degrees of freedom? Unfortunately, no, because measuring rotation from an accelerometer comes with some limitations:

  • It can only be used for rotation if it is not moving. As soon as the accelerometer moves, the new forces interfere with those being measured from gravity and corrupt the rotation calculations.
  • Rotation can not be reliably calculated on all 3 axes at all times. For example, if the Z axis is pointing straight up, and the X and Y axes are perpendicular to gravity (and therefore both measuring zero), it becomes impossible to detect rotation around the Z axis.
  • Accelerometers are noisy, which in turn causes 'drift' - which is when readings gradually become less accurate over time.
3 DoF Accelerometer - PiicoDev LIS3DH3 DoF Accelerometer - PiicoDev LIS3DH
3 DoF Accelerometer - PiicoDev LIS3DH

With these limitations in mind, accelerometers are still great for small-scale rotation detection, such as tilt sensors where you are interested in detecting tilt across one or two axes at a time - like rotating a screen, or balancing a ball on a flat surface.


6 Degrees of Freedom: Accelerometer & Gryo

6 DoF IMUs combine two sensors that have 3 different degrees of freedom each. Most common maker-level 6 DoF IMUs will consist of an Accelerometer and a Gyro to add rotation.

We've just discussed how an accelerometer can provide some rotation information, albeit not completely reliably. A Gyro is dedicated to measuring rotations, or more specifically, angular velocity, which is just what we need to bump our degrees of freedom from 3 up to 6.

As a 6 DoF IMU contains both an accelerometer and gyro, it will typically output the data from both sensors as 6 raw values: 3 values of acceleration for each axis of the accelerometer, and 3 values of rotational change for each axis of the gyro.

We can use these raw values if we want, giving us two independent motion sensors to work with. For example, we could use the accelerometer readings for tap/shake detection, and the gyro readings for more accurate tilt detection. However, the real power of the two sensors is unlocked when we combine them using Sensor Fusion.

6 DoF Accelerometer & Gyro - MPU60506 DoF Accelerometer & Gyro - MPU6050
6 DoF Accelerometer & Gyro - MPU6050

The following is an example of performing Sensor Fusion on an MPU6050 6 DoF IMU using the micropython-fusion library:

# Example of 6 DoF Sensor Fusion using a MPU6050 IMU

from machine import Pin, I2C
from imu import MPU6050
from fusion import Fusion
import time

i2c = I2C(1, sda=Pin(2), scl=Pin(3), freq=400000) 
imu = MPU6050(i2c)

fuse = Fusion()

while True:
    fuse.update_nomag((imu.accel.x, imu.accel.y, imu.accel.z), (imu.gyro.x, imu.gyro.y, imu.gyro.z))
    print(f'Orientation: {fuse.heading}, {fuse.pitch}, {fuse.roll}')
    
    time.sleep_ms(20)

When running this script on the Raspberry Pi Pico in Thonny, and rotating the 6 DoF IMU module around in the air, we see the Pitch and Roll values updating to reflect the orientation of the IMU, in radians.

However, since we are only fusing two sensors - Accelerometer and Gyro, Sensor Fusion cannot calculate Heading.

We need a 9 DoF for sensor fusion to calculate Heading, which we will get to in the next section.

Blue Line: Heading, Orange Line: Pitch, Green Line: RollBlue Line: Heading, Orange Line: Pitch, Green Line: Roll
Blue Line: Heading, Orange Line: Pitch, Green Line: Roll

So what's the point of a 6 DoF IMU if we can't get Heading from sensor fusion?
Well, we still have two axes of orientation, and they are far more reliable than if we were just using a 3 DoF IMU for rotation.

In many cases, you may only need two accurate axes of orientation, such as a pointing device or gaming controller which can only actually move within two axes of a screen or TV.

6 DoF sensors are also typically much cheaper than 9 DoF sensors, so if you only need to track two axes of movement then a 6 DoF IMU is usually the more affordable option.


9 Degrees of Freedom: Accelerometer, Gyro, & Magnetometer

9 DoF IMUs combine three sensors, each with 3 different degrees of freedom. This is typically achieved by adding a Magnetometer to the 6 DoF Accelerometer & Gyro combination, which adds the 3 DoF of direction.

Much like a 6 DoF IMU, a 9 DoF IMU will output 9 raw readings from each of its individual sensors: 3 axes of Acceleration, 3 axes of Gyro Rotation, and 3 axes of Magnetic field.

However, we now have the last 3 Degrees of Freedom we need to enable us to perform full sensor fusion and determine Heading, in addition to Pitch and Roll!

We could do this using software, however, an extra feature that many modern 9 DoF IMUs boast is onboard sensor fusion - meaning the module does the sensor fusion for you and provides the computed heading, pitch, and roll Euler angles in addition to the raw sensor values.

9 DoF Acceleromoter, Gyro & Magnetometer - BNO0559 DoF Acceleromoter, Gyro & Magnetometer - BNO055
9 DoF Acceleromoter, Gyro & Magnetometer - BNO055

Onboard Sensor Fusion

The following is an example of full sensor fusion performed on the Bosch BNO055, using the micropython-bno055 library to interface with the module over I2C:

# Example of onboard sensor fusion using the BNO055 9 DoF module

from machine import Pin, I2C
from bno055 import *
import time

i2c = I2C(1, sda=Pin(2), scl=Pin(3), freq=400000) 
time.sleep(1)
imu = BNO055(i2c)

while True:
    vals = imu.euler()
    print(f'Orientation: {vals[0]}, {vals[1]}, {vals[2]}')

    time.sleep_ms(20)

When running this script on the Raspberry Pi Pico in Thonny, and rotating the 9 DoF IMU module around in the air, we see can see that all three orientation components are now updating: Heading, Pitch, and Roll.

Blue Line: Heading, Orange Line: Pitch, Green Line: RollBlue Line: Heading, Orange Line: Pitch, Green Line: Roll
Blue Line: Heading, Orange Line: Pitch, Green Line: Roll

Software Sensor Fusion

Onboard sensor fusion is a wonderful feature, however, not all 9 DoF IMUs provide full sensor fusion from the module itself. In this case, you will need to perform the sensor fusion using code by feeding all nine sensor values to the sensor fusion library.

Note that while we need to add Magnetometer readings to achieve full sensor fusion, the fusion algorithms don't necessarily care where those readings come from.

With a 9 DoF IMU module, like the BNO055, they will all come from the single hardware module, but there is nothing stopping you from adding a standalone 3-axis Magnetometer module to a 6 DoF Accelerometer & Gyro module to make up all the required degrees of freedom.

Keep in mind a 9 DoF IMU will have all 3 sensors aligned, and will likely have better accuracy, whereas when manually adding a Magnetometer you will need to ensure that the different modules are physically aligned as best as possible, and even when doing your best it will likely still not be as accurate as an all-in-one 9 DoF IMU.

9 DoF by combining a 6 DoF IMU with a Magnetometer9 DoF by combining a 6 DoF IMU with a Magnetometer
9 DoF by combining a 6 DoF IMU with a Magnetometer

The following example combines an MPU6050 Accelerometer and Gyro with a PiicoDev Magnetometer to create a 9 DoF system with full sensor fusion.

Keep in mind, if you get strange results it might be that you need to physically adjust the rotation and position of each module to ensure their axes are all aligned.

# Example of 9 DoF Sensor Fusion using an MPU6050 and PiicoDev Magnetometer

from machine import Pin, I2C
from PiicoDev_QMC6310 import PiicoDev_QMC6310
from imu import MPU6050
from fusion import Fusion
import time

i2c = I2C(1, sda=Pin(2), scl=Pin(3), freq=400000) 
time.sleep(1)
imu = MPU6050(i2c)

magSensor = PiicoDev_QMC6310(suppress_warnings=True)
magSensor.setRange(1200)

fuse = Fusion()

while True:
    raw_data = magSensor.read()
    if not magSensor.dataValid():
        time.sleep(1)
        continue

    fuse.update(
        (imu.accel.x, imu.accel.y, imu.accel.z),
        (imu.gyro.x, imu.gyro.y, imu.gyro.z),
        (raw_data['x'], raw_data['y'], raw_data['z'])
    )
    print(f'Orientation: {fuse.heading}, {fuse.pitch}, {fuse.roll}')
    
    time.sleep_ms(20)

If you're just starting out and are looking to keep costs down while learning about IMUs, a great approach can be to start with just a 6 DoF IMU and add a Magnetometer to the mix later on.

However, a full 9 DoF IMU with onboard sensor fusion is the complete package, and if you're happy to pay a bit more, it will give you the most flexibility and best accuracy.


Conclusion

So that's the 3 different types of IMUs - 3, 6, and 9 Degrees of Freedom!

To summarise what we've covered in this guide:

  • Degrees of Freedom describes the different ways that an object can move in 3D space - translation, rotation, and orientation.
  • IMUs are usually made from a combination of three different sensors - accelerometers, gyros, and magnetometers.
  • 3 DoF IMUs, typically accelerometers, are the cheapest but the least accurate.
  • 6 DoF IMUs usually don't cost all that much more than 3 DoF IMUs, but can be used with sensor fusion to give two axes of orientation.
  • 9 DoF IMUs are the most accurate of the bunch, and can be used with sensor fusion to give three axes of orientation, but are also the most pricey.
  • Full 9 DoF sensor fusion can be achieved by combining a 6 DoF IMU with a Magnetometer module, usually at a lower cost, but also with a lower accuracy.

We're looking forward to hearing what you build using IMUs over in the forums, and if you have any questions or need some help, start the conversation below. We're full-time makers and happy to help.

Happy making!


Bonus Project Idea

Congratulations! You've just read through a significant amount of information and theory, but hopefully, you've learned a thing or two along the way.

As a small reward, here's the code for the self-balancing robot arm that is shown in this guide's accompanying video.

The robot arm is built using the 3DOF Robot Arm Kit, with the claw removed and a dish attached to the claw's servo. On top of the dish sits a BNO055 9 DoF IMU.

The servos are driven with a PiicoDev Servo Driver, and it's all controlled by a Raspberry Pi Pico. The different components are connected together with a PiicoDev Expansion Board for Pico, a PiicoDev Cable, and some jumper wire.

The micropython libraries needed are:

Note the code only uses basic stabilisation, very sudden movements of the arm will send it into an unstable state where it will flail about wildly - run at your own risk, and be ready to disconnect the power to the servos!

"""
Micropython code for a Self Balancing Robot Arm

Requires:
PiicoDev_Unified: https://github.com/CoreElectronics/CE-PiicoDev-PyPI/blob/main/src/PiicoDev_Unified.py
PiicoDev_Servo: https://github.com/CoreElectronics/CE-PiicoDev-PyPI/blob/main/src/PiicoDev_Servo.py
micropython-bno055: https://github.com/micropython-IMU/micropython-bno055

23/05/23 - Jacob Morris

"""

from PiicoDev_Servo import PiicoDev_Servo, PiicoDev_Servo_Driver
from machine import Pin, I2C
from bno055 import *
import time


# Initialise the Servo Driver Module
controller = PiicoDev_Servo_Driver()

# Each of the three joints/servos of the robot arm.
joint_1 = PiicoDev_Servo(controller, 1)  # Shoulder
joint_2 = PiicoDev_Servo(controller, 2)  # Elbow
joint_3 = PiicoDev_Servo(controller, 3)  # Claw

# Moving average buffers for each axis - to help smooth out noise
buffer_size = 3
x_buffer = []
y_buffer = []
z_buffer = []

# Set all joints to their midpoint before starting
joint_1.angle = 90
joint_2.angle = 90
joint_3.angle = 90

time.sleep(0.5)

# Initialize the BNO055 IMU
i2c = I2C(1, sda=Pin(2), scl=Pin(3), freq=400000) 
time.sleep(0.5)
imu = BNO055(i2c)


enable_servos = True
servo_delay_ms = 80  # Time between actioning the next servo positions
sample_rate_ms = 20  # Time between IMU samples

last_ms = time.ticks_ms()
calibrated = False

initial_heading = 0

while True:
    # The IMU needs to be calibrated first
    # First leave the arm dead still until the gyro is calibrated
    # Next rotate the arm left/right, back/forwards, around, until the mag is calibrated
    # Don't move too aggresively as once calibration is started the arm will immediately try to stabilise itself
    if not calibrated:
        cal_status = imu.cal_status()
        calibrated = cal_status[1] == 3 and cal_status[3] == 3
        print(cal_status[0], cal_status[1], cal_status[2], cal_status[3])
        time.sleep_ms(100)
        continue

    vals = imu.euler()
    
    x = vals[1]
    y = vals[2]
    z = vals[0]
    
    # Set the origin for the mag as wherever we were pointing when calibration finished
    if initial_heading == 0:
        initial_heading = z
        
    # Offset heading to the start point
    z = z - initial_heading
    
    # Avoid bouncing between 0 and 360
    if z > 180:
        z = z - 360
    
    # Update the moving average buffers
    x_buffer.append(x)
    y_buffer.append(y)
    z_buffer.append(z)
    if len(x_buffer) < buffer_size:
        continue
    
    x_buffer.pop(0)
    y_buffer.pop(0)
    z_buffer.pop(0)
    
    x_avg = sum(x_buffer) / len(x_buffer)
    y_avg = sum(y_buffer) / len(y_buffer)
    z_avg = sum(z_buffer) / len(z_buffer)
    
    
    # Try to get back to 0 on all axes, by positioning the servos at the inverse of the current measured orientation
    x_current = joint_2.angle
    x_target = x_current - x_avg / 2
    
    y_current = joint_1.angle
    y_target = y_current + y_avg / 2
    
    z_current = joint_3.angle
    z_target = z_current + z_avg / 2
    
    print(x, y, z, x_target, y_target, z_target)
    
    current_ms = time.ticks_ms()
    diff_ms = current_ms - last_ms

    # Move the servos to their desired angles
    if diff_ms > servo_delay_ms and enable_servos:
        last_ms = time.ticks_ms()
        
        if x_target >= 0 and x_target <= 180:  # Avoid pushing the servo past it's physical bounds
            joint_2.angle = x_target
        
        if y_target >= 0 and y_target <= 180:  # Avoid pushing the servo past it's physical bounds
            joint_1.angle = y_target
            
        if z_target >= 0 and z_target <= 180:  # Avoid pushing the servo past it's physical bounds
            joint_3.angle = z_target
    
    time.sleep_ms(sample_rate_ms)

Have a question? Ask the Author of this guide today!

Please enter minimum 20 characters

Your comment will be posted (automatically) on our Support Forum which is publicly accessible. Don't enter private information, such as your phone number.

Expect a quick reply during business hours, many of us check-in over the weekend as well.

Comments


Loading...
Feedback

Please continue if you would like to leave feedback for any of these topics:

  • Website features/issues
  • Content errors/improvements
  • Missing products/categories
  • Product assignments to categories
  • Search results relevance

For all other inquiries (orders status, stock levels, etc), please contact our support team for quick assistance.

Note: click continue and a draft email will be opened to edit. If you don't have an email client on your device, then send a message via the chat icon on the bottom left of our website.

Makers love reviews as much as you do, please follow this link to review the products you have purchased.