From de4b389f43044e5c13a2cccc5b73635fc81a820a Mon Sep 17 00:00:00 2001
From: Daniil Mordanov <153565951+Daniiiil1@users.noreply.github.com>
Date: Sun, 9 Aug 2026 20:18:19 +0700
Subject: [PATCH] Fix quaternion interpolation threshold
---
imu_complementary_filter/CMakeLists.txt | 7 +++
imu_complementary_filter/package.xml | 1 +
.../src/complementary_filter.cpp | 3 +-
.../test/complementary_filter_test.cpp | 54 +++++++++++++++++++
4 files changed, 64 insertions(+), 1 deletion(-)
create mode 100644 imu_complementary_filter/test/complementary_filter_test.cpp
diff --git a/imu_complementary_filter/CMakeLists.txt b/imu_complementary_filter/CMakeLists.txt
index 83620724..19d1e65f 100644
--- a/imu_complementary_filter/CMakeLists.txt
+++ b/imu_complementary_filter/CMakeLists.txt
@@ -71,6 +71,13 @@ install(DIRECTORY launch config
DESTINATION share/${PROJECT_NAME}
)
+if(BUILD_TESTING)
+ find_package(ament_cmake_gtest REQUIRED)
+ ament_add_gtest(complementary_filter_test
+ test/complementary_filter_test.cpp)
+ target_link_libraries(complementary_filter_test complementary_filter)
+endif()
+
ament_export_include_directories(include)
ament_export_libraries(complementary_filter)
ament_export_targets(
diff --git a/imu_complementary_filter/package.xml b/imu_complementary_filter/package.xml
index faf71180..d1f9c183 100644
--- a/imu_complementary_filter/package.xml
+++ b/imu_complementary_filter/package.xml
@@ -18,6 +18,7 @@
std_msgs
tf2
tf2_ros
+ ament_cmake_gtest
ament_cmake
diff --git a/imu_complementary_filter/src/complementary_filter.cpp b/imu_complementary_filter/src/complementary_filter.cpp
index e44525ea..3c4a6d81 100644
--- a/imu_complementary_filter/src/complementary_filter.cpp
+++ b/imu_complementary_filter/src/complementary_filter.cpp
@@ -496,7 +496,8 @@ void invertQuaternion(double q0, double q1, double q2, double q3,
void scaleQuaternion(double gain, double& dq0, double& dq1, double& dq2,
double& dq3)
{
- if (dq0 < 0.0) // 0.9
+ constexpr double interpolation_threshold = 0.9;
+ if (dq0 <= interpolation_threshold)
{
// Slerp (Spherical linear interpolation):
double angle = acos(dq0);
diff --git a/imu_complementary_filter/test/complementary_filter_test.cpp b/imu_complementary_filter/test/complementary_filter_test.cpp
new file mode 100644
index 00000000..fc54f44e
--- /dev/null
+++ b/imu_complementary_filter/test/complementary_filter_test.cpp
@@ -0,0 +1,54 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include
+
+#include
+
+#include "imu_complementary_filter/complementary_filter.h"
+
+namespace {
+
+constexpr double kTolerance = 1e-12;
+constexpr double kGain = 0.25;
+
+TEST(ScaleQuaternion, UsesSlerpForLargeCorrections)
+{
+ double q0 = 0.8;
+ double q1 = 0.6;
+ double q2 = 0.0;
+ double q3 = 0.0;
+
+ const double angle = std::acos(q0);
+ const double expected_q0 = std::cos(kGain * angle);
+ const double expected_q1 = std::sin(kGain * angle);
+
+ imu_tools::scaleQuaternion(kGain, q0, q1, q2, q3);
+
+ EXPECT_NEAR(q0, expected_q0, kTolerance);
+ EXPECT_NEAR(q1, expected_q1, kTolerance);
+ EXPECT_DOUBLE_EQ(q2, 0.0);
+ EXPECT_DOUBLE_EQ(q3, 0.0);
+}
+
+TEST(ScaleQuaternion, UsesNormalizedLerpForSmallCorrections)
+{
+ double q0 = 0.95;
+ double q1 = std::sqrt(1.0 - q0 * q0);
+ double q2 = 0.0;
+ double q3 = 0.0;
+
+ const double lerp_q0 = (1.0 - kGain) + kGain * q0;
+ const double lerp_q1 = kGain * q1;
+ const double norm = std::hypot(lerp_q0, lerp_q1);
+
+ imu_tools::scaleQuaternion(kGain, q0, q1, q2, q3);
+
+ EXPECT_NEAR(q0, lerp_q0 / norm, kTolerance);
+ EXPECT_NEAR(q1, lerp_q1 / norm, kTolerance);
+ EXPECT_DOUBLE_EQ(q2, 0.0);
+ EXPECT_DOUBLE_EQ(q3, 0.0);
+}
+
+} // namespace