Skip to content

Commit 4b30703

Browse files
sharminramlimintar
authored andcommitted
Added ability to reset IMU filters when ROS time jumps back (#165)
1 parent cc87241 commit 4b30703

8 files changed

Lines changed: 128 additions & 0 deletions

File tree

imu_complementary_filter/include/imu_complementary_filter/complementary_filter.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ class ComplementaryFilter
8787
void update(double ax, double ay, double az, double wx, double wy,
8888
double wz, double mx, double my, double mz, double dt);
8989

90+
// Reset the filter to the initial state.
91+
void reset();
92+
9093
private:
9194
static const double kGravity;
9295
static const double gamma_;

imu_complementary_filter/include/imu_complementary_filter/complementary_filter_ros.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ class ComplementaryFilterROS : public rclcpp::Node
5757
ComplementaryFilterROS();
5858
~ComplementaryFilterROS() override;
5959

60+
// Reset the filter to the initial state.
61+
void reset();
62+
6063
private:
6164
// Convenience typedefs
6265
typedef sensor_msgs::msg::Imu ImuMsg;
@@ -86,10 +89,12 @@ class ComplementaryFilterROS : public rclcpp::Node
8689
bool publish_debug_topics_{};
8790
std::string fixed_frame_;
8891
double orientation_variance_{};
92+
rclcpp::Duration time_jump_threshold_duration_{0, 0};
8993

9094
// State variables:
9195
ComplementaryFilter filter_;
9296
rclcpp::Time time_prev_;
97+
rclcpp::Time last_ros_time_;
9398
bool initialized_filter_;
9499

95100
void initializeParams();
@@ -100,6 +105,9 @@ class ComplementaryFilterROS : public rclcpp::Node
100105

101106
tf2::Quaternion hamiltonToTFQuaternion(double q0, double q1, double q2,
102107
double q3) const;
108+
109+
// Check whether ROS time has jumped back. If so, reset the filter.
110+
void checkTimeJump();
103111
};
104112

105113
} // namespace imu_tools

imu_complementary_filter/src/complementary_filter.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,16 @@ double ComplementaryFilter::getAdaptiveGain(double alpha, double ax, double ay,
454454
return factor * alpha;
455455
}
456456

