imu_tools: Madgwick and complementary filters for ROS 1 and ROS 2
ROS tools for IMU devices
At a glance
- What is it?
- The CCNYRoboticsLab imu_tools repository packages two orientation filters and an rviz plugin into the ROS distribution channels. The filters differ in approach and in licence, and neither of them produces a state estimate on its own.
- Who is it for?
- imu_tools fits a ROS developer who has a generic IMU and needs an orientation quaternion on a topic, and who wants the filter available from the distribution repository rather than vendored into a workspace.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 36 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 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Three packages: two orientation filters and an rviz plugin
The repository is called IMU tools for ROS, and it contains three packages that can be used together or separately.
`imu_filter_madgwick` is a filter which fuses angular velocities, accelerations and, optionally, magnetic readings from a generic IMU device into an orientation. It is based on the work of the x-io open source IMU and AHRS algorithms page.
`imu_complementary_filter` is a filter which fuses the same three inputs into an orientation quaternion using a novel approach based on a complementary fusion, and it cites a paper from the MDPI Sensors journal.
`rviz_imu_plugin` is a plugin for rviz which displays `sensor_msgs::Imu` messages. It is the visual half of the set, and the only one that touches nothing but a message type.
That division is the important part for anyone choosing between them. Both filters take raw inertial data and give back an orientation; the plugin shows whatever is on a topic. The choice between the two filters is a choice of algorithm and of licence, not of function.
The repository also points at the documentation it relies on: all nodes, topics and parameters are documented on the project wiki page rather than in the README. That is a deliberate division for a ROS package, where the wiki is the traditional place for interface documentation, but it does mean a reader of the README alone will not find the topic names or the parameter names.
Madgwick and complementary fusion are two answers to the same question
The two filters exist because fusing gyroscope, accelerometer and magnetometer data into a single orientation is not a solved problem, and there is more than one reasonable way to do it.
The Madgwick filter is described as based on the work published as open source IMU and AHRS algorithms, and it is the filter that is licensed as GPL, following the original implementation. The complementary filter is described as using a novel approach based on a complementary fusion, and it is BSD licensed.
Both take the same three inputs, angular velocities, accelerations and optional magnetic readings, and both produce an orientation, with the complementary filter documented as producing an orientation quaternion. Both are therefore drop-in candidates for the same ROS pipeline: subscribe to raw IMU data, publish a filtered orientation, and let something downstream consume it.
What the documentation does not offer is a comparison. There is no accuracy table, no benchmark and no statement about which filter is better under which conditions, so a team choosing between them has to decide from the underlying references and from its own data, and the two licence terms may decide it for them before the algorithm does.
Neither filter does state estimation. The README is explicit about what comes next: once you have a filtered orientation from `imu_filter_madgwick` or `imu_complementary_filter`, the common next step is fusing it with wheel odometry and optionally GPS to produce a full `odom` to `base_link` state estimate. That step lives in other packages, and the two it names are the subject of a later section.
Installing from apt, or cloning the branch for your distribution
This repository has been released into all current ROS 1 and ROS 2 distributions, which makes installation a single command on a machine that already has ROS:
sudo apt-get install ros-<YOUR_ROSDISTO>-imu-toolsYou replace the placeholder with your distribution name. This is the shortest path and the one to use unless you intend to modify the filters.
Building from source under ROS 1 means creating a catkin workspace and sourcing its `devel/setup.bash` file, making sure git is installed, and cloning the repository with the branch that matches your distribution. The README notes the example branches `melodic` and `noetic`:
sudo apt-get install gitgit clone -b <YOUR_ROSDISTO> https://github.com/CCNYRoboticsLab/imu_tools.gitThe dependencies are then resolved with rosdep:
rosdep install imu_toolsAnd the workspace is compiled with catkin:
cd ~/catkin_ws
catkin_makeThe ROS 2 path is the same clone with a different workspace convention. The README points at the ROS 2 documentation for creating a workspace and says to clone the proper branch of this repository instead of the sample repo, using the same command.
Two details in the repository make the distribution handling concrete. The default branch is `rolling`, which is the development branch of ROS 2, and the root carries `Dockerfile-foxy` and `Dockerfile-galactic`, so older distributions can be built in containers.
The rviz plugin is the piece you will use to check the output
`rviz_imu_plugin` displays `sensor_msgs::Imu` messages in rviz. That is the whole of its stated job, and it is worth separating from the filters, because the plugin is what turns a topic into something a human can look at while the filters are what produce the topic.
The practical sequence is the obvious one: run a filter node against a live IMU, then open rviz with the plugin loaded and watch the orientation change as the device moves. The plugin consumes the standard message type, so it does not care whether the orientation on the topic came from `imu_filter_madgwick`, from `imu_complementary_filter` or from some other node in your own graph.
What you need to know to do that is on the project wiki page, which the README names as the place where all nodes, topics and parameters are documented. The parameters matter here, because both filters take the same class of inputs and expose the kind of settings you would expect to tune, and the plugin needs the topic name and the frame you want to display. None of those names appear in the README, so the wiki page is a required step rather than an optional one.
The repository also has a `pyproject.toml` that configures black for the Python parts, with a line length of 120, a target version of `py38` and string normalisation skipped, and a `.clang-format` file for the C++ side. Both packages are therefore formatted by machine, which is what makes the pre-commit check meaningful.
Licences differ per package, and that decides some adoptions
The repository does not have a single licence, and the README lists them per package.
`imu_filter_madgwick` is currently licensed as GPL, following the original implementation. `imu_complementary_filter` is BSD. `rviz_imu_plugin` is BSD. The root of the repository carries the three licence files to match, `LICENSE`, `LICENSE.bsd` and `LICENSE.gplv3`, and GitHub itself cannot classify the repository as a single standard licence because of the mixture.
That is a genuine constraint rather than a formality. A GPL component linked into a larger robot stack carries the obligations that come with it, and teams that ship closed source binaries are the ones who have to think about it. The complementary filter and the rviz plugin are BSD, which is why a project that wants a permissive licence has a choice to make inside this repository rather than a single answer.
This is not legal advice, and the practical step is to read the three files in the repository root, because the README only names the licences and does not describe their terms. What matters for an adopter is that the choice between the two filters is entangled with the licence choice, since the BSD filter and the GPL filter both fuse the same inputs and neither of them is described as the more accurate one.
Filtering is not state estimation: robot_localization and FusionCore
The README closes the feedback loop by pointing at the packages that consume a filtered orientation, and it does so with a level of detail that is unusual in a ROS README.
The goal is a full `odom` to `base_link` state estimate, produced by fusing the filtered IMU orientation with wheel odometry and, optionally, GPS. Two ROS 2 packages are named.
`robot_localization` is described as a well-established EKF or UKF state estimator, widely used across the ROS ecosystem. It is the default answer for a team that wants a standard filter on a standard set of topics.
`FusionCore` is described as a UKF with online gyro bias estimation, where yaw drift compounds more slowly over long runs, with native GPS fusion for outdoor robots, and with a numerically stable filter that handles aggressive maneuvers without diverging. It is also available on apt for Jazzy and Humble as `ros-jazzy-fusioncore`.
Both take a filtered IMU topic as input, which is the point. The division of labour is that imu_tools produces the orientation and something else produces the state estimate, and the two named packages make different assumptions about the environment, one being a general estimator and the other being built around the problems that outdoor robots actually show, drifting yaw and aggressive motion.
The gyroscope bias point is the one to read twice. A filter that estimates the bias online is addressing a failure that a purely kinematic filter cannot, and the imu_tools filters are described only as producing orientation from the incoming data, with no mention of bias estimation in either of them.
Rolling branch, no releases, and a pre-commit check in CI
The project is not archived and the last push was on 2026-09-17. There are no GitHub releases, which is normal for a ROS package, since the distribution channel is the binary package in the ROS repositories rather than a release on GitHub.
The default branch is `rolling`, and the source install instructions make the branch choice explicit, with `melodic` and `noetic` given as examples for ROS 1. A user who clones without the branch argument gets the development branch, which is the wrong default for a stable system and the right one for development.
The code quality setup is described in the README as a pre-commit check that runs in CI, and the same section explains how to run it locally. The installation uses apt:
sudo apt install pre-commitRunning it over the whole repository is `pre-commit run -a`, and installing the git hooks so it runs on every commit is `pre-commit install`. The configuration is `.pre-commit-config.yaml` at the root, next to `.clang-format` for the C++ code, the black settings in `pyproject.toml`, and `.dockerfilelintrc` for the Dockerfiles used by the foxy and galactic builds.
So the upgrade path for a consumer is the distribution channel, not a version bump: the package version that arrives with `apt` follows the ROS distribution you are on, and the repository itself has no release tags to track.
Editorial conclusion
imu_tools fits a ROS developer who has a generic IMU and needs an orientation quaternion on a topic, and who wants the filter available from the distribution repository rather than vendored into a workspace. It is the wrong tool for a robot that needs a full `odom` to `base_link` estimate, since neither filter in this repository fuses wheel odometry or GPS, and it is the wrong choice for a project that cannot accept a GPL component, because `imu_filter_madgwick` is licensed as GPL. Before adopting it, read the `LICENSE`, `LICENSE.bsd` and `LICENSE.gplv3` files in the root to see which terms apply to which package, clone the branch that matches your distribution rather than the default `rolling` branch, and confirm on the project wiki page which topics and parameters the nodes expect, since the README defers all of that detail to it.
Frequently asked questions
How do I install imu_tools for ROS?
The repository has been released into all current ROS 1 and ROS 2 distributions, so on a machine with ROS installed you can run `sudo apt-get install ros-<YOUR_ROSDISTO>-imu-tools`. Building from source means cloning the branch that matches your distribution, running `rosdep install imu_tools` and compiling the catkin workspace with `catkin_make`.
What is the difference between imu_filter_madgwick and imu_complementary_filter?
Both fuse angular velocities, accelerations and optionally magnetic readings into an orientation. The Madgwick filter is based on the open source IMU and AHRS algorithms work and is licensed as GPL, while the complementary filter uses a complementary fusion approach and produces an orientation quaternion under a BSD licence.
Which licence applies to each package in imu_tools?
imu_filter_madgwick is licensed as GPL following the original implementation, and both imu_complementary_filter and rviz_imu_plugin are BSD. The repository root carries LICENSE, LICENSE.bsd and LICENSE.gplv3 for the three cases.
How do I turn a filtered IMU orientation into a full odom to base_link estimate?
The README points at two ROS 2 packages that take a filtered IMU topic as input: robot_localization, an EKF or UKF state estimator, and FusionCore, a UKF with online gyro bias estimation and native GPS fusion that is available on apt for Jazzy and Humble as `ros-jazzy-fusioncore`.
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/ccnyroboticslab-imu-tools)Was this useful?