InvensenseImu drives the MPU-6500 and MPU-9250 over I2C or SPI
Arduino and CMake library for communicating with the InvenSense MPU-6500, MPU-9250 and MPU-9255 nine-axis IMUs.
At a glance
- What is it?
- InvensenseImu is a C++ library for the InvenSense MPU-6500, MPU-9250 and MPU-9255 nine-axis IMUs, usable from Arduino or from a CMake build, with register level access, sensor specific classes, data ready and wake on motion examples, and a Teensy oriented build. It is MIT licensed and lives in the bfs namespace.
- Who is it for?
- InvensenseImu suits a robotics or drone project that has to read an MPU-6500 or MPU-9250 over I2C or SPI and wants a tested register level driver instead of a hand written one, since the library covers both buses, both chip families and the data ready and wake on motion paths, and it builds both from Arduino and from CMake.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 60 days ago.
- What is it written in?
- Mainly C++, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the chips are, and what the library wraps
InvensenseImu is a library for communicating with the InvenSense MPU-6500 and the InvenSense MPU-9250 and MPU-9255 Inertial Measurement Units, and it is compatible with the Arduino and CMake build systems.
The hardware description in the README is worth reading because the sensor families are not all the same thing. The InvenSense MPU-6500 is a three-axis gyroscope and three-axis accelerometer. The InvenSense MPU-9250 is a System in Package that combines two chips, the MPU-6500 gyroscope and accelerometer, and the AK8963 three-axis magnetometer. That distinction drives the class structure in the library, since the nine-axis parts need the magnetometer handled separately.
The bus options are the same across the family. The MPU-6500 and MPU-9250 support I2C, up to 400 kHz, and SPI communication, up to 1 MHz for register setup and 20 MHz for data reading. The split between the two SPI rates is a hardware characteristic worth knowing, because a driver that treats SPI as one speed will be either too slow for reading data or too fast for the setup phase, and the library passes the clock speed explicitly into the register methods.
The selectable full scale ranges are laid out in a table. The gyroscope offers plus or minus 250, 500, 1000 and 2000 degrees per second. The accelerometer offers plus or minus 2, 4, 8 and 16 g. The magnetometer, for the MPU-9250 only, offers plus or minus 4800 uT.
The chips sample the gyros, accelerometers and magnetometers with 16 bit analog to digital converters, and the README also notes programmable digital filters, a precision clock and an embedded temperature sensor.
The primary language is C++, the licence is MIT, and the last push to the repository was on 2026-08-24.
The two class layers
The library has two levels of API, and the README is clear about which one most people want.
The InvensenseImu class provides methods for reading and writing to registers on these sensors. It's expected that this should work with at least the MPU-6000, MPU-6050, MPU-6500, MPU-9150 and MPU-9250, although it may work for other sensors as well. Most users will likely prefer the sensor specific classes, below, however, this class may enable people to reach further into the device and use it as a starting point for their own sensor drivers.
That is a well-drawn distinction. The general class is the register layer, and its usefulness depends on the parts sharing a register map, which is exactly why MPU-6000 and MPU-6050 are listed alongside the newer parts. The sensor specific classes are the ones that know how to configure a particular device and interpret its data.
The register API itself is small and symmetric. WriteRegister takes a register address, the data and, for SPI, the clock speed, and there is an overload without the clock for I2C. ReadRegisters takes a register address, a count, the SPI clock where relevant, and a pointer to store the data, again with an I2C overload.
Constructors come in two forms. The default constructor requires calling Config to set up the I2C or SPI bus and either the I2C address or the SPI chip select pin. There are also constructors that take the bus and address, or the bus and chip select, directly. For SPI, any pin capable of digital I/O can be used as a chip select pin.
Begin initializes communication with the sensor, and the README makes a point about what it does not do: the communication bus is not initialized within this library and must be initialized separately, which enhances compatibility with other sensors that may be on the same bus. That is a deliberate design choice rather than an omission, since a driver that called Wire.begin() behind your back would fight with the rest of your program.
The sensor specific class and the address choice
The Mpu9250 class works with the MPU-9250 and MPU-9255 IMUs, and its constructor shows how the address handling works.
Mpu9250 mpu9250(&Wire, bfs::Mpu9250::I2C_ADDR_PRIM);The constructor takes the I2C bus object and an address. The address will be I2C_ADDR_PRIM, which is 0x68, if the AD0 pin is grounded and I2C_ADDR_SEC, which is 0x69, if the AD0 pin is pulled high.
The naming of those constants is worth pausing on, because it is a common source of confusion with these parts. The same physical sensor is at a different I2C address depending on a hardware strap, and on a bus with several IMUs you use the strap to give each one its own address. Naming the constants after the pin state rather than after the numeric value, which is what I2C_ADDR_PRIM and I2C_ADDR_SEC do, keeps that decision visible in the code rather than leaving a bare 0x68 that gives no clue which strap setting was intended.
The example code also shows the namespace convention, since the class is referenced as bfs::Mpu9250. The README states that the library is within the namespace bfs, which stands for Bolder Flight Systems, and that namespace is what keeps the class names from colliding with other sensor libraries in a project that includes more than one.
The topics list names the areas the library serves, including drone, drones, robotics, sensor, sensors, imu, imu-driver, imu-sensor, fifo and wake-on-motion, which is a good indication of what the codebase covers beyond the register layer.
Building it with CMake and the MCU define
The CMake path is the more involved of the two, and the README gives the exact commands.
cmake .. -DMCU=MK66FX1M0
makeThe build produces the library and example executables named i2c_example, spi_example, drdy_spi_example and wom_example, where the last is for the MPU-9250 only. The example source files are at examples/cmake.
The define is not optional decoration. The README notes that the cmake command includes a define specifying the microcontroller the code is being compiled for, and that this is required to correctly configure the code, CPU frequency and compile and linker options. The available MCUs are listed, and they are all NXP parts: MK20DX128, MK20DX256, MK64FX512, MK66FX1M0, MKL26Z64, and the three i.MX RT1062 variants IMXRT1062_T40, IMXRT1062_T41 and IMXRT1062_MMOD.
These are known to work with the same packages used in Teensy products, and the README adds that switching packages is known to work well, as long as it's only a package change.
The four examples map onto the four ways you actually talk to these chips. i2c_example and spi_example cover the two transports, drdy_spi_example covers the data ready interrupt, and wom_example covers the wake on motion interrupt. That last pair is what distinguishes this library from a bare register reader, since both interrupts are how a battery powered or low latency system avoids polling.
Each target also has a *_hex* variant for creating the hex file to upload to the microcontroller, and an *_upload* variant that uses the Teensy CLI Uploader to flash the Teensy. The README points to the build-tools repository for instructions on setting up the build environment.
The Arduino path and the examples
The Arduino route is the short one. Use the Arduino Library Manager to install this library, or clone it into your Arduino/libraries folder.
The header you include depends on the part you are using. For the MPU-6500 it is:
#include "mpu6500.h"and for the MPU-9250 it is:
#include "mpu9250.h"The same two includes apply to the CMake build, since the include path is the same, which is a small sign of a library that was designed to move between the two build systems rather than having a separate wrapper for each.
The example Arduino executables are at examples/arduino/, and the README says that Teensy 3.x, 4.x and LC devices are used for testing under Arduino and that the library should be compatible with other Arduino devices. That is a claim about the test hardware rather than a guarantee, but the wording is careful, saying it should be compatible rather than that it is.
The repository root gives a good picture of an Arduino library done properly. There is a library.properties, which is what the Arduino Library Manager reads, and a keywords.txt, which is what drives syntax highlighting in the Arduino IDE. Alongside those are a CMakeLists.txt for the CMake path, a CHANGELOG.md, a CONTRIBUTING.md and a LICENSE.md, plus a.gitlab-ci.yml, which suggests the continuous integration runs on GitLab.
The docs/ directory at the root is worth a look before you write code, since the README is a summary rather than a full reference and the class documentation for the sensor specific classes continues past the point where the README stops.
Where InvensenseImu fits, and where it stops
The comparison worth making is with the vendor's own sensor libraries and with the register access that a general purpose embedded framework gives you.
Against the InvenSense reference code, the difference is that this library is a thin, maintained C++ port rather than a reference implementation shipped with a board support package. The register access is the same, so the two are interchangeable at that level, but this one carries the sensor specific classes, the interrupt examples and the CMake build with the MCU define handling that most hobby projects end up writing themselves.
Against a general framework such as an embedded HAL or an RTOS sensor abstraction, the difference is scope. A framework gives you a uniform interface over many sensors and handles the bus arbitration and the driver abstraction; this library gives you one sensor family done properly with no dependencies. For a project with one or two IMUs on a Teensy, the framework is overhead.
The limits are worth stating plainly, because the library is a driver and not more than a driver. It reads and writes registers and provides classes for configuring and reading the sensors, but there is no sensor fusion in it, no calibration, and no orientation estimation. If you want roll and pitch in degrees rather than raw accelerometer counts, that is a filter you write or a different library you add. The magnetometer on the nine-axis parts is a separate chip with its own characteristics, and the README does not describe calibration handling for it.
The other limits are about scope of support. The general InvensenseImu class is expected to work with the MPU-6000, MPU-6050, MPU-6500, MPU-9150 and MPU-9250, and may work with others, so anything outside that list is a matter of your own testing. The CMake build names specific NXP microcontrollers, and while other packages are said to work if it is only a package change, the CPU frequency and compile options are configured from that define. And the repository has no GitHub releases, so there is no tagged version to pin and the CHANGELOG is the version record.
For the specific case of a drone or robot that reads an MPU-6500 or MPU-9250 and needs the data ready or wake on motion paths, this is a well-scoped, MIT licensed library with the register layer exposed and the Arduino and CMake routes both documented.
Editorial conclusion
InvensenseImu suits a robotics or drone project that has to read an MPU-6500 or MPU-9250 over I2C or SPI and wants a tested register level driver instead of a hand written one, since the library covers both buses, both chip families and the data ready and wake on motion paths, and it builds both from Arduino and from CMake. It is the wrong tool if you need magnetometer calibration or sensor fusion, because this library reads and writes registers and stops there, and it is the wrong tool if you are on hardware outside the listed NXP and Teensy targets without checking the MCU define list. Before adopting it, read the class reference for the sensor you plan to use, since the README says the sensor specific classes are what most users will prefer over the general InvensenseImu class.
Frequently asked questions
Which IMUs does the InvensenseImu library support?
It communicates with the InvenSense MPU-6500, MPU-9250 and MPU-9255. The general InvensenseImu class is expected to work with at least the MPU-6000, MPU-6050, MPU-6500, MPU-9150 and MPU-9250, and may work with other sensors as well.
How do I install InvensenseImu for Arduino?
Use the Arduino Library Manager to install the library, or clone it into your Arduino/libraries folder. Include mpu6500.h for the MPU-6500 or mpu9250.h for the MPU-9250. Example Arduino executables are at examples/arduino/ and the library is tested on Teensy 3.x, 4.x and LC devices.
How do I build InvensenseImu with CMake?
Create a build directory and from within it run cmake .. -DMCU=MK66FX1M0 followed by make. The MCU define is required to correctly configure the code, CPU frequency and compile and linker options, and the supported list includes MK20DX128, MK20DX256, MK64FX512, MK66FX1M0, MKL26Z64 and three i.MX RT1062 variants.
Which communication buses does the library support?
Both I2C, up to 400 kHz, and SPI, up to 1 MHz for register setup and 20 MHz for data reading. The InvensenseImu class has Config methods and constructors for each, and WriteRegister and ReadRegisters have I2C overloads that omit the SPI clock argument.
What is the difference between I2C_ADDR_PRIM and I2C_ADDR_SEC?
The address depends on the AD0 pin. The address will be I2C_ADDR_PRIM, 0x68, if the AD0 pin is grounded and I2C_ADDR_SEC, 0x69, if the AD0 pin is pulled high, so the constants let you name the strap state rather than a bare hexadecimal address.
Does InvensenseImu do sensor fusion or calibration?
No. The library provides register read and write methods and sensor specific classes for configuring and reading the parts. The README does not describe fusion, orientation estimation or magnetometer calibration, so that work sits outside the library.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/bolderflight-invensense-imu)Was this useful?