457+
void ComplementaryFilter::reset()
458+
{
459+
initialized_ = false;
460+
steady_state_ = false;
461+
q0_ = 1.0;
462+
q1_ = q2_ = q3_ = 0.0;
463+
wx_bias_ = wy_bias_ = wz_bias_ = 0.0;
464+
wx_prev_ = wy_prev_ = wz_prev_ = 0.0;
465+
}
466+
457467
void normalizeVector(double& x, double& y, double& z)
458468
{
459469
double norm = sqrt(x * x + y * y + z * z);

imu_complementary_filter/src/complementary_filter_ros.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ ComplementaryFilterROS::ComplementaryFilterROS()
4949
RCLCPP_INFO(this->get_logger(), "Starting ComplementaryFilterROS");
5050
initializeParams();
5151

52+
last_ros_time_ = this->get_clock()->now();
53+
5254
int queue_size = 5;
5355

5456
// Register publishers:
@@ -109,6 +111,7 @@ void ComplementaryFilterROS::initializeParams()
109111
double bias_alpha;
110112
bool do_adaptive_gain;
111113
double orientation_stddev;
114+
double time_jump_threshold;
112115

113116
// set "Not Dynamically Reconfigurable Parameters"
114117
auto descriptor = rcl_interfaces::msg::ParameterDescriptor();
@@ -138,6 +141,11 @@ void ComplementaryFilterROS::initializeParams()
138141
this->declare_parameter<double>("orientation_stddev", 0.0);
139142
orientation_variance_ = orientation_stddev * orientation_stddev;
140143

144+
time_jump_threshold =
145+
this->declare_parameter<double>("time_jump_threshold", 0.0);
146+
time_jump_threshold_duration_ =
147+
rclcpp::Duration::from_seconds(time_jump_threshold);
148+
141149
filter_.setDoBiasEstimation(do_bias_estimation);
142150
filter_.setDoAdaptiveGain(do_adaptive_gain);
143151

@@ -172,6 +180,8 @@ void ComplementaryFilterROS::initializeParams()
172180

173181
void ComplementaryFilterROS::imuCallback(ImuMsg::ConstSharedPtr imu_msg_raw)
174182
{
183+
checkTimeJump();
184+
175185
const geometry_msgs::msg::Vector3 &a = imu_msg_raw->linear_acceleration;
176186
const geometry_msgs::msg::Vector3 &w = imu_msg_raw->angular_velocity;
177187
const rclcpp::Time &time = imu_msg_raw->header.stamp;
@@ -203,6 +213,8 @@ void ComplementaryFilterROS::imuCallback(ImuMsg::ConstSharedPtr imu_msg_raw)
203213
void ComplementaryFilterROS::imuMagCallback(ImuMsg::ConstSharedPtr imu_msg_raw,
204214
MagMsg::ConstSharedPtr mag_msg)
205215
{
216+
checkTimeJump();
217+
206218
const geometry_msgs::msg::Vector3 &a = imu_msg_raw->linear_acceleration;
207219
const geometry_msgs::msg::Vector3 &w = imu_msg_raw->angular_velocity;
208220
const geometry_msgs::msg::Vector3 &m = mag_msg->magnetic_field;
@@ -323,4 +335,37 @@ void ComplementaryFilterROS::publish(ImuMsg::ConstSharedPtr imu_msg_raw)
323335
}
324336
}
325337

338+
void ComplementaryFilterROS::checkTimeJump()
339+
{
340+
const auto now = this->get_clock()->now();
341+
if (last_ros_time_ == rclcpp::Time(0, 0, last_ros_time_.get_clock_type()) ||
342+
last_ros_time_ <= now + time_jump_threshold_duration_)
343+
{
344+
last_ros_time_ = now;
345+
return;
346+
}
347+
348+
RCLCPP_WARN(this->get_logger(),
349+
"Detected jump back in time of %.1f s. Resetting IMU filter.",
350+
(last_ros_time_ - now).seconds());
351+
352+
if (time_jump_threshold_duration_ == rclcpp::Duration(0, 0) &&
353+
this->get_clock()->get_clock_type() == RCL_SYSTEM_TIME)
354+
{
355+
RCLCPP_INFO(this->get_logger(),
356+
"To ignore short time jumps back, use ~time_jump_threshold "
357+
"parameter of the filter.");
358+
}
359+
360+
reset();
361+
}
362+
363+
void ComplementaryFilterROS::reset()
364+
{
365+
filter_.reset();
366+
time_prev_ = rclcpp::Time(0, 0, this->get_clock()->get_clock_type());
367+
last_ros_time_ = this->get_clock()->now();
368+
initialized_filter_ = false;
369+
}
370+
326371
} // namespace imu_tools

imu_filter_madgwick/include/imu_filter_madgwick/imu_filter.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ class ImuFilter
9797
float az, float dt);
9898

9999
void getGravity(float& rx, float& ry, float& rz, float gravity = 9.80665);
100+
101+
// Reset the filter to the initial state.
102+
void reset();
100103
};
101104

102105
#endif // IMU_FILTER_MADWICK_IMU_FILTER_H

imu_filter_madgwick/include/imu_filter_madgwick/imu_filter_ros.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ class ImuFilterMadgwickRos : public imu_filter::BaseNode
5959
IMU_FILTER_MADGWICK_CPP_PUBLIC
6060
explicit ImuFilterMadgwickRos(const rclcpp::NodeOptions& options);
6161

62+
// Reset the filter to the initial state.
63+
void reset();
64+
6265
// Callbacks are public so they can be called when used as a library
6366
void imuCallback(ImuMsg::ConstSharedPtr imu_msg_raw);
6467
void imuMagCallback(ImuMsg::ConstSharedPtr imu_msg_raw,
@@ -97,11 +100,13 @@ class ImuFilterMadgwickRos : public imu_filter::BaseNode
97100
geometry_msgs::msg::Vector3 mag_bias_;
98101
double orientation_variance_;
99102
double yaw_offset_total_;
103+
rclcpp::Duration time_jump_threshold_duration_{0, 0};
100104

101105
// **** state variables
102106
std::mutex mutex_;
103107
bool initialized_;
104108
rclcpp::Time last_time_;
109+
rclcpp::Time last_ros_time_;
105110
tf2::Quaternion yaw_offsets_;
106111

107112
// **** filter implementation
@@ -120,4 +125,7 @@ class ImuFilterMadgwickRos : public imu_filter::BaseNode
120125
void checkTopicsTimerCallback();
121126

122127
void applyYawOffset(double& q0, double& q1, double& q2, double& q3);
128+
129+
// Check whether ROS time has jumped back. If so, reset the filter.
130+
void checkTimeJump();
123131
};

