|
fusioncore repositorycompass_msgs fusioncore_core fusioncore_datasets fusioncore_gazebo fusioncore_ros |
ROS Distro
|
Repository Summary
| Description | |
| Checkout URI | https://github.com/manankharwar/fusioncore.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-04-29 |
| Dev Status | UNKNOWN |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Packages
| Name | Version |
|---|---|
| compass_msgs | 0.2.1 |
| fusioncore_core | 0.2.1 |
| fusioncore_datasets | 0.2.1 |
| fusioncore_gazebo | 0.2.1 |
| fusioncore_ros | 0.2.1 |
README
FusionCore
ROS 2 sensor fusion: IMU + wheel encoders + GPS fused via UKF at 100 Hz. 22-state filter with IMU bias estimation, adaptive noise covariance, and chi-squared outlier rejection on every sensor.
Why I built this
I needed sensor fusion for a mobile robot project and reached for robot_localization like everyone does. It works well. But I wanted a filter that estimated IMU gyro and accelerometer bias as part of the state vector, adapted its noise covariance from real sensor behavior rather than config values, and rejected outliers on every sensor update: not just GPS.
So I built FusionCore. It’s a 22-state UKF that fuses IMU, wheel encoders, and GPS natively. Gyro and accelerometer bias are estimated continuously as filter states. Noise covariance adapts from the innovation sequence automatically. Every sensor update: IMU, wheel odometry, GPS: goes through a chi-squared gate before it touches the filter. GPS is handled in ECEF directly, no coordinate projection.
Benchmark
FusionCore vs robot_localization on the NCLT dataset: same IMU + wheel odometry + GPS, no manual tuning. Six sequences:
RL-EKF run with odom0_twist_rejection_threshold: 4.03 and odom1_pose_rejection_threshold: 3.72 (chi²-equivalent to FusionCore’s thresholds at 99.9% confidence).
| Sequence | FC ATE RMSE | RL-EKF ATE RMSE | RL-UKF |
|---|---|---|---|
| 2012-01-08 | 5.6 m | 13.0 m | NaN divergence at t=31 s |
| 2012-02-04 | 9.7 m | 19.1 m | NaN divergence at t=22 s |
| 2012-03-31 | 4.2 m | 54.3 m | NaN divergence at t=18 s |
| 2012-08-20 | 7.5 m | 24.1 m | NaN divergence |
| 2012-11-04 | 28.6 m | 9.6 m | NaN divergence |
| 2013-02-23 | 4.1 m | 11.0 m | NaN divergence |
Install
Supports ROS 2 Jazzy (Ubuntu 24.04) and Humble (Ubuntu 22.04).
mkdir -p ~/ros2_ws/src && cd ~/ros2_ws/src
git clone https://github.com/manankharwar/fusioncore.git
cd ~/ros2_ws
source /opt/ros/jazzy/setup.bash # or /opt/ros/humble/setup.bash
rosdep install --from-paths src --ignore-src -r -y
colcon build && source install/setup.bash
Headless / Raspberry Pi:
touch ~/ros2_ws/src/fusioncore/fusioncore_gazebo/COLCON_IGNOREbefore building to skip the Gazebo package.
Quick start
ros2 launch fusioncore_ros fusioncore_nav2.launch.py \
fusioncore_config:=/path/to/your_robot.yaml
Documentation
manankharwar.github.io/fusioncore
- Getting Started
- Configuration reference
- Hardware configs
- Nav2 integration
- Migrating from robot_localization
- How it works
License
Apache 2.0.
Citation
@software{kharwar2026fusioncore,
author = {Kharwar, Manan},
title = {FusionCore: ROS 2 UKF Sensor Fusion},
year = {2026},
publisher = {Zenodo},
version = {0.2.0},
doi = {10.5281/zenodo.19834991},
url = {https://doi.org/10.5281/zenodo.19834991}
}
File truncated at 100 lines see the full file
CONTRIBUTING
Contributing to FusionCore
Thanks for your interest. Contributions are welcome: hardware configs, bug fixes, tests, and documentation all help.
The fastest way to contribute
The most impactful contributions right now are hardware configs. If you have FusionCore running on a robot, platform, or IMU that isn’t in the repo yet, open a PR adding a YAML under fusioncore_ros/config/. See the hardware config section below.
Before you start
- Check open issues: the bug may already be reported
- Check Discussions: the question may already be answered
- For anything bigger than a typo fix, open an issue or Discussion first so we can align before you write code
Development setup
# Clone and build
git clone https://github.com/manankharwar/fusioncore.git
cd fusioncore
source /opt/ros/jazzy/setup.sh # replace jazzy with humble on Ubuntu 22.04
rosdep install -r --from-paths . --ignore-src --rosdistro jazzy -y # replace jazzy with humble on Ubuntu 22.04
colcon build --packages-up-to compass_msgs fusioncore_core fusioncore_ros --cmake-args -DBUILD_TESTING=ON
# Run all tests before and after your change
colcon test --packages-select compass_msgs fusioncore_core fusioncore_ros
colcon test-result --verbose
All 49 tests must pass. CI will catch it if they don’t.
Hardware configs
A hardware config is a YAML file under fusioncore_ros/config/ named after the platform (e.g. clearpath_husky.yaml, ublox_f9p.yaml).
Copy fusioncore_ros/config/fusioncore.yaml as the starting point and adjust:
-
imu.gyro_noise/imu.accel_noise: pull from your IMU’s datasheet -
gnss.base_noise_xy: your GPS receiver’s CEP spec - Any topic remaps specific to your platform
Add a comment at the top with: platform name, IMU model, GPS receiver model, and whether it was field-tested or tuned from datasheet only. Field-tested configs get merged faster.
Pull request checklist
-
All 49 tests pass (
colcon test-result --verboseshows 0 failures) -
For new features: tests added in
fusioncore_core/tests/ - For hardware configs: YAML includes a comment with platform + sensor details
- Commit message describes why, not just what
Code style
C++17. Follow the style of the surrounding code: no reformatting unrelated lines. clang-format is not enforced but is appreciated.
Reporting bugs
Use the Bug Report issue template. Include the output of colcon test-result --verbose if tests are involved.
Questions
Open a Discussion rather than an issue. Issues are for bugs and tracked work; Discussions are for questions, configs, and ideas.
Response time: typically within 24 hours.
|
fusioncore repositorycompass_msgs fusioncore_core fusioncore_datasets fusioncore_gazebo fusioncore_ros |
ROS Distro
|
Repository Summary
| Description | |
| Checkout URI | https://github.com/manankharwar/fusioncore.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-04-29 |
| Dev Status | UNKNOWN |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Packages
| Name | Version |
|---|---|
| compass_msgs | 0.2.1 |
| fusioncore_core | 0.2.1 |
| fusioncore_datasets | 0.2.1 |
| fusioncore_gazebo | 0.2.1 |
| fusioncore_ros | 0.2.1 |
README
FusionCore
ROS 2 sensor fusion: IMU + wheel encoders + GPS fused via UKF at 100 Hz. 22-state filter with IMU bias estimation, adaptive noise covariance, and chi-squared outlier rejection on every sensor.
Why I built this
I needed sensor fusion for a mobile robot project and reached for robot_localization like everyone does. It works well. But I wanted a filter that estimated IMU gyro and accelerometer bias as part of the state vector, adapted its noise covariance from real sensor behavior rather than config values, and rejected outliers on every sensor update: not just GPS.
So I built FusionCore. It’s a 22-state UKF that fuses IMU, wheel encoders, and GPS natively. Gyro and accelerometer bias are estimated continuously as filter states. Noise covariance adapts from the innovation sequence automatically. Every sensor update: IMU, wheel odometry, GPS: goes through a chi-squared gate before it touches the filter. GPS is handled in ECEF directly, no coordinate projection.
Benchmark
FusionCore vs robot_localization on the NCLT dataset: same IMU + wheel odometry + GPS, no manual tuning. Six sequences:
RL-EKF run with odom0_twist_rejection_threshold: 4.03 and odom1_pose_rejection_threshold: 3.72 (chi²-equivalent to FusionCore’s thresholds at 99.9% confidence).
| Sequence | FC ATE RMSE | RL-EKF ATE RMSE | RL-UKF |
|---|---|---|---|
| 2012-01-08 | 5.6 m | 13.0 m | NaN divergence at t=31 s |
| 2012-02-04 | 9.7 m | 19.1 m | NaN divergence at t=22 s |
| 2012-03-31 | 4.2 m | 54.3 m | NaN divergence at t=18 s |
| 2012-08-20 | 7.5 m | 24.1 m | NaN divergence |
| 2012-11-04 | 28.6 m | 9.6 m | NaN divergence |
| 2013-02-23 | 4.1 m | 11.0 m | NaN divergence |
Install
Supports ROS 2 Jazzy (Ubuntu 24.04) and Humble (Ubuntu 22.04).
mkdir -p ~/ros2_ws/src && cd ~/ros2_ws/src
git clone https://github.com/manankharwar/fusioncore.git
cd ~/ros2_ws
source /opt/ros/jazzy/setup.bash # or /opt/ros/humble/setup.bash
rosdep install --from-paths src --ignore-src -r -y
colcon build && source install/setup.bash
Headless / Raspberry Pi:
touch ~/ros2_ws/src/fusioncore/fusioncore_gazebo/COLCON_IGNOREbefore building to skip the Gazebo package.
Quick start
ros2 launch fusioncore_ros fusioncore_nav2.launch.py \
fusioncore_config:=/path/to/your_robot.yaml
Documentation
manankharwar.github.io/fusioncore
- Getting Started
- Configuration reference
- Hardware configs
- Nav2 integration
- Migrating from robot_localization
- How it works
License
Apache 2.0.
Citation
@software{kharwar2026fusioncore,
author = {Kharwar, Manan},
title = {FusionCore: ROS 2 UKF Sensor Fusion},
year = {2026},
publisher = {Zenodo},
version = {0.2.0},
doi = {10.5281/zenodo.19834991},
url = {https://doi.org/10.5281/zenodo.19834991}
}
File truncated at 100 lines see the full file
CONTRIBUTING
Contributing to FusionCore
Thanks for your interest. Contributions are welcome: hardware configs, bug fixes, tests, and documentation all help.
The fastest way to contribute
The most impactful contributions right now are hardware configs. If you have FusionCore running on a robot, platform, or IMU that isn’t in the repo yet, open a PR adding a YAML under fusioncore_ros/config/. See the hardware config section below.
Before you start
- Check open issues: the bug may already be reported
- Check Discussions: the question may already be answered
- For anything bigger than a typo fix, open an issue or Discussion first so we can align before you write code
Development setup
# Clone and build
git clone https://github.com/manankharwar/fusioncore.git
cd fusioncore
source /opt/ros/jazzy/setup.sh # replace jazzy with humble on Ubuntu 22.04
rosdep install -r --from-paths . --ignore-src --rosdistro jazzy -y # replace jazzy with humble on Ubuntu 22.04
colcon build --packages-up-to compass_msgs fusioncore_core fusioncore_ros --cmake-args -DBUILD_TESTING=ON
# Run all tests before and after your change
colcon test --packages-select compass_msgs fusioncore_core fusioncore_ros
colcon test-result --verbose
All 49 tests must pass. CI will catch it if they don’t.
Hardware configs
A hardware config is a YAML file under fusioncore_ros/config/ named after the platform (e.g. clearpath_husky.yaml, ublox_f9p.yaml).
Copy fusioncore_ros/config/fusioncore.yaml as the starting point and adjust:
-
imu.gyro_noise/imu.accel_noise: pull from your IMU’s datasheet -
gnss.base_noise_xy: your GPS receiver’s CEP spec - Any topic remaps specific to your platform
Add a comment at the top with: platform name, IMU model, GPS receiver model, and whether it was field-tested or tuned from datasheet only. Field-tested configs get merged faster.
Pull request checklist
-
All 49 tests pass (
colcon test-result --verboseshows 0 failures) -
For new features: tests added in
fusioncore_core/tests/ - For hardware configs: YAML includes a comment with platform + sensor details
- Commit message describes why, not just what
Code style
C++17. Follow the style of the surrounding code: no reformatting unrelated lines. clang-format is not enforced but is appreciated.
Reporting bugs
Use the Bug Report issue template. Include the output of colcon test-result --verbose if tests are involved.
Questions
Open a Discussion rather than an issue. Issues are for bugs and tracked work; Discussions are for questions, configs, and ideas.
Response time: typically within 24 hours.
|
fusioncore repositorycompass_msgs fusioncore_core fusioncore_datasets fusioncore_gazebo fusioncore_ros |
ROS Distro
|
Repository Summary
| Description | |
| Checkout URI | https://github.com/manankharwar/fusioncore.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-04-29 |
| Dev Status | UNKNOWN |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Packages
| Name | Version |
|---|---|
| compass_msgs | 0.2.1 |
| fusioncore_core | 0.2.1 |
| fusioncore_datasets | 0.2.1 |
| fusioncore_gazebo | 0.2.1 |
| fusioncore_ros | 0.2.1 |
README
FusionCore
ROS 2 sensor fusion: IMU + wheel encoders + GPS fused via UKF at 100 Hz. 22-state filter with IMU bias estimation, adaptive noise covariance, and chi-squared outlier rejection on every sensor.
Why I built this
I needed sensor fusion for a mobile robot project and reached for robot_localization like everyone does. It works well. But I wanted a filter that estimated IMU gyro and accelerometer bias as part of the state vector, adapted its noise covariance from real sensor behavior rather than config values, and rejected outliers on every sensor update: not just GPS.
So I built FusionCore. It’s a 22-state UKF that fuses IMU, wheel encoders, and GPS natively. Gyro and accelerometer bias are estimated continuously as filter states. Noise covariance adapts from the innovation sequence automatically. Every sensor update: IMU, wheel odometry, GPS: goes through a chi-squared gate before it touches the filter. GPS is handled in ECEF directly, no coordinate projection.
Benchmark
FusionCore vs robot_localization on the NCLT dataset: same IMU + wheel odometry + GPS, no manual tuning. Six sequences:
RL-EKF run with odom0_twist_rejection_threshold: 4.03 and odom1_pose_rejection_threshold: 3.72 (chi²-equivalent to FusionCore’s thresholds at 99.9% confidence).
| Sequence | FC ATE RMSE | RL-EKF ATE RMSE | RL-UKF |
|---|---|---|---|
| 2012-01-08 | 5.6 m | 13.0 m | NaN divergence at t=31 s |
| 2012-02-04 | 9.7 m | 19.1 m | NaN divergence at t=22 s |
| 2012-03-31 | 4.2 m | 54.3 m | NaN divergence at t=18 s |
| 2012-08-20 | 7.5 m | 24.1 m | NaN divergence |
| 2012-11-04 | 28.6 m | 9.6 m | NaN divergence |
| 2013-02-23 | 4.1 m | 11.0 m | NaN divergence |
Install
Supports ROS 2 Jazzy (Ubuntu 24.04) and Humble (Ubuntu 22.04).
mkdir -p ~/ros2_ws/src && cd ~/ros2_ws/src
git clone https://github.com/manankharwar/fusioncore.git
cd ~/ros2_ws
source /opt/ros/jazzy/setup.bash # or /opt/ros/humble/setup.bash
rosdep install --from-paths src --ignore-src -r -y
colcon build && source install/setup.bash
Headless / Raspberry Pi:
touch ~/ros2_ws/src/fusioncore/fusioncore_gazebo/COLCON_IGNOREbefore building to skip the Gazebo package.
Quick start
ros2 launch fusioncore_ros fusioncore_nav2.launch.py \
fusioncore_config:=/path/to/your_robot.yaml
Documentation
manankharwar.github.io/fusioncore
- Getting Started
- Configuration reference
- Hardware configs
- Nav2 integration
- Migrating from robot_localization
- How it works
License
Apache 2.0.
Citation
@software{kharwar2026fusioncore,
author = {Kharwar, Manan},
title = {FusionCore: ROS 2 UKF Sensor Fusion},
year = {2026},
publisher = {Zenodo},
version = {0.2.0},
doi = {10.5281/zenodo.19834991},
url = {https://doi.org/10.5281/zenodo.19834991}
}
File truncated at 100 lines see the full file
CONTRIBUTING
Contributing to FusionCore
Thanks for your interest. Contributions are welcome: hardware configs, bug fixes, tests, and documentation all help.
The fastest way to contribute
The most impactful contributions right now are hardware configs. If you have FusionCore running on a robot, platform, or IMU that isn’t in the repo yet, open a PR adding a YAML under fusioncore_ros/config/. See the hardware config section below.
Before you start
- Check open issues: the bug may already be reported
- Check Discussions: the question may already be answered
- For anything bigger than a typo fix, open an issue or Discussion first so we can align before you write code
Development setup
# Clone and build
git clone https://github.com/manankharwar/fusioncore.git
cd fusioncore
source /opt/ros/jazzy/setup.sh # replace jazzy with humble on Ubuntu 22.04
rosdep install -r --from-paths . --ignore-src --rosdistro jazzy -y # replace jazzy with humble on Ubuntu 22.04
colcon build --packages-up-to compass_msgs fusioncore_core fusioncore_ros --cmake-args -DBUILD_TESTING=ON
# Run all tests before and after your change
colcon test --packages-select compass_msgs fusioncore_core fusioncore_ros
colcon test-result --verbose
All 49 tests must pass. CI will catch it if they don’t.
Hardware configs
A hardware config is a YAML file under fusioncore_ros/config/ named after the platform (e.g. clearpath_husky.yaml, ublox_f9p.yaml).
Copy fusioncore_ros/config/fusioncore.yaml as the starting point and adjust:
-
imu.gyro_noise/imu.accel_noise: pull from your IMU’s datasheet -
gnss.base_noise_xy: your GPS receiver’s CEP spec - Any topic remaps specific to your platform
Add a comment at the top with: platform name, IMU model, GPS receiver model, and whether it was field-tested or tuned from datasheet only. Field-tested configs get merged faster.
Pull request checklist
-
All 49 tests pass (
colcon test-result --verboseshows 0 failures) -
For new features: tests added in
fusioncore_core/tests/ - For hardware configs: YAML includes a comment with platform + sensor details
- Commit message describes why, not just what
Code style
C++17. Follow the style of the surrounding code: no reformatting unrelated lines. clang-format is not enforced but is appreciated.
Reporting bugs
Use the Bug Report issue template. Include the output of colcon test-result --verbose if tests are involved.
Questions
Open a Discussion rather than an issue. Issues are for bugs and tracked work; Discussions are for questions, configs, and ideas.
Response time: typically within 24 hours.
|
fusioncore repositorycompass_msgs fusioncore_core fusioncore_datasets fusioncore_gazebo fusioncore_ros |
ROS Distro
|
Repository Summary
| Description | |
| Checkout URI | https://github.com/manankharwar/fusioncore.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-04-29 |
| Dev Status | UNKNOWN |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Packages
| Name | Version |
|---|---|
| compass_msgs | 0.2.1 |
| fusioncore_core | 0.2.1 |
| fusioncore_datasets | 0.2.1 |
| fusioncore_gazebo | 0.2.1 |
| fusioncore_ros | 0.2.1 |
README
FusionCore
ROS 2 sensor fusion: IMU + wheel encoders + GPS fused via UKF at 100 Hz. 22-state filter with IMU bias estimation, adaptive noise covariance, and chi-squared outlier rejection on every sensor.
Why I built this
I needed sensor fusion for a mobile robot project and reached for robot_localization like everyone does. It works well. But I wanted a filter that estimated IMU gyro and accelerometer bias as part of the state vector, adapted its noise covariance from real sensor behavior rather than config values, and rejected outliers on every sensor update: not just GPS.
So I built FusionCore. It’s a 22-state UKF that fuses IMU, wheel encoders, and GPS natively. Gyro and accelerometer bias are estimated continuously as filter states. Noise covariance adapts from the innovation sequence automatically. Every sensor update: IMU, wheel odometry, GPS: goes through a chi-squared gate before it touches the filter. GPS is handled in ECEF directly, no coordinate projection.
Benchmark
FusionCore vs robot_localization on the NCLT dataset: same IMU + wheel odometry + GPS, no manual tuning. Six sequences:
RL-EKF run with odom0_twist_rejection_threshold: 4.03 and odom1_pose_rejection_threshold: 3.72 (chi²-equivalent to FusionCore’s thresholds at 99.9% confidence).
| Sequence | FC ATE RMSE | RL-EKF ATE RMSE | RL-UKF |
|---|---|---|---|
| 2012-01-08 | 5.6 m | 13.0 m | NaN divergence at t=31 s |
| 2012-02-04 | 9.7 m | 19.1 m | NaN divergence at t=22 s |
| 2012-03-31 | 4.2 m | 54.3 m | NaN divergence at t=18 s |
| 2012-08-20 | 7.5 m | 24.1 m | NaN divergence |
| 2012-11-04 | 28.6 m | 9.6 m | NaN divergence |
| 2013-02-23 | 4.1 m | 11.0 m | NaN divergence |
Install
Supports ROS 2 Jazzy (Ubuntu 24.04) and Humble (Ubuntu 22.04).
mkdir -p ~/ros2_ws/src && cd ~/ros2_ws/src
git clone https://github.com/manankharwar/fusioncore.git
cd ~/ros2_ws
source /opt/ros/jazzy/setup.bash # or /opt/ros/humble/setup.bash
rosdep install --from-paths src --ignore-src -r -y
colcon build && source install/setup.bash
Headless / Raspberry Pi:
touch ~/ros2_ws/src/fusioncore/fusioncore_gazebo/COLCON_IGNOREbefore building to skip the Gazebo package.
Quick start
ros2 launch fusioncore_ros fusioncore_nav2.launch.py \
fusioncore_config:=/path/to/your_robot.yaml
Documentation
manankharwar.github.io/fusioncore
- Getting Started
- Configuration reference
- Hardware configs
- Nav2 integration
- Migrating from robot_localization
- How it works
License
Apache 2.0.
Citation
@software{kharwar2026fusioncore,
author = {Kharwar, Manan},
title = {FusionCore: ROS 2 UKF Sensor Fusion},
year = {2026},
publisher = {Zenodo},
version = {0.2.0},
doi = {10.5281/zenodo.19834991},
url = {https://doi.org/10.5281/zenodo.19834991}
}
File truncated at 100 lines see the full file
CONTRIBUTING
Contributing to FusionCore
Thanks for your interest. Contributions are welcome: hardware configs, bug fixes, tests, and documentation all help.
The fastest way to contribute
The most impactful contributions right now are hardware configs. If you have FusionCore running on a robot, platform, or IMU that isn’t in the repo yet, open a PR adding a YAML under fusioncore_ros/config/. See the hardware config section below.
Before you start
- Check open issues: the bug may already be reported
- Check Discussions: the question may already be answered
- For anything bigger than a typo fix, open an issue or Discussion first so we can align before you write code
Development setup
# Clone and build
git clone https://github.com/manankharwar/fusioncore.git
cd fusioncore
source /opt/ros/jazzy/setup.sh # replace jazzy with humble on Ubuntu 22.04
rosdep install -r --from-paths . --ignore-src --rosdistro jazzy -y # replace jazzy with humble on Ubuntu 22.04
colcon build --packages-up-to compass_msgs fusioncore_core fusioncore_ros --cmake-args -DBUILD_TESTING=ON
# Run all tests before and after your change
colcon test --packages-select compass_msgs fusioncore_core fusioncore_ros
colcon test-result --verbose
All 49 tests must pass. CI will catch it if they don’t.
Hardware configs
A hardware config is a YAML file under fusioncore_ros/config/ named after the platform (e.g. clearpath_husky.yaml, ublox_f9p.yaml).
Copy fusioncore_ros/config/fusioncore.yaml as the starting point and adjust:
-
imu.gyro_noise/imu.accel_noise: pull from your IMU’s datasheet -
gnss.base_noise_xy: your GPS receiver’s CEP spec - Any topic remaps specific to your platform
Add a comment at the top with: platform name, IMU model, GPS receiver model, and whether it was field-tested or tuned from datasheet only. Field-tested configs get merged faster.
Pull request checklist
-
All 49 tests pass (
colcon test-result --verboseshows 0 failures) -
For new features: tests added in
fusioncore_core/tests/ - For hardware configs: YAML includes a comment with platform + sensor details
- Commit message describes why, not just what
Code style
C++17. Follow the style of the surrounding code: no reformatting unrelated lines. clang-format is not enforced but is appreciated.
Reporting bugs
Use the Bug Report issue template. Include the output of colcon test-result --verbose if tests are involved.
Questions
Open a Discussion rather than an issue. Issues are for bugs and tracked work; Discussions are for questions, configs, and ideas.
Response time: typically within 24 hours.
|
fusioncore repositorycompass_msgs fusioncore_core fusioncore_datasets fusioncore_gazebo fusioncore_ros |
ROS Distro
|
Repository Summary
| Description | |
| Checkout URI | https://github.com/manankharwar/fusioncore.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-04-29 |
| Dev Status | UNKNOWN |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Packages
| Name | Version |
|---|---|
| compass_msgs | 0.2.1 |
| fusioncore_core | 0.2.1 |
| fusioncore_datasets | 0.2.1 |
| fusioncore_gazebo | 0.2.1 |
| fusioncore_ros | 0.2.1 |
README
FusionCore
ROS 2 sensor fusion: IMU + wheel encoders + GPS fused via UKF at 100 Hz. 22-state filter with IMU bias estimation, adaptive noise covariance, and chi-squared outlier rejection on every sensor.
Why I built this
I needed sensor fusion for a mobile robot project and reached for robot_localization like everyone does. It works well. But I wanted a filter that estimated IMU gyro and accelerometer bias as part of the state vector, adapted its noise covariance from real sensor behavior rather than config values, and rejected outliers on every sensor update: not just GPS.
So I built FusionCore. It’s a 22-state UKF that fuses IMU, wheel encoders, and GPS natively. Gyro and accelerometer bias are estimated continuously as filter states. Noise covariance adapts from the innovation sequence automatically. Every sensor update: IMU, wheel odometry, GPS: goes through a chi-squared gate before it touches the filter. GPS is handled in ECEF directly, no coordinate projection.
Benchmark
FusionCore vs robot_localization on the NCLT dataset: same IMU + wheel odometry + GPS, no manual tuning. Six sequences:
RL-EKF run with odom0_twist_rejection_threshold: 4.03 and odom1_pose_rejection_threshold: 3.72 (chi²-equivalent to FusionCore’s thresholds at 99.9% confidence).
| Sequence | FC ATE RMSE | RL-EKF ATE RMSE | RL-UKF |
|---|---|---|---|
| 2012-01-08 | 5.6 m | 13.0 m | NaN divergence at t=31 s |
| 2012-02-04 | 9.7 m | 19.1 m | NaN divergence at t=22 s |
| 2012-03-31 | 4.2 m | 54.3 m | NaN divergence at t=18 s |
| 2012-08-20 | 7.5 m | 24.1 m | NaN divergence |
| 2012-11-04 | 28.6 m | 9.6 m | NaN divergence |
| 2013-02-23 | 4.1 m | 11.0 m | NaN divergence |
Install
Supports ROS 2 Jazzy (Ubuntu 24.04) and Humble (Ubuntu 22.04).
mkdir -p ~/ros2_ws/src && cd ~/ros2_ws/src
git clone https://github.com/manankharwar/fusioncore.git
cd ~/ros2_ws
source /opt/ros/jazzy/setup.bash # or /opt/ros/humble/setup.bash
rosdep install --from-paths src --ignore-src -r -y
colcon build && source install/setup.bash
Headless / Raspberry Pi:
touch ~/ros2_ws/src/fusioncore/fusioncore_gazebo/COLCON_IGNOREbefore building to skip the Gazebo package.
Quick start
ros2 launch fusioncore_ros fusioncore_nav2.launch.py \
fusioncore_config:=/path/to/your_robot.yaml
Documentation
manankharwar.github.io/fusioncore
- Getting Started
- Configuration reference
- Hardware configs
- Nav2 integration
- Migrating from robot_localization
- How it works
License
Apache 2.0.
Citation
@software{kharwar2026fusioncore,
author = {Kharwar, Manan},
title = {FusionCore: ROS 2 UKF Sensor Fusion},
year = {2026},
publisher = {Zenodo},
version = {0.2.0},
doi = {10.5281/zenodo.19834991},
url = {https://doi.org/10.5281/zenodo.19834991}
}
File truncated at 100 lines see the full file
CONTRIBUTING
Contributing to FusionCore
Thanks for your interest. Contributions are welcome: hardware configs, bug fixes, tests, and documentation all help.
The fastest way to contribute
The most impactful contributions right now are hardware configs. If you have FusionCore running on a robot, platform, or IMU that isn’t in the repo yet, open a PR adding a YAML under fusioncore_ros/config/. See the hardware config section below.
Before you start
- Check open issues: the bug may already be reported
- Check Discussions: the question may already be answered
- For anything bigger than a typo fix, open an issue or Discussion first so we can align before you write code
Development setup
# Clone and build
git clone https://github.com/manankharwar/fusioncore.git
cd fusioncore
source /opt/ros/jazzy/setup.sh # replace jazzy with humble on Ubuntu 22.04
rosdep install -r --from-paths . --ignore-src --rosdistro jazzy -y # replace jazzy with humble on Ubuntu 22.04
colcon build --packages-up-to compass_msgs fusioncore_core fusioncore_ros --cmake-args -DBUILD_TESTING=ON
# Run all tests before and after your change
colcon test --packages-select compass_msgs fusioncore_core fusioncore_ros
colcon test-result --verbose
All 49 tests must pass. CI will catch it if they don’t.
Hardware configs
A hardware config is a YAML file under fusioncore_ros/config/ named after the platform (e.g. clearpath_husky.yaml, ublox_f9p.yaml).
Copy fusioncore_ros/config/fusioncore.yaml as the starting point and adjust:
-
imu.gyro_noise/imu.accel_noise: pull from your IMU’s datasheet -
gnss.base_noise_xy: your GPS receiver’s CEP spec - Any topic remaps specific to your platform
Add a comment at the top with: platform name, IMU model, GPS receiver model, and whether it was field-tested or tuned from datasheet only. Field-tested configs get merged faster.
Pull request checklist
-
All 49 tests pass (
colcon test-result --verboseshows 0 failures) -
For new features: tests added in
fusioncore_core/tests/ - For hardware configs: YAML includes a comment with platform + sensor details
- Commit message describes why, not just what
Code style
C++17. Follow the style of the surrounding code: no reformatting unrelated lines. clang-format is not enforced but is appreciated.
Reporting bugs
Use the Bug Report issue template. Include the output of colcon test-result --verbose if tests are involved.
Questions
Open a Discussion rather than an issue. Issues are for bugs and tracked work; Discussions are for questions, configs, and ideas.
Response time: typically within 24 hours.
|
fusioncore repositorycompass_msgs fusioncore_core fusioncore_datasets fusioncore_gazebo fusioncore_ros |
ROS Distro
|
Repository Summary
| Description | |
| Checkout URI | https://github.com/manankharwar/fusioncore.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-04-29 |
| Dev Status | UNKNOWN |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Packages
| Name | Version |
|---|---|
| compass_msgs | 0.2.1 |
| fusioncore_core | 0.2.1 |
| fusioncore_datasets | 0.2.1 |
| fusioncore_gazebo | 0.2.1 |
| fusioncore_ros | 0.2.1 |
README
FusionCore
ROS 2 sensor fusion: IMU + wheel encoders + GPS fused via UKF at 100 Hz. 22-state filter with IMU bias estimation, adaptive noise covariance, and chi-squared outlier rejection on every sensor.
Why I built this
I needed sensor fusion for a mobile robot project and reached for robot_localization like everyone does. It works well. But I wanted a filter that estimated IMU gyro and accelerometer bias as part of the state vector, adapted its noise covariance from real sensor behavior rather than config values, and rejected outliers on every sensor update: not just GPS.
So I built FusionCore. It’s a 22-state UKF that fuses IMU, wheel encoders, and GPS natively. Gyro and accelerometer bias are estimated continuously as filter states. Noise covariance adapts from the innovation sequence automatically. Every sensor update: IMU, wheel odometry, GPS: goes through a chi-squared gate before it touches the filter. GPS is handled in ECEF directly, no coordinate projection.
Benchmark
FusionCore vs robot_localization on the NCLT dataset: same IMU + wheel odometry + GPS, no manual tuning. Six sequences:
RL-EKF run with odom0_twist_rejection_threshold: 4.03 and odom1_pose_rejection_threshold: 3.72 (chi²-equivalent to FusionCore’s thresholds at 99.9% confidence).
| Sequence | FC ATE RMSE | RL-EKF ATE RMSE | RL-UKF |
|---|---|---|---|
| 2012-01-08 | 5.6 m | 13.0 m | NaN divergence at t=31 s |
| 2012-02-04 | 9.7 m | 19.1 m | NaN divergence at t=22 s |
| 2012-03-31 | 4.2 m | 54.3 m | NaN divergence at t=18 s |
| 2012-08-20 | 7.5 m | 24.1 m | NaN divergence |
| 2012-11-04 | 28.6 m | 9.6 m | NaN divergence |
| 2013-02-23 | 4.1 m | 11.0 m | NaN divergence |
Install
Supports ROS 2 Jazzy (Ubuntu 24.04) and Humble (Ubuntu 22.04).
mkdir -p ~/ros2_ws/src && cd ~/ros2_ws/src
git clone https://github.com/manankharwar/fusioncore.git
cd ~/ros2_ws
source /opt/ros/jazzy/setup.bash # or /opt/ros/humble/setup.bash
rosdep install --from-paths src --ignore-src -r -y
colcon build && source install/setup.bash
Headless / Raspberry Pi:
touch ~/ros2_ws/src/fusioncore/fusioncore_gazebo/COLCON_IGNOREbefore building to skip the Gazebo package.
Quick start
ros2 launch fusioncore_ros fusioncore_nav2.launch.py \
fusioncore_config:=/path/to/your_robot.yaml
Documentation
manankharwar.github.io/fusioncore
- Getting Started
- Configuration reference
- Hardware configs
- Nav2 integration
- Migrating from robot_localization
- How it works
License
Apache 2.0.
Citation
@software{kharwar2026fusioncore,
author = {Kharwar, Manan},
title = {FusionCore: ROS 2 UKF Sensor Fusion},
year = {2026},
publisher = {Zenodo},
version = {0.2.0},
doi = {10.5281/zenodo.19834991},
url = {https://doi.org/10.5281/zenodo.19834991}
}
File truncated at 100 lines see the full file
CONTRIBUTING
Contributing to FusionCore
Thanks for your interest. Contributions are welcome: hardware configs, bug fixes, tests, and documentation all help.
The fastest way to contribute
The most impactful contributions right now are hardware configs. If you have FusionCore running on a robot, platform, or IMU that isn’t in the repo yet, open a PR adding a YAML under fusioncore_ros/config/. See the hardware config section below.
Before you start
- Check open issues: the bug may already be reported
- Check Discussions: the question may already be answered
- For anything bigger than a typo fix, open an issue or Discussion first so we can align before you write code
Development setup
# Clone and build
git clone https://github.com/manankharwar/fusioncore.git
cd fusioncore
source /opt/ros/jazzy/setup.sh # replace jazzy with humble on Ubuntu 22.04
rosdep install -r --from-paths . --ignore-src --rosdistro jazzy -y # replace jazzy with humble on Ubuntu 22.04
colcon build --packages-up-to compass_msgs fusioncore_core fusioncore_ros --cmake-args -DBUILD_TESTING=ON
# Run all tests before and after your change
colcon test --packages-select compass_msgs fusioncore_core fusioncore_ros
colcon test-result --verbose
All 49 tests must pass. CI will catch it if they don’t.
Hardware configs
A hardware config is a YAML file under fusioncore_ros/config/ named after the platform (e.g. clearpath_husky.yaml, ublox_f9p.yaml).
Copy fusioncore_ros/config/fusioncore.yaml as the starting point and adjust:
-
imu.gyro_noise/imu.accel_noise: pull from your IMU’s datasheet -
gnss.base_noise_xy: your GPS receiver’s CEP spec - Any topic remaps specific to your platform
Add a comment at the top with: platform name, IMU model, GPS receiver model, and whether it was field-tested or tuned from datasheet only. Field-tested configs get merged faster.
Pull request checklist
-
All 49 tests pass (
colcon test-result --verboseshows 0 failures) -
For new features: tests added in
fusioncore_core/tests/ - For hardware configs: YAML includes a comment with platform + sensor details
- Commit message describes why, not just what
Code style
C++17. Follow the style of the surrounding code: no reformatting unrelated lines. clang-format is not enforced but is appreciated.
Reporting bugs
Use the Bug Report issue template. Include the output of colcon test-result --verbose if tests are involved.
Questions
Open a Discussion rather than an issue. Issues are for bugs and tracked work; Discussions are for questions, configs, and ideas.
Response time: typically within 24 hours.
|
fusioncore repositorycompass_msgs fusioncore_core fusioncore_datasets fusioncore_gazebo fusioncore_ros |
ROS Distro
|
Repository Summary
| Description | |
| Checkout URI | https://github.com/manankharwar/fusioncore.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-04-29 |
| Dev Status | UNKNOWN |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Packages
| Name | Version |
|---|---|
| compass_msgs | 0.2.1 |
| fusioncore_core | 0.2.1 |
| fusioncore_datasets | 0.2.1 |
| fusioncore_gazebo | 0.2.1 |
| fusioncore_ros | 0.2.1 |
README
FusionCore
ROS 2 sensor fusion: IMU + wheel encoders + GPS fused via UKF at 100 Hz. 22-state filter with IMU bias estimation, adaptive noise covariance, and chi-squared outlier rejection on every sensor.
Why I built this
I needed sensor fusion for a mobile robot project and reached for robot_localization like everyone does. It works well. But I wanted a filter that estimated IMU gyro and accelerometer bias as part of the state vector, adapted its noise covariance from real sensor behavior rather than config values, and rejected outliers on every sensor update: not just GPS.
So I built FusionCore. It’s a 22-state UKF that fuses IMU, wheel encoders, and GPS natively. Gyro and accelerometer bias are estimated continuously as filter states. Noise covariance adapts from the innovation sequence automatically. Every sensor update: IMU, wheel odometry, GPS: goes through a chi-squared gate before it touches the filter. GPS is handled in ECEF directly, no coordinate projection.
Benchmark
FusionCore vs robot_localization on the NCLT dataset: same IMU + wheel odometry + GPS, no manual tuning. Six sequences:
RL-EKF run with odom0_twist_rejection_threshold: 4.03 and odom1_pose_rejection_threshold: 3.72 (chi²-equivalent to FusionCore’s thresholds at 99.9% confidence).
| Sequence | FC ATE RMSE | RL-EKF ATE RMSE | RL-UKF |
|---|---|---|---|
| 2012-01-08 | 5.6 m | 13.0 m | NaN divergence at t=31 s |
| 2012-02-04 | 9.7 m | 19.1 m | NaN divergence at t=22 s |
| 2012-03-31 | 4.2 m | 54.3 m | NaN divergence at t=18 s |
| 2012-08-20 | 7.5 m | 24.1 m | NaN divergence |
| 2012-11-04 | 28.6 m | 9.6 m | NaN divergence |
| 2013-02-23 | 4.1 m | 11.0 m | NaN divergence |
Install
Supports ROS 2 Jazzy (Ubuntu 24.04) and Humble (Ubuntu 22.04).
mkdir -p ~/ros2_ws/src && cd ~/ros2_ws/src
git clone https://github.com/manankharwar/fusioncore.git
cd ~/ros2_ws
source /opt/ros/jazzy/setup.bash # or /opt/ros/humble/setup.bash
rosdep install --from-paths src --ignore-src -r -y
colcon build && source install/setup.bash
Headless / Raspberry Pi:
touch ~/ros2_ws/src/fusioncore/fusioncore_gazebo/COLCON_IGNOREbefore building to skip the Gazebo package.
Quick start
ros2 launch fusioncore_ros fusioncore_nav2.launch.py \
fusioncore_config:=/path/to/your_robot.yaml
Documentation
manankharwar.github.io/fusioncore
- Getting Started
- Configuration reference
- Hardware configs
- Nav2 integration
- Migrating from robot_localization
- How it works
License
Apache 2.0.
Citation
@software{kharwar2026fusioncore,
author = {Kharwar, Manan},
title = {FusionCore: ROS 2 UKF Sensor Fusion},
year = {2026},
publisher = {Zenodo},
version = {0.2.0},
doi = {10.5281/zenodo.19834991},
url = {https://doi.org/10.5281/zenodo.19834991}
}
File truncated at 100 lines see the full file
CONTRIBUTING
Contributing to FusionCore
Thanks for your interest. Contributions are welcome: hardware configs, bug fixes, tests, and documentation all help.
The fastest way to contribute
The most impactful contributions right now are hardware configs. If you have FusionCore running on a robot, platform, or IMU that isn’t in the repo yet, open a PR adding a YAML under fusioncore_ros/config/. See the hardware config section below.
Before you start
- Check open issues: the bug may already be reported
- Check Discussions: the question may already be answered
- For anything bigger than a typo fix, open an issue or Discussion first so we can align before you write code
Development setup
# Clone and build
git clone https://github.com/manankharwar/fusioncore.git
cd fusioncore
source /opt/ros/jazzy/setup.sh # replace jazzy with humble on Ubuntu 22.04
rosdep install -r --from-paths . --ignore-src --rosdistro jazzy -y # replace jazzy with humble on Ubuntu 22.04
colcon build --packages-up-to compass_msgs fusioncore_core fusioncore_ros --cmake-args -DBUILD_TESTING=ON
# Run all tests before and after your change
colcon test --packages-select compass_msgs fusioncore_core fusioncore_ros
colcon test-result --verbose
All 49 tests must pass. CI will catch it if they don’t.
Hardware configs
A hardware config is a YAML file under fusioncore_ros/config/ named after the platform (e.g. clearpath_husky.yaml, ublox_f9p.yaml).
Copy fusioncore_ros/config/fusioncore.yaml as the starting point and adjust:
-
imu.gyro_noise/imu.accel_noise: pull from your IMU’s datasheet -
gnss.base_noise_xy: your GPS receiver’s CEP spec - Any topic remaps specific to your platform
Add a comment at the top with: platform name, IMU model, GPS receiver model, and whether it was field-tested or tuned from datasheet only. Field-tested configs get merged faster.
Pull request checklist
-
All 49 tests pass (
colcon test-result --verboseshows 0 failures) -
For new features: tests added in
fusioncore_core/tests/ - For hardware configs: YAML includes a comment with platform + sensor details
- Commit message describes why, not just what
Code style
C++17. Follow the style of the surrounding code: no reformatting unrelated lines. clang-format is not enforced but is appreciated.
Reporting bugs
Use the Bug Report issue template. Include the output of colcon test-result --verbose if tests are involved.
Questions
Open a Discussion rather than an issue. Issues are for bugs and tracked work; Discussions are for questions, configs, and ideas.
Response time: typically within 24 hours.
|
fusioncore repositorycompass_msgs fusioncore_core fusioncore_datasets fusioncore_gazebo fusioncore_ros |
ROS Distro
|
Repository Summary
| Description | |
| Checkout URI | https://github.com/manankharwar/fusioncore.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-04-29 |
| Dev Status | UNKNOWN |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Packages
| Name | Version |
|---|---|
| compass_msgs | 0.2.1 |
| fusioncore_core | 0.2.1 |
| fusioncore_datasets | 0.2.1 |
| fusioncore_gazebo | 0.2.1 |
| fusioncore_ros | 0.2.1 |
README
FusionCore
ROS 2 sensor fusion: IMU + wheel encoders + GPS fused via UKF at 100 Hz. 22-state filter with IMU bias estimation, adaptive noise covariance, and chi-squared outlier rejection on every sensor.
Why I built this
I needed sensor fusion for a mobile robot project and reached for robot_localization like everyone does. It works well. But I wanted a filter that estimated IMU gyro and accelerometer bias as part of the state vector, adapted its noise covariance from real sensor behavior rather than config values, and rejected outliers on every sensor update: not just GPS.
So I built FusionCore. It’s a 22-state UKF that fuses IMU, wheel encoders, and GPS natively. Gyro and accelerometer bias are estimated continuously as filter states. Noise covariance adapts from the innovation sequence automatically. Every sensor update: IMU, wheel odometry, GPS: goes through a chi-squared gate before it touches the filter. GPS is handled in ECEF directly, no coordinate projection.
Benchmark
FusionCore vs robot_localization on the NCLT dataset: same IMU + wheel odometry + GPS, no manual tuning. Six sequences:
RL-EKF run with odom0_twist_rejection_threshold: 4.03 and odom1_pose_rejection_threshold: 3.72 (chi²-equivalent to FusionCore’s thresholds at 99.9% confidence).
| Sequence | FC ATE RMSE | RL-EKF ATE RMSE | RL-UKF |
|---|---|---|---|
| 2012-01-08 | 5.6 m | 13.0 m | NaN divergence at t=31 s |
| 2012-02-04 | 9.7 m | 19.1 m | NaN divergence at t=22 s |
| 2012-03-31 | 4.2 m | 54.3 m | NaN divergence at t=18 s |
| 2012-08-20 | 7.5 m | 24.1 m | NaN divergence |
| 2012-11-04 | 28.6 m | 9.6 m | NaN divergence |
| 2013-02-23 | 4.1 m | 11.0 m | NaN divergence |
Install
Supports ROS 2 Jazzy (Ubuntu 24.04) and Humble (Ubuntu 22.04).
mkdir -p ~/ros2_ws/src && cd ~/ros2_ws/src
git clone https://github.com/manankharwar/fusioncore.git
cd ~/ros2_ws
source /opt/ros/jazzy/setup.bash # or /opt/ros/humble/setup.bash
rosdep install --from-paths src --ignore-src -r -y
colcon build && source install/setup.bash
Headless / Raspberry Pi:
touch ~/ros2_ws/src/fusioncore/fusioncore_gazebo/COLCON_IGNOREbefore building to skip the Gazebo package.
Quick start
ros2 launch fusioncore_ros fusioncore_nav2.launch.py \
fusioncore_config:=/path/to/your_robot.yaml
Documentation
manankharwar.github.io/fusioncore
- Getting Started
- Configuration reference
- Hardware configs
- Nav2 integration
- Migrating from robot_localization
- How it works
License
Apache 2.0.
Citation
@software{kharwar2026fusioncore,
author = {Kharwar, Manan},
title = {FusionCore: ROS 2 UKF Sensor Fusion},
year = {2026},
publisher = {Zenodo},
version = {0.2.0},
doi = {10.5281/zenodo.19834991},
url = {https://doi.org/10.5281/zenodo.19834991}
}
File truncated at 100 lines see the full file
CONTRIBUTING
Contributing to FusionCore
Thanks for your interest. Contributions are welcome: hardware configs, bug fixes, tests, and documentation all help.
The fastest way to contribute
The most impactful contributions right now are hardware configs. If you have FusionCore running on a robot, platform, or IMU that isn’t in the repo yet, open a PR adding a YAML under fusioncore_ros/config/. See the hardware config section below.
Before you start
- Check open issues: the bug may already be reported
- Check Discussions: the question may already be answered
- For anything bigger than a typo fix, open an issue or Discussion first so we can align before you write code
Development setup
# Clone and build
git clone https://github.com/manankharwar/fusioncore.git
cd fusioncore
source /opt/ros/jazzy/setup.sh # replace jazzy with humble on Ubuntu 22.04
rosdep install -r --from-paths . --ignore-src --rosdistro jazzy -y # replace jazzy with humble on Ubuntu 22.04
colcon build --packages-up-to compass_msgs fusioncore_core fusioncore_ros --cmake-args -DBUILD_TESTING=ON
# Run all tests before and after your change
colcon test --packages-select compass_msgs fusioncore_core fusioncore_ros
colcon test-result --verbose
All 49 tests must pass. CI will catch it if they don’t.
Hardware configs
A hardware config is a YAML file under fusioncore_ros/config/ named after the platform (e.g. clearpath_husky.yaml, ublox_f9p.yaml).
Copy fusioncore_ros/config/fusioncore.yaml as the starting point and adjust:
-
imu.gyro_noise/imu.accel_noise: pull from your IMU’s datasheet -
gnss.base_noise_xy: your GPS receiver’s CEP spec - Any topic remaps specific to your platform
Add a comment at the top with: platform name, IMU model, GPS receiver model, and whether it was field-tested or tuned from datasheet only. Field-tested configs get merged faster.
Pull request checklist
-
All 49 tests pass (
colcon test-result --verboseshows 0 failures) -
For new features: tests added in
fusioncore_core/tests/ - For hardware configs: YAML includes a comment with platform + sensor details
- Commit message describes why, not just what
Code style
C++17. Follow the style of the surrounding code: no reformatting unrelated lines. clang-format is not enforced but is appreciated.
Reporting bugs
Use the Bug Report issue template. Include the output of colcon test-result --verbose if tests are involved.
Questions
Open a Discussion rather than an issue. Issues are for bugs and tracked work; Discussions are for questions, configs, and ideas.
Response time: typically within 24 hours.
|
fusioncore repositorycompass_msgs fusioncore_core fusioncore_datasets fusioncore_gazebo fusioncore_ros |
ROS Distro
|
Repository Summary
| Description | |
| Checkout URI | https://github.com/manankharwar/fusioncore.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-04-29 |
| Dev Status | UNKNOWN |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Packages
| Name | Version |
|---|---|
| compass_msgs | 0.2.1 |
| fusioncore_core | 0.2.1 |
| fusioncore_datasets | 0.2.1 |
| fusioncore_gazebo | 0.2.1 |
| fusioncore_ros | 0.2.1 |
README
FusionCore
ROS 2 sensor fusion: IMU + wheel encoders + GPS fused via UKF at 100 Hz. 22-state filter with IMU bias estimation, adaptive noise covariance, and chi-squared outlier rejection on every sensor.
Why I built this
I needed sensor fusion for a mobile robot project and reached for robot_localization like everyone does. It works well. But I wanted a filter that estimated IMU gyro and accelerometer bias as part of the state vector, adapted its noise covariance from real sensor behavior rather than config values, and rejected outliers on every sensor update: not just GPS.
So I built FusionCore. It’s a 22-state UKF that fuses IMU, wheel encoders, and GPS natively. Gyro and accelerometer bias are estimated continuously as filter states. Noise covariance adapts from the innovation sequence automatically. Every sensor update: IMU, wheel odometry, GPS: goes through a chi-squared gate before it touches the filter. GPS is handled in ECEF directly, no coordinate projection.
Benchmark
FusionCore vs robot_localization on the NCLT dataset: same IMU + wheel odometry + GPS, no manual tuning. Six sequences:
RL-EKF run with odom0_twist_rejection_threshold: 4.03 and odom1_pose_rejection_threshold: 3.72 (chi²-equivalent to FusionCore’s thresholds at 99.9% confidence).
| Sequence | FC ATE RMSE | RL-EKF ATE RMSE | RL-UKF |
|---|---|---|---|
| 2012-01-08 | 5.6 m | 13.0 m | NaN divergence at t=31 s |
| 2012-02-04 | 9.7 m | 19.1 m | NaN divergence at t=22 s |
| 2012-03-31 | 4.2 m | 54.3 m | NaN divergence at t=18 s |
| 2012-08-20 | 7.5 m | 24.1 m | NaN divergence |
| 2012-11-04 | 28.6 m | 9.6 m | NaN divergence |
| 2013-02-23 | 4.1 m | 11.0 m | NaN divergence |
Install
Supports ROS 2 Jazzy (Ubuntu 24.04) and Humble (Ubuntu 22.04).
mkdir -p ~/ros2_ws/src && cd ~/ros2_ws/src
git clone https://github.com/manankharwar/fusioncore.git
cd ~/ros2_ws
source /opt/ros/jazzy/setup.bash # or /opt/ros/humble/setup.bash
rosdep install --from-paths src --ignore-src -r -y
colcon build && source install/setup.bash
Headless / Raspberry Pi:
touch ~/ros2_ws/src/fusioncore/fusioncore_gazebo/COLCON_IGNOREbefore building to skip the Gazebo package.
Quick start
ros2 launch fusioncore_ros fusioncore_nav2.launch.py \
fusioncore_config:=/path/to/your_robot.yaml
Documentation
manankharwar.github.io/fusioncore
- Getting Started
- Configuration reference
- Hardware configs
- Nav2 integration
- Migrating from robot_localization
- How it works
License
Apache 2.0.
Citation
@software{kharwar2026fusioncore,
author = {Kharwar, Manan},
title = {FusionCore: ROS 2 UKF Sensor Fusion},
year = {2026},
publisher = {Zenodo},
version = {0.2.0},
doi = {10.5281/zenodo.19834991},
url = {https://doi.org/10.5281/zenodo.19834991}
}
File truncated at 100 lines see the full file
CONTRIBUTING
Contributing to FusionCore
Thanks for your interest. Contributions are welcome: hardware configs, bug fixes, tests, and documentation all help.
The fastest way to contribute
The most impactful contributions right now are hardware configs. If you have FusionCore running on a robot, platform, or IMU that isn’t in the repo yet, open a PR adding a YAML under fusioncore_ros/config/. See the hardware config section below.
Before you start
- Check open issues: the bug may already be reported
- Check Discussions: the question may already be answered
- For anything bigger than a typo fix, open an issue or Discussion first so we can align before you write code
Development setup
# Clone and build
git clone https://github.com/manankharwar/fusioncore.git
cd fusioncore
source /opt/ros/jazzy/setup.sh # replace jazzy with humble on Ubuntu 22.04
rosdep install -r --from-paths . --ignore-src --rosdistro jazzy -y # replace jazzy with humble on Ubuntu 22.04
colcon build --packages-up-to compass_msgs fusioncore_core fusioncore_ros --cmake-args -DBUILD_TESTING=ON
# Run all tests before and after your change
colcon test --packages-select compass_msgs fusioncore_core fusioncore_ros
colcon test-result --verbose
All 49 tests must pass. CI will catch it if they don’t.
Hardware configs
A hardware config is a YAML file under fusioncore_ros/config/ named after the platform (e.g. clearpath_husky.yaml, ublox_f9p.yaml).
Copy fusioncore_ros/config/fusioncore.yaml as the starting point and adjust:
-
imu.gyro_noise/imu.accel_noise: pull from your IMU’s datasheet -
gnss.base_noise_xy: your GPS receiver’s CEP spec - Any topic remaps specific to your platform
Add a comment at the top with: platform name, IMU model, GPS receiver model, and whether it was field-tested or tuned from datasheet only. Field-tested configs get merged faster.
Pull request checklist
-
All 49 tests pass (
colcon test-result --verboseshows 0 failures) -
For new features: tests added in
fusioncore_core/tests/ - For hardware configs: YAML includes a comment with platform + sensor details
- Commit message describes why, not just what
Code style
C++17. Follow the style of the surrounding code: no reformatting unrelated lines. clang-format is not enforced but is appreciated.
Reporting bugs
Use the Bug Report issue template. Include the output of colcon test-result --verbose if tests are involved.
Questions
Open a Discussion rather than an issue. Issues are for bugs and tracked work; Discussions are for questions, configs, and ideas.
Response time: typically within 24 hours.