imu_filter_madgwick/src/imu_filter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,3 +342,8 @@ void ImuFilter::getGravity(float& rx, float& ry, float& rz, float gravity)
342342
break;
343343
}
344344
}
345+
346+
void ImuFilter::reset()
347+
{
348+
setOrientation(1, 0, 0, 0);
349+
}

imu_filter_madgwick/src/imu_filter_ros.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ ImuFilterMadgwickRos::ImuFilterMadgwickRos(const rclcpp::NodeOptions &options)
6363
declare_parameter("publish_debug_topics", false, descriptor);
6464
get_parameter("publish_debug_topics", publish_debug_topics_);
6565

66+
double time_jump_threshold = 0.0;
67+
declare_parameter("time_jump_threshold", 0.0, descriptor);
68+
get_parameter("time_jump_threshold", time_jump_threshold);
69+
time_jump_threshold_duration_ =
70+
rclcpp::Duration::from_seconds(time_jump_threshold);
71+
6672
double yaw_offset = 0.0;
6773
declare_parameter("yaw_offset", 0.0, descriptor);
6874
get_parameter("yaw_offset", yaw_offset);
@@ -130,6 +136,8 @@ ImuFilterMadgwickRos::ImuFilterMadgwickRos(const rclcpp::NodeOptions &options)
130136
"The gravity vector is kept in the IMU message.");
131137
}
132138

139+
last_ros_time_ = this->get_clock()->now();
140+
133141
// **** define reconfigurable parameters.
134142
double gain;
135143
floating_point_range float_range = {0.0, 1.0, 0};
@@ -226,6 +234,8 @@ ImuFilterMadgwickRos::ImuFilterMadgwickRos(const rclcpp::NodeOptions &options)
226234

227235
void ImuFilterMadgwickRos::imuCallback(ImuMsg::ConstSharedPtr imu_msg_raw)
228236
{
237+
checkTimeJump();
238+
229239
std::lock_guard<std::mutex> lock(mutex_);
230240

231241
const geometry_msgs::msg::Vector3 &ang_vel = imu_msg_raw->angular_velocity;
@@ -291,6 +301,8 @@ void ImuFilterMadgwickRos::imuCallback(ImuMsg::ConstSharedPtr imu_msg_raw)
291301
void ImuFilterMadgwickRos::imuMagCallback(ImuMsg::ConstSharedPtr imu_msg_raw,
292302
MagMsg::ConstSharedPtr mag_msg)
293303
{
304+
checkTimeJump();
305+
294306
std::lock_guard<std::mutex> lock(mutex_);
295307

296308
const geometry_msgs::msg::Vector3 &ang_vel = imu_msg_raw->angular_velocity;
@@ -582,6 +594,40 @@ void ImuFilterMadgwickRos::checkTopicsTimerCallback()
582594
<< "...");
583595
}
584596

597+
void ImuFilterMadgwickRos::checkTimeJump()
598+
{
599+
const auto now = this->get_clock()->now();
600+
if (last_ros_time_ == rclcpp::Time(0, 0, last_ros_time_.get_clock_type()) ||
601+
last_ros_time_ <= now + time_jump_threshold_duration_)
602+
{
603+
last_ros_time_ = now;
604+
return;
605+
}
606+
607+
RCLCPP_WARN(this->get_logger(),
608+
"Detected jump back in time of %.1f s. Resetting IMU filter.",
609+
(last_ros_time_ - now).seconds());
610+
611+
if (time_jump_threshold_duration_ == rclcpp::Duration(0, 0) &&
612+
this->get_clock()->get_clock_type() == RCL_SYSTEM_TIME)
613+
{
614+
RCLCPP_INFO(this->get_logger(),
615+
"To ignore short time jumps back, use ~time_jump_threshold "
616+
"parameter of the filter.");
617+
}
618+
619+
reset();
620+
}
621+
622+
void ImuFilterMadgwickRos::reset()
623+
{
624+
std::lock_guard<std::mutex> lock(mutex_);
625+
filter_.reset();
626+
initialized_ = false;
627+
last_time_ = rclcpp::Time(0, 0, this->get_clock()->get_clock_type());
628+
last_ros_time_ = this->get_clock()->now();
629+
}
630+
585631
#include "rclcpp_components/register_node_macro.hpp"
586632

587633
RCLCPP_COMPONENTS_REGISTER_NODE(ImuFilterMadgwickRos)

0 commit comments

Comments
 (0)